# HG changeset patch # User Marcin Kuzminski # Date 2016-05-24 13:56:53 # Node ID 854a839ae1b4ddeff04ec8c43cc85d3c53446e38 # Parent 548fc4fc459107401620016c6f52791ece3d5bc0 project: added all source files and assets diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,5 @@ +[bumpversion] +current_version = 4.0.0 +message = release: Bump version {current_version} to {new_version} + +[bumpversion:file:rhodecode/VERSION] diff --git a/.coveragerc b/.coveragerc new file mode 100644 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,18 @@ +[run] + +branch = True + +include = + rhodecode/lib/* + rhodecode/model/* + rhodecode/controllers/* + +omit = + rhodecode/lib/vcs/remote/* + rhodecode/lib/dbmigrate/* + +[report] + +exclude_lines = + raise NotImplementedError + diff --git a/.jshintrc b/.jshintrc new file mode 100644 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,38 @@ +{ + /* + * ENVIRONMENTS + * ================= + */ + + // Define globals exposed by modern browsers. + "browser": true, + + // Define globals exposed by jQuery. + "jquery": true, + + /* + * ENFORCING OPTIONS + * ================= + */ + + // Prohibit use of == and != in favor of === and !==. + "eqeqeq": true, + + // Enforce tab width of 2 spaces. + "indent": 2, + + // Prohibit use of a variable before it is defined. + "latedef": true, + + // Enforce line length to 100 characters + "maxlen": 100, + + // Require capitalized names for constructor functions. + "newcap": true, + + // Enforce placing 'use strict' at the top function scope + "strict": true, + + // Prohibit use of explicitly undeclared variables. + "undef": true +} diff --git a/.release.cfg b/.release.cfg new file mode 100644 --- /dev/null +++ b/.release.cfg @@ -0,0 +1,31 @@ +[DEFAULT] +done = false + +[task:fixes_on_stable] +done = true + +[task:changelog_updated] +done = true + +[task:nix_dependencies_moved] +done = true + +[task:bump_version] +done = true + +[task:generate_js_routes] +done = true + +[task:generate_api_docs] +done = true + +[release] +state = prepared +version = 3.8.3 + +[task:updated_translation] + +[task:updated_trial_license] + +[task:generate_oss_licenses] + diff --git a/.tx/config b/.tx/config new file mode 100644 --- /dev/null +++ b/.tx/config @@ -0,0 +1,18 @@ +[main] +host = https://www.transifex.com + +[RhodeCode.pot] +source_file = rhodecode/i18n/rhodecode.pot +source_lang = en +type = PO + +trans.be = rhodecode/i18n/be/LC_MESSAGES/rhodecode.po +trans.de = rhodecode/i18n/de/LC_MESSAGES/rhodecode.po +trans.es = rhodecode/i18n/es/LC_MESSAGES/rhodecode.po +trans.fr = rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po +trans.it = rhodecode/i18n/it/LC_MESSAGES/rhodecode.po +trans.ja = rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po +trans.pl = rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po +trans.pt = rhodecode/i18n/pt/LC_MESSAGES/rhodecode.po +trans.ru = rhodecode/i18n/ru/LC_MESSAGES/rhodecode.po +trans.zh = rhodecode/i18n/zh/LC_MESSAGES/rhodecode.po diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,1 @@ +.. include:: docs/release-notes/release-notes.rst \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,137 @@ +module.exports = function(grunt) { + grunt.initConfig({ + + dirs: { + css: "rhodecode/public/css", + js: { + "src": "rhodecode/public/js/src", + "dest": "rhodecode/public/js" + } + }, + + concat: { + dist: { + src: [ + // Base libraries + '<%= dirs.js.src %>/jquery-1.11.1.min.js', + '<%= dirs.js.src %>/logging.js', + '<%= dirs.js.src %>/bootstrap.js', + '<%= dirs.js.src %>/mousetrap.js', + '<%= dirs.js.src %>/moment.js', + '<%= dirs.js.src %>/appenlight-client-0.4.1.min.js', + + // Plugins + '<%= dirs.js.src %>/plugins/jquery.pjax.js', + '<%= dirs.js.src %>/plugins/jquery.dataTables.js', + '<%= dirs.js.src %>/plugins/flavoured_checkbox.js', + '<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js', + '<%= dirs.js.src %>/plugins/jquery.autocomplete.js', + '<%= dirs.js.src %>/plugins/jquery.debounce.js', + '<%= dirs.js.src %>/plugins/jquery.timeago.js', + '<%= dirs.js.src %>/plugins/jquery.timeago-extension.js', + + // Select2 + '<%= dirs.js.src %>/select2/select2.js', + + // Code-mirror + '<%= dirs.js.src %>/codemirror/codemirror.js', + '<%= dirs.js.src %>/codemirror/codemirror_loadmode.js', + '<%= dirs.js.src %>/codemirror/codemirror_hint.js', + '<%= dirs.js.src %>/codemirror/codemirror_overlay.js', + '<%= dirs.js.src %>/codemirror/codemirror_placeholder.js', + // TODO: mikhail: this is an exception. Since the code mirror modes + // are loaded "on the fly", we need to keep them in a public folder + '<%= dirs.js.dest %>/mode/meta.js', + '<%= dirs.js.dest %>/mode/meta_ext.js', + '<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js', + + // Rhodecode utilities + '<%= dirs.js.src %>/rhodecode/utils/array.js', + '<%= dirs.js.src %>/rhodecode/utils/string.js', + '<%= dirs.js.src %>/rhodecode/utils/pyroutes.js', + '<%= dirs.js.src %>/rhodecode/utils/ajax.js', + '<%= dirs.js.src %>/rhodecode/utils/autocomplete.js', + '<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js', + '<%= dirs.js.src %>/rhodecode/utils/ie.js', + '<%= dirs.js.src %>/rhodecode/utils/os.js', + + // Rhodecode widgets + '<%= dirs.js.src %>/rhodecode/widgets/multiselect.js', + + // Rhodecode components + '<%= dirs.js.src %>/rhodecode/pyroutes.js', + '<%= dirs.js.src %>/rhodecode/codemirror.js', + '<%= dirs.js.src %>/rhodecode/comments.js', + '<%= dirs.js.src %>/rhodecode/constants.js', + '<%= dirs.js.src %>/rhodecode/files.js', + '<%= dirs.js.src %>/rhodecode/followers.js', + '<%= dirs.js.src %>/rhodecode/menus.js', + '<%= dirs.js.src %>/rhodecode/notifications.js', + '<%= dirs.js.src %>/rhodecode/permissions.js', + '<%= dirs.js.src %>/rhodecode/pjax.js', + '<%= dirs.js.src %>/rhodecode/pullrequests.js', + '<%= dirs.js.src %>/rhodecode/settings.js', + '<%= dirs.js.src %>/rhodecode/select2_widgets.js', + '<%= dirs.js.src %>/rhodecode/tooltips.js', + '<%= dirs.js.src %>/rhodecode/users.js', + '<%= dirs.js.src %>/rhodecode/appenlight.js', + + // Rhodecode main module + '<%= dirs.js.src %>/rhodecode.js' + ], + dest: '<%= dirs.js.dest %>/scripts.js', + nonull: true + } + }, + + less: { + development: { + options: { + compress: false, + yuicompress: false, + optimization: 0 + }, + files: { + "<%= dirs.css %>/style.css": "<%= dirs.css %>/main.less" + } + }, + production: { + options: { + compress: true, + yuicompress: true, + optimization: 2 + }, + files: { + "<%= dirs.css %>/style.css": "<%= dirs.css %>/main.less" + } + } + }, + + watch: { + less: { + files: ["<%= dirs.css %>/*.less"], + tasks: ["less:production"] + }, + js: { + files: ["<%= dirs.js.src %>/**/*.js"], + tasks: ["concat:dist"] + } + }, + + jshint: { + rhodecode: { + src: '<%= dirs.js.src %>/rhodecode/**/*.js', + options: { + jshintrc: '.jshintrc' + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + + grunt.registerTask('default', ['less:production', 'concat:dist']); +}; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,690 @@ +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License, version 3 +(only), as published by the Free Software Foundation. + + +This program incorporates work covered by the following copyright and +permission notice: + + Copyright (c) 2014-2016 - packaging + file: + Copyright (c) 2008-2011 - msgpack-python + file:licenses/msgpack_license.txt + +Both licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +imitations under the License. + + +Below is the full text of GNU Affero General Public License, version 3 + + + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,48 @@ +# top level files +include test.ini +include MANIFEST.in +include README.rst +include rhodecode/VERSION + +# docs +recursive-include docs * + +# init.d +recursive-include init.d * + +# translations +recursive-include rhodecode/i18n * + +# bin stuff +recursive-include rhodecode/bin * + +# hook templates +recursive-include rhodecode/config/hook_templates * + +# non-python core stuff +recursive-include rhodecode *.cfg +recursive-include rhodecode *.json +recursive-include rhodecode *.ini_tmpl +recursive-include rhodecode *.sh + +# images, css +include rhodecode/public/css/*.css +include rhodecode/public/images/*.* + +# sound files +include rhodecode/public/sounds/*.mp3 +include rhodecode/public/sounds/*.wav + +# fonts +recursive-include rhodecode/public/fonts/ProximaNova * +recursive-include rhodecode/public/fonts/RCIcons * + +# js +recursive-include rhodecode/public/js * + +# templates +recursive-include rhodecode/templates * + +# skip any tests files +recursive-exclude rhodecode/tests * + diff --git a/Makefile b/Makefile new file mode 100644 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ + +WEBPACK=./node_modules/webpack/bin/webpack.js +GRUNT=grunt +NODE_PATH=./node_modules +FLAKE8=flake8 setup.py pytest_pylons/ rhodecode/ --select=E124 --ignore=E711,E712,E510,E121,E122,E126,E127,E128,E501,F401 --max-line-length=100 --exclude=*rhodecode/lib/dbmigrate/*,*rhodecode/tests/*,*rhodecode/lib/vcs/utils/* +CI_PREFIX=enterprise + +.PHONY: help clean test test-clean test-lint test-only + +help: + @echo "TODO: describe Makefile" + +clean: test-clean + find . -type f \( -iname '*.c' -o -iname '*.pyc' -o -iname '*.so' \) -exec rm '{}' ';' + +test: test-clean test-lint test-only + +test-clean: + rm -rf coverage.xml htmlcov junit.xml pylint.log result + +test-lint: + if [ "$$IN_NIX_SHELL" = "1" ]; then \ + $(FLAKE8); \ + else \ + $(FLAKE8) --format=pylint --exit-zero > pylint.log; \ + fi + +test-only: + PYTHONHASHSEED=random py.test -vv -r xw --cov=rhodecode --cov-report=term-missing --cov-report=html rhodecode/tests/ + +web-build: + NODE_PATH=$(NODE_PATH) $(GRUNT) + +web-test: + @echo "no test for our javascript, yet!" + +docs-bootstrap: + (cd docs; nix-build default.nix -o result) + @echo "Please go to docs folder and run make html" diff --git a/README.rst b/README.rst new file mode 100644 --- /dev/null +++ b/README.rst @@ -0,0 +1,101 @@ +========= +RhodeCode +========= + +About +----- + +``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_ +and Subversion_ with a built in push/pull server, full text search, +pull requests and powerfull code-review system. It works on http/https and +has a few unique features like: + - plugable architecture + - advanced permission system with IP restrictions + - rich set of authentication plugins including LDAP, + ActiveDirectory, Atlassian Crowd, Http-Headers, Pam, Token-Auth. + - live code-review chat + - full web based file editing + - unified multi vcs support + - snippets (gist) system + - integration with all 3rd party issue trackers + +RhodeCode also provides rich API, and multiple event hooks so it's easy +integrable with existing external systems. + +RhodeCode is similar in some respects to gitlab_, github_ or bitbucket_, +however RhodeCode can be run as standalone hosted application on your own server. +RhodeCode can be installed on \*nix or Windows systems. + +RhodeCode uses `PEP386 versioning `_ + +Installation +------------ +Please visit https://docs.rhodecode.com/RhodeCode-Control/tasks/install-cli.html +for more details + + +Source code +----------- + +The latest sources can be obtained from official RhodeCode instance +https://code.rhodecode.com + + +RhodeCode Features +------------------ + +Check out all features of RhodeCode at https://rhodecode.com/features + +License +------- + +``RhodeCode`` is dual-licensed with AGPLv3 and commercial license. +Please see LICENSE.txt file for details. + + +Getting help +------------ + +Listed bellow are various support resources that should help. + +.. note:: + + Please try to read the documentation before posting any issues, especially + the **troubleshooting section** + +- Official issue tracker `RhodeCode Issue tracker `_ + +- Search our community portal `Community portal `_ + +- Join #rhodecode on FreeNode (irc.freenode.net) + or use http://webchat.freenode.net/?channels=rhodecode for web access to irc. + +- You can also follow RhodeCode on twitter **@RhodeCode** where we often post + news and other interesting stuff about RhodeCode. + + +Online documentation +-------------------- + +Online documentation for the current version of RhodeCode is available at + - http://rhodecode.com/docs + +You may also build the documentation for yourself - go into ``docs/`` and run:: + + nix-build default.nix -o result && make clean html + +(You need to have sphinx_ installed to build the documentation. If you don't +have sphinx_ installed you can install it via the command: +``pip install sphinx``) + +.. _virtualenv: http://pypi.python.org/pypi/virtualenv +.. _python: http://www.python.org/ +.. _sphinx: http://sphinx.pocoo.org/ +.. _mercurial: http://mercurial.selenic.com/ +.. _bitbucket: http://bitbucket.org/ +.. _github: http://github.com/ +.. _gitlab: http://gitlab.com/ +.. _subversion: http://subversion.tigris.org/ +.. _git: http://git-scm.com/ +.. _celery: http://celeryproject.org/ +.. _vcs: http://pypi.python.org/pypi/vcs diff --git a/acceptance_tests/README.rst b/acceptance_tests/README.rst new file mode 100644 --- /dev/null +++ b/acceptance_tests/README.rst @@ -0,0 +1,47 @@ +README - Quickstart +=================== + +This folder contains functional tests and the automation of specification +examples. Details about testing can be found in +`/docs-internal/testing/index.rst`. + + +Setting up your Rhodecode Enterprise instance +--------------------------------------------- + +The tests will create users and repositories as needed, so you can start with a +new and empty instance. + +Use the following example call for the database setup of Enterprise:: + + paster setup-rhodecode \ + --user=admin \ + --email=admin@example.com \ + --password=secret \ + --api-key=9999999999999999999999999999999999999999 \ + your-enterprise-config.ini + +This way the username, password and auth token of the admin user will match the +defaults from the test run. + + +Usage +----- + +1. Make sure your Rhodecode Enterprise instance is running at + http://localhost:5000. + +2. Enter `nix-shell` from the acceptance_tests folder:: + + cd acceptance_tests + nix-shell -I ~/dev + + Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path. + +3. Run the tests:: + + py.test -c example.ini -vs + + The parameter ``-vs`` allows you to see debugging output during the test + run. Check ``py.test --help`` and the documentation at http://pytest.org to + learn all details about the test runner. diff --git a/configs/development.ini b/configs/development.ini new file mode 100644 --- /dev/null +++ b/configs/development.ini @@ -0,0 +1,575 @@ +################################################################################ +################################################################################ +# RhodeCode Enterprise - configuration file # +# Built-in functions and variables # +# The %(here)s variable will be replaced with the parent directory of this file# +# # +################################################################################ + +[DEFAULT] +debug = true +pdebug = false +################################################################################ +## Uncomment and replace with the email address which should receive ## +## any error reports after an application crash ## +## Additionally these settings will be used by the RhodeCode mailing system ## +################################################################################ +#email_to = admin@localhost +#error_email_from = paste_error@localhost +#app_email_from = rhodecode-noreply@localhost +#error_message = +#email_prefix = [RhodeCode] + +#smtp_server = mail.server.com +#smtp_username = +#smtp_password = +#smtp_port = +#smtp_use_tls = false +#smtp_use_ssl = true +## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.) +#smtp_auth = + +[server:main] +## COMMON ## +host = 127.0.0.1 +port = 5000 + +########################## +## WAITRESS WSGI SERVER ## +########################## +use = egg:waitress#main +## number of worker threads +threads = 5 +## MAX BODY SIZE 100GB +max_request_body_size = 107374182400 +## Use poll instead of select, fixes file descriptors limits problems. +## May not work on old windows systems. +asyncore_use_poll = true + + +########################## +## GUNICORN WSGI SERVER ## +########################## +## run with gunicorn --log-config --paste +#use = egg:gunicorn#main +## Sets the number of process workers. You must set `instance_id = *` +## when this option is set to more than one worker, recommended +## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers +## The `instance_id = *` must be set in the [app:main] section below +#workers = 1 +## number of threads for each of the worker, must be set to 1 for gevent +## generally recommened to be at 1 +#threads = 1 +## process name +#proc_name = rhodecode +## type of worker class, one of sync, gevent +## recommended for bigger setup is using of of other than sync one +#worker_class = sync +## max number of requests that worker will handle before being gracefully +## restarted, could prevent memory leaks +#max_requests = 1000 +#max_requests_jitter = 30 +## ammount of time a worker can spend with handling a request before it +## gets killed and restarted. Set to 6hrs +#timeout = 21600 + + +## prefix middleware for RhodeCode, disables force_https flag. +## allows to set RhodeCode under a prefix in server. +## eg https://server.com/. Enable `filter-with =` option below as well. +#[filter:proxy-prefix] +#use = egg:PasteDeploy#prefix +#prefix = / + +[app:main] +use = egg:rhodecode-enterprise-ce +## enable proxy prefix middleware, defined below +#filter-with = proxy-prefix + +# During development the we want to have the debug toolbar enabled +pyramid.includes = + pyramid_debugtoolbar + rhodecode.utils.debugtoolbar + rhodecode.lib.middleware.request_wrapper + +pyramid.reload_templates = true + +debugtoolbar.hosts = 0.0.0.0/0 +debugtoolbar.exclude_prefixes = + /css + /fonts + /images + /js + +## RHODECODE PLUGINS ## +rhodecode.includes = + rhodecode.api + + +# api prefix url +rhodecode.api.url = /_admin/api + + +## END RHODECODE PLUGINS ## + +full_stack = true + +## Serve static files via RhodeCode, disable to serve them via HTTP server +static_files = true + +## Optional Languages +## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh +lang = en + +## perform a full repository scan on each server start, this should be +## set to false after first startup, to allow faster server restarts. +startup.import_repos = false + +## Uncomment and set this path to use archive download cache. +## Once enabled, generated archives will be cached at this location +## and served from the cache during subsequent requests for the same archive of +## the repository. +#archive_cache_dir = /tmp/tarballcache + +## change this to unique ID for security +app_instance_uuid = rc-production + +## cut off limit for large diffs (size in bytes) +cut_off_limit_diff = 1024000 +cut_off_limit_file = 256000 + +## use cache version of scm repo everywhere +vcs_full_cache = true + +## force https in RhodeCode, fixes https redirects, assumes it's always https +## Normally this is controlled by proper http flags sent from http server +force_https = false + +## use Strict-Transport-Security headers +use_htsts = false + +## number of commits stats will parse on each iteration +commit_parse_limit = 25 + +## git rev filter option, --all is the default filter, if you need to +## hide all refs in changelog switch this to --branches --tags +git_rev_filter = --branches --tags + +# Set to true if your repos are exposed using the dumb protocol +git_update_server_info = false + +## RSS/ATOM feed options +rss_cut_off_limit = 256000 +rss_items_per_page = 10 +rss_include_diff = false + +## gist URL alias, used to create nicer urls for gist. This should be an +## url that does rewrites to _admin/gists/. +## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal +## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/ +gist_alias_url = + +## List of controllers (using glob pattern syntax) that AUTH TOKENS could be +## used for access. +## Adding ?auth_token = to the url authenticates this request as if it +## came from the the logged in user who own this authentication token. +## +## Syntax is :. +## To enable access to raw_files put `FilesController:raw`. +## To enable access to patches add `ChangesetController:changeset_patch`. +## The list should be "," separated and on a single line. +## +## Recommended controllers to enable: +# ChangesetController:changeset_patch, +# ChangesetController:changeset_raw, +# FilesController:raw, +# FilesController:archivefile, +# GistsController:*, +api_access_controllers_whitelist = + +## default encoding used to convert from and to unicode +## can be also a comma separated list of encoding in case of mixed encodings +default_encoding = UTF-8 + +## instance-id prefix +## a prefix key for this instance used for cache invalidation when running +## multiple instances of rhodecode, make sure it's globally unique for +## all running rhodecode instances. Leave empty if you don't use it +instance_id = + +## alternative return HTTP header for failed authentication. Default HTTP +## response is 401 HTTPUnauthorized. Currently HG clients have troubles with +## handling that causing a series of failed authentication calls. +## Set this variable to 403 to return HTTPForbidden, or any other HTTP code +## This will be served instead of default 401 on bad authnetication +auth_ret_code = + +## use special detection method when serving auth_ret_code, instead of serving +## ret_code directly, use 401 initially (Which triggers credentials prompt) +## and then serve auth_ret_code to clients +auth_ret_code_detection = false + +## locking return code. When repository is locked return this HTTP code. 2XX +## codes don't break the transactions while 4XX codes do +lock_ret_code = 423 + +## allows to change the repository location in settings page +allow_repo_location_change = true + +## allows to setup custom hooks in settings page +allow_custom_hooks_settings = true + +## generated license token, goto license page in RhodeCode settings to obtain +## new token +license_token = + +## supervisor connection uri, for managing supervisor and logs. +supervisor.uri = +## supervisord group name/id we only want this RC instance to handle +supervisor.group_id = dev + +## Display extended labs settings +labs_settings_active = true + +#################################### +### CELERY CONFIG #### +#################################### +use_celery = false +broker.host = localhost +broker.vhost = rabbitmqhost +broker.port = 5672 +broker.user = rabbitmq +broker.password = qweqwe + +celery.imports = rhodecode.lib.celerylib.tasks + +celery.result.backend = amqp +celery.result.dburi = amqp:// +celery.result.serialier = json + +#celery.send.task.error.emails = true +#celery.amqp.task.result.expires = 18000 + +celeryd.concurrency = 2 +#celeryd.log.file = celeryd.log +celeryd.log.level = debug +celeryd.max.tasks.per.child = 1 + +## tasks will never be sent to the queue, but executed locally instead. +celery.always.eager = false + +#################################### +### BEAKER CACHE #### +#################################### +# default cache dir for templates. Putting this into a ramdisk +## can boost performance, eg. %(here)s/data_ramdisk +cache_dir = %(here)s/data + +## locking and default file storage for Beaker. Putting this into a ramdisk +## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data +beaker.cache.data_dir = %(here)s/data/cache/beaker_data +beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock + +beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long + +beaker.cache.super_short_term.type = memory +beaker.cache.super_short_term.expire = 10 +beaker.cache.super_short_term.key_length = 256 + +beaker.cache.short_term.type = memory +beaker.cache.short_term.expire = 60 +beaker.cache.short_term.key_length = 256 + +beaker.cache.long_term.type = memory +beaker.cache.long_term.expire = 36000 +beaker.cache.long_term.key_length = 256 + +beaker.cache.sql_cache_short.type = memory +beaker.cache.sql_cache_short.expire = 10 +beaker.cache.sql_cache_short.key_length = 256 + +# default is memory cache, configure only if required +# using multi-node or multi-worker setup +#beaker.cache.auth_plugins.type = ext:database +#beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock +#beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode +#beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode +#beaker.cache.auth_plugins.sa.pool_recycle = 3600 +#beaker.cache.auth_plugins.sa.pool_size = 10 +#beaker.cache.auth_plugins.sa.max_overflow = 0 + +beaker.cache.repo_cache_long.type = memorylru_base +beaker.cache.repo_cache_long.max_items = 4096 +beaker.cache.repo_cache_long.expire = 2592000 + +# default is memorylru_base cache, configure only if required +# using multi-node or multi-worker setup +#beaker.cache.repo_cache_long.type = ext:memcached +#beaker.cache.repo_cache_long.url = localhost:11211 +#beaker.cache.repo_cache_long.expire = 1209600 +#beaker.cache.repo_cache_long.key_length = 256 + +#################################### +### BEAKER SESSION #### +#################################### + +## .session.type is type of storage options for the session, current allowed +## types are file, ext:memcached, ext:database, and memory(default). +beaker.session.type = file +beaker.session.data_dir = %(here)s/data/sessions/data + +## db based session, fast, and allows easy management over logged in users ## +#beaker.session.type = ext:database +#beaker.session.table_name = db_session +#beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode +#beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode +#beaker.session.sa.pool_recycle = 3600 +#beaker.session.sa.echo = false + +beaker.session.key = rhodecode +beaker.session.secret = develop-rc-uytcxaz +beaker.session.lock_dir = %(here)s/data/sessions/lock + +## Secure encrypted cookie. Requires AES and AES python libraries +## you must disable beaker.session.secret to use this +#beaker.session.encrypt_key = +#beaker.session.validate_key = + +## sets session as invalid(also logging out user) if it haven not been +## accessed for given amount of time in seconds +beaker.session.timeout = 2592000 +beaker.session.httponly = true +#beaker.session.cookie_path = / + +## uncomment for https secure cookie +beaker.session.secure = false + +## auto save the session to not to use .save() +beaker.session.auto = false + +## default cookie expiration time in seconds, set to `true` to set expire +## at browser close +#beaker.session.cookie_expires = 3600 + +################################### +## SEARCH INDEXING CONFIGURATION ## +################################### + +search.module = rhodecode.lib.index.whoosh +search.location = %(here)s/data/index + +################################### +## ERROR AND LOG HANDLING SYSTEM ## +################################### + +## Appenlight is tailored to work with RhodeCode, see +## http://appenlight.com for details how to obtain an account + +## appenlight integration enabled +appenlight = false + +appenlight.server_url = https://api.appenlight.com +appenlight.api_key = YOUR_API_KEY +;appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5 + +# used for JS client +appenlight.api_public_key = YOUR_API_PUBLIC_KEY + +## TWEAK AMOUNT OF INFO SENT HERE + +## enables 404 error logging (default False) +appenlight.report_404 = false + +## time in seconds after request is considered being slow (default 1) +appenlight.slow_request_time = 1 + +## record slow requests in application +## (needs to be enabled for slow datastore recording and time tracking) +appenlight.slow_requests = true + +## enable hooking to application loggers +appenlight.logging = true + +## minimum log level for log capture +appenlight.logging.level = WARNING + +## send logs only from erroneous/slow requests +## (saves API quota for intensive logging) +appenlight.logging_on_error = false + +## list of additonal keywords that should be grabbed from environ object +## can be string with comma separated list of words in lowercase +## (by default client will always send following info: +## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that +## start with HTTP* this list be extended with additional keywords here +appenlight.environ_keys_whitelist = + +## list of keywords that should be blanked from request object +## can be string with comma separated list of words in lowercase +## (by default client will always blank keys that contain following words +## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf' +## this list be extended with additional keywords set here +appenlight.request_keys_blacklist = + +## list of namespaces that should be ignores when gathering log entries +## can be string with comma separated list of namespaces +## (by default the client ignores own entries: appenlight_client.client) +appenlight.log_namespace_blacklist = + + +################################################################################ +## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## +## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## +## execute malicious code after an exception is raised. ## +################################################################################ +#set debug = false + + +############## +## STYLING ## +############## +debug_style = true + +######################################################### +### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### +######################################################### +sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30 +#sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode +#sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode + +# see sqlalchemy docs for other advanced settings + +## print the sql statements to output +sqlalchemy.db1.echo = false +## recycle the connections after this ammount of seconds +sqlalchemy.db1.pool_recycle = 3600 +sqlalchemy.db1.convert_unicode = true + +## the number of connections to keep open inside the connection pool. +## 0 indicates no limit +#sqlalchemy.db1.pool_size = 5 + +## the number of connections to allow in connection pool "overflow", that is +## connections that can be opened above and beyond the pool_size setting, +## which defaults to five. +#sqlalchemy.db1.max_overflow = 10 + + +################## +### VCS CONFIG ### +################## +vcs.server.enable = true +vcs.server = localhost:9900 +# Available protocols: pyro4, http +vcs.server.protocol = pyro4 + +# available impl: +# vcsserver.scm_app (EE only, for testing), +# rhodecode.lib.middleware.utils.scm_app_http +# pyro4 +#vcs.scm_app_implementation = rhodecode.lib.middleware.utils.scm_app_http + +vcs.server.log_level = debug +vcs.start_server = true +vcs.backends = hg, git, svn +vcs.connection_timeout = 3600 +## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. +## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible +#vcs.svn.compatible_version = pre-1.8-compatible + +################################ +### LOGGING CONFIGURATION #### +################################ +[loggers] +keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer + +[handlers] +keys = console, console_sql + +[formatters] +keys = generic, color_formatter, color_formatter_sql + +############# +## LOGGERS ## +############# +[logger_root] +level = NOTSET +handlers = console + +[logger_routes] +level = DEBUG +handlers = +qualname = routes.middleware +## "level = DEBUG" logs the route matched and routing variables. +propagate = 1 + +[logger_beaker] +level = DEBUG +handlers = +qualname = beaker.container +propagate = 1 + +[logger_pyro4] +level = DEBUG +handlers = +qualname = Pyro4 +propagate = 1 + +[logger_templates] +level = INFO +handlers = +qualname = pylons.templating +propagate = 1 + +[logger_rhodecode] +level = DEBUG +handlers = +qualname = rhodecode +propagate = 1 + +[logger_sqlalchemy] +level = INFO +handlers = console_sql +qualname = sqlalchemy.engine +propagate = 0 + +[logger_whoosh_indexer] +level = DEBUG +handlers = +qualname = whoosh_indexer +propagate = 1 + +############## +## HANDLERS ## +############## + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = DEBUG +formatter = color_formatter + +[handler_console_sql] +class = StreamHandler +args = (sys.stderr,) +level = DEBUG +formatter = color_formatter_sql + +################ +## FORMATTERS ## +################ + +[formatter_generic] +class = rhodecode.lib.logging_formatter.Pyro4AwareFormatter +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S + +[formatter_color_formatter] +class = rhodecode.lib.logging_formatter.ColorFormatter +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S + +[formatter_color_formatter_sql] +class = rhodecode.lib.logging_formatter.ColorFormatterSql +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S diff --git a/configs/gunicorn_config.py b/configs/gunicorn_config.py new file mode 100644 --- /dev/null +++ b/configs/gunicorn_config.py @@ -0,0 +1,96 @@ +"""gunicorn config hooks""" + +import multiprocessing +import sys +import threading +import traceback + + +# GLOBAL # +errorlog = '-' +accesslog = '-' +loglevel = 'debug' + +# SECURITY # +limit_request_line = 4094 +limit_request_fields = 100 +limit_request_field_size = 8190 + +# SERVER MECHANICS # +# None == system temp dir # +worker_tmp_dir = None +tmp_upload_dir = None +#proc_name = + +# self adjust workers based on CPU # +#workers = multiprocessing.cpu_count() * 2 + 1 + +access_log_format = '[%(p)s] %(h)15s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" request_time:%(L)s' + +# For the gevent worker classes # +# this limits the maximum number of simultaneous clients that # +# a single process can handle. # +#worker_connections = 10 + +# Max requests to handle by each worker before restarting it, # +# could prevent memory leaks # +#max_requests = 1000 +#max_requests_jitter = 30 + + +# If a worker does not notify the master process in this # +# number of seconds it is killed and a new worker is spawned # +# to replace it. # +#timeout = 3600 + +access_log_format = ( + '[%(p)-10s] %(h)s time:%(L)s %(l)s %(u)s ' + '%(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"') + + +def post_fork(server, worker): + server.log.info("[<%s>] worker spawned", worker.pid) + + +def pre_fork(server, worker): + pass + + +def pre_exec(server): + server.log.info("Forked child, re-executing.") + + +def when_ready(server): + server.log.info("Server is ready. Spawning workers") + + +def worker_int(worker): + worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid) + + # get traceback info + id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) + code = [] + for thread_id, stack in sys._current_frames().items(): + code.append( + "\n# Thread: %s(%d)" % (id2name.get(thread_id, ""), thread_id)) + for fname, lineno, name, line in traceback.extract_stack(stack): + code.append('File: "%s", line %d, in %s' % (fname, lineno, name)) + if line: + code.append(" %s" % (line.strip())) + worker.log.debug("\n".join(code)) + + +def worker_abort(worker): + worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid) + + +def pre_request(worker, req): + return + worker.log.debug("[<%-10s>] PRE WORKER: %s %s", + worker.pid, req.method, req.path) + + +def post_request(worker, req, environ, resp): + return + worker.log.debug("[<%-10s>] POST WORKER: %s %s resp: %s", worker.pid, + req.method, req.path, resp.status_code) \ No newline at end of file diff --git a/configs/init.d/.readme.txt b/configs/init.d/.readme.txt new file mode 100644 --- /dev/null +++ b/configs/init.d/.readme.txt @@ -0,0 +1,1 @@ +Example init scripts. \ No newline at end of file diff --git a/configs/init.d/supervisord.conf b/configs/init.d/supervisord.conf new file mode 100644 --- /dev/null +++ b/configs/init.d/supervisord.conf @@ -0,0 +1,61 @@ +; Sample supervisor RhodeCode config file. +; +; For more information on the config file, please see: +; http://supervisord.org/configuration.html +; +; Note: shell expansion ("~" or "$HOME") is not supported. Environment +; variables can be expanded using this syntax: "%(ENV_HOME)s". + +[unix_http_server] +file=/tmp/supervisor.sock ; (the path to the socket file) +;chmod=0700 ; socket file mode (default 0700) +;chown=nobody:nogroup ; socket file uid:gid owner +;username=user ; (default is no username (open server)) +;password=123 ; (default is no password (open server)) + +[supervisord] +logfile=/home/ubuntu/rhodecode/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/home/ubuntu/rhodecode/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=true ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) +;umask=022 ; (process file creation umask;default 022) +user=ubuntu ; (default is current user, required if root) +;identifier=supervisor ; (supervisord identifier, default is 'supervisor') +;directory=/tmp ; (default is not to cd during start) +;nocleanup=true ; (don't clean up tempfiles at start;default false) +;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP) +environment=HOME=/home/ubuntu,LANG=en_US.UTF-8 ; (key value pairs to add to environment) +;strip_ansi=false ; (strip ansi escape codes in logs; def. false) + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket +;username=chris ; should be same as http_username if set +;password=123 ; should be same as http_password if set + + +; restart with supervisorctl restart rhodecode:* +[program:rhodecode] +numprocs = 1 +numprocs_start = 5000 +directory=/home/ubuntu/rhodecode/source +command = /home/ubuntu/rhodecode/venv/bin/paster serve /home/ubuntu/rhodecode/source/prod.ini +process_name = %(program_name)s_%(process_num)04d +redirect_stderr=true +stdout_logfile=/home/ubuntu/rhodecode/rhodecode.log + +[program:rhodecode_workers] +numproces = 1 +directory = /home/ubuntu/rhodecode/source +command = /home/ubuntu/rhodecode/venv/bin/paster celeryd /home/ubuntu/rhodecode/source/prod.ini --autoscale=10,2 +redirect_stderr=true +stdout_logfile=/%(here)s/rhodecode_workers.log diff --git a/configs/production.ini b/configs/production.ini new file mode 100644 --- /dev/null +++ b/configs/production.ini @@ -0,0 +1,541 @@ +################################################################################ +################################################################################ +# RhodeCode Enterprise - configuration file # +# Built-in functions and variables # +# The %(here)s variable will be replaced with the parent directory of this file# +# # +################################################################################ + +[DEFAULT] +debug = true +pdebug = false +################################################################################ +## Uncomment and replace with the email address which should receive ## +## any error reports after an application crash ## +## Additionally these settings will be used by the RhodeCode mailing system ## +################################################################################ +#email_to = admin@localhost +#error_email_from = paste_error@localhost +#app_email_from = rhodecode-noreply@localhost +#error_message = +#email_prefix = [RhodeCode] + +#smtp_server = mail.server.com +#smtp_username = +#smtp_password = +#smtp_port = +#smtp_use_tls = false +#smtp_use_ssl = true +## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.) +#smtp_auth = + +[server:main] +## COMMON ## +host = 127.0.0.1 +port = 5000 + +########################## +## WAITRESS WSGI SERVER ## +########################## +use = egg:waitress#main +## number of worker threads +threads = 5 +## MAX BODY SIZE 100GB +max_request_body_size = 107374182400 +## Use poll instead of select, fixes file descriptors limits problems. +## May not work on old windows systems. +asyncore_use_poll = true + + +########################## +## GUNICORN WSGI SERVER ## +########################## +## run with gunicorn --log-config --paste +#use = egg:gunicorn#main +## Sets the number of process workers. You must set `instance_id = *` +## when this option is set to more than one worker, recommended +## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers +## The `instance_id = *` must be set in the [app:main] section below +#workers = 1 +## number of threads for each of the worker, must be set to 1 for gevent +## generally recommened to be at 1 +#threads = 1 +## process name +#proc_name = rhodecode +## type of worker class, one of sync, gevent +## recommended for bigger setup is using of of other than sync one +#worker_class = sync +## max number of requests that worker will handle before being gracefully +## restarted, could prevent memory leaks +#max_requests = 1000 +#max_requests_jitter = 30 +## ammount of time a worker can spend with handling a request before it +## gets killed and restarted. Set to 6hrs +#timeout = 21600 + + +## prefix middleware for RhodeCode, disables force_https flag. +## allows to set RhodeCode under a prefix in server. +## eg https://server.com/. Enable `filter-with =` option below as well. +#[filter:proxy-prefix] +#use = egg:PasteDeploy#prefix +#prefix = / + +[app:main] +use = egg:rhodecode-enterprise-ce +## enable proxy prefix middleware, defined below +#filter-with = proxy-prefix + +full_stack = true + +## Serve static files via RhodeCode, disable to serve them via HTTP server +static_files = true + +## Optional Languages +## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh +lang = en + +## perform a full repository scan on each server start, this should be +## set to false after first startup, to allow faster server restarts. +startup.import_repos = false + +## Uncomment and set this path to use archive download cache. +## Once enabled, generated archives will be cached at this location +## and served from the cache during subsequent requests for the same archive of +## the repository. +#archive_cache_dir = /tmp/tarballcache + +## change this to unique ID for security +app_instance_uuid = rc-production + +## cut off limit for large diffs (size in bytes) +cut_off_limit_diff = 1024000 +cut_off_limit_file = 256000 + +## use cache version of scm repo everywhere +vcs_full_cache = true + +## force https in RhodeCode, fixes https redirects, assumes it's always https +## Normally this is controlled by proper http flags sent from http server +force_https = false + +## use Strict-Transport-Security headers +use_htsts = false + +## number of commits stats will parse on each iteration +commit_parse_limit = 25 + +## git rev filter option, --all is the default filter, if you need to +## hide all refs in changelog switch this to --branches --tags +git_rev_filter = --branches --tags + +# Set to true if your repos are exposed using the dumb protocol +git_update_server_info = false + +## RSS/ATOM feed options +rss_cut_off_limit = 256000 +rss_items_per_page = 10 +rss_include_diff = false + +## gist URL alias, used to create nicer urls for gist. This should be an +## url that does rewrites to _admin/gists/. +## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal +## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/ +gist_alias_url = + +## List of controllers (using glob pattern syntax) that AUTH TOKENS could be +## used for access. +## Adding ?auth_token = to the url authenticates this request as if it +## came from the the logged in user who own this authentication token. +## +## Syntax is :. +## To enable access to raw_files put `FilesController:raw`. +## To enable access to patches add `ChangesetController:changeset_patch`. +## The list should be "," separated and on a single line. +## +## Recommended controllers to enable: +# ChangesetController:changeset_patch, +# ChangesetController:changeset_raw, +# FilesController:raw, +# FilesController:archivefile, +# GistsController:*, +api_access_controllers_whitelist = + +## default encoding used to convert from and to unicode +## can be also a comma separated list of encoding in case of mixed encodings +default_encoding = UTF-8 + +## instance-id prefix +## a prefix key for this instance used for cache invalidation when running +## multiple instances of rhodecode, make sure it's globally unique for +## all running rhodecode instances. Leave empty if you don't use it +instance_id = + +## alternative return HTTP header for failed authentication. Default HTTP +## response is 401 HTTPUnauthorized. Currently HG clients have troubles with +## handling that causing a series of failed authentication calls. +## Set this variable to 403 to return HTTPForbidden, or any other HTTP code +## This will be served instead of default 401 on bad authnetication +auth_ret_code = + +## use special detection method when serving auth_ret_code, instead of serving +## ret_code directly, use 401 initially (Which triggers credentials prompt) +## and then serve auth_ret_code to clients +auth_ret_code_detection = false + +## locking return code. When repository is locked return this HTTP code. 2XX +## codes don't break the transactions while 4XX codes do +lock_ret_code = 423 + +## allows to change the repository location in settings page +allow_repo_location_change = true + +## allows to setup custom hooks in settings page +allow_custom_hooks_settings = true + +## generated license token, goto license page in RhodeCode settings to obtain +## new token +license_token = + +## supervisor connection uri, for managing supervisor and logs. +supervisor.uri = +## supervisord group name/id we only want this RC instance to handle +supervisor.group_id = prod + +## Display extended labs settings +labs_settings_active = true + +#################################### +### CELERY CONFIG #### +#################################### +use_celery = false +broker.host = localhost +broker.vhost = rabbitmqhost +broker.port = 5672 +broker.user = rabbitmq +broker.password = qweqwe + +celery.imports = rhodecode.lib.celerylib.tasks + +celery.result.backend = amqp +celery.result.dburi = amqp:// +celery.result.serialier = json + +#celery.send.task.error.emails = true +#celery.amqp.task.result.expires = 18000 + +celeryd.concurrency = 2 +#celeryd.log.file = celeryd.log +celeryd.log.level = debug +celeryd.max.tasks.per.child = 1 + +## tasks will never be sent to the queue, but executed locally instead. +celery.always.eager = false + +#################################### +### BEAKER CACHE #### +#################################### +# default cache dir for templates. Putting this into a ramdisk +## can boost performance, eg. %(here)s/data_ramdisk +cache_dir = %(here)s/data + +## locking and default file storage for Beaker. Putting this into a ramdisk +## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data +beaker.cache.data_dir = %(here)s/data/cache/beaker_data +beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock + +beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long + +beaker.cache.super_short_term.type = memory +beaker.cache.super_short_term.expire = 10 +beaker.cache.super_short_term.key_length = 256 + +beaker.cache.short_term.type = memory +beaker.cache.short_term.expire = 60 +beaker.cache.short_term.key_length = 256 + +beaker.cache.long_term.type = memory +beaker.cache.long_term.expire = 36000 +beaker.cache.long_term.key_length = 256 + +beaker.cache.sql_cache_short.type = memory +beaker.cache.sql_cache_short.expire = 10 +beaker.cache.sql_cache_short.key_length = 256 + +# default is memory cache, configure only if required +# using multi-node or multi-worker setup +#beaker.cache.auth_plugins.type = ext:database +#beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock +#beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode +#beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode +#beaker.cache.auth_plugins.sa.pool_recycle = 3600 +#beaker.cache.auth_plugins.sa.pool_size = 10 +#beaker.cache.auth_plugins.sa.max_overflow = 0 + +beaker.cache.repo_cache_long.type = memorylru_base +beaker.cache.repo_cache_long.max_items = 4096 +beaker.cache.repo_cache_long.expire = 2592000 + +# default is memorylru_base cache, configure only if required +# using multi-node or multi-worker setup +#beaker.cache.repo_cache_long.type = ext:memcached +#beaker.cache.repo_cache_long.url = localhost:11211 +#beaker.cache.repo_cache_long.expire = 1209600 +#beaker.cache.repo_cache_long.key_length = 256 + +#################################### +### BEAKER SESSION #### +#################################### + +## .session.type is type of storage options for the session, current allowed +## types are file(default), ext:memcached, ext:database, and memory. +#beaker.session.type = file + +## db based session, fast, and allows easy management over logged in users ## +#beaker.session.type = ext:database +#beaker.session.lock_dir = %(here)s/data/cache/session_db_lock +#beaker.session.table_name = db_session +#beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode +#beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode +#beaker.session.sa.pool_recycle = 3600 +#beaker.session.sa.echo = false + +beaker.session.key = rhodecode +beaker.session.secret = production-rc-uytcxaz + +## Secure encrypted cookie. Requires AES and AES python libraries +## you must disable beaker.session.secret to use this +#beaker.session.encrypt_key = +#beaker.session.validate_key = + +## sets session as invalid(also logging out user) if it haven not been +## accessed for given amount of time in seconds +beaker.session.timeout = 2592000 +beaker.session.httponly = true +#beaker.session.cookie_path = / + +## uncomment for https secure cookie +beaker.session.secure = false + +## auto save the session to not to use .save() +beaker.session.auto = false + +## default cookie expiration time in seconds, set to `true` to set expire +## at browser close +#beaker.session.cookie_expires = 3600 + +################################### +## SEARCH INDEXING CONFIGURATION ## +################################### + +search.module = rhodecode.lib.index.whoosh +search.location = %(here)s/data/index + +################################### +## ERROR AND LOG HANDLING SYSTEM ## +################################### + +## Appenlight is tailored to work with RhodeCode, see +## http://appenlight.com for details how to obtain an account + +## appenlight integration enabled +appenlight = false + +appenlight.server_url = https://api.appenlight.com +appenlight.api_key = YOUR_API_KEY +;appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5 + +# used for JS client +appenlight.api_public_key = YOUR_API_PUBLIC_KEY + +## TWEAK AMOUNT OF INFO SENT HERE + +## enables 404 error logging (default False) +appenlight.report_404 = false + +## time in seconds after request is considered being slow (default 1) +appenlight.slow_request_time = 1 + +## record slow requests in application +## (needs to be enabled for slow datastore recording and time tracking) +appenlight.slow_requests = true + +## enable hooking to application loggers +appenlight.logging = true + +## minimum log level for log capture +appenlight.logging.level = WARNING + +## send logs only from erroneous/slow requests +## (saves API quota for intensive logging) +appenlight.logging_on_error = false + +## list of additonal keywords that should be grabbed from environ object +## can be string with comma separated list of words in lowercase +## (by default client will always send following info: +## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that +## start with HTTP* this list be extended with additional keywords here +appenlight.environ_keys_whitelist = + +## list of keywords that should be blanked from request object +## can be string with comma separated list of words in lowercase +## (by default client will always blank keys that contain following words +## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf' +## this list be extended with additional keywords set here +appenlight.request_keys_blacklist = + +## list of namespaces that should be ignores when gathering log entries +## can be string with comma separated list of namespaces +## (by default the client ignores own entries: appenlight_client.client) +appenlight.log_namespace_blacklist = + + +################################################################################ +## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## +## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## +## execute malicious code after an exception is raised. ## +################################################################################ +set debug = false + + +############## +## STYLING ## +############## +debug_style = false + +######################################################### +### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### +######################################################### +#sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30 +sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode +#sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode + +# see sqlalchemy docs for other advanced settings + +## print the sql statements to output +sqlalchemy.db1.echo = false +## recycle the connections after this ammount of seconds +sqlalchemy.db1.pool_recycle = 3600 +sqlalchemy.db1.convert_unicode = true + +## the number of connections to keep open inside the connection pool. +## 0 indicates no limit +#sqlalchemy.db1.pool_size = 5 + +## the number of connections to allow in connection pool "overflow", that is +## connections that can be opened above and beyond the pool_size setting, +## which defaults to five. +#sqlalchemy.db1.max_overflow = 10 + + +################## +### VCS CONFIG ### +################## +vcs.server.enable = true +vcs.server = localhost:9900 +# Available protocols: pyro4, http +vcs.server.protocol = pyro4 +vcs.server.log_level = info +vcs.start_server = false +vcs.backends = hg, git, svn +vcs.connection_timeout = 3600 +## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. +## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible +#vcs.svn.compatible_version = pre-1.8-compatible + +################################ +### LOGGING CONFIGURATION #### +################################ +[loggers] +keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer + +[handlers] +keys = console, console_sql + +[formatters] +keys = generic, color_formatter, color_formatter_sql + +############# +## LOGGERS ## +############# +[logger_root] +level = NOTSET +handlers = console + +[logger_routes] +level = DEBUG +handlers = +qualname = routes.middleware +## "level = DEBUG" logs the route matched and routing variables. +propagate = 1 + +[logger_beaker] +level = DEBUG +handlers = +qualname = beaker.container +propagate = 1 + +[logger_pyro4] +level = DEBUG +handlers = +qualname = Pyro4 +propagate = 1 + +[logger_templates] +level = INFO +handlers = +qualname = pylons.templating +propagate = 1 + +[logger_rhodecode] +level = DEBUG +handlers = +qualname = rhodecode +propagate = 1 + +[logger_sqlalchemy] +level = INFO +handlers = console_sql +qualname = sqlalchemy.engine +propagate = 0 + +[logger_whoosh_indexer] +level = DEBUG +handlers = +qualname = whoosh_indexer +propagate = 1 + +############## +## HANDLERS ## +############## + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = INFO +formatter = generic + +[handler_console_sql] +class = StreamHandler +args = (sys.stderr,) +level = WARN +formatter = generic + +################ +## FORMATTERS ## +################ + +[formatter_generic] +class = rhodecode.lib.logging_formatter.Pyro4AwareFormatter +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S + +[formatter_color_formatter] +class = rhodecode.lib.logging_formatter.ColorFormatter +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S + +[formatter_color_formatter_sql] +class = rhodecode.lib.logging_formatter.ColorFormatterSql +format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %Y-%m-%d %H:%M:%S diff --git a/configs/rcchannelstream.ini b/configs/rcchannelstream.ini new file mode 100644 --- /dev/null +++ b/configs/rcchannelstream.ini @@ -0,0 +1,6 @@ +[channelstream] +admin_secret = secret +secret = secret +port = 9800 +demo = false +allow_posting_from = 127.0.0.1 diff --git a/default.nix b/default.nix new file mode 100644 --- /dev/null +++ b/default.nix @@ -0,0 +1,215 @@ +# Nix environment for the community edition +# +# This shall be as lean as possible, just producing the Enterprise +# derivation. For advanced tweaks to pimp up the development environment we use +# "shell.nix" so that it does not have to clutter this file. + +{ pkgs ? (import {}) +, pythonPackages ? "python27Packages" +, pythonExternalOverrides ? self: super: {} +, doCheck ? true +}: + +let pkgs_ = pkgs; in + +let + pkgs = pkgs_.overridePackages (self: super: { + # Override subversion derivation to + # - activate python bindings + # - set version to 1.8 + subversion = super.subversion18.override { + httpSupport = true; + pythonBindings = true; + python = self.python27Packages.python; + }; + }); + + inherit (pkgs.lib) fix extends; + + basePythonPackages = with builtins; if isAttrs pythonPackages + then pythonPackages + else getAttr pythonPackages pkgs; + + elem = builtins.elem; + basename = path: with pkgs.lib; last (splitString "/" path); + startsWith = prefix: full: let + actualPrefix = builtins.substring 0 (builtins.stringLength prefix) full; + in actualPrefix == prefix; + + src-filter = path: type: with pkgs.lib; + let + ext = last (splitString "." path); + in + !elem (basename path) [ + ".git" ".hg" "__pycache__" ".eggs" "node_modules" + "build" "data" "tmp"] && + !elem ext ["egg-info" "pyc"] && + !startsWith "result" path; + + rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.; + + # Load the generated node packages + nodePackages = pkgs.callPackage "${pkgs.path}/pkgs/top-level/node-packages.nix" rec { + self = nodePackages; + generated = pkgs.callPackage ./pkgs/node-packages.nix { inherit self; }; + }; + + # TODO: Should be taken automatically out of the generates packages. + # apps.nix has one solution for this, although I'd prefer to have the deps + # from package.json mapped in here. + nodeDependencies = with nodePackages; [ + grunt + grunt-contrib-concat + grunt-contrib-jshint + grunt-contrib-less + grunt-contrib-watch + jshint + ]; + + pythonGeneratedPackages = self: basePythonPackages.override (a: { + inherit self; + }) + // (scopedImport { + self = self; + super = basePythonPackages; + inherit pkgs; + inherit (pkgs) fetchurl fetchgit; + } ./pkgs/python-packages.nix); + + pythonOverrides = import ./pkgs/python-packages-overrides.nix { + inherit + basePythonPackages + pkgs; + }; + + pythonLocalOverrides = self: super: { + rhodecode-enterprise-ce = + let + version = "${builtins.readFile ./rhodecode/VERSION}"; + linkNodeModules = '' + echo "Link node packages" + # TODO: check if this adds stuff as a dependency, closure size + rm -fr node_modules + mkdir -p node_modules + ${pkgs.lib.concatMapStrings (dep: '' + ln -sfv ${dep}/lib/node_modules/${dep.pkgName} node_modules/ + '') nodeDependencies} + echo "DONE: Link node packages" + ''; + in super.rhodecode-enterprise-ce.override (attrs: { + + inherit doCheck; + name = "rhodecode-enterprise-ce-${version}"; + version = version; + src = rhodecode-enterprise-ce-src; + + buildInputs = + attrs.buildInputs ++ + (with self; [ + pkgs.nodePackages.grunt-cli + pkgs.subversion + pytest-catchlog + rc_testdata + ]); + + propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [ + rhodecode-tools + ]); + + # TODO: johbo: Make a nicer way to expose the parts. Maybe + # pkgs/default.nix? + passthru = { + inherit myPythonPackagesUnfix; + pythonPackages = self; + }; + + LC_ALL = "en_US.UTF-8"; + LOCALE_ARCHIVE = + if pkgs.stdenv ? glibc + then "${pkgs.glibcLocales}/lib/locale/locale-archive" + else ""; + + # Somewhat snappier setup of the development environment + # TODO: move into shell.nix + # TODO: think of supporting a stable path again, so that multiple shells + # can share it. + shellHook = '' + tmp_path=$(mktemp -d) + export PATH="$tmp_path/bin:$PATH" + export PYTHONPATH="$tmp_path/${self.python.sitePackages}:$PYTHONPATH" + mkdir -p $tmp_path/${self.python.sitePackages} + python setup.py develop --prefix $tmp_path --allow-hosts "" + '' + linkNodeModules; + + preCheck = '' + export PATH="$out/bin:$PATH" + ''; + + postCheck = '' + rm -rf $out/lib/${self.python.libPrefix}/site-packages/pytest_pylons + rm -rf $out/lib/${self.python.libPrefix}/site-packages/rhodecode/tests + ''; + + preBuild = linkNodeModules + '' + grunt + rm -fr node_modules + ''; + + postInstall = '' + # python based programs need to be wrapped + ln -s ${self.supervisor}/bin/supervisor* $out/bin/ + ln -s ${self.gunicorn}/bin/gunicorn $out/bin/ + ln -s ${self.PasteScript}/bin/paster $out/bin/ + + # rhodecode-tools + # TODO: johbo: re-think this. Do the tools import anything from enterprise? + ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/ + + # note that condition should be restricted when adding further tools + for file in $out/bin/*; do #*/ + wrapProgram $file \ + --prefix PYTHONPATH : $PYTHONPATH \ + --set PYTHONHASHSEED random + done + + mkdir $out/etc + cp configs/production.ini $out/etc + + echo "Writing meta information for rccontrol to nix-support/rccontrol" + mkdir -p $out/nix-support/rccontrol + cp -v rhodecode/VERSION $out/nix-support/rccontrol/version + echo "DONE: Meta information for rccontrol written" + + # TODO: johbo: Make part of ac-tests + if [ ! -f rhodecode/public/js/scripts.js ]; then + echo "Missing scripts.js" + exit 1 + fi + if [ ! -f rhodecode/public/css/style.css ]; then + echo "Missing style.css" + exit 1 + fi + ''; + + }); + + rc_testdata = self.buildPythonPackage rec { + name = "rc_testdata-0.7.0"; + src = pkgs.fetchhg { + url = "https://code.rhodecode.com/upstream/rc_testdata"; + rev = "v0.7.0"; + sha256 = "0w3z0zn8lagr707v67lgys23sl6pbi4xg7pfvdbw58h3q384h6rx"; + }; + }; + + }; + + # Apply all overrides and fix the final package set + myPythonPackagesUnfix = + (extends pythonExternalOverrides + (extends pythonLocalOverrides + (extends pythonOverrides + pythonGeneratedPackages))); + myPythonPackages = (fix myPythonPackagesUnfix); + +in myPythonPackages.rhodecode-enterprise-ce diff --git a/docs-internal/vcs/http-transition.rst b/docs-internal/vcs/http-transition.rst new file mode 100644 --- /dev/null +++ b/docs-internal/vcs/http-transition.rst @@ -0,0 +1,15 @@ +.. _vcs-http: + +======================================== + Transition to HTTP based communication +======================================== + +We are in the process of replacing the Pyro4 based communication with an HTTP +based implementation. Currently both backends are supported and can be +activated via various settings in the configuration. + +To run the system in full HTTP based mode, use the following settings:: + + vcs.hooks.protocol = http + vcs.scm_app_implementation = rhodecode.lib.middleware.utils.scm_app_http + vcs.server.protocol = http diff --git a/docs-internal/vcs/index.rst b/docs-internal/vcs/index.rst new file mode 100644 --- /dev/null +++ b/docs-internal/vcs/index.rst @@ -0,0 +1,23 @@ + +====================================== + VCS client and VCSServer integration +====================================== + +Enterprise uses the VCSServer as a backend to provide version control +functionalities. This section describes the components in Enterprise which talk +to the VCSServer. + +The client library is implemented in :mod:`rhodecode.lib.vcs`. For HTTP based +access of the command line clients special middlewares and utilities are +implemented in :mod:`rhodecode.lib.middleware`. + + + + +.. toctree:: + :maxdepth: 2 + + http-transition + middleware + vcsserver + subversion diff --git a/docs/.howto b/docs/.howto new file mode 100644 --- /dev/null +++ b/docs/.howto @@ -0,0 +1,4 @@ +# building the docs +cd docs +nix-build default.nix -o result +make clean html \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = ./result/bin/sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/RhodeCodeInstaller.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/RhodeCodeInstaller.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/RhodeCodeInstaller" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/RhodeCodeInstaller" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,18 @@ +{% extends "!layout.html" %} +{% set css_files = css_files + ['_static/add.css'] %} + +{% block footer %} +{{ super() }} + + + +{% endblock %} diff --git a/docs/admin/adding-anonymous-user.rst b/docs/admin/adding-anonymous-user.rst new file mode 100644 --- /dev/null +++ b/docs/admin/adding-anonymous-user.rst @@ -0,0 +1,22 @@ +.. _permissions-info-anon-ref: + +Anonymous Users +--------------- + +By default, |RCM| provides |repo| access for registered users only. It can be +configured to be **world-open** in terms of read and write permissions. This +configuration is called "Anonymous Access" and allows |RCM| to be used as a +public hub where unregistered users have access to your |repos|. + +Anonymous access is useful for open source projects, universities, +or if running inside a restricted internal corporate network to serve +documents to all employees. Anonymous users get the default user permission +settings that are applied across the whole |RCM| system. + +To enable anonymous access to your |repos|, use the following steps: + +1. From the |RCM| interface, select :menuselection:`Admin --> Permissions`. +2. On the Application tab, check the :guilabel:`Allow anonymous access` box. +3. Select :guilabel:`Save`. +4. To set the anonymous user access permissions, which are based on the + default user settings, see :ref:`permissions-default-ref`. diff --git a/docs/admin/adding-new-user.rst b/docs/admin/adding-new-user.rst new file mode 100644 --- /dev/null +++ b/docs/admin/adding-new-user.rst @@ -0,0 +1,20 @@ +.. _permissions-add-user: + +Adding Users +------------ + +To create a new user, use the following steps. + +1. Select :menuselection:`Admin --> Users` in the top menu. +2. Select the :guilabel:`Add User` button at the top right. +3. Set the user credentials. +4. Select :guilabel:`Save`. + +Once the user is created you can set which groups they belong to using the +following steps: + +1. From the :menuselection:`Admin --> Users Groups` page select + :guilabel:`edit` beside the user group you want to include them in. +2. On the :guilabel:`Settings` page, move the user from + :guilabel:`Available Members` into :guilabel:`Chosen Members` and + :guilabel:`Save`. \ No newline at end of file diff --git a/docs/admin/admin-tricks.rst b/docs/admin/admin-tricks.rst new file mode 100644 --- /dev/null +++ b/docs/admin/admin-tricks.rst @@ -0,0 +1,222 @@ +.. _admin-tricks: + +One-time Admin Tasks +-------------------- + +* :ref:`web-analytics` +* :ref:`admin-tricks-license` +* :ref:`announcements` +* :ref:`md-rst` +* :ref:`repo-stats` +* :ref:`server-side-merge` +* :ref:`remap-rescan` +* :ref:`custom-hooks` +* :ref:`clear-repo-cache` +* :ref:`set-repo-pub` +* :ref:`ping` + +.. _web-analytics: + +Adding Web Analytics +^^^^^^^^^^^^^^^^^^^^ + +If you wish to add a Google Analytics, or any other kind of tracker to your +|RCE| instance you can add the necessary codes to the header or footer +section of each instance using the following steps: + +1. From the |RCE| interface, select + :menuselection:`Admin --> Settings --> Global` +2. To add a tracking code to you instance, enter it in the header or footer + section and select **Save** + +Use the example templates in the drop-down menu to set up your configuration. + +.. _admin-tricks-license: + +Licence Key Management +^^^^^^^^^^^^^^^^^^^^^^ + +To manage your license key, go to +:menuselection:`Admin --> Settings --> License`. +On this page you can see the license key details. If you need a new license, +or have questions about your current one, contact support@rhodecode.com + +.. _announcements: + +Server-wide Announcements +^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you need to make a server-wide announcement to all users, +you can add a message to be displayed using the following steps: + +1. From the |RCE| interface, select + :menuselection:`Admin --> Settings --> Global` +2. To add a message that will be displayed to all users, + select :guilabel:`Server Announcement` from the drop-down menu and + change the ``var message = "TYPE YOUR MESSAGE HERE";`` example line. +3. Select :guilabel:`Save`, and you will see the message once your page + refreshes. + +.. image:: ../images/server-wide-announcement.png + :alt: Server Wide Announcement + +.. _md-rst: + +Markdown or RST Rendering +^^^^^^^^^^^^^^^^^^^^^^^^^ + +|RCE| can use `Markdown`_ or `reStructured Text`_ in commit message, +code review messages, and inline comments. To set the default to either, +select your preference from the drop-down menu on the +:menuselection:`Admin --> Settings --> Visual` page and select +:guilabel:`Save settings`. + +.. _repo-stats: + +Enabling Repository Statistics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To enable |repo| statistics, use the following steps: + +1. From the |RCE| interface, open + :menuselection:`Admin --> Repositories` and select + :guilabel:`Edit` beside the |repo| for which you wish to enable statistics. +2. Check the :guilabel:`Enable statistics` box, and select :guilabel:`Save` + +.. _server-side-merge: + +Enabling Server-side Merging +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To enable server-side merging, use the following steps: + +1. From the |RCE| interface, open :menuselection:`Admin --> Settings --> VCS` +2. Check the :guilabel:`Server-side merge` box, and select + :guilabel:`Save Settings` + +If you encounter slow performance with server-side merging enabled, check the +speed at which your server is performing actions. When server-side merging is +enabled, the following actions occurs on the server. + +* A |pr| is created in the database. +* A shadow |repo| is created as a working environment for the |pr|. +* On display, |RCE| checks if the |pr| can be merged. + +To check how fast the shadow |repo| creation is occurring on your server, use +the following steps: + +1. Log into your server and create a directory in your |repos| folder. +2. Clone a |repo| that is showing slow performance and time the action. + +.. code-block:: bash + + # One option is to use the time command + $ time hg clone SOURCE_REPO TARGET + +.. _remap-rescan: + +Remap and Rescan Repositories +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may want to Remap and rescan the |repos| that |RCE| is managing to ensure +the system is always up-to-date. This is useful after importing, deleting, +or carrying out general cleaning up operations. To do this use the +following steps: + +1. From the |RCE|, open + :menuselection:`Admin --> Settings --> Remap and rescan` +2. Click :guilabel:`Rescan Repositories` + +Check the additional options if needed: + +* :guilabel:`Destroy old data`: Useful for purging deleted repository + information from the database. +* :guilabel:`Invalidate cache for all repositories`: Use this to completely + remap all |repos|. Useful when importing or migrating |repos| to ensure all + new information is picked up. + +.. _custom-hooks: + +Adding Custom Hooks +^^^^^^^^^^^^^^^^^^^ + +To add custom hooks to your instance, use the following steps: + +1. Open :menuselection:`Admin --> Settings --> Hooks` +2. Add your custom hook details, you can use a file path to specify custom + hook scripts, for example: ``python:/path/to/custom_hook.py`` +3. Select :guilabel:`Save` + +Also, see the |RC| Extensions section of the :ref:`rc-tools` guide. |RC| +Extensions can be used to add additional hooks to your instance and comes +with a number of pre-built plugins if you chose to install them. + +.. _clear-repo-cache: + +Clearing |repo| cache +^^^^^^^^^^^^^^^^^^^^^ + +If you need to clear the cache for a particular |repo|, use the following steps: + +1. Open :menuselection:`Admin --> Repositories` and select :guilabel:`Edit` + beside the |repo| whose cache you wish to clear. +2. On the |repo| settings page, go to the :guilabel:`Caches` tab and select + :guilabel:`Invalidate repository cache`. + +.. _set-lang: + +Changing Default Language +^^^^^^^^^^^^^^^^^^^^^^^^^ + +To change the default language of a |RCE| instance, change the language code +in the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. To +do this, use the following steps. + +1. Open the :file:`rhodecode.ini` file and set the required language code. + +.. code-block:: ini + + ## Optional Languages + ## en(default), de, fr, it, ja, pl, pt, ru, zh + lang = de + +2. Restart the |RCE| instance and check that the language has been updated. + +.. code-block:: bash + + $ rccontrol restart enterprise-2 + Instance "enterprise-2" successfully stopped. + Instance "enterprise-2" successfully started. + +.. image:: ../images/language.png + +.. _set-repo-pub: + +Setting Repositories to Publish +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To automatically promote your local |repos| to public after pushing to |RCE|, +enable the :guilabel:`Set repositories as publishing` option on the +:menuselection:`Admin --> Settings --> VCS` page. + +.. note:: + + This option is enabled by default on most |RCE| versions, but if upgrading + from a 1.7.x version it could be disabled on upgrade due to inheriting + older default settings. + +.. _ping: + +Pinging the |RCE| Server +^^^^^^^^^^^^^^^^^^^^^^^^ + +You can check the IP Address of your |RCE| instance using the +following URL: ``{instance-URL}/_admin/ping``. + +.. code-block:: bash + + $ curl https://your.rhodecode.url/_admin/ping + pong[rce-7880] => 203.0.113.23 + +.. _Markdown: http://daringfireball.net/projects/markdown/ +.. _reStructured Text: http://docutils.sourceforge.net/docs/index.html diff --git a/docs/admin/apache-conf-examples.rst b/docs/admin/apache-conf-examples.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-conf-examples.rst @@ -0,0 +1,114 @@ +.. _apache-conf-eg: + +Apache Configuration Examples +----------------------------- + +Use the following example to securely configure your Apache HTTP virtual hosts +file. + +.. code-block:: apache + + + ServerName hg.myserver.com + ServerAlias hg.myserver.com + + + Order allow,deny + Allow from all + + + # important ! + # Directive to properly generate url (clone url) for pylons + + ProxyPreserveHost On + + #rhodecode instance + ProxyPass / http://127.0.0.1:5000/ + ProxyPassReverse / http://127.0.0.1:5000/ + + # Set strict HTTPS + Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" + + # Set x-frame options + Header always append X-Frame-Options SAMEORIGIN + + # To enable https use line below + # SetEnvIf X-Url-Scheme https HTTPS=1 + + # Secure your Diffie-hellmann deployment + SSLProtocol all -SSLv2 -SSLv3 + SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA + SSLHonorCipherOrder on + SSLOpenSSLConfCmd DHParameters "{path to dhparams.pem}" + + + +Use the following example to configure Apache for a multi-node setup. The +timeout setting should be increased if you experience timeouts when working +with large |repos|. + +.. code-block:: apache + + # + # Timeout: The number of seconds before receives and sends time out. + # + Timeout 600 + + + + ProxyRequests off + + #important ! + #Directive to properly generate url (clone url) for pylons + ProxyPreserveHost On + + ServerName your.rce.com + ServerAlias your.rce.com + + + # WebHead1 + BalancerMember http://10.58.1.171:10002 route=1 + # WebHead2 + BalancerMember http://10.58.1.172:10001 route=2 + + # Security "technically we aren't blocking + # anyone but this the place to make those + # chages + Order Deny,Allow + Deny from none + Allow from all + + # Load Balancer Settings + # We will be configuring a simple Round + # Robin style load balancer. This means + # that all webheads take an equal share of + # of the load. + ProxySet stickysession=ROUTEID + + + + # balancer-manager + # This tool is built into the mod_proxy_balancer + # module and will allow you to do some simple + # modifications to the balanced group via a gui + # web interface. + + SetHandler balancer-manager + + # recommend locking this one down to your + # your office + Order deny,allow + Allow from all + + + # Point of Balance + # This setting will allow to explicitly name the + # the location in the site that we want to be + # balanced, in this example we will balance "/" + # or everything in the site. + ProxyPass /balancer-manager ! + ProxyPass / balancer://mycluster/ + + ProxyPassReverse / balancer://mycluster/ + + diff --git a/docs/admin/apache-config.rst b/docs/admin/apache-config.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-config.rst @@ -0,0 +1,15 @@ +.. _apache-ws-ref: + +Apache HTTP Server Configuration +-------------------------------- + +To set up your Apache Web Server for optimal performance and security, use +the information in the following sections. + +.. toctree:: + + apache-diffie-hellman + apache-conf-examples + apache-subdirectory + apache-reverse-proxy + apache-wsgi-coding diff --git a/docs/admin/apache-diffie-hellman.rst b/docs/admin/apache-diffie-hellman.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-diffie-hellman.rst @@ -0,0 +1,34 @@ +.. _dh-apache: + +Diffie-Hellman Security +----------------------- + +To secure your web server, the `Guide to Deploying Diffie-Hellman for TLS`_ +contains important information worth reading. This link contains some good +`secure Apache configuration`_ examples. + +To secure your deployment of Diffie-Hellman, configure the following: + +1. Generate a strong Diffie-hellman group, 2048-bit or stronger. + +.. code-block:: bash + + # to generate your dhparam.pem file, run in the terminal + openssl dhparam -out /etc/apache/ssl/dhparam.pem 2048 + +2. Configure your server to only use modern, secure cipher suites in the + virtual hosts configuration file. + +.. code-block:: apache + + # Set the protocol to only use modern, secure cipher suites. + SSLProtocol all -SSLv2 -SSLv3 + SSLHonorCipherOrder on + SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA + + # Specify your DH params file as follows + SSLOpenSSLConfCmd DHParameters "{path to dhparams.pem}" + + +.. _Guide to Deploying Diffie-Hellman for TLS: https://weakdh.org/sysadmin.html +.. _secure Apache configuration: http://www.apache-ssl.org/httpd.conf.example diff --git a/docs/admin/apache-reverse-proxy.rst b/docs/admin/apache-reverse-proxy.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-reverse-proxy.rst @@ -0,0 +1,33 @@ +Apache Reverse Proxy +^^^^^^^^^^^^^^^^^^^^ + +Here is a sample configuration file for using Apache as a reverse proxy. + +.. code-block:: apache + + + ServerName hg.myserver.com + ServerAlias hg.myserver.com + + ## uncomment root directive if you want to serve static files by nginx + ## requires static_files = false in .ini file + DocumentRoot /path/to/installation/rhodecode/public + + + Order allow,deny + Allow from all + + + #important ! + #Directive to properly generate url (clone url) for pylons + ProxyPreserveHost On + + #rhodecode instance + ProxyPass / http://127.0.0.1:5000/ + ProxyPassReverse / http://127.0.0.1:5000/ + + #to enable https use line below + #SetEnvIf X-Url-Scheme https HTTPS=1 + + + diff --git a/docs/admin/apache-subdirectory.rst b/docs/admin/apache-subdirectory.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-subdirectory.rst @@ -0,0 +1,32 @@ +.. _apache-sub-ref: + +Apache URL Prefix Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use the following example to configure Apache to use a URL prefix. + +.. code-block:: apache + + > # Change into your chosen prefix + ProxyPass http://127.0.0.1:5000/ + ProxyPassReverse http://127.0.0.1:5000/ + SetEnvIf X-Url-Scheme https HTTPS=1 + + +In addition to the regular Apache setup you will need to add the following +lines into the ``rhodecode.ini`` file. + +* In the the ``[app:main]`` section of your ``rhodecode.ini`` file add the + following line. + +.. code-block:: ini + + filter-with = proxy-prefix + +* At the end of the ``rhodecode.ini`` file add the following section. + +.. code-block:: ini + + [filter:proxy-prefix] + use = egg:PasteDeploy#prefix + prefix = / # Change into your chosen prefix diff --git a/docs/admin/apache-wsgi-coding.rst b/docs/admin/apache-wsgi-coding.rst new file mode 100644 --- /dev/null +++ b/docs/admin/apache-wsgi-coding.rst @@ -0,0 +1,55 @@ +.. _apache-wsgi-ref: + +Apache WSGI Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +|RCM| can also be set up with Apache under ``mod_wsgi``. To configure this +use the following steps. + +1. Install ``mod_wsgi`` using the following command: + ``aptitude install libapache2-mod-wsgi``. +2. Enable ``mod_wsgi`` using the following command: ``a2enmod wsgi`` +3. Create a ``wsgi`` dispatch script, using the following examples. + +.. code-block:: bash + + WSGIDaemonProcess pylons \ + threads=4 \ + # check the python virtual env location + python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages + # Check the install location + WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi + WSGIPassAuthorization On + # user=www-data group=www-data # Enable if running Apache as root + +.. note:: + + Do not set ``processes=num`` in this configuration file. Running |RCE| in + multiprocess mode with Apache is not supported. + +The following is an example ``wsgi`` dispatch script. + +.. code-block:: python + + import os + os.environ["HGENCODING"] = "UTF-8" + os.environ['PYTHON_EGG_CACHE'] = '/home/web/rhodecode/.egg-cache' + + # Set the current dir + os.chdir('/home/web/rhodecode/') + + import site + site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages") + + from paste.deploy import loadapp + from paste.script.util.logging_config import fileConfig + + fileConfig('/home/web/rhodecode/production.ini') + application = loadapp('config:/home/web/rhodecode/production.ini') + +.. note:: + + When using `mod_wsgi` the same version of |hg| must be running in your + system's |PY| environment and on |RCM|. To check the |RCM| version, + on the interface go to + :menuselection:`Admin --> Settings --> System Info` diff --git a/docs/admin/backup-restore.rst b/docs/admin/backup-restore.rst new file mode 100644 --- /dev/null +++ b/docs/admin/backup-restore.rst @@ -0,0 +1,127 @@ +.. _backup-ref: + +Backup and Restore +================== + +*“The condition of any backup is unknown until a restore is attempted.”* +`Schrödinger's Backup`_ + +To snapshot an instance of |RCE|, and save its settings, you need to backup the +following parts of the system at the same time. + +* The |repos| managed by the instance. +* The |RCE| database. +* Any configuration files or extensions that you've configured. + +.. important:: + + Ideally you should script all of these functions so that it creates a + backup snapshot of your system at a particular timestamp and then run that + script regularly. + +Backup Details +-------------- + +To backup the relevant parts of |RCE| required to restore your system, use +the information in this section to identify what is important to you. + +Repository Backup +^^^^^^^^^^^^^^^^^ + +To back up your |repos|, use the API to get a list of all |repos| managed, +and then clone them to your backup location. + +Use the ``get_repos`` method to list all your managed |repos|, +and use the ``clone_uri`` information that is returned. See the :ref:`api` +for more information. + +.. important:: + + This will not work for |svn| |repos|. Currently the only way to back up + your |svn| |repos| is to make a copy of them. + + It is also important to note, that you can only restore the |svn| |repos| + using the same version as they were saved with. + +Database Backup +^^^^^^^^^^^^^^^ + +The instance database contains all the |RCE| permissions settings, +and user management information. To backup your database, +export it using the following appropriate example, and then move it to your +backup location: + +.. code-block:: bash + + # For MySQL DBs + $ mysqldump -u -p db_name > mysql-db-backup + + # For PostgreSQL DBs + $ pg_dump dbname > postgresql-db-backup + + # For SQLlite + $ sqlite3 rhodecode.db ‘.dump’ > sqlite-db-backup + + +The default |RCE| SQLite database location is +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.db` + +If running MySQL or PostgreSQL databases, you will have configured these +separately, for more information see :ref:`rhodecode-database-ref` + +Configuration File Backup +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Depending on your setup, you could have a number of configuration files that +should be backed up. You may have some, or all of the configuration files +listed in the :ref:`config-rce-files` section. Ideally you should back these +up at the same time as the database and |repos|. + +Gist Backup +^^^^^^^^^^^ + +To backup the gists on your |RCE| instance you can use the ``get_users`` and +``get_gists`` API methods to fetch the gists for each user on the instance. + +Extension Backups +^^^^^^^^^^^^^^^^^ + +You should also backup any extensions added in the +:file:`home/{user}/.rccontrol/{instance-id}/rcextensions` directory. + +Full-text Search Backup +^^^^^^^^^^^^^^^^^^^^^^^ + +You may also have full text search set up, but the index can be rebuild from +re-imported |repos| if necessary. You will most likely want to backup your +:file:`mapping.ini` file if you've configured that. For more information, see +the :ref:`indexing-ref` section. + +Restoration Steps +----------------- + +To restore an instance of |RCE| from its backed up components, use the +following steps. + +1. Install a new instance of |RCE|. +2. Once installed, configure the instance to use the backed up + :file:`rhodecode.ini` file. Ensure this file points to the backed up + database, see the :ref:`config-database` section. +3. Restart |RCE| and remap and rescan your |repos|, see the + :ref:`remap-rescan` section. + +Post Restoration Steps +^^^^^^^^^^^^^^^^^^^^^^ + +Once you have restored your |RCE| instance to basic functionality, you can +then work on restoring any specific setup changes you had made. + +* To recreate the |RCE| index, use the backed up :file:`mapping.ini` file if + you had made changes and rerun the indexer. See the + :ref:`indexing-ref` section for details. +* To reconfigure any extensions, copy the backed up extensions into the + :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` and also specify + any custom hooks if necessary. See the :ref:`integrations-ref` section for + details. + +.. _Schrödinger's Backup: http://novabackup.novastor.com/blog/schrodingers-backup-good-bad-backup/ diff --git a/docs/admin/cleanup-cmds.rst b/docs/admin/cleanup-cmds.rst new file mode 100644 --- /dev/null +++ b/docs/admin/cleanup-cmds.rst @@ -0,0 +1,23 @@ +.. _clean-up-cmds: + +|RCT| Clean Up Commands +======================= + +|RCT| comes with a number of functions which can be used to administer your +|RCE| instances. Two of these can be used to automate the cleanup of gists +and |repos| + +rhodecode-cleanup-gists +----------------------- + +Use this command to delete gists within RhodeCode Enterprise. It takes a +number of options for specifying the kind of gists you want deleted, and it +is possible to run these commands from a cron job or cleanup script. For more +information, see the :ref:`tools-cli` + +rhodecode-cleanup-repos +----------------------- + +Use this command to delete |repos| from your |RCE| instances. It takes +a number of options specifying the kind of |repos| you want deleted. For more +information, see the :ref:`tools-cli` diff --git a/docs/admin/config-files-overview.rst b/docs/admin/config-files-overview.rst new file mode 100644 --- /dev/null +++ b/docs/admin/config-files-overview.rst @@ -0,0 +1,74 @@ +.. _config-files: + +Configuration Files Overview +============================ + +|RCE| and |RCC| have a number of different configuration files. The following +is a brief explanation of each, and links to their associated configuration +sections. + +.. rst-class:: dl-horizontal + + \- **rhodecode.ini** + Default location: + :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` + + This is the main |RCE| configuration file and controls much of its + default behaviour. It is also used to configure certain customer + settings. Here are some of the most common reasons to make changes to + this file. + + * :ref:`config-database` + * :ref:`set-up-mail` + * :ref:`increase-gunicorn` + * :ref:`x-frame` + + \- **mapping.ini** + Default location: + :file:`/home/{user}/.rccontrol/{instance-id}/mapping.ini` + + This file is used to control the |RCE| indexer. It comes configured + to index your instance. To change the default configuration, see + :ref:`advanced-indexing`. + + \- **vcsserver.ini** + Default location: + :file:`/home/{user}/.rccontrol/{vcsserver-id}/vcsserver.ini` + + The VCS Server handles the connection between your |repos| and |RCE|. + See the :ref:`vcs-server` section for configuration options and more + detailed information. + + \- **supervisord.ini** + Default location: + :file:`/home/{user}/.rccontrol/supervisor/supervisord.ini` + + |RCC| uses Supervisor to monitor and manage installed instances of + |RCE| and the VCS Server. |RCC| will manage this file completely, + unless you install |RCE| in self-managed mode. For more information, + see the :ref:`Supervisor Setup` section. + + \- **.rccontrol.ini** + Default location: :file:`/home/{user}/.rccontrol.ini` + + This file contains the instances that |RCC| starts at boot, which is all + by default, but for more information, see + the :ref:`Manually Start At Boot ` section. + + \- **.rhoderc** + Default location: :file:`/home/{user}/.rhoderc` + + This file is used by the |RCE| API when accessing an instance from a + remote machine. The API checks this file for connection and + authentication details. For more details, see the :ref:`config-rhoderc` + section. + + \- **MANIFEST** + Default location: :file:`/home/{user}/.rccontrol/cache/MANIFEST` + + |RCC| uses this file to source the latest available builds from the + secure |RC| download channels. The only reason to mess with this file + is if you need to do an offline installation, + see the :ref:`Offline Installation` + instructions, otherwise |RCC| will completely manage this file. + diff --git a/docs/admin/default-user-perms.rst b/docs/admin/default-user-perms.rst new file mode 100644 --- /dev/null +++ b/docs/admin/default-user-perms.rst @@ -0,0 +1,32 @@ +.. _default-perms: + +Default User Permissions +------------------------ + +There are two ways in which the default user settings work: + +System-wide Level +^^^^^^^^^^^^^^^^^ + +On a system-wide level, you can set the default user permissions so that +all new users are given a certain set of permissions unless individually +tailored, or added to a user group. For more information about system-wide +default permissions, see the :ref:`permissions-info-anon-ref` and +:ref:`permissions-default-ref` sections. + +User Group Level +^^^^^^^^^^^^^^^^ + +On a user group level, you can set the default user settings for the user +group, and all users within that group will get those default permissions +unless individually tailored. For more information about setting default +permissions for all the different entities, see the +:ref:`permissions-default-ref` section. + +For more detailed information about managing the different permissions +settings, see the following sections: + +* :ref:`permissions-info-anon-ref` +* :ref:`permissions-add-user` +* :ref:`permissions-default-ref` +* :ref:`permissions-info-add-group-ref` \ No newline at end of file diff --git a/docs/admin/enable-debug.rst b/docs/admin/enable-debug.rst new file mode 100644 --- /dev/null +++ b/docs/admin/enable-debug.rst @@ -0,0 +1,136 @@ +.. _debug-mode: + +Enabling Debug Mode +------------------- + +To enable debug mode on a |RCE| instance you need to set the debug property +in the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. To +do this, use the following steps + +1. Open the file and set the ``debug`` line to ``true`` +2. Restart you instance using the ``rccontrol restart`` command, + see the following example: + +You can also set the log level, the follow are the valid options; +``debug``, ``info``, ``warning``, or ``fatal``. + +.. code-block:: ini + + [DEFAULT] + debug = true + pdebug = false + +.. code-block:: bash + + # Restart your instance + $ rccontrol restart enterprise-1 + Instance "enterprise-1" successfully stopped. + Instance "enterprise-1" successfully started. + +Debug and Logging Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Further debugging and logging settings can also be set in the +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. + +In the logging section, the various packages that run with |RCE| can have +different debug levels set. If you want to increase the logging level change +``level = DEBUG`` line to one of the valid options. + +You also need to change the log level for handlers. See the example +``##handler`` section below. The ``handler`` level takes the same options as +the ``debug`` level. + +.. code-block:: ini + + ################################ + ### LOGGING CONFIGURATION #### + ################################ + [loggers] + keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer + + [handlers] + keys = console, console_sql, file, file_rotating + + [formatters] + keys = generic, color_formatter, color_formatter_sql + + ############# + ## LOGGERS ## + ############# + [logger_root] + level = NOTSET + handlers = console + + [logger_routes] + level = DEBUG + handlers = + qualname = routes.middleware + ## "level = DEBUG" logs the route matched and routing variables. + propagate = 1 + + [logger_beaker] + level = DEBUG + handlers = + qualname = beaker.container + propagate = 1 + + [logger_pyro4] + level = DEBUG + handlers = + qualname = Pyro4 + propagate = 1 + + [logger_templates] + level = INFO + handlers = + qualname = pylons.templating + propagate = 1 + + [logger_rhodecode] + level = DEBUG + handlers = + qualname = rhodecode + propagate = 1 + + [logger_sqlalchemy] + level = INFO + handlers = console_sql + qualname = sqlalchemy.engine + propagate = 0 + + [logger_whoosh_indexer] + level = DEBUG + handlers = + qualname = whoosh_indexer + propagate = 1 + + ############## + ## HANDLERS ## + ############## + + [handler_console] + class = StreamHandler + args = (sys.stderr,) + level = INFO + formatter = generic + + [handler_console_sql] + class = StreamHandler + args = (sys.stderr,) + level = WARN + formatter = generic + + [handler_file] + class = FileHandler + args = ('rhodecode.log', 'a',) + level = INFO + formatter = generic + + [handler_file_rotating] + class = logging.handlers.TimedRotatingFileHandler + # 'D', 5 - rotate every 5days + # you can set 'h', 'midnight' + args = ('rhodecode.log', 'D', 5, 10,) + level = INFO + formatter = generic diff --git a/docs/admin/glossary.rst b/docs/admin/glossary.rst new file mode 100644 --- /dev/null +++ b/docs/admin/glossary.rst @@ -0,0 +1,50 @@ +.. _glossary: + +Glossary +======== + +.. glossary:: + + DVCS + Distributed Version Control System, usually referring to |git| or |hg|. + + Extension + An extension extends the capabilities of, or the data available to, + an existing software application. + + Full-text Search + Indexing all files and |repos| managed by |RCE| and + making this data searchable from the interface. + + Gist + A note that can only be edited by the author and shared using its + link within others. The sharing permissions can be set during + its creation. + + Gunicorn + A Python WSGI HTTP Server used by |RCE|. + + Hook + A hook intercepts function calls, messages, or events passed between + software components and can be used to trigger plugins, or their + extensions. + + Horizontal scaling + Adding more machines or workers into your pool of resources. + + Instance + A single installed version of one of the |RC| products. It could + refer to |RCE| or the VCS server depending on the context. + + Plugin + A Plugin is software that adds a specific feature to an existing + software application. + + tmpfs + Temporary file storage kept in volatile memory instead of persistent + storage. + + VCS Server + The VCS Server handles the abstraction layer between the + supported version control systems and RhodeCode Enterprise. + diff --git a/docs/admin/indexing.rst b/docs/admin/indexing.rst new file mode 100644 --- /dev/null +++ b/docs/admin/indexing.rst @@ -0,0 +1,235 @@ +.. _indexing-ref: + +Full-text Search +---------------- + +By default |RCM| uses `Whoosh`_ to index |repos| and provide full-text search. +To run the indexer you need to use an |authtoken| with admin rights to all +|repos|. + +To index new content added, you have the option to set the indexer up in a +number of ways, for example: + +* Call the indexer via a cron job. We recommend running this nightly, + unless you need everything indexed immediately. +* Set the indexer to infinitely loop and reindex as soon as it has run its + cycle. +* Hook the indexer up with your CI server to reindex after each push. + +The indexer works by indexing new commits added since the last run. If you +wish to build a brand new index from scratch each time, +use the ``force`` option in the configuration file. + +.. important:: + + You need to have |RCT| installed, see :ref:`install-tools`. Since |RCE| + 3.5.0 they are installed by default. + +To set up indexing, use the following steps: + +1. :ref:`config-rhoderc`, if running tools remotely. +2. :ref:`run-index` +3. :ref:`set-index` +4. :ref:`advanced-indexing` + +.. _config-rhoderc: + +Configure the ``.rhoderc`` File +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +|RCT| uses the :file:`/home/{user}/.rhoderc` file for connection details +to |RCM| instances. If this file is not automatically created, +you can configure it using the following example. You need to configure the +details for each instance you want to index. + +.. code-block:: bash + + # Check the instance details + # of the instance you want to index + $ rccontrol status + + - NAME: enterprise-1 + - STATUS: RUNNING + - TYPE: Momentum + - VERSION: 1.5.0 + - URL: http://127.0.0.1:10000 + +To get your API Token, on the |RCM| interface go to +:menuselection:`username --> My Account --> Auth tokens` + +.. code-block:: ini + + # Configure .rhoderc with matching details + # This allows the indexer to connect to the instance + [instance:enterprise-1] + api_host = http://127.0.0.1:10000 + api_key = + repo_dir = /home//repos + +.. _run-index: + +Run the Indexer +^^^^^^^^^^^^^^^ + +Run the indexer using the following command, and specify the instance you +want to index: + +.. code-block:: bash + + # From inside a virtualevv + (venv)$ rhodecode-index --instance-name=enterprise-1 + + # Using default installation + $ /home/user/.rccontrol/enterprise-4/profile/bin/rhodecode-index \ + --instance-name=enterprise-4 + + # Using a custom mapping file + $ /home/user/.rccontrol/enterprise-4/profile/bin/rhodecode-index \ + --instance-name=enterprise-4 \ + --mapping=/home/user/.rccontrol/enterprise-4/mapping.ini + +.. note:: + + |RCT| require |PY| 2.7 to run. + +.. _set-index: + +Schedule the Indexer +^^^^^^^^^^^^^^^^^^^^ + +To schedule the indexer, configure the crontab file to run the indexer inside +your |RCT| virtualenv using the following steps. + +1. Open the crontab file, using ``crontab -e``. +2. Add the indexer to the crontab, and schedule it to run as regularly as you + wish. +3. Save the file. + +.. code-block:: bash + + $ crontab -e + + # The virtualenv can be called using its full path, so for example you can + # put this example into the crontab + + # Run the indexer daily at 4am using the default mapping settings + * 4 * * * /home/ubuntu/.virtualenv/rhodecode-venv/bin/rhodecode-index \ + --instance-name=enterprise-1 + + # Run the indexer every Sunday at 3am using default mapping + * 3 * * 0 /home/ubuntu/.virtualenv/rhodecode-venv/bin/rhodecode-index \ + --instance-name=enterprise-1 + + # Run the indexer every 15 minutes + # using a specially configured mapping file + */15 * * * * ~/.rccontrol/enterprise-4/profile/bin/rhodecode-index \ + --instance-name=enterprise-4 \ + --mapping=/home/user/.rccontrol/enterprise-4/mapping.ini + +.. _advanced-indexing: + +Advanced Indexing +^^^^^^^^^^^^^^^^^ + +|RCT| indexes based on the :file:`mapping.ini` file. To configure your index, +you can specify different options in this file. The default location is: + +* :file:`/home/{user}/.rccontrol/{instance-id}/mapping.ini`, using default + |RCT|. +* :file:`~/venv/lib/python2.7/site-packages/rhodecode_tools/templates/mapping.ini`, + when using ``virtualenv``. + +.. note:: + + If you need to create the :file:`mapping.ini` file, use the |RCT| + ``rhodecode-index --create-mapping path/to/file`` API call. For details, + see the :ref:`tools-cli` section. + +The indexer runs in a random order to prevent a failing |repo| from stopping +a build. To configure different indexing scenarios, set the following options +inside the :file:`mapping.ini` and specify the altered file using the +``--mapping`` option. + +* ``index_files`` : Index the specified file types. +* ``skip_files`` : Do not index the specified file types. +* ``index_files_content`` : Index the content of the specified file types. +* ``skip_files_content`` : Do not index the content of the specified files. +* ``force`` : Create a fresh index on each run. +* ``max_filesize`` : Files larger than the set size will not be indexed. +* ``commit_parse_limit`` : Set the batch size when indexing commit messages. + Set to a lower number to lessen memory load. +* ``repo_limit`` : Set the maximum number or |repos| indexed per run. +* ``[INCLUDE]`` : Set |repos| you want indexed. This takes precedent over + ``[EXCLUDE]``. +* ``[EXCLUDE]`` : Set |repos| you do not want indexed. Exclude can be used to + not index branches, forks, or log |repos|. + +At the end of the file you can specify conditions for specific |repos| that +will override the default values. To configure your indexer, +use the following example :file:`mapping.ini` file. + +.. code-block:: ini + + [__DEFAULT__] + # default patterns for indexing files and content of files. + # Binary files are skipped by default. + + # Index python and markdown files + index_files = *.py, *.md + + # Do not index these file types + skip_files = *.svg, *.log, *.dump, *.txt + + # Index both file types and their content + index_files_content = *.cpp, *.ini, *.py + + # Index file names, but not file content + skip_files_content = *.svg, + + # Force rebuilding an index from scratch. Each repository will be rebuild + # from scratch with a global flag. Use local flag to rebuild single repos + force = false + + # Do not index files larger than 385KB + max_filesize = 385KB + + # Limit commit indexing to 500 per batch + commit_parse_limit = 500 + + # Limit each index run to 25 repos + repo_limit = 25 + + # __INCLUDE__ is more important that __EXCLUDE__. + + [__INCLUDE__] + # Include all repos with these names + + docs/* = 1 + lib/* = 1 + + [__EXCLUDE__] + # Do not include the following repo in index + + dev-docs/* = 1 + legacy-repos/* = 1 + *-dev/* = 1 + + # Each repo that needs special indexing is a separate section below. + # In each section set the options to override the global configuration + # parameters above. + # If special settings are not configured, the global configuration values + # above are inherited. If no special repositories are + # defined here RhodeCode will use the API to ask for all repositories + + # For this repo use different settings + [special-repo] + commit_parse_limit = 20, + skip_files = *.idea, *.xml, + + # For another repo use different settings + [another-special-repo] + index_files = *, + max_filesize = 800MB + commit_parse_limit = 20000 + +.. _Whoosh: https://pypi.python.org/pypi/Whoosh/ diff --git a/docs/admin/lab-settings.rst b/docs/admin/lab-settings.rst new file mode 100644 --- /dev/null +++ b/docs/admin/lab-settings.rst @@ -0,0 +1,41 @@ +.. _lab-settings: + +Lab Settings +============ + +|RCE| Lab Settings is for delivering features which may require an additional +level of support to optimize for production scenarios. To enable lab settings, +use the following instructions: + +1. Open the |RCE| configuration file, + :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` + +2. Add the following configuration option in the ``[app:main]`` section. + +.. code-block:: bash + + [app:main] + + ## Display extended labs settings + labs_settings_active = true + +3. Restart your |RCE| instance + +.. code-block:: bash + + $ rccontrol restart enterprise-1 + +4. You will see the labs setting on the + :menuselection:`Admin --> Settings --> labs` page. + +.. image:: ../images/lab-setting.png + +Available Lab Extras +-------------------- + +Once lab settings are enabled, the following features are available. + +.. toctree:: + :maxdepth: 1 + + svn-http diff --git a/docs/admin/nginx-config-example.rst b/docs/admin/nginx-config-example.rst new file mode 100644 --- /dev/null +++ b/docs/admin/nginx-config-example.rst @@ -0,0 +1,71 @@ +Nginx Configuration Example +--------------------------- + +Use the following example to configure Nginx as a your web server. + +.. code-block:: nginx + + upstream rc { + + server 127.0.0.1:5000; + + # add more instances for load balancing + # server 127.0.0.1:5001; + # server 127.0.0.1:5002; + } + + ## gist alias + + server { + listen 443; + server_name gist.myserver.com; + access_log /var/log/nginx/gist.access.log; + error_log /var/log/nginx/gist.error.log; + + ssl on; + ssl_certificate gist.rhodecode.myserver.com.crt; + ssl_certificate_key gist.rhodecode.myserver.com.key; + + ssl_session_timeout 5m; + + ssl_protocols SSLv3 TLSv1; + ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5; + ssl_prefer_server_ciphers on; + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; + + # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits + ssl_dhparam /etc/nginx/ssl/dhparam.pem; + + rewrite ^/(.+)$ https://rhodecode.myserver.com/_admin/gists/$1; + rewrite (.*) https://rhodecode.myserver.com/_admin/gists; + } + + server { + listen 443; + server_name rhodecode.myserver.com; + access_log /var/log/nginx/rhodecode.access.log; + error_log /var/log/nginx/rhodecode.error.log; + + ssl on; + ssl_certificate rhodecode.myserver.com.crt; + ssl_certificate_key rhodecode.myserver.com.key; + + ssl_session_timeout 5m; + + ssl_protocols SSLv3 TLSv1; + ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5; + ssl_prefer_server_ciphers on; + + ## uncomment root directive if you want to serve static files by nginx + ## requires static_files = false in .ini file + # root /path/to/installation/rhodecode/public; + + include /etc/nginx/proxy.conf; + location / { + try_files $uri @rhode; + } + + location @rhode { + proxy_pass http://rc; + } + } diff --git a/docs/admin/nginx-config.rst b/docs/admin/nginx-config.rst new file mode 100644 --- /dev/null +++ b/docs/admin/nginx-config.rst @@ -0,0 +1,14 @@ +.. _nginx-ws-ref: + +Nginx Configuration +=================== + +To set up your Nginx Web Server for optimal performance and security, use +the information in the following sections. + +.. toctree:: + + nginx-diffie-hellman + nginx-config-example + nginx-tuning + nginx-url-prefix diff --git a/docs/admin/nginx-diffie-hellman.rst b/docs/admin/nginx-diffie-hellman.rst new file mode 100644 --- /dev/null +++ b/docs/admin/nginx-diffie-hellman.rst @@ -0,0 +1,34 @@ +.. _dh-nginx: + +Diffie-Hellman Security +----------------------- + +To secure your web server, the `Guide to Deploying Diffie-Hellman for TLS`_ +contains important information worth reading. This link contains a good +`nginx secure configuration`_ example. The documentation below also contains +good security settings with some additional |RCE| specific examples. + +To secure your deployment of Diffie-Hellman, configure the following: + +* Generate a strong Diffie-hellman group, 2048-bit or stronger. + +.. code-block:: bash + + # to generate your dhparam.pem file, run in the terminal + openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 + +* Configure your server to only use modern, secure cipher suites in the + virtual hosts configuration file. + +.. code-block:: nginx + + # Set the TLS protocols and to only use modern, secure cipher suites. + ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + + # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits + ssl_dhparam /etc/nginx/ssl/dhparam.pem; + +.. _Guide to Deploying Diffie-Hellman for TLS: https://weakdh.org/sysadmin.html +.. _nginx secure configuration: https://gist.github.com/plentz/6737338 diff --git a/docs/admin/nginx-tuning.rst b/docs/admin/nginx-tuning.rst new file mode 100644 --- /dev/null +++ b/docs/admin/nginx-tuning.rst @@ -0,0 +1,33 @@ +.. _nginx-tuning: + +Nginx Tuning +------------ + +Set the following properties in your ``/etc/nginx/proxy.conf`` so it does not +timeout during large pushes. + +.. code-block:: nginx + + proxy_redirect off; + proxy_set_header Host $host; + + ## needed for container auth + # proxy_set_header REMOTE_USER $remote_user; + # proxy_set_header X-Forwarded-User $remote_user; + + proxy_set_header X-Url-Scheme $scheme; + proxy_set_header X-Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy-host $proxy_host; + proxy_buffering off; + proxy_connect_timeout 7200; + proxy_send_timeout 7200; + proxy_read_timeout 7200; + proxy_buffers 8 32k; + # Set this to a larger number if you experience timeouts + client_max_body_size 1024m; + client_body_buffer_size 128k; + large_client_header_buffers 8 64k; + add_header X-Frame-Options SAMEORIGIN; + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; diff --git a/docs/admin/nginx-url-prefix.rst b/docs/admin/nginx-url-prefix.rst new file mode 100644 --- /dev/null +++ b/docs/admin/nginx-url-prefix.rst @@ -0,0 +1,33 @@ +.. _nginx_url-pre: + +Nginx URL Prefix Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use the following example to configure Nginx to use a URL prefix. + +.. code-block:: nginx + + location /foo { + rewrite /foo(.*) /$1 break; + proxy_pass http://localhost:3200; + proxy_redirect off; + proxy_set_header Host $host; + } + +In addition to the Nginx configuration you will need to add the following +lines into the ``rhodecode.ini`` file. + +* In the the ``[app:main]`` section of your ``rhodecode.ini`` file add the + following line. + +.. code-block:: ini + + filter-with = proxy-prefix + +* At the end of the ``rhodecode.ini`` file add the following section. + +.. code-block:: ini + + [filter:proxy-prefix] + use = egg:PasteDeploy#prefix + prefix = / # Change into your chosen prefix diff --git a/docs/admin/public-access.rst b/docs/admin/public-access.rst new file mode 100644 --- /dev/null +++ b/docs/admin/public-access.rst @@ -0,0 +1,12 @@ +.. _public-access: + +Public Access +------------- + +By default |RCM| allows users to read all **public** |repos|. User +permissions and |repo| access can be configured explicitly, +and those permissions will override any default settings. The default +settings can be found under the following section: + +* :menuselection:`Admin --> Permissions --> Object` +* :menuselection:`Admin --> Permissions --> Global` diff --git a/docs/admin/repo-extra-fields.rst b/docs/admin/repo-extra-fields.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-extra-fields.rst @@ -0,0 +1,68 @@ +.. _repo-xtra: + +Repository Extra Fields +======================= + +Extra fields attached to a |repo| allow you to configure additional actions for +|RCX|. To install and read more about |RCX|, see the :ref:`install-rcx` section. + +Enabling Extra Fields +--------------------- + +To enable extra fields on |repos|, use the following steps: + +1. Go to the :menuselection:`Admin --> Settings --> Visual` page. +2. Check the :guilabel:`Use repository extra fields` box. +3. Save your changes. + + +Configuring Extra Fields +------------------------ + +To configure extra fields per repository, use the following steps: + +1. Go to :menuselection:`Admin --> Repositories` and select :guilabel:`Edit` + beside the |repo| to which you wish to add extra fields. +2. On the |repo| settings page, select the :guilabel:`Extra fields` tab. + +.. image:: ../images/extra-repo-fields.png + + +Example Usage +------------- + +To use the extra fields in an extension, see the example below. For more +information and examples, see the :ref:`integrations-ref` section. + +.. code-block:: python + + call = load_extension('http_notify.py') + if call: + url = 'http://default.url' # + + # possibly extract the URL from extra fields + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # an endpoint url data will be sent to, fetched from extra fields + # if exists, or fallback to default + kwargs['URL'] = kwargs.pop('webhook_url', None) or url + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # set additional keys and values to be sent via POST to given URL + kwargs['caller_type'] = 'rhodecode' + kwargs['date'] = time.time() # import time before + call(**kwargs) diff --git a/docs/admin/repo-hooks.rst b/docs/admin/repo-hooks.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-hooks.rst @@ -0,0 +1,56 @@ +.. _repo-hooks: + +|RCE| Repository Hooks +====================== + +|RCE| installs hooks inside each of the |repos| that it manages. These +hooks enable users to execute custom actions based on certain events. +This is the complete list of |repos| hooks and the events which trigger them: + +.. rst-class:: dl-horizontal + + \--CREATE_REPO_HOOK + Any time a |repo| is created. + + \--CREATE_REPO_GROUP_HOOK + Any time a |repo| group is created. + + \--CREATE_USER_HOOK + Any time a user is created. + + \--DELETE_REPO_HOOK + Any time a |repo| is created. + + \--DELETE_USER_HOOK + Any time a user is deleted. + + \--PRE_CREATE_USER_HOOK + Any time a user is created but before the action is executed by |RCE|. + + \--PRE_PULL + Any pull from a |repo| but before the action is executed by |RCE|. + + \--PRE_PUSH + Any push to a |repo| but before the action is executed by |RCE|. + + \--POST_PUSH + After any push to a |repo|. + + \--PUSH_HOOK + Any push to a |repo|, including editing tags or branches. + Commits via API actions that update references are also counted. + + \--PULL_HOOK + Any pull from a Repository. + +Using Repository Hooks +---------------------- + +To use these hooks you need to install |RCX|. For more information, see the +:ref:`install-rcx` section. + +Creating Extensions +------------------- + +To create your own extensions using these hooks, see the :ref:`dev-plug` +section. diff --git a/docs/admin/repo-issue-tracker.rst b/docs/admin/repo-issue-tracker.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-issue-tracker.rst @@ -0,0 +1,30 @@ +.. _repo-it: + +Repository Issue Tracker +======================== + +You can set an issue tracker connection in two ways with |RCE|. + +* At instance level, for more information see the + :ref:`rhodecode-issue-trackers-ref` section. +* At |repo| level. This allows you to configure a |repo| to use a different + issue tracker to the default one. + +Set an Issue Tracker per Repository +----------------------------------- + +To configure a |repo| to work with a different issue tracker to the default one, +use the following steps: + +1. Open :menuselection:`Admin --> Repositories --> repo name --> Edit --> Issue Tracker` +2. Uncheck the :guilabel:`Inherit from default settings` box. +3. Click :guilabel:`Add New`. +4. Fill in the following settings: + + * :guilabel:`Description`: A name for this set of rules. + * :guilabel:`Pattern`: The regular expression that will match issues + tagged in commit messages, or more see :ref:`issue-tr-eg-ref`. + * :guilabel:`URL`: The URL to your issue tracker. + * :guilabel:`Prefix`: The prefix with which you want to mark issues. + +5. Click :guilabel:`Save`. diff --git a/docs/admin/repo-perm-steps.rst b/docs/admin/repo-perm-steps.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-perm-steps.rst @@ -0,0 +1,45 @@ +.. _set-repo-perms: + +Setting Repository Permissions +------------------------------ + +To set the permissions on an individual |repo|, use the following steps: + +1. Open :menuselection:`Admin --> Repositories` and select + :guilabel:`edit` beside the |repo| you wish to configure. +2. On the |repo| settings page you will see a number of tabs. Exploring these + you will find the following main configuration options for a |repo|. +3. Once you make changes, select :guilabel:`Save` + +* :guilabel:`Repository group`: Lets you to add a |repo| to a |repo| group. +* :guilabel:`Owner`: Lets you change the |repo| owner. Useful when users are + moving roles within an organisation. +* :guilabel:`Enable automatic locking`: For more information, + see :ref:`repo-locking` +* :guilabel:`User Access`: On the permissions tab you can add users, + or user groups, and set the permissions each has for that |repo|. +* :guilabel:`Invalidate repository cache`: On the Caches tab you can delete + the |repo| cache, sometimes needed when mirroring. + +.. _set-repo-group-perms: + +Setting Repository Group Permissions +------------------------------------ + +To set the permissions on a Repository Group, use the following steps: + +1. Open :menuselection:`Admin --> Repository groups` and select + :guilabel:`edit` beside the |repo| you wish to configure. +2. On the |repo| group settings page you will see a number of tabs. Exploring + these you will find the following main configuration options: + +* :guilabel:`Owner`: Lets you change the group owner. Useful when users are + moving roles within an organisation. +* :guilabel:`Group parent`: Lets you add the |repo| group as a sub-group + of a larger group, i.e. :guilabel:`QA-Repos >> QA-Repos-Berlin` +* :guilabel:`Enable automatic locking`: For more information, + see :ref:`repo-locking` +* :guilabel:`User Access`: On the permissions tab you can add users, + or user groups, and set the permissions each has for that |repo| group. +* :guilabel:`Add Child Group`: Allows you to add sub-repository-groups + that will all share the same permissions. diff --git a/docs/admin/repo-vcs.rst b/docs/admin/repo-vcs.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-vcs.rst @@ -0,0 +1,48 @@ +.. _per-repo-vcs: + +Repository VCS Settings +======================= + +You can configure |repo| VCS (Version Control System) settings at a global +level, and individually per |repo|. Global settings are applied by default. +If you configure individual settings per |repo|, these will remain unaffected +by any subsequent global changes. + +Set Global Repository Settings +------------------------------ + +To configure |repo| settings across your |RCE| instance use the following steps: + +1. Go to to the :menuselection:`Admin --> Settings --> VCS` page. +2. Configure the following |repo| options: + + * :guilabel:`Web`: Require SSL if necessary. + * :guilabel:`Hooks`: Enable built in hooks. + * :guilabel:`Mercurial Settings`: Configure |hg| specific settings. + * :guilabel:`Repositories Location`: Set the file system |repos| location. + * :guilabel:`Subversion Settings`: Configure |svn| specific settings. + * :guilabel:`Pull Request Settings`: Enable the listed additional |pr| + features. + +3. Click :guilabel:`Save`. + + +Set Individual Repository Settings +---------------------------------- + +To configure specific VCS settings for an individual |repo|, use the following +steps: + +1. Go to to the :menuselection:`Admin --> Repositories --> Edit --> VCS` page. +2. Uncheck the :guilabel:`Inherit from global settings` box. +3. Configure the following |repo| options: + + * :guilabel:`Hooks`: Enable built in hooks. + * :guilabel:`Mercurial Settings` (|hg| Only): Configure |hg| specific + settings. + * :guilabel:`Subversion Settings` (|svn| Only): Configure |svn| specific + settings. + * :guilabel:`Pull Request Settings` (|git| and |hg| Only): Enable the + listed additional |pr| features. + +3. Click :guilabel:`Save`. diff --git a/docs/admin/reset-information.rst b/docs/admin/reset-information.rst new file mode 100644 --- /dev/null +++ b/docs/admin/reset-information.rst @@ -0,0 +1,95 @@ +.. _rhodecode-reset-ref: + +Settings Management +------------------- + +All |RCE| settings can be set from the user interface, but in the event that +it somehow becomes unavailable you can use ``ishell`` inside your |RCE| +``virtualenv`` to carry out emergency measures. + +.. warning:: + + Logging into the |RCE| database with ``iShell`` should only be done by an + experienced and knowledgeable database administrator. + +Reset Admin Account Privileges +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you accidentally remove your admin privileges from the admin account you +can restore them using ``ishell``. Use the following example to reset your +account permissions. + +.. code-block:: bash + + # Open iShell from the terminal + $ .rccontrol/enterprise-5/profile/bin/paster \ + ishell .rccontrol/enterprise-5/rhodecode.ini + +.. code-block:: mysql + + # Use this example to change user permissions + In [1]: adminuser = User.get_by_username('username') + In [2]: adminuser.admin = True + In [3]: Session.add(adminuser);Session().commit() + In [4]: exit() + +Set to read global ``.hgrc`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, |RCE| does not read global ``hgrc`` files in +``/etc/mercurial/hgrc`` or ``/etc/mercurial/hgrc.d`` because it +can lead to issues. This is set in the ``rhodecode_ui`` table for which +there is no UI. If you need to edit this you can +manually change the settings using SQL statements with ``ishell``. Use the +following example to make changes to this table. + +.. code-block:: bash + + # Open iShell from the terminal + $ .rccontrol/enterprise-5/profile/bin/paster \ + ishell.rccontrol/enterprise-5/rhodecode.ini + +.. code-block:: mysql + + # Use this example to enable global .hgrc access + In [4]: new_option = RhodeCodeUi() + In [5]: new_option.ui_section='web' + In [6]: new_option.ui_key='allow_push' + In [7]: new_option.ui_value='*' + In [8]: Session().add(new_option);Session().commit() + +Manually Reset Password +^^^^^^^^^^^^^^^^^^^^^^^ + +If you need to manually reset a user password, use the following steps. + +1. Navigate to your |RCE| install location. +2. Run the interactive ``ishell`` prompt. +3. Set a new password. + +Use the following code example to carry out these steps. + +.. code-block:: bash + + # starts the ishell interactive prompt + $ .rccontrol/enterprise-5/profile/bin/paster \ + ishell .rccontrol/enterprise-5/rhodecode.ini + +.. code-block:: mysql + + from rhodecode.lib.auth import generate_auth_token + from rhodecode.lib.auth import get_crypt_password + + # Enter the user name whose password you wish to change + my_user = 'USERNAME' + u = User.get_by_username(my_user) + + # If this fails then the user does not exist + u.auth_token = generate_auth_token(my_user) + + # Set the new password + u.password = get_crypt_password('PASSWORD') + + Session().add(u) + Session().commit() + exit diff --git a/docs/admin/rhodecode-backup.rst b/docs/admin/rhodecode-backup.rst new file mode 100644 --- /dev/null +++ b/docs/admin/rhodecode-backup.rst @@ -0,0 +1,26 @@ +.. _backup: + +==================== +Backing up RhodeCode +==================== + + +Settings +-------- + +Just copy your .ini file, it contains all RhodeCode settings. + +Whoosh index +------------ + +Whoosh index is located in **/data/index** directory where you installed +RhodeCode ie. the same place where the ini file is located + + +Database +-------- + +When using sqlite just copy rhodecode.db. +Any other database engine requires a manual backup operation. + +Database backup will contain all gathered statistics \ No newline at end of file diff --git a/docs/admin/sec-instance-basics.rst b/docs/admin/sec-instance-basics.rst new file mode 100644 --- /dev/null +++ b/docs/admin/sec-instance-basics.rst @@ -0,0 +1,31 @@ +.. _instance-basics: + +3 Basic User Security Steps +=========================== + +By implementing the following user configuration tasks, you will help to +secure your |RCE| instances. + + +Define the Instance Wide Default User +------------------------------------- + +The default user settings are applied across the whole instance. You should +define the default user so that newly created users immediately have +permission settings attached to their profile. For more information about +defining the default user settings, see the :ref:`default-perms` section. + +Configure Specific User Groups +------------------------------ + +By defining user groups, it allows you to put users into them and +have the group permissions applied to their profile. For more information about +defining the default user settings, see the :ref:`user-admin-set` section. + +Define the Default User in Each Group +------------------------------------- + +Apart from the system wide user permissions, each user group can apply its +settings to the default user permissions within the scope of the group. To +set the default user's permissions inside a user group, see the +:ref:`permissions-info-repo-group-access` section. diff --git a/docs/admin/sec-ip-white.rst b/docs/admin/sec-ip-white.rst new file mode 100644 --- /dev/null +++ b/docs/admin/sec-ip-white.rst @@ -0,0 +1,19 @@ +.. _settip-ip-white: + +Setting IP Restrictions +======================= + +To restrict access to your |RCE| instance you can set an IP Whitelist that +will only allow access from specific IP Addresses. This is useful for +ensuring only users on the company VPN can access the instance. + +To set this, go to +:menuselection:`Username --> Permissions --> IP Whitelist`, and add the safe +range of IP Addresses to the list. + +.. important:: + + Add the IP Address that you are currently using first, + otherwise you'll lock yourself out of the instance. + +.. image:: ../images/ip-whitey.png diff --git a/docs/admin/sec-x-frame.rst b/docs/admin/sec-x-frame.rst new file mode 100644 --- /dev/null +++ b/docs/admin/sec-x-frame.rst @@ -0,0 +1,57 @@ +.. _x-frame: + +Securing HTTPS Connections +-------------------------- + +* To secure your |RCE| instance against `Cross Frame Scripting`_ exploits, you + should configure your webserver ``x-frame-options`` setting. + +* To configure your instance for `HTTP Strict Transport Security`_, you need to + configure the ``Strict-Transport-Security`` setting. + +Nginx +^^^^^ + +In your nginx configuration, add the following lines in the correct files. For +more detailed information see the :ref:`nginx-ws-ref` section. + +.. code-block:: nginx + + # Add this line to the nginx.conf file + add_header X-Frame-Options SAMEORIGIN; + + # This line needs to be added inside your virtual hosts block/file + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; + +Apache +^^^^^^ + +In your :file:`apache2.conf` file, add the following line. For more detailed +information see the :ref:`apache-ws-ref` section. + +.. code-block:: apache + + # Add this to your virtual hosts file + Header always append X-Frame-Options SAMEORIGIN + + # Add this line in your virtual hosts file + Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" + +|RCE| Configuration +^^^^^^^^^^^^^^^^^^^ + +|RCE| can also be configured to force strict *https* connections and Strict +Transport Security. To set this, configure the following options to ``true`` +in the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. + +.. code-block:: ini + + ## force https in RhodeCode, fixes https redirects, assumes it's always https + force_https = false + + ## use Strict-Transport-Security headers + use_htsts = false + + +.. _Cross Frame Scripting: https://www.owasp.org/index.php/Cross_Frame_Scripting +.. _HTTP Strict Transport Security: https://www.owasp.org/index.php/HTTP_Strict_Transport_Security \ No newline at end of file diff --git a/docs/admin/sec-your-server.rst b/docs/admin/sec-your-server.rst new file mode 100644 --- /dev/null +++ b/docs/admin/sec-your-server.rst @@ -0,0 +1,179 @@ +.. _sec-your-server: + +Securing Your Server +-------------------- + +|RCE| runs on your hardware, and while it is developed with security in mind +it is also important that you ensure your servers are well secured. In this +section we will cover some basic security practices that are best to +configure when setting up your |RCE| instances. + +SSH Keys +^^^^^^^^ + +Using SSH keys to access your server provides more security than using the +standard username and password combination. To set up your SSH Keys, use the +following steps: + +1. On your local machine create the public/private key combination. The + private key you will keep, and the matching public key is copied to the + server. Setting a passphrase here is optional, if you set one you will + always be prompted for it when logging in. + +.. code-block:: bash + + # Generate SSH Keys + user@ubuntu:~$ ssh-keygen -t rsa + +.. code-block:: bash + + Generating public/private rsa key pair. + Enter file in which to save the key (/home/user/.ssh/id_rsa): + Created directory '/home/user/.ssh'. + Enter passphrase (empty for no passphrase): + Enter same passphrase again: + Your identification has been saved in /home/user/.ssh/id_rsa. + Your public key has been saved in /home/user/.ssh/id_rsa.pub. + The key fingerprint is: + 02:82:38:95:e5:30:d2:ad:17:60:15:7f:94:17:9f:30 user@ubuntu + The key's randomart image is: + +--[ RSA 2048]----+ + +2. SFTP to your server, and copy the public key to the ``~/.ssh`` folder. + +.. code-block:: bash + + # SFTP to your server + $ sftp user@hostname + + # copy your public key + sftp> mput /home/user/.ssh/id_rsa.pub /home/user/.ssh + Uploading /home/user/.ssh/id_rsa.pub to /home/user/.ssh/id_rsa.pub + /home/user/.ssh/id_rsa.pub 100% 394 0.4KB/s 00:00 + +3. On your server, add the public key to the :file:`~/.ssh/authorized_keys` + file. + +.. code-block:: bash + + $ cat /home/user/.ssh/id_rsa.pub > /home/user/.ssh/authorized_keys + +You should now be able to log into your server using your SSH +Keys. If you've added a passphrase you'll be asked for it. For more +information about using SSH keys with |RCE| |repos|, see the +:ref:`ssh-connection` section. + +VPN Whitelist +^^^^^^^^^^^^^ + +Most company networks will have a VPN. If you need to set one up, there are +many tutorials online for how to do that. Getting it right requires good +knowledge and attention to detail. Once set up, you can configure your +|RCE| instances to only allow user access from the VPN, to do this see the +:ref:`settip-ip-white` section. + +Public Key Infrastructure and SSL/TLS Encryption +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Public key infrastructure (PKI) is a system that creates, manages, and +validates certificates for identifying nodes on a network and encrypting +communication between them. SSL or TLS certificates can be used to +authenticate different entities with one another. To read more about PKIs, +see the `OpenSSL PKI tutorial`_ site, or this `Cloudflare PKI post`_. + +If the network you are running is SSL/TLS encrypted, you can configure |RCE| +to always use secure connections using the ``force_https`` and ``use_htsts`` +options in the :file:`/home/user/.rccontrol/instance-id/rhodecode.ini` file. +For more details, see the :ref:`x-frame` section. + +FireWalls and Ports +^^^^^^^^^^^^^^^^^^^ + +Setting up a network firewall for your internal traffic is a good way +of keeping it secure by blocking off any ports that should not be used. +Additionally, you can set non-default ports for certain functions which adds +an extra layer of security to your setup. + +A well configured firewall will restrict access to everything except the +services you need to remain open. By exposing fewer services you reduce the +number of potential vulnerabilities. + +There are a number of different firewall solutions, but for most Linux systems +using the built in `IpTables`_ firewall should suffice. On BSD systems you +can use `IPFILTER`_ or `IPFW`_. Use the following examples, and the IpTables +documentation to configure your IP Tables on Ubuntu. + +Changing the default SSH port. + +.. code-block:: bash + + # Open SSH config file and change to port 10022 + vi /etc/ssh/sshd_config + + # What ports, IPs and protocols we listen for + Port 10022 + +Setting IP Table rules for SSH traffic. It is important to note that the +default policy of your IpTables can differ and it is worth checking how each +is configured. The options are *ACCEPT*, *REJECT*, *DROP*, or *LOG*. The +usual practice is to block access on all ports and then enable access only on +the ports you with to expose. + +.. code-block:: bash + + # Check iptables policy + $ sudo iptables -L + + Chain INPUT (policy ACCEPT) + target prot opt source destination + + Chain FORWARD (policy ACCEPT) + target prot opt source destination + + Chain OUTPUT (policy ACCEPT) + target prot opt source destination + + # Close all ports by default + $ sudo iptables -P INPUT DROP + + $ sudo iptables -L + Chain INPUT (policy DROP) + target prot opt source destination + DROP all -- anywhere anywhere + + Chain FORWARD (policy ACCEPT) + target prot opt source destination + + Chain OUTPUT (policy ACCEPT) + target prot opt source destination + +.. code-block:: bash + + # Deny outbound SSH traffic + sudo iptables -A OUTPUT -p tcp --dport 10022 -j DROP + + # Allow incoming SSH traffic on port 10022 + sudo iptables -A INPUT -p tcp --dport 10022 -j ACCEPT + + # Allow incoming HTML traffic on port 80 and 443 + iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT + iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT + +Saving your IP Table rules, and restoring them from file. + +.. code-block:: bash + + # Save you IP Table Rules + iptables-save + + # Save your IP Table Rules to a file + sudo sh -c "iptables-save > /etc/iptables.rules" + + # Restore your IP Table rules from file + iptables-restore < /etc/iptables.rules + +.. _OpenSSL PKI tutorial: https://pki-tutorial.readthedocs.org/en/latest/# +.. _Cloudflare PKI post: https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/ +.. _IpTables: https://help.ubuntu.com/community/IptablesHowTo +.. _IPFW: https://www.freebsd.org/doc/handbook/firewalls-ipfw.html +.. _IPFILTER: https://www.freebsd.org/doc/handbook/firewalls-ipf.html diff --git a/docs/admin/security-tips.rst b/docs/admin/security-tips.rst new file mode 100644 --- /dev/null +++ b/docs/admin/security-tips.rst @@ -0,0 +1,15 @@ +.. _sec-tips: + +============= +Security Tips +============= + +The following section contains security tips for ensuring your |RCE| +instances are configured in as secure a manner as possible. + +.. toctree:: + + sec-your-server + sec-x-frame + sec-instance-basics + sec-ip-white diff --git a/docs/admin/setting-default-permissions.rst b/docs/admin/setting-default-permissions.rst new file mode 100644 --- /dev/null +++ b/docs/admin/setting-default-permissions.rst @@ -0,0 +1,69 @@ +.. _permissions-default-ref: + +Setting Default Permissions +--------------------------- + +Default permissions allow you to configure |RCM| so that when a new |repo|, user group, +or user is created their permissions are already defined. To set default permissions you need administrator +privileges. See the following sections for setting up your permissions system: + +* :ref:`user-default-ref` +* :ref:`user-group-default-ref` +* :ref:`repo-default-ref` +* :ref:`repo-group-default-ref` + +.. _user-default-ref: + +Setting User defaults +^^^^^^^^^^^^^^^^^^^^^ + +To set default user permissions, use the following steps. + +1. From the |RCM| interface, select :menuselection:`Admin --> Permissions` +2. Select the :guilabel:`Global` tab from the left-hand menu. The permissions + set on this screen apply to users and user-groups across the whole instance. +3. Save your changes + +.. _user-group-default-ref: + +Setting User Group defaults +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To set default user group permissions, use the following steps. + +1. From the |RCM| interface, select :menuselection:`Admin --> User groups` +2. Select :guilabel:`Permissions`, and configure the default user + permissions. All users will get these permissions unless + individually set. +3. Select :guilabel:`Global permissions`, and if you wish to configure + non-standard behaviour, uncheck the + :guilabel:`inherit from default settings` box and configure the desired + permissions +4. Save your changes + +.. _repo-default-ref: + +Setting Repository defaults +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To set default |repo| permissions, use the following steps. + +1. From the |RCM| interface, select :menuselection:`Admin --> Permissions` +2. Select the :guilabel:`Object` tab from the left-hand menu and set the + |perm| permissions +3. Save your changes + +.. _repo-group-default-ref: + +Setting Repository Group defaults +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To set default Repository Group permissions, use the following steps. + +1. From the |RCM| interface, select :menuselection:`Admin --> Repository Groups` +2. Select :guilabel:`Edit` beside the |repo| group you wish to configure +3. On the left-hand pane select :guilabel:`Permissions` +4. Set the default permissions for all |repos| created in this group +5. Save your changes + +.. |perm| replace:: :guilabel:`None, Read, Write, or Admin` diff --git a/docs/admin/setting-repo-perms.rst b/docs/admin/setting-repo-perms.rst new file mode 100644 --- /dev/null +++ b/docs/admin/setting-repo-perms.rst @@ -0,0 +1,26 @@ +.. _permissions-info-add-group-ref: + +Repository Administration +========================= + +Repository permissions in |RCM| can be managed in a number of different ways. +This overview should give you an insight into how you could adopt particular +settings for your needs: + +* Global |repo| permissions: This allows you to set the default permissions + for each new |repo| created within |RCM|, see :ref:`repo-default-ref`. All + |repos| created will inherit these permissions unless explicitly configured. +* Individual |repo| permissions: To set individual |repo| permissions, + see :ref:`set-repo-perms`. +* Repository Group permissions: This allows you to define the permissions for + a group, and all |repos| created within that group will inherit the same + permissions. + +.. toctree:: + + repo-perm-steps + repo-extra-fields + repo-hooks + repo-issue-tracker + repo-vcs + diff --git a/docs/admin/setting-usergroup-permissions.rst b/docs/admin/setting-usergroup-permissions.rst new file mode 100644 --- /dev/null +++ b/docs/admin/setting-usergroup-permissions.rst @@ -0,0 +1,25 @@ +.. _permissions-info-repo-group-access: + +Setting User Group Permissions +------------------------------ + +To set User Group |repo| permissions, use follow these steps: + +1. From the |RCE| interface, select + :menuselection:`Admin --> User Group --> Add User Group` +2. Enter a group name and description, and select :guilabel:`Save` +3. Select :guilabel:`edit` beside the new User Group. On the following + screen you will see a number of tabs. Exploring these + you will find the following most used options: + +* :guilabel:`Owner`: This allows you to change the User Group owner. As + super-admin you will still have access to this, but changing the owner lets + you delegate the user group management to another manager. +* :guilabel:`Members`: This allows you to added or remove users from the + group. +* :guilabel:`User Permissions`: On the permissions tab you can set the + permissions for each member. If not individually set, the members will + inherit the default user permissions. +* :guilabel:`Inherit from default settings`: On the Global Permissions tab + you can uncheck this option and explicitly configure the permissions for + the group. diff --git a/docs/admin/svn-http.rst b/docs/admin/svn-http.rst new file mode 100644 --- /dev/null +++ b/docs/admin/svn-http.rst @@ -0,0 +1,84 @@ +.. _svn-http: + +|svn| With Write Over HTTP +-------------------------- + +To use |svn| with write access, the currently supported method is over HTTP. +This requires you to configure your local machine so that it can access your +|RCE| instance. + +Prerequisites +^^^^^^^^^^^^^ + +- Enable lab setting on your |RCE| instance, see :ref:`lab-settings`. +- You need to install the following tools on your local machine: ``Apache`` and + ``mod_dav_svn``. Use the following Ubuntu as an example. + +.. code-block:: bash + + $ sudo apt-get install apache2 libapache2-mod-svn + +Once installed you need to enable ``dav_svn``: + +.. code-block:: bash + + $ sudo a2enmod dav_svn + +Configuring Apache Setup +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. tip:: + + It is recommended to run Apache on a port other than 80, due to possible + conflicts with other HTTP servers like nginx. To do this, set the + ``Listen`` parameter in the ``/etc/apache2/ports.conf`` file, for example + ``Listen 8090`` + + It is also recommended to run apache as the same user as |RCE|, otherwise + permission issues could occur. To do this edit the ``/etc/apache2/envvars`` + + .. code-block:: apache + + export APACHE_RUN_USER=ubuntu + export APACHE_RUN_GROUP=ubuntu + +1. To configure Apache, create and edit a virtual hosts file, for example + :file:`/etc/apache2/sites-available/default.conf`, or create another + virtual hosts file and add a location section inside the + ```` section. + +.. code-block:: apache + + + DAV svn + # Must be explicit path, relative not supported + SVNParentPath /PATH/TO/REPOSITORIES + SVNListParentPath On + Allow from all + Order allow,deny + + +.. note:: + + Once configured, check that you can see the list of repositories on your + |RCE| instance. + +2. Go to the :menuselection:`Admin --> Settings --> Labs` page, and + enable :guilabel:`Proxy Subversion HTTP requests`, and specify the + :guilabel:`Subversion HTTP Server URL`. + +Using |svn| +^^^^^^^^^^^ + +Once |svn| has been enabled on your instance, you can use it using the +following examples. For more |svn| information, see the `Subversion Red Book`_ + +.. code-block:: bash + + # To clone a repository + svn clone http://my-svn-server.example.com/my-svn-repo + + # svn commit + svn commit + +.. _Subversion Red Book: http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.ref.svn diff --git a/docs/admin/system-admin.rst b/docs/admin/system-admin.rst new file mode 100644 --- /dev/null +++ b/docs/admin/system-admin.rst @@ -0,0 +1,29 @@ +.. _rhodecode-admin-ref: + +System Administration +===================== + +The following are the most common system administration tasks. + +.. only:: latex + + * :ref:`vcs-server` + * :ref:`apache-ws-ref` + * :ref:`nginx-ws-ref` + * :ref:`rhodecode-tuning-ref` + * :ref:`indexing-ref` + * :ref:`rhodecode-reset-ref` + +.. toctree:: + + config-files-overview + vcs-server + apache-config + nginx-config + backup-restore + tuning-rhodecode + indexing + reset-information + enable-debug + admin-tricks + cleanup-cmds diff --git a/docs/admin/system-overview.rst b/docs/admin/system-overview.rst new file mode 100644 --- /dev/null +++ b/docs/admin/system-overview.rst @@ -0,0 +1,163 @@ +.. _system-overview-ref: + +System Overview +=============== + +Latest Version +-------------- + +* |release| on Unix and Windows systems. + +System Architecture +------------------- + +The following diagram shows a typical production architecture. + +.. image:: ../images/architecture-diagram.png + :align: center + +Supported Operating Systems +--------------------------- + +Linux +^^^^^ + +* Ubuntu 14.04 +* CentOS 6.2 and 7 +* Debian 7.8 +* RedHat Fedora +* Arch Linux +* SUSE Linux + +Windows +^^^^^^^ + +* Windows Vista Ultimate 64bit +* Windows 7 Ultimate 64bit +* Windows 8 Professional 64bit +* Windows 8.1 Enterprise 64bit +* Windows Server 2008 64bit +* Windows Server 2008-R2 64bit +* Windows Server 2012 64bit + +Supported Databases +------------------- + +* SQLite +* MySQL +* MariaDB +* PostgreSQL + +Supported Browsers +------------------ + +* Chrome +* Safari +* Firefox +* Internet Explorer 10 & 11 + +System Requirements +------------------- + +|RCM| performs best on machines with ultra-fast hard disks. Generally disk +performance is more important than CPU performance. In a corporate production +environment handling 1000s of users and |repos| you should deploy on a 12+ +core 64GB RAM server. In short, the more RAM the better. + +.. _config-rce-files: + +Configuration Files +------------------- + +* :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` +* :file:`/home/{user}/.rccontrol/{instance-id}/mapping.ini` +* :file:`/home/{user}/.rccontrol/{vcsserver-id}/vcsserver.ini` +* :file:`/home/{user}/.rccontrol/supervisor/supervisord.ini` +* :file:`/home/{user}/.rccontrol.ini` +* :file:`/home/{user}/.rhoderc` +* :file:`/home/{user}/.rccontrol/cache/MANIFEST` + +For more information, see the :ref:`config-files` section. + +Log Files +--------- + +* :file:`/home/{user}/.rccontrol/{instance-id}/enterprise.log` +* :file:`/home/{user}/.rccontrol/{vcsserver-id}/vcsserver.log` +* :file:`/home/{user}/.rccontrol/supervisor/supervisord.log` +* :file:`/tmp/rccontrol.log` +* :file:`/tmp/rhodecode_tools.log` + +Storage Files +------------- + +* :file:`/home/{user}/.rccontrol/{instance-id}/data/index/{index-file.toc}` +* :file:`/home/{user}/repos/.rc_gist_store` +* :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.db` +* :file:`/opt/rhodecode/store/{unique-hash}` + +Default Repositories Location +----------------------------- + +* :file:`/home/{user}/repos` + +Connection Methods +------------------ + +* HTTPS +* SSH +* |RCM| API + +Internationalization Support +---------------------------- + +Currently available in the following languages, see `Transifex`_ for the +latest details. If you want a new language added, please contact us. To +configure your language settings, see the :ref:`set-lang` section. + +.. hlist:: + + * Belorussian + * Chinese + * French + * German + * Italian + * Japanese + * Portuguese + * Polish + * Russian + * Spanish + +Licencing Information +--------------------- + +* See licencing information `here`_ + +Peer-to-peer Failover Support +----------------------------- + +* Yes + +Additional Binaries +------------------- + +* Yes, see :ref:`rhodecode-nix-ref` for full details. + +Remote Connectivity +------------------- + +* Available + +Executable Files +---------------- + +Windows: :file:`RhodeCode-installer-{version}.exe` + +Deprecated Support +------------------ + +- Internet Explorer 8 support deprecated since version 3.7.0. +- Internet Explorer 9 support deprecated since version 3.8.0. + +.. _here: https://rhodecode.com/licenses/ +.. _Transifex: https://www.transifex.com/projects/p/RhodeCode/ diff --git a/docs/admin/tuning-change-encoding.rst b/docs/admin/tuning-change-encoding.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-change-encoding.rst @@ -0,0 +1,22 @@ +.. _change-encoding: + +Change Default Encoding +----------------------- + +|RCE| uses ``utf8`` encoding by default. You can change the default encoding +in the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. To +change the default encoding used by |RCE|, set a new value for the +``default_encoding``. + +.. code-block:: ini + + # default encoding used to convert from and to unicode + # can be also a comma separated list of encoding in case of mixed + # encodings + default_encoding = utf8 + +.. note:: + + Changing the default encoding will affect many parts of your |RCE| + installation, including committers names, + file names, and the encoding of commit messages. diff --git a/docs/admin/tuning-change-large-file-dir.rst b/docs/admin/tuning-change-large-file-dir.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-change-large-file-dir.rst @@ -0,0 +1,32 @@ +.. _hg-lrg-loc: + +Change the |hg| Large Files Location +------------------------------------ + +|RCE| manages |hg| larges files from the following default location +:file:`/home/{user}/repos/.cache/largefiles`. If you wish to change this, use +the following steps: + +1. Open ishell from the terminal and use it to log into the |RCE| database by + specifying the instance :file:`rhodecode.ini` file. + +.. code-block:: bash + + # Open iShell from the terminal and set ini file + $ .rccontrol/enterprise-1/profile/bin/paster ishell .rccontrol/enterprise-1/rhodecode.ini + +2. Run the following commands, and ensure that |RCE| has write access to the + new directory: + +.. code-block:: mysql + + # Once logged into the database, use SQL to redirect + # the large files location + In [1]: from rhodecode.model.settings import SettingsModel + In [2]: SettingsModel().get_ui_by_key('usercache') + Out[2]: /mnt/hgfs/shared/workspace/xxxx/.cache/largefiles]> + + In [3]: largefiles_cache = SettingsModel().get_ui_by_key('usercache') + In [4]: largefiles_cache.ui_value = '/new/path’ + In [5]: Session().add(largefiles_cache);Session().commit() + diff --git a/docs/admin/tuning-gunicorn.rst b/docs/admin/tuning-gunicorn.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-gunicorn.rst @@ -0,0 +1,111 @@ +.. _increase-gunicorn: + +Increase Gunicorn Workers +------------------------- + +.. important:: + + If you increase the number of :term:`Gunicorn` workers, you also need to + increase the threadpool size of the VCS Server. The recommended size is + 6 times the number of Gunicorn workers. To set this, see + :ref:`vcs-server-config-file`. + +|RCE| comes with `Gunicorn`_ packaged in its Nix environment. To improve +performance you can increase the number of workers. To do this, use the +following steps: + +1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. +2. In the ``[server:main]`` section, increase the number of Gunicorn + ``workers`` using the following formula :math:`(2 * Cores) + 1`. + +.. code-block:: ini + + [server:main] + host = 127.0.0.1 + port = 10002 + use = egg:gunicorn#main + workers = 1 + threads = 1 + proc_name = RhodeCodeEnterprise + worker_class = sync + max_requests = 1000 + timeout = 3600 + +3. In the ``[app:main]`` section, set the ``instance_id`` property to ``*``. + +.. code-block:: ini + + # In the [app:main] section + [app:main] + # You must set `instance_id = *` + instance_id = * + +4. Save your changes. +5. Restart your |RCE| instance, using the following command: + +.. code-block:: bash + + $ rccontrol restart enterprise-1 + +If you scale across different machines, each |RCM| instance +needs to store its data on a shared disk, preferably together with your +|repos|. This data directory contains template caches, a whoosh index, +and is used for task locking to ensure safety across multiple instances. +To do this, set the following properties in the :file:`rhodecode.ini` file to +set the shared location across all |RCM| instances. + +.. code-block:: ini + + cache_dir = /file/path # set to shared location + search.location = /file/path # set to shared location + + #################################### + ### BEAKER CACHE #### + #################################### + beaker.cache.data_dir = /file/path # set to shared location + beaker.cache.lock_dir = /file/path # set to shared location + + + +Gunicorn SSL support +-------------------- + + +:term:`Gunicorn` wsgi server allows users to use HTTPS connection directly +without a need to use HTTP server like Nginx or Apache. To Configure +SSL support directly with :term:`Gunicorn` you need to simply add the key +and certificate paths to your configuration file. + +1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. +2. In the ``[server:main]`` section, add two new variables + called `certfile` and `keyfile`. + +.. code-block:: ini + + [server:main] + host = 127.0.0.1 + port = 10002 + use = egg:gunicorn#main + workers = 1 + threads = 1 + proc_name = RhodeCodeEnterprise + worker_class = sync + max_requests = 1000 + timeout = 3600 + # adding ssl support + certfile = /home/ssl/my_server_com.pem + keyfile = /home/ssl/my_server_com.key + +4. Save your changes. +5. Restart your |RCE| instance, using the following command: + +.. code-block:: bash + + $ rccontrol restart enterprise-1 + +After this is enabled you can *only* access your instances via https:// +protocol. Check out more docs here `Gunicorn SSL Docs`_ + + +.. _Gunicorn: http://gunicorn.org/ +.. _Gunicorn SSL Docs: http://docs.gunicorn.org/en/stable/settings.html#ssl diff --git a/docs/admin/tuning-hg-auth-loop.rst b/docs/admin/tuning-hg-auth-loop.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-hg-auth-loop.rst @@ -0,0 +1,17 @@ +.. _hg-auth-loop: + +|hg| Authentication Tuning +-------------------------- + +When using external authentication tools such as LDAP with |hg|, a +password retry loop in |hg| can result in users being locked out due to too +many failed password attempts. To prevent this from happening, add the +following setting to your +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file, in the +``[app:main]`` section. + + +.. code-block:: ini + + [app:main] + auth_ret_code_detection = true diff --git a/docs/admin/tuning-increase-cache-size.rst b/docs/admin/tuning-increase-cache-size.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-increase-cache-size.rst @@ -0,0 +1,17 @@ +.. _cache-size: + +Increase Cache Size +------------------- + +When managing hundreds of |repos| from the main |RCE| interface the system +can become slow when the cache expires. Increasing the cache expiration +option improves the response times of the main user interface. +To increase your cache size, change the following default value in the +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. The value +is specified in seconds. + +.. code-block:: ini + + beaker.cache.long_term.expire=3600 # day (86400) week (604800) + +.. note:: The |RCE| cache automatically expires for changed |repos|. diff --git a/docs/admin/tuning-increase-db-performance.rst b/docs/admin/tuning-increase-db-performance.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-increase-db-performance.rst @@ -0,0 +1,23 @@ +.. _db-session-ref: + +Increase Database Performance +----------------------------- + +To increase database performance switch to database-based user sessions. +File-based sessions are only suitable for smaller setups. The most common +issue being file limit errors which occur if there are lots of session files. +Therefore, in a large scale deployment, to give better performance, +scalability, and maintainability we recommend switching from file-based +sessions to database-based user sessions. + +To switch to database-based user sessions uncomment the following section in +your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. + +.. code-block:: ini + + # db session + beaker.session.type = ext:database + + # adjust this property to include your database credentials + beaker.session.sa.url = postgresql://postgres:@localhost/rhodecode + beaker.session.table_name = db_session diff --git a/docs/admin/tuning-mount-cache-memory.rst b/docs/admin/tuning-mount-cache-memory.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-mount-cache-memory.rst @@ -0,0 +1,42 @@ +.. _data-mem: + +Mount Cache Folders To Memory +----------------------------- + +To increase the performance of folders containing cache data, you can mount +them to memory. The following folders specified in the :file:`rhodecode.ini` +file would benefit from this. + +.. code-block:: ini + + cache_dir = %(here)s/data + search.location = %(here)s/data/index + +Use the following Ubuntu example to mount these to memory, or see your +particular |os| instructions. The expected performance benefit is +approximately 5%. You should ensure you allocate an adequate amount of memory +depending on your available resources. + +.. code-block:: bash + + # mount to memory with 2GB limit and 755 write permissions + mount -t tmpfs -o size=2G,mode=0755 tmpfs /home/user/.rccontrol/enterprise-1/data + mount -t tmpfs -o size=2G,mode=0755 tmpfs /home/user/.rccontrol/enterprise-1/data/index + +.. _move-tmp: + +Move ``tmp`` to TMPFS +--------------------- + +|RCE| components heavily use the :file:`/tmp` folder, so moving your +:file:`/tmp` folder into to a RAM-based TMPS can lead to a noticeable +performance boost. + +.. code-block:: bash + + # mount tmp to memory with 2GB limit and 755 write permissions + mount -t tmpfs -o size=2G,mode=0755 tmpfs /tmp + +For more information about TMPFS, see the documentation `here`_. + +.. _here: https://wiki.archlinux.org/index.php/Tmpfs diff --git a/docs/admin/tuning-rhodecode.rst b/docs/admin/tuning-rhodecode.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-rhodecode.rst @@ -0,0 +1,20 @@ +.. _rhodecode-tuning-ref: + +Tuning |RCE| +============ + +To customize your |RCE| |version| installation for maximum performance you +may find some of the following methods useful. + +.. toctree:: + + tuning-gunicorn + tuning-vcs-memory-cache + tuning-increase-db-performance + tuning-scale-horizontally + tuning-increase-cache-size + tuning-mount-cache-memory + tuning-change-encoding + tuning-change-large-file-dir + tuning-hg-auth-loop + diff --git a/docs/admin/tuning-scale-horizontally.rst b/docs/admin/tuning-scale-horizontally.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-scale-horizontally.rst @@ -0,0 +1,51 @@ +.. _scale-horizontal: + +Scale Horizontally +------------------ + +Horizontal scaling means adding more machines or workers into your pool of +resources. Horizontally scaling |RCE| gives a huge performance increase, +especially under large traffic scenarios with a high number of requests. This +is very beneficial when |RCE| is serving many users simultaneously, +or if continuous integration servers are automatically pulling and pushing code. + +To horizontally scale |RCE| you should use the following steps: + +1. In the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file, + set ``instance_id = *``. This enables |RCE| to use multiple nodes. +2. Define the number of worker threads using the formula + :math:`(2 * Cores) + 1`. For example 4 CPU cores would lead to + :math:`(2 * 4) + 1 = 9` workers. In some cases it's ok to increase number of + workers even beyond this formula. Generally the more workers, the more + simultaneous connections the system can handle. + +It is recommended to create another dedicated |RCE| instance to handle +traffic from build farms or continuous integration servers. + +.. note:: + + You should configure your load balancing accordingly. We recommend writing + load balancing rules that will separate regular user traffic from + automated process traffic like continuous servers or build bots. + +If you scale across different machines, each |RCE| instance needs to store +its data on a shared disk, preferably together with your repositories. This +data directory contains template caches, a whoosh index, +and is used for task locking to ensure safety across multiple instances. To +do this, set the following properties in the +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file to set +the shared location across all |RCE| instances. + +.. code-block:: ini + + cache_dir = /file/path # set to shared directory location + search.location = /file/path # set to shared directory location + beaker.cache.data_dir = /file/path # set to shared directory location + beaker.cache.lock_dir = /file/path # set to shared directory location + +.. note:: + + If Celery is used on each instance then you should run separate Celery + instances, but the message broker should be the same for all of them. + This excludes one RabbitMQ shared server. + diff --git a/docs/admin/tuning-vcs-memory-cache.rst b/docs/admin/tuning-vcs-memory-cache.rst new file mode 100644 --- /dev/null +++ b/docs/admin/tuning-vcs-memory-cache.rst @@ -0,0 +1,8 @@ +.. _adjust-vcs-mem-cache: + +Adjusting VCS Memory Cache +-------------------------- + +The VCS Server mamory cache can be adjusted to work best with the resources +available to your |RCE| instance. If you find that memory resources are under +pressure, see the :ref:`vcs-server-maintain` section for details. diff --git a/docs/admin/user-admin.rst b/docs/admin/user-admin.rst new file mode 100644 --- /dev/null +++ b/docs/admin/user-admin.rst @@ -0,0 +1,23 @@ +.. _user-admin-set: + +User Administration +=================== + +|RCM| enables you to define permissions for the following entities within the +system; **users**, **user groups**, **repositories**, **repository groups**. + +Within each one of these entities you can set default settings, +and then all users or |repos| inherit those default permission settings +unless individually defined. Each of these entities can have the following +permissions applied to it; |perm|. + +.. toctree:: + + public-access + default-user-perms + adding-anonymous-user + adding-new-user + setting-default-permissions + setting-usergroup-permissions + +.. |perm| replace:: **None**, **Read**, **Write**, or **Admin** \ No newline at end of file diff --git a/docs/admin/vcs-server.rst b/docs/admin/vcs-server.rst new file mode 100644 --- /dev/null +++ b/docs/admin/vcs-server.rst @@ -0,0 +1,301 @@ +.. _vcs-server: + +VCS Server Management +--------------------- + +The VCS Server handles |RCM| backend functionality. You need to configure +a VCS Server to run with a |RCM| instance. If you do not, you will be missing +the connection between |RCM| and its |repos|. This will cause error messages +on the web interface. You can run your setup in the following configurations, +currently the best performance is one VCS Server per |RCM| instance: + +* One VCS Server per |RCM| instance. +* One VCS Server handling multiple instances. + +.. important:: + + If your server locale settings are not correctly configured, + |RCE| and the VCS Server can run into issues. See this `Ask Ubuntu`_ post + which explains the problem and gives a solution. + +For more information, see the following sections: + +* :ref:`install-vcs` +* :ref:`config-vcs` +* :ref:`vcs-server-options` +* :ref:`vcs-server-versions` +* :ref:`vcs-server-maintain` +* :ref:`vcs-server-config-file` + +.. _install-vcs: + +VCS Server Installation +^^^^^^^^^^^^^^^^^^^^^^^ + +To install a VCS Server, see +:ref:`Installing a VCS server `. + +.. _config-vcs: + +Hooking |RCE| to its VCS Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To configure a |RCE| instance to use a VCS server, see +:ref:`Configuring the VCS Server connection `. + +.. _vcs-server-options: + +|RCE| VCS Server Options +^^^^^^^^^^^^^^^^^^^^^^^^ + +The following list shows the available options on the |RCM| side of the +connection to the VCS Server. The settings are configured per +instance in the +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. + +.. rst-class:: dl-horizontal + + \vcs.backends + Set a comma-separated list of the |repo| options available from the + web interface. The default is ``hg, git, svn``, + which is all |repo| types available. + + \vcs.connection_timeout + Set the length of time in seconds that the VCS Server waits for + requests to process. After the timeout expires, + the request is closed. The default is ``3600``. Set to a higher + number if you experience network latency, or timeout issues with very + large push/pull requests. + + \vcs.server.enable + Enable or disable the VCS Server. The available options are ``true`` or + ``false``. The default is ``true``. + + \vcs.server + Set the host, either hostname or IP Address, and port of the VCS server + you wish to run with your |RCM| instance. + +.. code-block:: ini + + ################## + ### VCS CONFIG ### + ################## + # set this line to match your VCS Server + vcs.server = 127.0.0.1:10004 + # Set to False to disable the VCS Server + vcs.server.enable = True + vcs.backends = hg, git, svn + vcs.connection_timeout = 3600 + + +.. _vcs-server-versions: + +VCS Server Versions +^^^^^^^^^^^^^^^^^^^ + +An updated version of the VCS Server is released with each |RCE| version. Use +the VCS Server number that matches with the |RCE| version to pair the +appropriate ones together. For |RCE| versions pre 3.3.0, +VCS Server 1.X.Y works with |RCE| 3.X.Y, for example: + +* VCS Server 1.0.0 works with |RCE| 3.0.0 +* VCS Server 1.2.2 works with |RCE| 3.2.2 + +For |RCE| versions post 3.3.0, the VCS Server and |RCE| version numbers +match, for example: + +* VCS Server |release| works with |RCE| |release| + +.. _vcs-server-maintain: + +VCS Server Memory Optimization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To configure the VCS server to manage the cache efficiently, you need to +configure the following options in the +:file:`/home/{user}/.rccontrol/{vcsserver-id}/vcsserver.ini` file. Once +configured, restart the VCS Server. + +.. rst-class:: dl-horizontal + + \beaker.cache.repo_object.type = memorylru + Configures the cache to discard the least recently used items. + This setting takes the following valid options: + + * ``memorylru``: The default setting, which removes the least recently + used items from the cache. + * ``memory``: Runs the VCS Server without clearing the cache. + * ``nocache``: Runs the VCS Server without a cache. This will + dramatically reduce the VCS Server performance. + + \beaker.cache.repo_object.max_items = 100 + Sets the maximum number of items stored in the cache, before the cache + starts to be cleared. + + As a general rule of thumb, running this value at 120 resulted in a + 5GB cache. Running it at 240 resulted in a 9GB cache. Your results + will differ based on usage patterns and |repo| sizes. + + Tweaking this value to run at a fairly constant memory load on your + server will help performance. + +To clear the cache completely, you can restart the VCS Server. + +.. important:: + + While the VCS Server handles a restart gracefully on the web interface, + it will drop connections during push/pull requests. So it is recommended + you only perform this when there is very little traffic on the instance. + +Use the following example to restart your VCS Server, +for full details see the :ref:`RhodeCode Control CLI `. + +.. code-block:: bash + + $ rccontrol status + +.. code-block:: vim + + - NAME: vcsserver-1 + - STATUS: RUNNING + - TYPE: VCSServer + - VERSION: 1.0.0 + - URL: http://127.0.0.1:10001 + + $ rccontrol restart vcsserver-1 + Instance "vcsserver-1" successfully stopped. + Instance "vcsserver-1" successfully started. + +.. _vcs-server-config-file: + +VCS Server Configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +You can configure settings for multiple VCS Servers on your +system using their individual configuration files. Use the following +properties inside the configuration file to set up your system. The default +location is :file:`home/{user}/.rccontrol/{vcsserver-id}/vcsserver.ini`. +For a more detailed explanation of the logger levers, see :ref:`debug-mode`. + +.. rst-class:: dl-horizontal + + \host + Set the host on which the VCS Server will run. + + \port + Set the port number on which the VCS Server will be available. + + \locale + Set the locale the VCS Server expects. + + \threadpool_size + Set the size of the threadpool used to communicate + with the WSGI workers. This should be at least 6 times the number of + WSGI worker processes. + + \timeout + Set the timeout for RPC communication in seconds. + +.. note:: + + After making changes, you need to restart your VCS Server to pick them up. + +.. code-block:: ini + + ################################################################################ + # RhodeCode VCSServer - configuration # + # # + ################################################################################ + + [DEFAULT] + host = 127.0.0.1 + port = 9900 + locale = en_US.UTF-8 + # number of worker threads, this should be set based on a formula threadpool=N*6 + # where N is number of RhodeCode Enterprise workers, eg. running 2 instances + # 8 gunicorn workers each would be 2 * 8 * 6 = 96, threadpool_size = 96 + threadpool_size = 16 + timeout = 0 + + # cache regions, please don't change + beaker.cache.regions = repo_object + beaker.cache.repo_object.type = memorylru + beaker.cache.repo_object.max_items = 1000 + + # cache auto-expires after N seconds + beaker.cache.repo_object.expire = 10 + beaker.cache.repo_object.enabled = true + + + ################################ + ### LOGGING CONFIGURATION #### + ################################ + [loggers] + keys = root, vcsserver, pyro4, beaker + + [handlers] + keys = console + + [formatters] + keys = generic + + ############# + ## LOGGERS ## + ############# + [logger_root] + level = NOTSET + handlers = console + + [logger_vcsserver] + level = DEBUG + handlers = + qualname = vcsserver + propagate = 1 + + [logger_beaker] + level = DEBUG + handlers = + qualname = beaker + propagate = 1 + + [logger_pyro4] + level = DEBUG + handlers = + qualname = Pyro4 + propagate = 1 + + + ############## + ## HANDLERS ## + ############## + + [handler_console] + class = StreamHandler + args = (sys.stderr,) + level = DEBUG + formatter = generic + + [handler_file] + class = FileHandler + args = ('vcsserver.log', 'a',) + level = DEBUG + formatter = generic + + [handler_file_rotating] + class = logging.handlers.TimedRotatingFileHandler + # 'D', 5 - rotate every 5days + # you can set 'h', 'midnight' + args = ('vcsserver.log', 'D', 5, 10,) + level = DEBUG + formatter = generic + + ################ + ## FORMATTERS ## + ################ + + [formatter_generic] + format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s + datefmt = %Y-%m-%d %H:%M:%S + + +.. _Ask Ubuntu: http://askubuntu.com/questions/162391/how-do-i-fix-my-locale-issue diff --git a/docs/api/api.rst b/docs/api/api.rst new file mode 100644 --- /dev/null +++ b/docs/api/api.rst @@ -0,0 +1,2824 @@ +.. _api: + +API Documentation +================= + +The |RCE| API uses a single scheme for calling all API methods. The API is +implemented with JSON protocol in both directions. To send API requests to +your instance of |RCE|, use the following URL format +``/_admin`` + +.. note:: + + To use the API, you should configure the :file:`~/.rhoderc` file with + access details per instance. For more information, see + :ref:`config-rhoderc`. + + +API ACCESS FOR WEB VIEWS +------------------------ + +API access can also be turned on for each web view in |RCE| that is +decorated with a `@LoginRequired` decorator. To enable API access, change +the standard login decorator to `@LoginRequired(api_access=True)`. + +From |RCM| version 1.7.0 you can configure a white list +of views that have API access enabled by default. To enable these, +edit the |RCM| configuration ``.ini`` file. The default location is: + +* |RCM| Pre-2.2.7 :file:`root/rhodecode/data/production.ini` +* |RCM| 3.0 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` + +To configure the white list, edit this section of the file. In this +configuration example, API access is granted to the patch/diff raw file and +archive. + +.. code-block:: ini + + ## List of controllers (using glob syntax) that AUTH TOKENS could be used for access. + ## Adding ?auth_token = to the url authenticates this request as if it + ## came from the the logged in user who own this authentication token. + ## + ## Syntax is :. + ## The list should be "," separated and on a single line. + ## + api_access_controllers_whitelist = ChangesetController:changeset_patch,ChangesetController:changeset_raw,ilesController:raw,FilesController:archivefile, + +After this change, a |RCE| view can be accessed without login by adding a +GET parameter ``?auth_token=`` to a url. For example to +access the raw diff. + +.. code-block:: html + + http:////changeset-diff/?auth_token= + +By default this is only enabled on RSS/ATOM feed views. Exposing raw diffs is a +good way to integrate with 3rd party services like code review, or build farms +that could download archives. + +API ACCESS +---------- + +All clients are required to send JSON-RPC spec JSON data. + +.. code-block:: bash + + { + "id:"", + "auth_token":"", + "method":"", + "args":{"":""} + } + +Example call for auto pulling from remote repositories using curl: + +.. code-block:: bash + + curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1, + "auth_token":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull", "args":{"repo":"CPython"}}' + +Provide those parameters: + - **id** A value of any type, which is used to match the response with the + request that it is replying to. + - **auth_token** for access and permission validation. + - **method** is name of method to call + - **args** is an ``key:value`` list of arguments to pass to method + +.. note:: + + To get your |authtoken|, from the |RCE| interface, + go to: + :menuselection:`username --> My account --> Auth tokens` + + For security reasons you should always create a dedicated |authtoken| for + API use only. + + +The |RCE| API will always return a JSON-RPC response: + +.. code-block:: bash + + { + "id": , # matching id sent by request + "result": ""|null, # JSON formatted result, null if any errors + "error": "null"| # JSON formatted error (if any) + } + +All responses from API will be with `HTTP/1.0 200 OK` status code. +If there is an error when calling the API, the *error* key will contain a +failure description and the *result* will be `null`. + +API CLIENT +---------- + +To install the |RCE| API, see :ref:`install-tools`. To configure the API per +instance, see the :ref:`rc-tools` section as you need to configure a +:file:`~/.rhoderc` file with your |authtokens|. + +Once you have set up your instance API access, use the following examples to +get started. + +.. code-block:: bash + + # Getting the 'rhodecode' repository + # from a RhodeCode Enterprise instance + rhodecode-api --instance-name=enterprise-1 get_repo repoid:rhodecode + + Calling method get_repo => http://127.0.0.1:5000 + Server response + { + + } + + # Creating a new mercurial repository called 'brand-new' + # with a description 'Repo-description' + rhodecode-api --instance-name=enterprise-1 create_repo repo_name:brand-new repo_type:hg description:Repo-description + { + "error": null, + "id": 1110, + "result": { + "msg": "Created new repository `brand-new`", + "success": true, + "task": null + } + } + +A broken example, what not to do. + +.. code-block:: bash + + # A call missing the required arguments + # and not specifying the instance + rhodecode-api get_repo + + Calling method get_repo => http://127.0.0.1:5000 + Server response + "Missing non optional `repoid` arg in JSON DATA" + +You can specify pure JSON using the ``--format`` parameter. + +.. code-block:: bash + + rhodecode-api --format=json get_repo repoid:rhodecode + +In such case only output that this function shows is pure JSON, we can use that +and pipe output to some json formatter. + +If output is in pure JSON format, you can pipe output to a JSON formatter. + +.. code-block:: bash + + rhodecode-api --instance-name=enterprise-1 --format=json get_repo repoid:rhodecode | python -m json.tool + +API METHODS +----------- + +Each method by default required following arguments. + +.. code-block:: bash + + id : "" + auth_token : "" + method : "" + args : {} + +Use each **param** from docs and put it in args, Optional parameters +are not required in args. + +.. code-block:: bash + + args: {"repoid": "rhodecode"} + +.. Note: From this point on things are generated by the script in + `scripts/fabfile.py`. To change things below, update the docstrings in the + ApiController. + +.. --- API DEFS MARKER --- + +pull +---- + +.. py:function:: pull(apiuser, repoid) + + Triggers a pull on the given repository from a remote location. You + can use this to keep remote repositories up-to-date. + + This command can only be run using an |authtoken| with admin + rights to the specified repository. For more information, + see :ref:`config-token-ref`. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "Pulled from ``" + "repository": "" + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "Unable to pull changes from ``" + } + + +strip +----- + +.. py:function:: strip(apiuser, repoid, revision, branch) + + Strips the given revision from the specified repository. + + * This will remove the revision and all of its decendants. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param revision: The revision you wish to strip. + :type revision: str + :param branch: The branch from which to strip the revision. + :type branch: str + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "'Stripped commit from repo ``'" + "repository": "" + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "Unable to strip commit from repo ``" + } + + +rescan_repos +------------ + +.. py:function:: rescan_repos(apiuser, remove_obsolete=) + + Triggers a rescan of the specified repositories. + + * If the ``remove_obsolete`` option is set, it also deletes repositories + that are found in the database but not on the file system, so called + "clean zombies". + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param remove_obsolete: Deletes repositories from the database that + are not found on the filesystem. + :type remove_obsolete: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : + result : { + 'added': [,...] + 'removed': [,...] + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + 'Error occurred during rescan repositories action' + } + + +invalidate_cache +---------------- + +.. py:function:: invalidate_cache(apiuser, repoid, delete_keys=) + + Invalidates the cache for the specified repository. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param repoid: Sets the repository name or repository ID. + :type repoid: str or int + :param delete_keys: This deletes the invalidated keys instead of + just flagging them. + :type delete_keys: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : + result : { + 'msg': Cache for repository `` was invalidated, + 'repository': + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + 'Error occurred during cache invalidation action' + } + + +lock +---- + +.. py:function:: lock(apiuser, repoid, locked=, userid=>) + + Sets the lock state of the specified |repo| by the given user. + From more information, see :ref:`repo-locking`. + + * If the ``userid`` option is not set, the repository is locked to the + user who called the method. + * If the ``locked`` parameter is not set, the current lock state of the + repository is displayed. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Sets the repository name or repository ID. + :type repoid: str or int + :param locked: Sets the lock state. + :type locked: Optional(``True`` | ``False``) + :param userid: Set the repository lock to this user. + :type userid: Optional(str or int) + + Example error output: + + .. code-block:: bash + + id : + result : { + 'repo': '', + 'locked': , + 'locked_since': , + 'locked_by': , + 'lock_reason': , + 'lock_state_changed': , + 'msg': 'Repo `` locked by `` on .' + or + 'msg': 'Repo `` not locked.' + or + 'msg': 'User `` set lock state for repo `` to ``' + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + 'Error occurred locking repository `` + } + + +get_locks +--------- + +.. py:function:: get_locks(apiuser, userid=>) + + Displays all repositories locked by the specified user. + + * If this command is run by a non-admin user, it returns + a list of |repos| locked by that user. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid whose list of locked |repos| will be + displayed. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : + result : { + [repo_object, repo_object,...] + } + error : null + + +get_ip +------ + +.. py:function:: get_ip(apiuser, userid=>) + + Displays the IP Address as seen from the |RCE| server. + + * This command displays the IP Address, as well as all the defined IP + addresses for the specified user. If the ``userid`` is not set, the + data returned is for the user calling the method. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid for which associated IP Address data + is returned. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : + result : { + "server_ip_addr": "", + "user_ips": [ + { + "ip_addr": "", + "ip_range": ["", ""], + }, + ... + ] + } + + +show_ip +------- + +.. py:function:: show_ip(apiuser, userid=>) + + Displays the IP Address as seen from the |RCE| server. + + * This command displays the IP Address, as well as all the defined IP + addresses for the specified user. If the ``userid`` is not set, the + data returned is for the user calling the method. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid for which associated IP Address data + is returned. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : + result : { + "server_ip_addr": "", + "user_ips": [ + { + "ip_addr": "", + "ip_range": ["", ""], + }, + ... + ] + } + + +get_license_info +---------------- + +.. py:function:: get_license_info(apiuser) + + Returns the |RCE| license information. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : + result : { + 'rhodecode_version': , + 'token': , + 'issued_to': , + 'issued_on': , + 'expires_on': , + 'type': , + 'users_limit': , + 'key': + } + error : null + + +set_license_key +--------------- + +.. py:function:: set_license_key(apiuser, key) + + Sets the |RCE| license key. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param key: This is the license key to be set. + :type key: str + + Example output: + + .. code-block:: bash + + id : + result: { + "msg" : "updated license information", + "key": + } + error: null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "license key is not valid" + or + "trial licenses cannot be uploaded" + or + "error occurred while updating license" + } + + +get_server_info +--------------- + +.. py:function:: get_server_info(apiuser) + + Returns the |RCE| server information. + + This includes the running version of |RCE| and all installed + packages. This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : + result : { + 'modules': [,...] + 'py_version': , + 'platform': , + 'rhodecode_version': + } + error : null + + +get_user +-------- + +.. py:function:: get_user(apiuser, userid=>) + + Returns the information associated with a username or userid. + + * If the ``userid`` is not set, this command returns the information + for the ``userid`` calling the method. + + .. note:: + + Normal users may only run this command against their ``userid``. For + full privileges you must run this command using an |authtoken| with + admin rights. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid for which data will be returned. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": , + "result": { + "active": true, + "admin": false, + "api_key": "api-key", + "api_keys": [ list of keys ], + "email": "user@example.com", + "emails": [ + "user@example.com" + ], + "extern_name": "rhodecode", + "extern_type": "rhodecode", + "firstname": "username", + "ip_addresses": [], + "language": null, + "last_login": "Timestamp", + "lastname": "surnae", + "permissions": { + "global": [ + "hg.inherit_default_perms.true", + "usergroup.read", + "hg.repogroup.create.false", + "hg.create.none", + "hg.extern_activate.manual", + "hg.create.write_on_repogroup.false", + "hg.usergroup.create.false", + "group.none", + "repository.none", + "hg.register.none", + "hg.fork.repository" + ], + "repositories": { "username/example": "repository.write"}, + "repositories_groups": { "user-group/repo": "group.none" }, + "user_groups": { "user_group_name": "usergroup.read" } + }, + "user_id": 32, + "username": "username" + } + } + + +get_users +--------- + +.. py:function:: get_users(apiuser) + + Lists all users in the |RCE| user database. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : + result: [, ...] + error: null + + +create_user +----------- + +.. py:function:: create_user(apiuser, username, email, password=, firstname=, lastname=, active=, admin=, extern_name=, extern_type=, force_password_change=) + + Creates a new user and returns the new user object. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param username: Set the new username. + :type username: str or int + :param email: Set the user email address. + :type email: str + :param password: Set the new user password. + :type password: Optional(str) + :param firstname: Set the new user firstname. + :type firstname: Optional(str) + :param lastname: Set the new user surname. + :type lastname: Optional(str) + :param active: Set the user as active. + :type active: Optional(``True`` | ``False``) + :param admin: Give the new user admin rights. + :type admin: Optional(``True`` | ``False``) + :param extern_name: Set the authentication plugin name. + Using LDAP this is filled with LDAP UID. + :type extern_name: Optional(str) + :param extern_type: Set the new user authentication plugin. + :type extern_type: Optional(str) + :param force_password_change: Force the new user to change password + on next login. + :type force_password_change: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : + result: { + "msg" : "created new user ``", + "user": + } + error: null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "user `` already exist" + or + "email `` already exist" + or + "failed to create user ``" + } + + +update_user +----------- + +.. py:function:: update_user(apiuser, userid, username=, email=, password=, firstname=, lastname=, active=, admin=, extern_type=, extern_name=) + + Updates the details for the specified user, if that user exists. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param userid: Set the ``userid`` to update. + :type userid: str or int + :param username: Set the new username. + :type username: str or int + :param email: Set the new email. + :type email: str + :param password: Set the new password. + :type password: Optional(str) + :param firstname: Set the new first name. + :type firstname: Optional(str) + :param lastname: Set the new surname. + :type lastname: Optional(str) + :param active: Set the new user as active. + :type active: Optional(``True`` | ``False``) + :param admin: Give the user admin rights. + :type admin: Optional(``True`` | ``False``) + :param extern_name: Set the authentication plugin user name. + Using LDAP this is filled with LDAP UID. + :type extern_name: Optional(str) + :param extern_type: Set the authentication plugin type. + :type extern_type: Optional(str) + + + Example output: + + .. code-block:: bash + + id : + result: { + "msg" : "updated user ID: ", + "user": , + } + error: null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "failed to update user ``" + } + + +delete_user +----------- + +.. py:function:: delete_user(apiuser, userid) + + Deletes the specified user from the |RCE| user database. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + .. important:: + + Ensure all open pull requests and open code review + requests to this user are close. + + Also ensure all repositories, or repository groups owned by this + user are reassigned before deletion. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Set the user to delete. + :type userid: str or int + + Example output: + + .. code-block:: bash + + id : + result: { + "msg" : "deleted user ID: ", + "user": null + } + error: null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "failed to delete user ID: " + } + + +get_user_group +-------------- + +.. py:function:: get_user_group(apiuser, usergroupid) + + Returns the data of an existing user group. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group from which to return data. + :type usergroupid: str or int + + Example error output: + + .. code-block:: bash + + { + "error": null, + "id": , + "result": { + "active": true, + "group_description": "group description", + "group_name": "group name", + "members": [ + { + "name": "owner-name", + "origin": "owner", + "permission": "usergroup.admin", + "type": "user" + }, + { + { + "name": "user name", + "origin": "permission", + "permission": "usergroup.admin", + "type": "user" + }, + { + "name": "user group name", + "origin": "permission", + "permission": "usergroup.write", + "type": "user_group" + } + ], + "owner": "owner name", + "users": [], + "users_group_id": 2 + } + } + + +get_user_groups +--------------- + +.. py:function:: get_user_groups(apiuser) + + Lists all the existing user groups within RhodeCode. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example error output: + + .. code-block:: bash + + id : + result : [,...] + error : null + + +create_user_group +----------------- + +.. py:function:: create_user_group(apiuser, group_name, description=, owner=>, active=) + + Creates a new user group. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param group_name: Set the name of the new user group. + :type group_name: str + :param description: Give a description of the new user group. + :type description: str + :param owner: Set the owner of the new user group. + If not set, the owner is the |authtoken| user. + :type owner: Optional(str or int) + :param active: Set this group as active. + :type active: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : + result: { + "msg": "created new user group ``", + "user_group": + } + error: null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "user group `` already exist" + or + "failed to create group ``" + } + + +update_user_group +----------------- + +.. py:function:: update_user_group(apiuser, usergroupid, group_name=, description=, owner=, active=) + + Updates the specified `user group` with the details provided. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the id of the `user group` to update. + :type usergroupid: str or int + :param group_name: Set the new name the `user group` + :type group_name: str + :param description: Give a description for the `user group` + :type description: str + :param owner: Set the owner of the `user group`. + :type owner: Optional(str or int) + :param active: Set the group as active. + :type active: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": 'updated user group ID: ', + "user_group": + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "failed to update user group ``" + } + + +delete_user_group +----------------- + +.. py:function:: delete_user_group(apiuser, usergroupid) + + Deletes the specified `user group`. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: filled automatically from apikey + :type apiuser: AuthUser + :param usergroupid: + :type usergroupid: int + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "deleted user group ID: " + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "failed to delete user group ID: " + or + "RepoGroup assigned to " + } + + +add_user_to_user_group +---------------------- + +.. py:function:: add_user_to_user_group(apiuser, usergroupid, userid) + + Adds a user to a `user group`. If the user already exists in the group + this command will return false. + + This command can only be run using an |authtoken| with admin rights to + the specified user group. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the name of the `user group` to which a + user will be added. + :type usergroupid: int + :param userid: Set the `user_id` of the user to add to the group. + :type userid: int + + Example output: + + .. code-block:: bash + + id : + result : { + "success": True|False # depends on if member is in group + "msg": "added member `` to user group `` | + User is already in that group" + + } + error : null + + Example error output: + + .. code-block:: bash + + id : + result : null + error : { + "failed to add member to user group ``" + } + + +remove_user_from_user_group +--------------------------- + +.. py:function:: remove_user_from_user_group(apiuser, usergroupid, userid) + + Removes a user from a user group. + + * If the specified user is not in the group, this command will return + `false`. + + This command can only be run using an |authtoken| with admin rights to + the specified user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Sets the user group name. + :type usergroupid: str or int + :param userid: The user you wish to remove from |RCE|. + :type userid: str or int + + Example output: + + .. code-block:: bash + + id : + result: { + "success": True|False, # depends on if member is in group + "msg": "removed member from user group | + User wasn't in group" + } + error: null + + +grant_user_permission_to_user_group +----------------------------------- + +.. py:function:: grant_user_permission_to_user_group(apiuser, usergroupid, userid, perm) + + Set permissions for a user in a user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group to edit permissions on. + :type usergroupid: str or int + :param userid: Set the user from whom you wish to set permissions. + :type userid: str + :param perm: (usergroup.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "Granted perm: `` for user: `` in user group: ``", + "success": true + } + error : null + + +revoke_user_permission_from_user_group +-------------------------------------- + +.. py:function:: revoke_user_permission_from_user_group(apiuser, usergroupid, userid) + + Revoke a users permissions in a user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group from which to revoke the user + permissions. + :type: usergroupid: str or int + :param userid: Set the userid of the user whose permissions will be + revoked. + :type userid: str + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "Revoked perm for user: `` in user group: ``", + "success": true + } + error : null + + +grant_user_group_permission_to_user_group +----------------------------------------- + +.. py:function:: grant_user_group_permission_to_user_group(apiuser, usergroupid, sourceusergroupid, perm) + + Give one user group permissions to another user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group on which to edit permissions. + :type usergroupid: str or int + :param sourceusergroupid: Set the source user group to which + access/permissions will be granted. + :type sourceusergroupid: str or int + :param perm: (usergroup.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "Granted perm: `` for user group: `` in user group: ``", + "success": true + } + error : null + + +revoke_user_group_permission_from_user_group +-------------------------------------------- + +.. py:function:: revoke_user_group_permission_from_user_group(apiuser, usergroupid, sourceusergroupid) + + Revoke the permissions that one user group has to another. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group on which to edit permissions. + :type usergroupid: str or int + :param sourceusergroupid: Set the user group from which permissions + are revoked. + :type sourceusergroupid: str or int + + Example output: + + .. code-block:: bash + + id : + result : { + "msg": "Revoked perm for user group: `` in user group: ``", + "success": true + } + error : null + + +get_pull_request +---------------- + +.. py:function:: get_pull_request(apiuser, repoid, pullrequestid) + + Get a pull request based on the given ID. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID from where the pull + request was opened. + :type repoid: str or int + :param pullrequestid: ID of the requested pull request. + :type pullrequestid: int + + Example output: + + .. code-block:: bash + + "id": , + "result": + { + "pull_request_id": "", + "url": "", + "title": "", + "description": "<description>", + "status" : "<status>", + "created_on": "<date_time_created>", + "updated_on": "<date_time_updated>", + "commit_ids": [ + ... + "<commit_id>", + "<commit_id>", + ... + ], + "review_status": "<review_status>", + "mergeable": { + "status": "<bool>", + "message": "<message>", + }, + "source": { + "clone_url": "<clone_url>", + "repository": "<repository_name>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "target": { + "clone_url": "<clone_url>", + "repository": "<repository_name>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "author": <user_obj>, + "reviewers": [ + ... + { + "user": "<user_obj>", + "review_status": "<review_status>", + } + ... + ] + }, + "error": null + + +get_pull_requests +----------------- + +.. py:function:: get_pull_requests(apiuser, repoid, status=<Optional:'new'>) + + Get all pull requests from the repository specified in `repoid`. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID. + :type repoid: str or int + :param status: Only return pull requests with the specified status. + Valid options are. + * ``new`` (default) + * ``open`` + * ``closed`` + :type status: str + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + [ + ... + { + "pull_request_id": "<pull_request_id>", + "url": "<url>", + "title" : "<title>", + "description": "<description>", + "status": "<status>", + "created_on": "<date_time_created>", + "updated_on": "<date_time_updated>", + "commit_ids": [ + ... + "<commit_id>", + "<commit_id>", + ... + ], + "review_status": "<review_status>", + "mergeable": { + "status": "<bool>", + "message: "<message>", + }, + "source": { + "clone_url": "<clone_url>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "target": { + "clone_url": "<clone_url>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "author": <user_obj>, + "reviewers": [ + ... + { + "user": "<user_obj>", + "review_status": "<review_status>", + } + ... + ] + } + ... + ], + "error": null + + +merge_pull_request +------------------ + +.. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>) + + Merge the pull request specified by `pullrequestid` into its target + repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The Repository name or repository ID of the + target repository to which the |pr| is to be merged. + :type repoid: str or int + :param pullrequestid: ID of the pull request which shall be merged. + :type pullrequestid: int + :param userid: Merge the pull request as this user. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + { + "executed": "<bool>", + "failure_reason": "<int>", + "merge_commit_id": "<merge_commit_id>", + "possible": "<bool>" + }, + "error": null + + +close_pull_request +------------------ + +.. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>) + + Close the pull request specified by `pullrequestid`. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID to which the pull + request belongs. + :type repoid: str or int + :param pullrequestid: ID of the pull request to be closed. + :type pullrequestid: int + :param userid: Close the pull request as this user. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + { + "pull_request_id": "<int>", + "closed": "<bool>" + }, + "error": null + + +comment_pull_request +-------------------- + +.. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, status=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>) + + Comment on the pull request specified with the `pullrequestid`, + in the |repo| specified by the `repoid`, and optionally change the + review status. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + :param message: The text content of the comment. + :type message: str + :param status: (**Optional**) Set the approval status of the pull + request. Valid options are: + * not_reviewed + * approved + * rejected + * under_review + :type status: str + :param userid: Comment on the pull request as this user + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : + { + "pull_request_id": "<Integer>", + "comment_id": "<Integer>" + } + error : null + + +create_pull_request +------------------- + +.. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title, description=<Optional:''>, reviewers=<Optional:None>) + + Creates a new pull request. + + Accepts refs in the following formats: + + * branch:<branch_name>:<sha> + * branch:<branch_name> + * bookmark:<bookmark_name>:<sha> (Mercurial only) + * bookmark:<bookmark_name> (Mercurial only) + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param source_repo: Set the source repository name. + :type source_repo: str + :param target_repo: Set the target repository name. + :type target_repo: str + :param source_ref: Set the source ref name. + :type source_ref: str + :param target_ref: Set the target ref name. + :type target_ref: str + :param title: Set the pull request title. + :type title: str + :param description: Set the pull request description. + :type description: Optional(str) + :param reviewers: Set the new pull request reviewers list. + :type reviewers: Optional(list) + + +update_pull_request +------------------- + +.. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>, close_pull_request=<Optional:None>) + + Updates a pull request. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + :param title: Set the pull request title. + :type title: str + :param description: Update pull request description. + :type description: Optional(str) + :param reviewers: Update pull request reviewers list with new value. + :type reviewers: Optional(list) + :param update_commits: Trigger update of commits for this pull request + :type: update_commits: Optional(bool) + :param close_pull_request: Close this pull request with rejected state + :type: close_pull_request: Optional(bool) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : + { + "msg": "Updated pull request `63`", + "pull_request": <pull_request_object>, + "updated_reviewers": { + "added": [ + "username" + ], + "removed": [] + }, + "updated_commits": { + "added": [ + "<sha1_hash>" + ], + "common": [ + "<sha1_hash>", + "<sha1_hash>", + ], + "removed": [] + } + } + error : null + + +get_repo +-------- + +.. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>) + + Gets an existing repository by its name or repository_id. + + The members section so the output returns users groups or users + associated with that repository. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository id. + :type repoid: str or int + :param cache: use the cached value for last changeset + :type: cache: Optional(bool) + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": <repo_id>, + "result": { + "clone_uri": null, + "created_on": "timestamp", + "description": "repo description", + "enable_downloads": false, + "enable_locking": false, + "enable_statistics": false, + "followers": [ + { + "active": true, + "admin": false, + "api_key": "****************************************", + "api_keys": [ + "****************************************" + ], + "email": "user@example.com", + "emails": [ + "user@example.com" + ], + "extern_name": "rhodecode", + "extern_type": "rhodecode", + "firstname": "username", + "ip_addresses": [], + "language": null, + "last_login": "2015-09-16T17:16:35.854", + "lastname": "surname", + "user_id": <user_id>, + "username": "name" + } + ], + "fork_of": "parent-repo", + "landing_rev": [ + "rev", + "tip" + ], + "last_changeset": { + "author": "User <user@example.com>", + "branch": "default", + "date": "timestamp", + "message": "last commit message", + "parents": [ + { + "raw_id": "commit-id" + } + ], + "raw_id": "commit-id", + "revision": <revision number>, + "short_id": "short id" + }, + "lock_reason": null, + "locked_by": null, + "locked_date": null, + "members": [ + { + "name": "super-admin-name", + "origin": "super-admin", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "repository.write", + "type": "user_group" + } + ], + "owner": "owner-name", + "permissions": [ + { + "name": "super-admin-name", + "origin": "super-admin", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "repository.write", + "type": "user_group" + } + ], + "private": true, + "repo_id": 676, + "repo_name": "user-group/repo-name", + "repo_type": "hg" + } + } + + +get_repos +--------- + +.. py:function:: get_repos(apiuser) + + Lists all existing repositories. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [ + { + "repo_id" : "<repo_id>", + "repo_name" : "<reponame>" + "repo_type" : "<repo_type>", + "clone_uri" : "<clone_uri>", + "private": : "<bool>", + "created_on" : "<datetimecreated>", + "description" : "<description>", + "landing_rev": "<landing_rev>", + "owner": "<repo_owner>", + "fork_of": "<name_of_fork_parent>", + "enable_downloads": "<bool>", + "enable_locking": "<bool>", + "enable_statistics": "<bool>", + }, + ... + ] + error: null + + +get_repo_changeset +------------------ + +.. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>) + + Returns information about a changeset. + + Additionally parameters define the amount of details returned by + this function. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository id + :type repoid: str or int + :param revision: revision for which listing should be done + :type revision: str + :param details: details can be 'basic|extended|full' full gives diff + info details like the diff itself, and number of changed files etc. + :type details: Optional(str) + + +get_repo_changesets +------------------- + +.. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>) + + Returns a set of changesets limited by the number of commits starting + from the `start_rev` option. + + Additional parameters define the amount of details returned by this + function. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param start_rev: The starting revision from where to get changesets. + :type start_rev: str + :param limit: Limit the number of changesets to this amount + :type limit: str or int + :param details: Set the level of detail returned. Valid option are: + ``basic``, ``extended`` and ``full``. + :type details: Optional(str) + + .. note:: + + Setting the parameter `details` to the value ``full`` is extensive + and returns details like the diff itself, and the number + of changed files. + + +get_repo_nodes +-------------- + +.. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>) + + Returns a list of nodes and children in a flat list for a given + path at given revision. + + It's possible to specify ret_type to show only `files` or `dirs`. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param revision: The revision for which listing should be done. + :type revision: str + :param root_path: The path from which to start displaying. + :type root_path: str + :param ret_type: Set the return type. Valid options are + ``all`` (default), ``files`` and ``dirs``. + :type ret_type: Optional(str) + :param details: Returns extended information about nodes, such as + md5, binary, and or content. The valid options are ``basic`` and + ``full``. + :type details: Optional(str) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [ + { + "name" : "<name>" + "type" : "<type>", + "binary": "<true|false>" (only in extended mode) + "md5" : "<md5 of file content>" (only in extended mode) + }, + ... + ] + error: null + + +create_repo +----------- + +.. py:function:: create_repo(apiuser, repo_name, repo_type, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, copy_permissions=<Optional:False>) + + Creates a repository. + + * If the repository name contains "/", all the required repository + groups will be created. + + For example "foo/bar/baz" will create |repo| groups "foo" and "bar" + (with "foo" as parent). It will also create the "baz" repository + with "bar" as |repo| group. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repo_name: Set the repository name. + :type repo_name: str + :param repo_type: Set the repository type; 'hg','git', or 'svn'. + :type repo_type: str + :param owner: user_id or username + :type owner: Optional(str) + :param description: Set the repository description. + :type description: Optional(str) + :param private: + :type private: bool + :param clone_uri: + :type clone_uri: str + :param landing_rev: <rev_type>:<rev> + :type landing_rev: str + :param enable_locking: + :type enable_locking: bool + :param enable_downloads: + :type enable_downloads: bool + :param enable_statistics: + :type enable_statistics: bool + :param copy_permissions: Copy permission from group in which the + repository is being created. + :type copy_permissions: bool + + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Created new repository `<reponame>`", + "success": true, + "task": "<celery task id or None if done sync>" + } + error: null + + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + 'failed to create repository `<repo_name>` + } + + +add_field_to_repo +----------------- + +.. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>) + + Adds an extra field to a repository. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository id. + :type repoid: str or int + :param key: Create a unique field key for this repository. + :type key: str + :param label: + :type label: Optional(str) + :param description: + :type description: Optional(str) + + +remove_field_from_repo +---------------------- + +.. py:function:: remove_field_from_repo(apiuser, repoid, key) + + Removes an extra field from a repository. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param key: Set the unique field key for this repository. + :type key: str + + +update_repo +----------- + +.. py:function:: update_repo(apiuser, repoid, name=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, group=<Optional:None>, fork_of=<Optional:None>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, fields=<Optional:''>) + + Updates a repository with the given information. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: repository name or repository ID. + :type repoid: str or int + :param name: Update the |repo| name. + :type name: str + :param owner: Set the |repo| owner. + :type owner: str + :param group: Set the |repo| group the |repo| belongs to. + :type group: str + :param fork_of: Set the master |repo| name. + :type fork_of: str + :param description: Update the |repo| description. + :type description: str + :param private: Set the |repo| as private. (True | False) + :type private: bool + :param clone_uri: Update the |repo| clone URI. + :type clone_uri: str + :param landing_rev: Set the |repo| landing revision. Default is + ``tip``. + :type landing_rev: str + :param enable_statistics: Enable statistics on the |repo|, + (True | False). + :type enable_statistics: bool + :param enable_locking: Enable |repo| locking. + :type enable_locking: bool + :param enable_downloads: Enable downloads from the |repo|, + (True | False). + :type enable_downloads: bool + :param fields: Add extra fields to the |repo|. Use the following + example format: ``field_key=field_val,field_key2=fieldval2``. + Escape ', ' with \, + :type fields: str + + +fork_repo +--------- + +.. py:function:: fork_repo(apiuser, repoid, fork_name, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, copy_permissions=<Optional:False>, private=<Optional:False>, landing_rev=<Optional:'rev:tip'>) + + Creates a fork of the specified |repo|. + + * If using |RCE| with Celery this will immediately return a success + message, even though the fork will be created asynchronously. + + This command can only be run using an |authtoken| with fork + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set repository name or repository ID. + :type repoid: str or int + :param fork_name: Set the fork name. + :type fork_name: str + :param owner: Set the fork owner. + :type owner: str + :param description: Set the fork descripton. + :type description: str + :param copy_permissions: Copy permissions from parent |repo|. The + default is False. + :type copy_permissions: bool + :param private: Make the fork private. The default is False. + :type private: bool + :param landing_rev: Set the landing revision. The default is tip. + + Example output: + + .. code-block:: bash + + id : <id_for_response> + api_key : "<api_key>" + args: { + "repoid" : "<reponame or repo_id>", + "fork_name": "<forkname>", + "owner": "<username or user_id = Optional(=apiuser)>", + "description": "<description>", + "copy_permissions": "<bool>", + "private": "<bool>", + "landing_rev": "<landing_rev>" + } + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Created fork of `<reponame>` as `<forkname>`", + "success": true, + "task": "<celery task id or None if done sync>" + } + error: null + + +delete_repo +----------- + +.. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>) + + Deletes a repository. + + * When the `forks` parameter is set it's possible to detach or delete + forks of deleted repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param forks: Set to `detach` or `delete` forks from the |repo|. + :type forks: Optional(str) + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Deleted repository `<reponame>`", + "success": true + } + error: null + + +comment_commit +-------------- + +.. py:function:: comment_commit(apiuser, repoid, commit_id, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>) + + Set a commit comment, and optionally change the status of the commit. + This command can be executed only using api_key belonging to user + with admin rights, or repository administrator. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param commit_id: Specify the commit_id for which to set a comment. + :type commit_id: str + :param message: The comment text. + :type message: str + :param userid: Set the user name of the comment creator. + :type userid: Optional(str or int) + :param status: status, one of 'not_reviewed', 'approved', 'rejected', + 'under_review' + :type status: str + + Example error output: + + .. code-block:: json + + { + "id" : <id_given_in_input>, + "result" : { + "msg": "Commented on commit `<commit_id>` for repository `<repoid>`", + "status_change": null or <status>, + "success": true + }, + "error" : null + } + + +changeset_comment +----------------- + +.. py:function:: changeset_comment(apiuser, repoid, revision, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>) + + .. deprecated:: 3.4.0 + + Please use method `comment_commit` instead. + + + Set a changeset comment, and optionally change the status of the + changeset. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param revision: Specify the revision for which to set a comment. + :type revision: str + :param message: The comment text. + :type message: str + :param userid: Set the user name of the comment creator. + :type userid: Optional(str or int) + :param status: Set the comment status. The following are valid options: + * not_reviewed + * approved + * rejected + * under_review + :type status: str + + Example error output: + + .. code-block:: json + + { + "id" : <id_given_in_input>, + "result" : { + "msg": "Commented on commit `<revision>` for repository `<repoid>`", + "status_change": null or <status>, + "success": true + }, + "error" : null + } + + +grant_user_permission +--------------------- + +.. py:function:: grant_user_permission(apiuser, repoid, userid, perm) + + Grant permissions for the specified user on the given repository, + or update existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param userid: Set the user name. + :type userid: str + :param perm: Set the user permissions, using the following format + ``(repository.(none|read|write|admin))`` + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`", + "success": true + } + error: null + + +revoke_user_permission +---------------------- + +.. py:function:: revoke_user_permission(apiuser, repoid, userid) + + Revoke permission for a user on the specified repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param userid: Set the user name of revoked user. + :type userid: str or int + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`", + "success": true + } + error: null + + +grant_user_group_permission +--------------------------- + +.. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm) + + Grant permission for a user group on the specified repository, + or update existing permissions. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param usergroupid: Specify the ID of the user group. + :type usergroupid: str or int + :param perm: Set the user group permissions using the following + format: (repository.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`", + "success": true + + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo `<repo>`' + } + + +revoke_user_group_permission +---------------------------- + +.. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid) + + Revoke the permissions of a user group on a given repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param usergroupid: Specify the user group ID. + :type usergroupid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`", + "success": true + } + error: null + + +get_repo_group +-------------- + +.. py:function:: get_repo_group(apiuser, repogroupid) + + Return the specified |repo| group, along with permissions, + and repositories inside the group + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Specify the name of ID of the repository group. + :type repogroupid: str or int + + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": repo-group-id, + "result": { + "group_description": "repo group description", + "group_id": 14, + "group_name": "group name", + "members": [ + { + "name": "super-admin-username", + "origin": "super-admin", + "permission": "group.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "group.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "group.write", + "type": "user_group" + } + ], + "owner": "owner-name", + "parent_group": null, + "repositories": [ repo-list ] + } + } + + +get_repo_groups +--------------- + +.. py:function:: get_repo_groups(apiuser) + + Returns all repository groups. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + +create_repo_group +----------------- + +.. py:function:: create_repo_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, copy_permissions=<Optional:False>) + + Creates a repository group. + + * If the repository group name contains "/", all the required repository + groups will be created. + + For example "foo/bar/baz" will create |repo| groups "foo" and "bar" + (with "foo" as parent). It will also create the "baz" repository + with "bar" as |repo| group. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param group_name: Set the repository group name. + :type group_name: str + :param description: Set the |repo| group description. + :type description: str + :param owner: Set the |repo| group owner. + :type owner: str + :param copy_permissions: + :type copy_permissions: + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Created new repo group `<repo_group_name>`" + "repo_group": <repogroup_object> + } + error : null + + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + failed to create repo group `<repogroupid>` + } + + +update_repo_group +----------------- + +.. py:function:: update_repo_group(apiuser, repogroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, parent=<Optional:None>, enable_locking=<Optional:False>) + + Updates repository group with the details given. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the ID of repository group. + :type repogroupid: str or int + :param group_name: Set the name of the |repo| group. + :type group_name: str + :param description: Set a description for the group. + :type description: str + :param owner: Set the |repo| group owner. + :type owner: str + :param parent: Set the |repo| group parent. + :type parent: str or int + :param enable_locking: Enable |repo| locking. The default is false. + :type enable_locking: bool + + +delete_repo_group +----------------- + +.. py:function:: delete_repo_group(apiuser, repogroupid) + + Deletes a |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of repository group to be + deleted. + :type repogroupid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'msg': 'deleted repo group ID:<repogroupid> <repogroupname> + 'repo_group': null + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete repo group ID:<repogroupid> <repogroupname>" + } + + +grant_user_permission_to_repo_group +----------------------------------- + +.. py:function:: grant_user_permission_to_repo_group(apiuser, repogroupid, userid, perm, apply_to_children=<Optional:'none'>) + + Grant permission for a user on the given repository group, or update + existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of repository group. + :type repogroupid: str or int + :param userid: Set the user name. + :type userid: str + :param perm: (group.(none|read|write|admin)) + :type perm: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`" + } + + +revoke_user_permission_from_repo_group +-------------------------------------- + +.. py:function:: revoke_user_permission_from_repo_group(apiuser, repogroupid, userid, apply_to_children=<Optional:'none'>) + + Revoke permission for a user in a given repository group. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of the repository group. + :type repogroupid: str or int + :param userid: Set the user name to revoke. + :type userid: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`" + } + + +grant_user_group_permission_to_repo_group +----------------------------------------- + +.. py:function:: grant_user_group_permission_to_repo_group(apiuser, repogroupid, usergroupid, perm, apply_to_children=<Optional:'none'>) + + Grant permission for a user group on given repository group, or update + existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or id of repository group + :type repogroupid: str or int + :param usergroupid: id of usergroup + :type usergroupid: str or int + :param perm: (group.(none|read|write|admin)) + :type perm: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`", + "success": true + + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`" + } + + +revoke_user_group_permission_from_repo_group +-------------------------------------------- + +.. py:function:: revoke_user_group_permission_from_repo_group(apiuser, repogroupid, usergroupid, apply_to_children=<Optional:'none'>) + + Revoke permission for user group on given repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: name or id of repository group + :type repogroupid: str or int + :param usergroupid: + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`" + } + + +get_gist +-------- + +.. py:function:: get_gist(apiuser, gistid, content=<Optional:False>) + + Get the specified gist, based on the gist ID. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param gistid: Set the id of the private or public gist + :type gistid: str + :param content: Return the gist content. Default is false. + :type content: Optional(bool) + + +get_gists +--------- + +.. py:function:: get_gists(apiuser, userid=<Optional:<OptionalAttr:apiuser>>) + + Get all gists for given user. If userid is empty returned gists + are for user who called the api + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: user to get gists for + :type userid: Optional(str or int) + + +create_gist +----------- + +.. py:function:: create_gist(apiuser, files, owner=<Optional:<OptionalAttr:apiuser>>, gist_type=<Optional:u'public'>, lifetime=<Optional:-1>, acl_level=<Optional:u'acl_public'>, description=<Optional:''>) + + Creates a new Gist. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param files: files to be added to the gist. The data structure has + to match the following example:: + + {'filename': {'content':'...', 'lexer': null}, + 'filename2': {'content':'...', 'lexer': null}} + + :type files: dict + :param owner: Set the gist owner, defaults to api method caller + :type owner: Optional(str or int) + :param gist_type: type of gist ``public`` or ``private`` + :type gist_type: Optional(str) + :param lifetime: time in minutes of gist lifetime + :type lifetime: Optional(int) + :param acl_level: acl level for this gist, can be + ``acl_public`` or ``acl_private`` If the value is set to + ``acl_private`` only logged in users are able to access this gist. + If not set it defaults to ``acl_public``. + :type acl_level: Optional(str) + :param description: gist description + :type description: Optional(str) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "created new gist", + "gist": {} + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to create gist" + } + + +delete_gist +----------- + +.. py:function:: delete_gist(apiuser, gistid) + + Deletes existing gist + + :param apiuser: filled automatically from apikey + :type apiuser: AuthUser + :param gistid: id of gist to delete + :type gistid: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "deleted gist ID: <gist_id>", + "gist": null + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete gist ID:<gist_id>" + } + diff --git a/docs/auth/auth.rst b/docs/auth/auth.rst new file mode 100644 --- /dev/null +++ b/docs/auth/auth.rst @@ -0,0 +1,37 @@ +.. _authentication-ref: + +Authentication Options +====================== + +|RCE| provides a built in authentication plugin +``rhodecode.lib.auth_rhodecode``. This is enabled by default and accessed +through the administrative interface. Additionally, +|RCE| provides a Pluggable Authentication System (PAS). This gives the +administrator greater control over how users authenticate with the system. + +.. important:: + + You can disable the built in |RCM| authentication plugin + ``rhodecode.lib.auth_rhodecode`` and force all authentication to go + through your authentication plugin. However, if you do this, + and your external authentication tools fails, you will be unable to + access |RCM|. + +|RCM| comes with the following user authentication management plugins: + +.. only:: latex + + * :ref:`config-ldap-ref` + * :ref:`config-pam-ref` + * :ref:`config-crowd-ref` + * :ref:`config-token-ref` + +.. toctree:: + + ldap-config-steps + crowd-auth + pam-auth + token-auth + ssh-connection + + diff --git a/docs/auth/crowd-auth.rst b/docs/auth/crowd-auth.rst new file mode 100644 --- /dev/null +++ b/docs/auth/crowd-auth.rst @@ -0,0 +1,15 @@ +.. _config-crowd-ref: + +Crowd +----- + +To enable Crowd authentication, use the following steps: + +1. From the |RCM| interface, go to :menuselection:`Admin --> Authentication` +2. Enable the ``rhodecode.lib.auth_modules.auth_crowd`` library and select + :guilabel:`Save` +3. On the Crowd plugin settings section, do the following: + + * Check the :guilabel:`Enable` checkbox + * Enter your Crowd server settings + * Select :guilabel:`Save` diff --git a/docs/auth/ldap-active-directory.rst b/docs/auth/ldap-active-directory.rst new file mode 100644 --- /dev/null +++ b/docs/auth/ldap-active-directory.rst @@ -0,0 +1,22 @@ +.. _ldap-act-dir-ref: + +Active Directory +---------------- + +|RCM| can use Microsoft Active Directory for user authentication. This is +done through an LDAP or LDAPS connection to Active Directory. Use the +following example LDAP configuration setting to set your Active Directory +authentication. + +.. code-block:: ini + + # Set the Base DN + Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local + # Set the Active Directory SAM-Account-Name + Login Attribute = sAMAccountName + # Set the Active Directory user name + First Name Attribute = usernameame + # Set the Active Directory user surname + Last Name Attribute = user_surname + # Set the Active Directory user email + E-mail Attribute = userEmail \ No newline at end of file diff --git a/docs/auth/ldap-authentication.rst b/docs/auth/ldap-authentication.rst new file mode 100644 --- /dev/null +++ b/docs/auth/ldap-authentication.rst @@ -0,0 +1,107 @@ +.. _ldap-gloss-ref: + +|LDAP| Glossary +--------------- + +This topic aims to give you a concise overview of the different settings and +requirements that enabling |LDAP| on |RCE| requires. + +Required settings +^^^^^^^^^^^^^^^^^ + +The following LDAP attributes are required when enabling |LDAP| on |RCE|. + +* **Hostname** or **IP Address**: Use a comma separated list for failover + support. +* **First Name** +* **Surname** +* **Email** +* **Port**: Port `389` for unencrypted LDAP or port `636` for SSL-encrypted + LDAP (LDAPS). +* **Base DN (Distinguished Name)**: The Distinguished Name (DN) + is how searches for users will be performed, and these searches can be + controlled by using an LDAP Filter or LDAP Search Scope. A DN is a sequence of + relative distinguished names (RDN) connected by commas. For example, + +.. code-block:: vim + + DN: cn='Monty Python',ou='people',dc='example',dc='com' + +* **Connection security level**: The following are the valid types: + + * *No encryption*: This connection type uses a plain non-encrypted connection. + * *LDAPS connection*: This connection type uses end-to-end SSL. To enable + an LDAPS connection you must set the following requirements: + + * You must specify port `636` + * Certificate checks are required. + * To enable ``START_TLS`` on LDAP connection, set the path to the SSL + certificate in the default LDAP configuration file. The default + `ldap.conf` file is located in `/etc/openldap/ldap.conf`. + +.. code-block:: vim + + TLS_CACERT /etc/ssl/certs/ca.crt + +* The LDAP username or account used to connect to |RCE|. This will be added + to the LDAP filter for locating the user object. +* For example, if an LDAP filter is specified as `LDAPFILTER`, + the login attribute is specified as `uid`, and the user connects as + `jsmith`, then the LDAP Filter will be like the following example. + +.. code-block:: vim + + (&(LDAPFILTER)(uid=jsmith)) + +* The LDAP search scope must be set. This limits how far LDAP will search for + a matching object. + + * ``BASE`` Only allows searching of the Base DN. + * ``ONELEVEL`` Searches all entries under the Base DN, + but not the Base DN itself. + * ``SUBTREE`` Searches all entries below the Base DN, but not Base DN itself. + +.. note:: + + When using ``SUBTREE`` LDAP filtering it is useful to limit object location. + +Optional settings +^^^^^^^^^^^^^^^^^ + +The following are optional when enabling LDAP on |RCM| + +* An LDAP account is only required if the LDAP server does not allow + anonymous browsing of records. +* An LDAP password is only required if the LDAP server does not allow + anonymous browsing of records +* Using an LDAP filter is optional. An LDAP filter defined by `RFC 2254`_. This + is more useful that the LDAP Search Scope if set to `SUBTREE`. The filter + is useful for limiting which LDAP objects are identified as representing + Users for authentication. The filter is augmented by Login Attribute + below. This can commonly be left blank. +* Certificate Checks are only required if you need to use LDAPS. + You can use the following levels of LDAP service with RhodeCode Enterprise: + + * **NEVER** : A serve certificate will never be requested or checked. + * **ALLOW** : A server certificate is requested. Failure to provide a + certificate or providing a bad certificate will not terminate the session. + * **TRY** : A server certificate is requested. Failure to provide a + certificate does not halt the session; providing a bad certificate + halts the session. + * **DEMAND** : A server certificate is requested and must be provided + and authenticated for the session to proceed. + * **HARD** : The same as DEMAND. + +.. note:: + + Only **DEMAND** or **HARD** offer full SSL security while the other + options are vulnerable to man-in-the-middle attacks. + + |RCE| uses ``OPENLDAP`` libraries. This allows **DEMAND** or + **HARD** LDAPS connections to use self-signed certificates or + certificates that do not have traceable certificates of authority. + To enable this functionality install the SSL certificates in the + following directory: `/etc/openldap/cacerts` + + +.. _RFC 2254: http://www.rfc-base.org/rfc-2254.html \ No newline at end of file diff --git a/docs/auth/ldap-config-steps.rst b/docs/auth/ldap-config-steps.rst new file mode 100644 --- /dev/null +++ b/docs/auth/ldap-config-steps.rst @@ -0,0 +1,88 @@ +.. _config-ldap-ref: + +LDAP +---- + +|RCM| supports LDAP (Lightweight Directory Access Protocol) authentication. +All LDAP versions are supported, with the following |RCM| plugins managing each: + +* For LDAPv3 use ``rhodecode.lib.auth_modules.auth_ldap_group`` +* For older LDAP versions use ``rhodecode.lib.auth_modules.auth_ldap`` + +.. important:: + + The email used with your |RCE| super-admin account needs to match the email + address attached to your admin profile in LDAP. This is because + within |RCE| the user email needs to be unique, and multiple users + cannot share an email account. + + Likewise, if as an admin you also have a user account, the email address + attached to the user account needs to be different. + +LDAP Configuration Steps +^^^^^^^^^^^^^^^^^^^^^^^^ + +To configure |LDAP|, use the following steps: + +1. From the |RCM| interface, select + :menuselection:`Admin --> Authentication` +2. Enable the required plugin and select :guilabel:`Save` +3. Select the :guilabel:`Enabled` check box in the plugin configuration section +4. Add the required LDAP information and :guilabel:`Save`, for more details, + see :ref:`config-ldap-examples` + +For a more detailed description of LDAP objects, see :ref:`ldap-gloss-ref`: + +.. _config-ldap-examples: + +Example LDAP configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: bash + + # Auth Cache TTL + 3600 + # Host + https://ldap1.server.com/ldap-admin/,https://ldap2.server.com/ldap-admin/ + # Port + 389 + # Account + cn=admin,dc=rhodecode,dc=com + # Password + ldap-user-password + # LDAP connection security + LDAPS + # Certificate checks level + DEMAND + # Base DN + cn=Rufus Magillacuddy,ou=users,dc=rhodecode,dc=com + # User Search Base + ou=groups,ou=users + # LDAP search filter + (objectClass=person) + # LDAP search scope + SUBTREE + # Login attribute + rmagillacuddy + # First Name Attribute + Rufus + # Last Name Attribute + Magillacuddy + # Email Attribute + LDAP-Registered@email.ac + # User Member of Attribute + Organizational Role + # Group search base + cn=users,ou=groups,dc=rhodecode,dc=com + # LDAP Group Search Filter + (objectclass=posixGroup) + # Group Name Attribute + users + # Group Member Of Attribute + cn + # Admin Groups + admin,devops,qa + +.. toctree:: + + ldap-active-directory + ldap-authentication diff --git a/docs/auth/ldap-configuration-example.rst b/docs/auth/ldap-configuration-example.rst new file mode 100644 --- /dev/null +++ b/docs/auth/ldap-configuration-example.rst @@ -0,0 +1,13 @@ + LDAP Host hostname1,hostname2 # testing here + Port port + Account: `uid=admin,cn=users,cn=accounts,dc=localdomain,dc=tld` + Password: userpassword #Testing this here + Connection Security LDAPS + Certificate Checks ``NEVER`` + Base DN cn=users,cn=accounts,dc=localdomain,dc=tld + LDAP Search Filter (objectClass=person) + LDAP Search Scope SUBTREE + Login Attribute uid + First Name Attribute givenname + Last Name Attribute sn + Email Attribute mail diff --git a/docs/auth/pam-auth.rst b/docs/auth/pam-auth.rst new file mode 100644 --- /dev/null +++ b/docs/auth/pam-auth.rst @@ -0,0 +1,14 @@ +.. _config-pam-ref: + +PAM +--- + +To enable PAM authentication, use the following steps: + +1. From the |RCM| interface, go to :menuselection:`Admin --> Authentication` +2. Enable the ``rhodecode.lib.auth_modules.auth_pam`` library and select save +3. On the PAM plugin settings section, do the following: + + * Check the :guilabel:`Enable` checkbox + * Enter your PAM server settings + * Select :guilabel:`Save` diff --git a/docs/auth/ssh-connection.rst b/docs/auth/ssh-connection.rst new file mode 100644 --- /dev/null +++ b/docs/auth/ssh-connection.rst @@ -0,0 +1,129 @@ +.. _ssh-connection: + +SSH Connection +-------------- + +If you wish to connect to your Git or Mercurial |repos| using SSH, use the +following instructions. + +.. note:: + + SSH access with full |RCE| permissions will require an Admin |authtoken|. + + You need to install the |RC| SSH tool on the server which is running + the |RCE| instance. + +1. Gather the following information about the instance you wish to connect to: + + * *Hostname*: Use the ``rccontrol status`` command to view instance details. + * *API key*: From the |RCE|, go to + :menuselection:`username --> My Account --> Auth Tokens` + * *Configuration file*: Identify the configuration file for that instance, + the default is :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` + * Identify which |git| and |hg| packages your |RCM| instance is using. + + * For |git|, see + :menuselection:`Admin --> Settings --> System Info` + * For |hg|, use the ``which hg`` command. + +2. Clone the |RC| SSH script, + ``hg clone https://code.rhodecode.com/rhodecode-ssh`` +3. Copy the ``sshwrapper.sample.ini``, and save it as ``sshwrapper.ini`` +4. Configure the :file:`sshwrapper.ini` file using the following example: + +.. code-block:: ini + + [api] + host=http://localhost:10005 + key=24a67076d69c84670132f55166ac79d1faafd660 + + [shell] + shell=/bin/bash -l + + [vcs] + root=/path/to/repos/ + + [rhodecode] + config=/home/user/.rccontrol/enterprise-3/rhodecode.ini + + [vcs:hg] + path=/usr/bin/hg + + # should be a base dir for all git binaries, i.e. not ../bin/git + [vcs:git] + path=/usr/bin + + [keys] + path=/home/user/.ssh/authorized_keys + +5. Add the public key to your |RCE| instance server using the + :file:`addkey.py` script. This script automatically creates + the :file:`authorized_keys` file which was specified in your + :file:`sshwrapper.ini` configuration. Use the following example: + +.. code-block:: bash + + $ ./addkey.py --user username --shell --key /home/username/.ssh/id_rsa.pub + +.. important:: + + To give SSH access to all users, you will need to maintain + each users |authtoken| in the :file:`authorized_keys` file. + +6. Connect to your server using SSH from your local machine. + +.. code-block:: bash + + $ ssh user@localhost + Enter passphrase for key '/home/username/.ssh/id_rsa': + +If you need to manually configure the ``authorized_keys`` file, +add a line for each key using the following example: + +.. code-block:: vim + + command="/home/user/.rhodecode-ssh/sshwrapper.py --user username --shell", + no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa yourpublickey + +.. tip:: + + Best practice would be to create a special SSH user account with each + users |authtoken| attached. + + |RCE| will manage the user permissions based on the |authtoken| supplied. + This would allow you to immediately revoke all SSH access by removing one + user from your server if you needed to. + +See the following command line example of setting this up. These steps +take place on the server. + +.. code-block:: bash + + # On the RhodeCode Enterprise server + # set up user and clone SSH tool + $ sudo adduser testuser + $ sudo su - testuser + $ hg clone https://code.rhodecode.com/rhodecode-ssh + $ cd rhodecode-ssh + + # Copy and modify the sshwrapper.ini as explained in step 4 + $ cp sshwrapper.sample.ini sshwrapper.ini + + $ cd ~ + $ mkdir .ssh + $ touch .ssh/authorized_keys + + # copy your ssh public key, id_rsa.pub, from your local machine + # to the server. We’ll use it in the next step + + $ python addkey.py --user testuser --shell --key /path/to/id_rsa.pub + + # Note: testssh - user on the rhodecode instance + $ chmod 755 sshwrapper.py + +Test the connection from your local machine using the following example: + +.. code-block:: bash + + # Test connection using the ssh command from the local machine + $ ssh testuser@my-server.example.com diff --git a/docs/auth/token-auth.rst b/docs/auth/token-auth.rst new file mode 100644 --- /dev/null +++ b/docs/auth/token-auth.rst @@ -0,0 +1,76 @@ +.. _config-token-ref: + +Authentication Tokens +--------------------- + +|RCE| has 4 different kinds of authentication tokens. + +* *API tokens*: API tokens can only be used to execute |RCE| API operations. + You can store your API token and assign it to each instance in + the :file:`/home/{user}/.rhoderc` file. See the + example in :ref:`indexing-ref` section for more details. + +* *Feed tokens*: The feed token can only be used to access the RSS feed. + Usually those are safe to store inside your RSS feed reader. + +* *VCS tokens*: You can use these to authenticate with |git|, |hg| and |svn| + operations instead of a password. They are designed to be used with + CI Servers or other third party tools that require |repo| access. + They are also a good replacement for SSH based access. + To use these tokens you need be enabled special authentication method on + |RCE|, as they are disabled by default. + See :ref:`enable-vcs-tokens`. + +* *Web Interface tokens*: These token allows users to access the web + interface of |RCE| without logging in. + + You can add these tokens to an |RCE| server url, to expose the page content + based on the given token. + + This is useful to integrate 3rd party systems, good example is to expose + raw diffs to another code-review system without having to worry about + authentication. + + These tokens only work if a certain view is whitelisted + under `api_access_controllers_whitelist` inside + the :file:`rhodecode.ini` file. + +.. code-block:: bash + + # To download a repo without logging into Web UI + https://rhodecode.com/repo/archive/tip.zip?auth_token=<web-api-token> + + # To show commit diff without logging into Web UI + https://rhodecode.com/repo/changeset-diff/<sha>?auth_token=<web-api-token> + +.. _enable-vcs-tokens: + +Enabling VCS Tokens +^^^^^^^^^^^^^^^^^^^ + +To enable VCS Tokens, use the following steps: + +1. Go to :menuselection:`Admin --> Authentication`. +2. Enable the ``rhodecode.lib.auth_modules.auth_token`` plugin. +3. Click :guilabel:`Save`. + +Authentication Token Tips +^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use Authentication Tokens instead of your password with external services. +* Create multiple Authentication Tokens on your account to enable + access to your |repos| with a different |authtoken| per method used. +* Set an expiry limit on certain tokens if you think it would be a good idea. + +Creating Tokens +^^^^^^^^^^^^^^^ + +To create authentication tokens for an user, use the following steps: + +1. From the |RCM| interface go to + :menuselection:`Username --> My Account --> Auth tokens`. + +2. Label and Add the tokens you wish to use with |RCE|. + +.. image:: ../images/tokens.png + diff --git a/docs/code-review/approve-changes.rst b/docs/code-review/approve-changes.rst new file mode 100644 --- /dev/null +++ b/docs/code-review/approve-changes.rst @@ -0,0 +1,13 @@ +.. _code-approve-changes-ref: + +Approve Code Changes +-------------------- + +To approve commits, use the following steps: + +1. Open the commit for review +2. Leave your comments inline or in the message box. +3. Set the review status from the drop-down menu and select :guilabel:`Comment` + +.. image:: ../images/set-ci-status.png + :alt: Setting Commit Status \ No newline at end of file diff --git a/docs/code-review/code-review.rst b/docs/code-review/code-review.rst new file mode 100644 --- /dev/null +++ b/docs/code-review/code-review.rst @@ -0,0 +1,27 @@ +.. _code-review-ref: + +Code Review +=========== + +|RCM| provides two ways in which you can review code. You can review |prs| or +commits. To better understand |prs|, see the :ref:`pull-requests-ref` +and :ref:`collaborate-ref` sections. For more information about why +code review matters, see these posts on the topic: + +* `Code Review - Fix Bugs Early and Often`_ +* `Code Review - How to Convince a Skeptic`_ +* `Code Review - Learn How NASA Codes`_ + +You can also use the |RCE| API set up continuous integration servers to leave +comments from a test suite. See the :ref:`api` and +:ref:`integrations-ref` sections for examples on how to set this up. + +.. toctree:: + + review-diffs + approve-changes + reviewing-best-practices + +.. _Code Review - Fix Bugs Early and Often: https://rhodecode.com/blog/code-review-fix-bugs-early-often/ +.. _Code Review - How to Convince a Skeptic: https://rhodecode.com/blog/code-review-convince-skeptic/ +.. _Code Review - Learn How NASA Codes: https://rhodecode.com/blog/code-review-learn-nasa-codes/ diff --git a/docs/code-review/review-diffs.rst b/docs/code-review/review-diffs.rst new file mode 100644 --- /dev/null +++ b/docs/code-review/review-diffs.rst @@ -0,0 +1,42 @@ +.. _code-diff-side-ref: + +Reviewing Diffs +--------------- + +Diffs are representations of changes made between different changesets of +a file. |RCE| provides 4 different types of diffs for each commit or +changeset, and depending on your preference you can use whichever for code +review purposes. + +* Plain diff +* Full diff +* Side-by-side diff +* Raw diff + +Reviewing Changes +----------------- + +|RCM| displays all code changes made with each commit. Removed content is +marked in red and new content in green. + +.. image:: ../images/plain-diff.png + :alt: Plain Diff + +Side-By-Side Diffs +------------------ + +To review code with a side-by-side diff, use the following steps: + +1. Open the repository in which you wish to review a file +2. Select the revision you wish to review +3. Select the side-by-side diff icon beside the file name + +.. image:: ../images/side-by-side-diff.png + :alt: Side by side diff + + +Notifying Users +--------------- + +To notify other users of you comments, or requests for feedback, +see :ref:`review-notifications-ref` diff --git a/docs/code-review/reviewing-best-practices.rst b/docs/code-review/reviewing-best-practices.rst new file mode 100644 --- /dev/null +++ b/docs/code-review/reviewing-best-practices.rst @@ -0,0 +1,21 @@ +.. _code-best-practices-ref: + +Code Review - Best Practices +---------------------------- + +The following is a list of best practices for reviewing code gathered from +various sources: + +* **Implement a Core Review standard**, because the yield of the Code Review + phase is 50 to 80% better than that of the Test phase. +* Review between **100 and 300 lines of code** at a time and spend 30-60 minutes + doing it for best results. +* **Avoid code review meetings**, because meetings contributed only 4% of the + defects found in the code inspections. +* Slow down to a comfortable pace, as reviewers **slower than 400 lines per + hour are above average** in their ability to uncover defects. But when faster + than 450 lines/hour the defect density is below average in 87% of the cases. +* Take a time-out, because defects are found at relatively constant rates + through the first **60 minutes of inspection**. At that point the + checklist-style review levels off sharply; the other review styles level + off slightly later. In no case is a defect discovered after 90 minutes. \ No newline at end of file diff --git a/docs/collaboration/approve-pull-request.rst b/docs/collaboration/approve-pull-request.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/approve-pull-request.rst @@ -0,0 +1,19 @@ +Approve |prs| +------------- + +To approve a |pr|, use the following steps: + +1. Select :menuselection:`username --> Notifications --> Pull Requests` + and open the |pr| you with to approve +2. Leave your review comments inline, or in the commit message. +3. Leave a commit message that outlines the review. +4. Set the review status to :guilabel:`Approved` +5. Select :guilabel:`Comment` + +If you approve the |pr|, you will be able to merge automatically if |RCM| +detects that it can do so safely. You will see this message: + +:guilabel:`This pull request can be automatically merged.` + +Otherwise you will need to merge the |pr| locally and push your changes, see +:ref:`manual-merge-requests-ref`. diff --git a/docs/collaboration/collaboration.rst b/docs/collaboration/collaboration.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/collaboration.rst @@ -0,0 +1,24 @@ +.. _collaborate-ref: + +Collaboration +============= + +.. note:: + + Forking and branching does not work with |svn| |repos|. + +Collaboration in |RCM| is accomplished through a combination of the following +functions: + +.. only:: latex + + * :ref:`review-notifications-ref` + * :ref:`forks-branches-ref` + * :ref:`pull-requests-ref` + +.. toctree:: + + workflow + forks-branches + repo-locking + diff --git a/docs/collaboration/fixing-common-commits.rst b/docs/collaboration/fixing-common-commits.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/fixing-common-commits.rst @@ -0,0 +1,31 @@ +.. _merging-empty-repo-ref: + +Merging Forks with an Empty Repository +====================================== + +When a new repository is created, it has no commits. If the empty repository is +forked, neither |repo| will have any shared information to link them together, +making it impossible to create a |pr| to merge them. + +To avoid this problem, create an initial commit on the new repository before +forking it. It can be accomplished, for example, by adding a README file to the +master repository and commiting it to the server before forking. + +In case the fork was already made and you are unable to push or merge due to the +lack of a common commit between both repositories, the following steps would +enable you to fix this problem. + +1. Create a commit on the master repository. +2. Pull the changes from the fork to the master repository, and rebase them + on top of the new commit. + + .. code-block:: bash + + #pull from the fork into master + $ hg pull -r fork-commit-id + +3. If the changes were made locally, push the changes to the server. +4. On the forked repository, pull the changes from master. + +Now you should be able to create a |pr| or merge between both repositories. + diff --git a/docs/collaboration/forks-branches.rst b/docs/collaboration/forks-branches.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/forks-branches.rst @@ -0,0 +1,101 @@ +.. _forks-branches-ref: + +Forking and Branching +--------------------- + +Forking clones the original |repo| and creates an independent |repo|. +Branching allows you to develop independently +of the main branch based on the changeset branched, but remains linked to the +main |repo|. + +Both provide excellent collaboration functionality, +and do not differ greatly, but you can find many online discussions +where people fight about the differences. + +Fork a |repo| +^^^^^^^^^^^^^ + +To fork a |repo|, use the following steps: + +1. Select :menuselection:`Admin --> repositories` +2. Select the |repo| you wish to fork. +3. Select :menuselection:`Options --> Fork` +4. On the :guilabel:`Create fork` page, set the following properties: + + * The fork name + * The fork description + * If the fork is private or public + * The copy permissions + +Branch a |git| |repo| +^^^^^^^^^^^^^^^^^^^^^ + +Currently branching is only supported from the command line but is picked up +on the web interface. To branch a |git| |repo| use the following example: + +.. code-block:: bash + + # branch and checkout + git branch new-branch + git checkout new-branch + + # same function shorthand + git checkout -b new-branch + + # Example usage + $ git checkout -b example-branch + Switched to a new branch 'example-branch' + + $ git status + On branch example-branch + Initial commit + nothing to commit (create/copy files and use "git add" to track) + $ vi example-script.sh + $ git add example-script.sh + $ git commit -a -m "ghost script: initial file" + $ git push + +Once it is pushed to the |RCM| server, you can switch to the newly created +branch using the following steps: + +1. Select :menuselection:`Admin --> Repositories`. +2. Select the |repo| you branched. +3. Select :menuselection:`Switch To --> Branches` and choose the new branch. + +For more information, your can read more here on the Git website, +`Git Branching`_. + +Branch a |hg| |repo| +^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + To use branches in |hg| like |git|, use the `hg bookmark` option instead. + Also see the :ref:`bvb` section for more information. + +To branch a |hg| |repo|, use the following example and push your changes to +the main |repo|. Once pushed, you can view the new branch in |RCE| by +selecting :menuselection:`Switch To --> Branches` from the |repo| page. + +.. code-block:: bash + + $ hg branch example-456 + $ hg ci -m "branch: ticket #456" + $ hg push --new-branch + +Bookmark a |hg| |repo| +^^^^^^^^^^^^^^^^^^^^^^ + +Bookmarks are used in |hg| in much the same way as branches are in |git|. See +the `Mercurial Bookmarks`_ documentation for more information. + +.. code-block:: bash + + $ hg bookmark example-456 + $ hg ci -m "branch: ticket #456" + $ hg push -B example-456 + +.. image:: ../images/branch-example.png + +.. _Git Branching: http://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging +.. _Mercurial Bookmarks: https://mercurial.selenic.com/wiki/Bookmarks diff --git a/docs/collaboration/mention-reviewer-function.rst b/docs/collaboration/mention-reviewer-function.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/mention-reviewer-function.rst @@ -0,0 +1,39 @@ +.. _user-notify-ref: + +Using Notifications +------------------- + +To notify users of items that require their attention you can use the mention +function. The mention function allows you to use ``@username`` within |RCM|. +The notification function can be used within the following +items to highlight their need for attention: + +* Commit messages +* Pull requests +* Inline comments +* Code review + +.. note:: + + Mentioned users will receive an email and a notification. + +Pull Request Notifications +-------------------------- + +To notify a user of a pull request, use the following steps. + +1. Open the repository fork +2. Select :guilabel:`Open new pull request` +3. Add the :guilabel:`@username` in the :guilabel:`Pull request viewers` + input field. +4. Select :guilabel:`Submit Pull Request` + +Commit Message Notifications +---------------------------- + +To notify a user in a commit message, use the following steps. + +1. Open a repository with commits in it. +2. Click on the commit message or revision number. +3. Add an :guilabel:`@username` in an inline comment or in your approval + comment and commit. diff --git a/docs/collaboration/merge-pull-request.rst b/docs/collaboration/merge-pull-request.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/merge-pull-request.rst @@ -0,0 +1,35 @@ +.. _merge-requests-ref: + +Merge a |pr| +------------ + +|RCM| can detect if it can automatically merge the changes in a |pr|. If it +can, you will see the following message: +:guilabel:`This pull request can be automatically merged.` To merge, +click the big blue button! To enable this feature, see :ref:`server-side-merge`. + +.. image:: ../images/merge-pr-button.png + +If you cannot automatically merge a |pr|, you will see one of the following +messages: + +* :guilabel:`This pull request cannot be merged because of conflicts` +* :guilabel:`Reviewer approval is pending` + +.. _manual-merge-requests-ref: + +Manual Merge a |PR| +^^^^^^^^^^^^^^^^^^^ + +If |RCM| cannot safely merge the changes in a |pr|, +usually due to conflicts, you need to manually merge the changes on the +command line. You can see more information for each |repo| type at the +following links: + +* `Git Manual Merging`_ +* `Mercurial Manual Merging`_ +* `Subversion Manual Merging`_ + +.. _Git Manual Merging: http://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging +.. _Mercurial Manual Merging: http://hgbook.red-bean.com/read/a-tour-of-mercurial-merging-work.html +.. _Subversion Manual Merging: http://svnbook.red-bean.com/en/1.7/svn.branchmerge.basicmerging.html diff --git a/docs/collaboration/notifications-overview.rst b/docs/collaboration/notifications-overview.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/notifications-overview.rst @@ -0,0 +1,22 @@ +Notifications Overview +---------------------- + +|RCM| has an integrated notification system which alerts users to requests +that they have received. Notifications can occur for the following reasons: + +* Pull request reviews +* Commit message mentions + +When someone opens a |pr| on one of your |repos|, or adds you as a |pr| +reviewer, you will receive a notification in |RCE| and an email, +if not configured see :ref:`set-up-mail`. Also, during the review process you +receive notifications on the following actions: + +* New comments +* Status changes +* Inline code review comments + +Each notifications provides a link to take you directly to the issue. + +.. image:: ../images/notifications.png + :alt: Notifying Colleagues diff --git a/docs/collaboration/open-pull-request.rst b/docs/collaboration/open-pull-request.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/open-pull-request.rst @@ -0,0 +1,34 @@ +.. _open-requests-ref: + +Open a |pr| +----------- + +.. important:: + + To open a |pr|, it is necessary that the source and the target repositories + have at least one commit in common. For more information, + see :ref:`merging-empty-repo-ref`. + + +Once you have finished your work on a fork and want your work merged with the +original |repo|, you need to open a |pr|. To open a |pr| and send for +review, use the following steps: + +1. Select + :menuselection:`Admin --> repositories --> repo name --> Options --> Create Pull Request` +2. On the :guilabel:`New Pull Request` page, enter the following information: + + * The |pr| name. + * The |pr| description. + * Add the reviewer names in the :guilabel:`Pull Request Reviewer` field. + +3. Review the changesets that make up the |pr|. +4. Select :guilabel:`Submit Pull Request`. + +.. image:: ../images/open-pr.png + :alt: Open a pull request + +The pull request can either be merged into the original repository, +or it can be declined due to issues during the review process. If issues +arise, you can fix them and update the |pr|. For more, +see :ref:`update-requests-ref`. diff --git a/docs/collaboration/pr-flow.rst b/docs/collaboration/pr-flow.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/pr-flow.rst @@ -0,0 +1,7 @@ +Pull Request Workflow +--------------------- + +The following diagram represents a standard pull request workflow. + +.. image:: ../images/pull-request-flow.png + :align: center diff --git a/docs/collaboration/pull-req-mgmt.rst b/docs/collaboration/pull-req-mgmt.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/pull-req-mgmt.rst @@ -0,0 +1,47 @@ +Pull request management +----------------------- + +.. only:: html + + There are two ways of tracking |prs| within |RCM|. + + 1. :ref:`prs-your-review` + 2. :ref:`prs-per-repo` + +.. _prs-your-review: + +Pull requests for your review +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To view pull requests for your review, use the following steps: + +1. From the |RCM| interface, Select + :menuselection:`username --> Notifications` +2. Select :guilabel:`Pull Requests` + +.. image:: ../images/prs-for-my-review.png + :alt: pull requests for my review + +.. _prs-per-repo: + +Pull requests per |repo| +^^^^^^^^^^^^^^^^^^^^^^^^ + +To view pull requests going to and from a |repo|, use the following steps: + +1. Select the |repo| you wish to view +2. Select :guilabel:`Pull Requests` from the top menu +3. On the left-hand pane you will see the following options for |pr| + management on that |repo|: + + * :guilabel:`Opened`: Pull requests opened on this |repo|. + * :guilabel:`Opened by me`: Pull requests you opened on this |repo|. + * :guilabel:`Awaiting my review`: Pull requests awaiting your review. + * :guilabel:`Closed`: Closed |prs| on this |repo|. + * :guilabel:`Awaiting review`: Pull requests still awaiting review on + this |repo|. + * :guilabel:`From this repo`: Pull requests opened on another |repo| with + the changes coming from this |repo|. + +.. image:: ../images/pr-screen.png + :alt: pull request dashboard diff --git a/docs/collaboration/pull-requests.rst b/docs/collaboration/pull-requests.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/pull-requests.rst @@ -0,0 +1,29 @@ +.. _pull-requests-ref: + +Pull Requests +============= + +Once a |pr| is open, you can use a variety of different code review functions +to ensure the quality or style of code is appropriate for your standards. The +|pr| is then merged with the main branch when it is approved. The following +steps are an overview of the workflow: + +1. Create a fork or branch of a |repo|. +2. Complete your works and open a pull request. +3. Notify users to review and approve the |pr|. +4. Merge the code to the target |repo|. + +.. toctree:: + + pr-flow + pull-req-mgmt + open-pull-request.rst + review-pull-request.rst + update-pull-request + approve-pull-request.rst + merge-pull-request.rst + fixing-common-commits.rst + + + + diff --git a/docs/collaboration/repo-locking.rst b/docs/collaboration/repo-locking.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/repo-locking.rst @@ -0,0 +1,15 @@ +.. _repo-locking: + +Repository Locking +------------------ + +Repository locking means that when a user pulls from a |repo|, +only a push by that user will unlock it. This allows an +Admin to pull from a |repo| and ensure that no changes can be introduced. You +need Admin access to the |repo| to enable +|repo| locking. To enable |repo| locking, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories`, + then :guilabel:`Edit` beside the |repo| you wish to lock. +2. From the left-hand pane, select + :menuselection:`Advanced --> Lock Repository` \ No newline at end of file diff --git a/docs/collaboration/review-notifications.rst b/docs/collaboration/review-notifications.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/review-notifications.rst @@ -0,0 +1,9 @@ +.. _review-notifications-ref: + +Notifications +============= + +.. toctree:: + + notifications-overview + mention-reviewer-function diff --git a/docs/collaboration/review-pull-request.rst b/docs/collaboration/review-pull-request.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/review-pull-request.rst @@ -0,0 +1,27 @@ +.. _review-requests-ref: + +Review a |pr| +------------- + +To review a pull request, use the following steps: + +1. Open the review request from + :menuselection:`Admin --> Repositories --> repo name --> Pull Requests --> Awaiting my review` +2. Leave your review comments inline, or in the commit message. +3. Set the review status from one of the following options: + + * :guilabel:`Not Reviewed` + * :guilabel:`Approved` + * :guilabel:`Approved & Closed` + * :guilabel:`Rejected` + * :guilabel:`Rejected & Closed` + * :guilabel:`Under Review` + +4. Select Comment + +When the |pr| is approved by all reviewers you will be able to merge +automatically if |RCM| detects that it can do so safely. You will see this +message: `This pull request can be automatically merged.` + +If rejected, you can fix the issues raised during review and then update the +|pr|. diff --git a/docs/collaboration/supported-workflows.rst b/docs/collaboration/supported-workflows.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/supported-workflows.rst @@ -0,0 +1,9 @@ +Supported Workflows +------------------- + +|RCM| can be used to develop using a variety of different workflows. + +* Centralized, using |svn|, |git|, or |hg| |repos| +* Feature-Branch, using |git| or |hg| |repos| +* Fork-Pull, using |git| or |hg| |repos| +* Gitflow, using |git| |repos| diff --git a/docs/collaboration/update-pull-request.rst b/docs/collaboration/update-pull-request.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/update-pull-request.rst @@ -0,0 +1,47 @@ +.. _update-requests-ref: + +Update a |pr| +------------- + +.. important:: + + Updating a |pr| invalidates all previous reviews, and the status set by + each reviewer. This means all reviewers need to review and approve the + |pr| again. + +If you have made changes on the fork or branch from where a |pr| originates, +you can update the |pr|, using the following steps: + +1. Commit and push your changes to the |RCE| server. +2. Open the |pr| you wish to update, and select the :guilabel:`Update commits` + button. + +.. image:: ../images/update-pr-button.png + :scale: 50 % + :alt: Update Pull Request + :align: Center + + +Once updated the following commit message will be automatically added to the +|pr|. + +:guilabel:`Auto status change to "Under Review", pull request updated with 1 added, 0 removed commits.` + +3. Review the new commit messages and changes as before, +4. Set the review status and click :guilabel:`Comment` + +Inline Comments +^^^^^^^^^^^^^^^ + +When updating a |pr|, inline comments can move around depending on which line +they are attached: + +* If the line content changes but remains in place, the inline comment will + remain where it was originally. +* If the line to which the inline comment is attached moves, the comment will + move with it. +* If the diff changes substantially and the line to which the comment was + attached is no longer in the diff, the inline comment will be hidden but + with an icon to display it if necessary. + + diff --git a/docs/collaboration/workflow-branch.rst b/docs/collaboration/workflow-branch.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/workflow-branch.rst @@ -0,0 +1,70 @@ +.. _branch-wf: + +Branching Workflow +================== + +The branching workflow is usually used with specific guidelines about how to +use and name branches. A general rule of thumb is that each branch should be +specifically named and used for a defined purpose. See the +:ref:`forks-branches-ref` section for detailed steps about how to create +branches. + +.. code-block:: bash + + # Mercurial Branch + $ hg bookmark issue-568 + + # Git Branch + $ git branch issue-568 + $ git checkout issue-568 + + +Branching Overview +------------------ + +.. image:: ../images/git-flow-diagram.png + :align: center + +:Legend: The following code examples correspond with the numbered steps in + the diagram. + +.. code-block:: bash + + #1 clone your fork locally and pull the latest changes from upstream + $ git clone git://your-fork + $ git pull --rebase upstream master + + #2 create a new branch + $ git checkout -b branch-1 + + #3 push the branch to your remote fork + $ git push origin branch-1 + + #4 Open a pull request from your fork to upstream/master + + #5 Merge your pull request with the upstream/master + $ git merge --no-ff pull request + + #6 pull and rebase your work plus any other work to your local branch + $ git checkout master + $ git pull --rebase upstream master + + #7 push the new commit history to your fork + $ git push origin master + + + +Setting up a Branching Workflow +------------------------------- + +Setting up a branching workflow requires giving users access to the |repo|. +For more information, see the :ref:`permissions-info-add-group-ref` section. + +Using a Branching Workflow +-------------------------- + +If you are on a team that uses a branching workflow, see the +:ref:`forks-branches-ref` section for how to create branches, and also the +:ref:`pull-requests-ref` section. You may also find the +:ref:`squash-rebase` section useful. + diff --git a/docs/collaboration/workflow-fork.rst b/docs/collaboration/workflow-fork.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/workflow-fork.rst @@ -0,0 +1,43 @@ +.. _fork-flow: + +Forking Workflow +================ + +The forking workflow means that everyone on a team has permission to fork a +|repo| and once they have completed their work, open a pull request to have it +accepted into the main |repo|. + +In a forking workflow, not everyone will have write access to the main |repo|. +This means that only those with write access can merge |prs| once they have +been approved. Usually, the forking workflow is used with |hg|, and branching +with |git|. + +Forking Overview +---------------- + +.. image:: ../images/fork-flow.png + :align: center + + +Setting Up a Forking Workflow +----------------------------- + +Setting up a forking workflow in |RCE| would look something like this. + +1. Create a user group with write access. +2. Create a user group with read access. +3. Assign team members to the appropriate groups. +4. Users with contributions should open a pull request to + the main |repo| and set a user with write access as the reviewer. +5. Once the |pr| is approved, the write access user would merge it with the + main |repo|. + +For more information about setting up user groups, see the :ref:`user-admin-set` +section. + +Using a Forking Workflow +------------------------ + +If you are on a team that uses a forking workflow, see the +:ref:`forks-branches-ref` section for how to fork a |repo|, and also the +:ref:`pull-requests-ref` section. diff --git a/docs/collaboration/workflow.rst b/docs/collaboration/workflow.rst new file mode 100644 --- /dev/null +++ b/docs/collaboration/workflow.rst @@ -0,0 +1,14 @@ +.. _workflow: + +Workflow Support +================ + +|RCE| supports a number of developer workflows depending on whichever setup +your team wishes to adopt. Use the information in the following sections to +get an idea of what may work best for you. + +.. toctree:: + + workflow-fork + workflow-branch + diff --git a/docs/common.py b/docs/common.py new file mode 100644 --- /dev/null +++ b/docs/common.py @@ -0,0 +1,32 @@ +# Try and keep this list alphabetical +# ui is for user interface elements and messages +# button - that's obvious + +rst_epilog = ''' +.. |AE| replace:: Appenlight +.. |authtoken| replace:: Authentication Token +.. |authtokens| replace:: **Auth Tokens** +.. |git| replace:: Git +.. |hg| replace:: Mercurial +.. |svn| replace:: Subversion +.. |LDAP| replace:: LDAP / Active Directory +.. |os| replace:: operating system +.. |OS| replace:: Operating System +.. |PY| replace:: Python +.. |pr| replace:: pull request +.. |prs| replace:: pull requests +.. |psf| replace:: Python Software Foundation +.. |repo| replace:: repository +.. |repos| replace:: repositories +.. |RCI| replace:: RhodeCode Control +.. |RCC| replace:: RhodeCode Control +.. |RCV| replace:: RhodeCode Enterprise +.. |RCM| replace:: RhodeCode Enterprise +.. |RCE| replace:: RhodeCode Enterprise +.. |RCX| replace:: RhodeCode Extensions +.. |RCT| replace:: RhodeCode Tools +.. |RCEBOLD| replace:: **RhodeCode Enterprise** +.. |RCEITALICS| replace:: `RhodeCode Enterprise` +.. |RC| replace:: RhodeCode +.. |RNS| replace:: Release Notes +''' diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- +# +# RhodeCode Enterprise documentation build configuration file, created by +# sphinx-quickstart on Tue Nov 4 11:48:37 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import datetime +import sphinx_rtd_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('.')) +import common + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.pngmath' +] + +intersphinx_mapping = { + 'enterprise': ('https://docs.rhodecode.com/RhodeCode-Enterprise/', None), + 'control': ('https://docs.rhodecode.com/RhodeCode-Control/', None), +} + +if tags.has('dev'): + intersphinx_mapping.update({ + 'enterprise': ('https://ci.rhodecode.com/documentation/Momentum/', None), + 'control': ('https://ci.rhodecode.com/documentation/Control/', None), + }) + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +# TODO: johbo: Move into common package for documentation utilities +def _get_version(): + with open('../rhodecode/VERSION') as f: + return f.read().strip() + +# The full version, including alpha/beta/rc tags. +release = _get_version() +# The short X.Y version. +version = '.'.join(release.split('.', 2)[:2]) # First two parts of release + +# General information about the project. +project = u'RhodeCode Enterprise %s ' % _get_version() +copyright = u'2010-{now.year}, RhodeCode GmbH'.format( + now=datetime.datetime.today()) + + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +rst_epilog = common.rst_epilog + """ +.. |async| replace:: asynchronous +""" + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + # Special directories + '_build', + 'result', + + # Other RST files + 'admin/rhodecode-backup.rst', + 'auth/ldap-configuration-example.rst', + 'issue-trackers/redmine.rst', + 'known-issues/error-msg-guide.rst', + 'tutorials/docs-build.rst', + 'integrations/example-ext.py', + 'collaboration/supported-workflows.rst', +] + + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +keep_warnings = tags.has("dev") + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'rctheme' +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None +html_sidebars = { + '**': ['globaltoc.html'], +} + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = 'images/favicon.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['static/css/add.css'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'rhodecode-enterprise' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + 'classoptions': ',oneside', + 'babel': '\\usepackage[english]{babel}', + +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'RhodeCodeEnterprise.tex', u'RhodeCode Enterprise', + u'RhodeCode GmbH', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +latex_show_pagerefs = True + +# If true, show URL addresses after external links. +latex_show_urls = 'footnote' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + +# Mode for literal blocks wider than the frame. Can be +# overflow, shrink or truncate +pdf_fit_mode = "truncate" + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'rhodecodeenterprise', u'RhodeCode Enterprise', + [u'RhodeCode GmbH'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'RhodeCodeEnterprise', u'RhodeCode Enterprise', + u'RhodeCode Docs Team', 'RhodeCodeEnterprise', 'RhodeCode Docs Project', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +# We want to see todo notes in case of a pre-release build of the documentation +todo_include_todos = tags.has("dev") diff --git a/docs/contributing/api.rst b/docs/contributing/api.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/api.rst @@ -0,0 +1,60 @@ + +===== + API +===== + + + +Naming conventions +================== + +We keep the calls in the form ``{verb}_{noun}``. + + + +Change and Deprecation +====================== + +API deprecation is documented in the section :ref:`deprecated` together with +other notes about deprecated parts of the application. + + +Deprecated API calls +-------------------- + +- Make sure to add them into the section :ref:`deprecated`. + +- Use `deprecated` inside of the call docstring to make our users aware of the + deprecation:: + + .. deprecated:: 1.2.3 + + Use `new_call_name` instead to fetch this information. + +- Make sure to log on level `logging.WARNING` a message that the API call or + specific parameters are deprecated. + +- If possible return deprecation information inside of the result from the API + call. Use the attribute `_warning_` to contain a message. + + +Changed API calls +----------------- + +- If the change is significant, consider to use `versionchanged` in the + docstring:: + + .. versionchanged:: 1.2.3 + + Optional explanation if reasonable. + + +Added API calls +--------------- + +- Use `versionadded` to document since which version this API call is + available:: + + .. versionadded:: 1.2.3 + + Optional explanation if reasonable. diff --git a/docs/contributing/contributing.rst b/docs/contributing/contributing.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/contributing.rst @@ -0,0 +1,19 @@ +.. _contributing: + +Contributing to RhodeCode +========================= + + + +Welcome to contribution guides and development docs of RhodeCode. + + + +.. toctree:: + :maxdepth: 1 + + testing/index + dev-setup + db-schema + dev-settings + api diff --git a/docs/contributing/db-schema.rst b/docs/contributing/db-schema.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/db-schema.rst @@ -0,0 +1,52 @@ +======================= +DB Schema and Migration +======================= + +To create or alter tables in the database it's necessary to change a couple of +files, apart from configuring the settings pointing to the latest database +schema. + + +Database Model and ORM +---------------------- + +On ``rhodecode.model.db`` you will find the database definition of all tables and +fields. Any fresh install database will be correctly created by the definitions +here. So, any change to this files will affect the tests without having to change +any other file. + +A second layer are the businness classes that are inside ``rhodecode.model``. + + +Database Migration +------------------ + +Three files play a role when creating database migrations: + + * Database schema inside ``rhodecode.lib.dbmigrate`` + * Database version inside ``rhodecode.lib.dbmigrate`` + * Configuration ``__dbversion__`` at ``rhodecode.__init__`` + + +Schema is a snapshot of the database version BEFORE the migration. So, it's +the initial state before any changes were added. The name convention is +the latest release version where the snapshot were created, and not the +target version of this code. + +Version is the method that will define how to UPGRADE/DOWNGRADE the database. + +``rhodecode.__init__`` contains only a variable that defines up to which version of +the database will be used to upgrade. Eg.: ``__dbversion__ = 45`` + + +For examples on how to create those files, please see the existing code. + + +Migration Command +^^^^^^^^^^^^^^^^^ + +After you changed the database ORM and migration files, you can run:: + + paster upgrade-db <ini-file> + +And the database will be upgraded up to the version defined in the ``__init__`` file. \ No newline at end of file diff --git a/docs/contributing/dev-settings.rst b/docs/contributing/dev-settings.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/dev-settings.rst @@ -0,0 +1,46 @@ + +========================== + Settings for Development +========================== + + +We have a few settings which are intended to be used only for development +purposes. This section contains an overview of them. + + + +`debug_style` +============= + +Enables the section "Style" in the application. This section provides an +overview of all components which are found in the frontend style of the +application. + + + +`vcs.start_server` +================== + +Starts the server as a subprocess while the system comes up. Intended usage is +to ease development. + + + +`[logging]` +=========== + +Use this to configure loggig to your current needs. The documentation of +Python's `logging` module explains all details. The following snippets are +useful for day to day development work. + + +Mute SQL output +--------------- + +They come out of the package `sqlalchemy.engine`:: + + [logger_sqlalchemy] + level = WARNING + handlers = console_sql + qualname = sqlalchemy.engine + propagate = 0 diff --git a/docs/contributing/dev-setup.rst b/docs/contributing/dev-setup.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/dev-setup.rst @@ -0,0 +1,141 @@ + +=================== + Development setup +=================== + + +RhodeCode Enterprise runs inside a Nix managed environment. This ensures build +environment dependencies are correctly declared and installed during setup. +It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode +Enterprise for efficient cluster management. + +To set up RhodeCode Enterprise inside the Nix environment use the following steps: + + + +Setup Nix Package Manager +------------------------- + +To install the Nix Package Manager please run:: + + $ curl https://nixos.org/nix/install | sh + +or go to https://nixos.org/nix/ and follow their installation instructions. +Once this is correctly set up on your system you should be able to use the +following commands: + +* `nix-env` + +* `nix-shell` + + +.. tip:: + + Update your channels frequently by running ``nix-channel --upgrade``. + + +Switch nix to latest STABLE channel +----------------------------------- + +run:: + + nix-channel --add https://nixos.org/channels/nixos-16.03 nixpkgs + +Followed by:: + + nix-channel --update + + +Clone the required repositories +------------------------------- + +After Nix is set up, clone the RhodeCode Enterprise Community Edition, and +RhodeCode VCSServer repositories into the same directory. +To do this, use the following example:: + + mkdir rhodecode-develop && cd rhodecode-develop + hg clone https://code.rhodecode.com/rhodecode-enterprise-ce + hg clone https://code.rhodecode.com/rhodecode-vcsserver + +.. note:: + + If you cannot clone the repository, please request read permissions. + + + +Enter the Development Shell +--------------------------- + +The final step is to start into the development shell. To do this run the +following command from inside the cloned repository:: + + cd ~/rhodecode-enterprise-ce + nix-shell --arg dev true + +.. note:: + + On the first run, this will take a while to download and optionally compile + a few things. The next runs of it will be faster. + + + +Creating a Development Configuration +------------------------------------ + +To create a development environment for RhodeCode Enterprise, +use the following steps: + +1. Create a copy of `~/rhodecode-enterprise-ce/configs/development.ini` +2. Adjust the configuration settings to your needs + + .. note:: + + It is recommended to call it `dev.ini`. + + +Setup the Development Database +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To create a development database use the following example. This is a one +time operation:: + + paster setup-rhodecode dev.ini \ + --user=admin --password=secret \ + --email=admin@example.com \ + --repos=~/my_dev_repos + + +Start the Development Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When starting the development server, you should start the vcsserver as a +separate process. To do this use one of the following examples: + +1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example: + + .. code-block:: python + + ### VCS CONFIG ### + ################## + vcs.start_server = true + vcs.server = localhost:9900 + vcs.server.log_level = debug + + Then start the server using the following command: ``rcserver dev.ini`` + +2. Start the development server using the following example:: + + rcserver --with-vcsserver dev.ini + +3. Start the development server in a different terminal using the following + example:: + + vcsserver + + +Run the Environment Tests +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Please make sure that the test are passing to verify that your environment is +set up correctly. More details about the tests are described in: +:file:`/docs/dev/testing`. diff --git a/docs/contributing/testing/index.rst b/docs/contributing/testing/index.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/testing/index.rst @@ -0,0 +1,28 @@ + + +============================ + Testing and Specifications +============================ + + +.. toctree:: + :maxdepth: 2 + + unit-and-functional + spec-by-example + naming-conventions + + + +Overview +======== + +We have a quite big test suite inside of :file:`rhodecode/tests` which is a mix +of unit tests and functional or integration tests. More details are in +:ref:`test-unit-and-functional`. + + +Apart from that we start to apply "Specification by Example" and maintain a +collection of such specifications together with an implementation so that it can +be validated in an automatic way. The files can be found in +:file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`. diff --git a/docs/contributing/testing/naming-conventions.rst b/docs/contributing/testing/naming-conventions.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/testing/naming-conventions.rst @@ -0,0 +1,29 @@ + +==================== + Naming conventions +==================== + + +Fixtures +======== + +We found so far a few patterns emerging in our py.test fixtures. The naming +conventions for those are documented on this page. + + +Utilities - ``_util`` +--------------------- + +Used for fixtures which are used to ensure that the pre-conditions of the test +are met. Usually it does not matter so much for the test how they achieve +this. Most utilities will clean up automatically after themselves. + +Use the suffix ``_util``. + + +Page objects - ``{route_name}_page`` +------------------------------------ + +Used as abstractions of pages. + +Use the suffix ``_page`` and if possible use the route name as the prefix. diff --git a/docs/contributing/testing/spec-by-example.rst b/docs/contributing/testing/spec-by-example.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/testing/spec-by-example.rst @@ -0,0 +1,75 @@ + +.. _test-spec-by-example: + +========================== + Specification by Example +========================== + + +.. Avoid duplicating the quickstart instructions by importing the README + file. + +.. include:: ../../../acceptance_tests/README.rst + + + +Choices of technology and tools +=============================== + + +`nix` as runtime environment +---------------------------- + +We settled to use the `nix` tools to provide us the needed environment for +running the tests. + + + +`Gherkins` as specification language +------------------------------------ + +To specify by example, we settled on Gherkins as the semi-formal specification +language. + + +`py.test` as a runner +--------------------- + +After experimenting with `behave` and `py.test` our choice was `pytest-bdd` +because it allows us to use our existing knowledge about `py.test` and avoids +that we have to learn another tool. + + + +Concepts +======== + +The logic is structured around the design pattern of "page objects". The +documentation of `python-selemium` contains a few more details about this +pattern. + + + +Page Objects +------------ + +We introduce an abstraction class for every page which we have to interact with +in order to validate the specifications. + +The implementation for the page objects is inside of the module +:mod:`page_objects`. The class :class:`page_objects.base.BasePage` should be +used as a base for all page object implementations. + + + +Locators +-------- + +The specific information how to locate an element inside of the DOM tree of a +page is kept in a separate class. This class serves mainly as a data container, +it shall not contain any logic. + +The reason for keeping the locators separate is that we expect a frequent need +for change whenever we work on our templates. In such a case it is more +efficient to have all locators together and update them there instead of having +to find all locators inside of the logic of a page object. diff --git a/docs/contributing/testing/unit-and-functional.rst b/docs/contributing/testing/unit-and-functional.rst new file mode 100644 --- /dev/null +++ b/docs/contributing/testing/unit-and-functional.rst @@ -0,0 +1,61 @@ + +.. _test-unit-and-functional: + +=========================== + Unit and Functional Tests +=========================== + + + +py.test based test suite +======================== + + +The test suite is in the folder :file:`rhodecode/tests/` and should be run with +the test runner `py.test` inside of your `nix-shell` environment:: + + # In case you need the cythonized version + CYTHONIZE=1 python setup.py develop --prefix=$tmp_path + + py.test rhodecode + + + +py.test integration +------------------- + +The integration with the test runner is based on the following three parts: + +- `pytest_pylons` is a py.test plugin which does the integration with the + Pylons web framework. It sets up the Pylons environment based on a given ini + file. + + Tests which depend on the Pylons environment to be set up must request the + fixture `pylonsapp`. + +- :file:`rhodecode/tests/plugin.py` contains the integration of py.test with + RhodeCode Enterprise itself. + +- :file:`conftest.py` plugins are used to provide a special integration for + certain groups of tests based on the directory location. + + + +VCS backend selection +--------------------- + +The py.test integration provides a parameter `--backends`. It will skip all +tests which are marked for other backends. + +To run only Subversion tests:: + + py.test rhodecode --backends=svn + + + +Frontend / Styling support +========================== + +All relevant style components have an example inside of the "Style" section +within the application. Enable the setting `debug_style` to make this section +visible in your local instance of the application. diff --git a/docs/default.nix b/docs/default.nix new file mode 100644 --- /dev/null +++ b/docs/default.nix @@ -0,0 +1,134 @@ +{ system ? builtins.currentSystem +}: + +let + + pkgs = import <nixpkgs> { inherit system; }; + + inherit (pkgs) fetchurl fetchgit; + + buildPythonPackage = pkgs.python27Packages.buildPythonPackage; + python = pkgs.python27Packages.python; + + Jinja2 = buildPythonPackage rec { + name = "Jinja2-2.7.3"; + src = fetchurl { + url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz"; + md5 = "b9dffd2f3b43d673802fe857c8445b1a"; + }; + propagatedBuildInputs = [ MarkupSafe ]; + }; + + MarkupSafe = buildPythonPackage rec { + name = "MarkupSafe-0.23"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz"; + md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; + }; + }; + + Pygments = buildPythonPackage rec { + name = "Pygments-2.0.2"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/P/Pygments/${name}.tar.gz"; + md5 = "238587a1370d62405edabd0794b3ec4a"; + }; + }; + + alabaster = buildPythonPackage rec { + name = "alabaster-0.7.3"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/a/alabaster/${name}.tar.gz"; + md5 = "67428d1383fd833f1282fed5deba0898"; + }; + }; + + six = buildPythonPackage rec { + name = "six-1.9.0"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz"; + md5 = "476881ef4012262dfc8adc645ee786c4"; + }; + }; + + snowballstemmer = buildPythonPackage rec { + name = "snowballstemmer-1.2.0"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz"; + md5 = "51f2ef829db8129dd0f2354f0b209970"; + }; + }; + + pytz = buildPythonPackage rec { + name = "pytz-2015.2"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz"; + md5 = "08440d994cfbbf13d3343362cc3173f7"; + }; + }; + + babel = buildPythonPackage rec { + name = "Babel-1.3"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz"; + md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; + }; + propagatedBuildInputs = [ + pytz + ]; + }; + + Sphinx = buildPythonPackage (rec { + name = "Sphinx-1.3.1"; + src = fetchurl { + url = "http://pypi.python.org/packages/source/S/Sphinx/${name}.tar.gz"; + md5 = "8786a194acf9673464c5455b11fd4332"; + }; + propagatedBuildInputs = [ + docutils + Jinja2 + Pygments + alabaster + six + snowballstemmer + pytz + babel + + # TODO: johbo: Had to include it here so that can be imported + sphinx_rtd_theme + ]; + }); + + docutils = buildPythonPackage rec { + name = "docutils-0.12"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz"; + md5 = "4622263b62c5c771c03502afa3157768"; + }; + }; + + sphinx_rtd_theme = buildPythonPackage rec { + name = "sphinx_rtd_theme-0.1.9"; + src = fetchurl { + url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz"; + md5 = "86a25c8d47147c872e42dc84cc66f97b"; + }; + + # Note: johbo: Sphinx needs this package and this package needs sphinx, + # ignore the requirements file to solve this cycle. + postPatch = '' + rm requirements.txt + touch requirements.txt + ''; + + # TODO: johbo: Tests would require sphinx and this creates recursion issues + doCheck = false; + }; + +in python.buildEnv.override { + inherit python; + extraLibs = [ + Sphinx + sphinx_rtd_theme + ]; +} diff --git a/docs/images/ae-verify.png b/docs/images/ae-verify.png new file mode 100644 index 0000000000000000000000000000000000000000..7d8ce87f94dcc81b5c5f782050a894dc4de9a75d GIT binary patch literal 204070 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 +~(qplSh0QVeI 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 diff --git a/docs/images/architecture-diagram.png b/docs/images/architecture-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7d102820f46f7f69a913b3e4d254c280c67cdb81 GIT binary patch literal 30443 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�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 TPiRUu0DeKGlq4&~jlcdM56o|j diff --git a/docs/images/branch-example.png b/docs/images/branch-example.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a55ea6b36779ce832e85308763c8180445d50a GIT binary patch literal 84844 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 zˀ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 SpQ1nf^JFEJB&x-}2mKFRKpchu diff --git a/docs/images/clean-rce.png b/docs/images/clean-rce.png new file mode 100644 index 0000000000000000000000000000000000000000..bb45539be46ba8c119e9038f6a3cb0db5e1addbf GIT binary patch literal 74930 zc${pz19WCfvoIV^Y-eKIwlT47+cqY)@dOjwHYZLdw)4cc^UwL-`{6(L?zQ%=MpgAL zbaz#+)sc$wk_fQ4upl5H2+~qw${--%&wpPX=x={p9#z<uK|o;3twco?rA0-F6rCN+ zt!&LeK%^p5)1XvUtT0D<pXR>P6N4#>I0WC*bcbza$0k5Plm8a7<PaM|!B!Fz6T<oP zD<aqg)RZm)a-GPqUw|kikOdL5F24aubKo*Jr_thym-EWwvi&OWt>?+_=pB?u&=dwj zx(*#=>|NC;A)J+zge5BI4POWZ{JIYlyMBcltTYgW@Vb@x0pvttucp6hY5VD8IpNSz zWd%eC6nex_d1VYbPvRC#he#F@<R_V;f&#{*GtK}TF$>Yah&i`?F0VPadG6KJLnuT$ z5g#l_?xZoyJ_wPY&}j^tJ6?fk39;?a(e*QQCyDJ$oP`tew7931^KFNgKv13hWbg6N zN49y4X7X?p+TDBSB;;0VI*F9A*=OFwO)n|8bkjAVwN%pn&s^croVY42zdarY<~x)3 zcdU$&%(J|G&qRx3utpW#0?dp-=Lda5CF8Pru*T5nnOo&dVmLZoEV8Aek~YZbhjv-Q z8+d7d<2YbDD;5{60GV&lyr+>r93Tn%ynAJzqy|o0crVlB=jEP<th^Q=c1jyS%q}qG z;?x3t1CLizncX&xgz*HYoHLviTm<4I$T=pes~`=BDVQB)TL&p`=mkl43K6jk#Rbl= z6C%_nGzygg!fF_!OO%?;+*ukl!6RIffQ6Me?kFOUklugLh>*@K8xu1Hn!z7(m-qZJ z*xm>^dlSw63ld~$RjS^oz6CdPm#txytd)MLDKQHkF;Kn_6K4L<=6ID5o(N1@2>ezE zrwkn5Fi_Sa2;e5U^Q|jT5E?Ym5Wz6SGXXx72;UY$N0@*Lq_bZ@5wW7rND(P6Bsm`g z0G{5*?g)1u__hOs4KldHo&lm_h#O3VCl*wez*hujCGwg8V+y${YM+3F4k0cwtB5xg zF7`*l^1CVshA2>xeF5YHEaxYKFlWC0F$x=WtngJnBNHseAe$!4QgHg9dL7z1LU>>0 zE|(`i0P<*{bBCqvo4~i$zVscPYd=pAe*}dBkf_jtLRF=2RJ18@<AfMLqr_p9vXx%S zlvNQbU>4&}MK;9|@_#Gk&1$k?ObLC@x0}s9R%H9$P0)>_7r`L8T&VL$<B!K|$T7^l z2Rvk9#O%n5VMYeDEFJ}Zaya$yg7LIrjq#;P7_*8dU0U4YZ*61#`otB8^KZ7qk3=mv z>p>U8h(?r7TmU|KLW}Ubk$T7SHogte4dxATT|#^8Cm4l+${o4u%V#P+!n_d1VZvd9 zzNcNu>v;(3V2b{*9fcia78vnR(opvS`~fDTEGoGLiZv9`2$-SjAr@n_8=4#H8~#W! zWm2tVFljzzj`A4SVAmWrsaM%F;<H4((aKShTLx$R_K^38_gs-*mP&ZkN-3)23_rku zEI@8xGKAWIVlZ`o;tGip@hr(K<&8uVQ91PqS-S*_OoQre$^rhE6LoM(T1qs!jCG^x z&jqb=|8i-oil+LeUe^ZKU-wEU-{%ThxNzukIC0`+YbK2{Cs;&P(baNJMa)!MmEsj^ zmBXzxvp8a<W%4op#LahDp*65Hm^T<T;51+~9GO8KQ*~hGNGlXz%___h{^_Mt(%x$d z?KC|~Dk1li5g4aWbxGMD2Trh0Y^J}F%p`auE2M0bZqt0pf>!63B9|r9I7;nS3_L5Z zDX$lw7r)3TF!)tL)1Fd)qqbM%tMb%wQkK>l6P3<)6*_5{Yh%${RpJ(I7kdf5&45)K z*8f?mT;Qw(#1Ku}9g;FmVXk4KP{mN=R}-&Ttk|rWw_daUWzB6pWj(VHd8&R|e@cFu zbBcybgWH4qogJ5*zy_7Anr)x`$;REve_?J3c6sgBVg-8zed*M~^ql>Ie}(9*(;ux` zl|mN<tV)~W>@pw4R!O8K*5&Bs%0HcjNM}07clSuAPYi=}jrzY0)Eld|18sLq6U_fu zGFeJ--ZM`!+p_yM>Y8{h-11L!rUh`aaQ<N7F}@$t{Jk>4HPW{EoD-P~vtBfCko(sg zH(jHxvQKna{a9;Oi5tTYRb343@DFnix9RBULowwrP111FX46vBKGfMNK`KQm&z7)l zEY9ecj;aLLHCKw(08K9wOMM)(k7XCfuooB`7?SGntL3Zp=M@*<&T$@R9|c#DxXO6y z@T~Flxhi;_@oexV0j@cyfH>}MCk|&!o;;_|W8?jXvEo4t;OTDG)!GHcKIW<V<>Q9l z6#sPhtlz-khDnHIIOXs8b(eSxL6yica}FlTF1l_GFTEQIA1I%6pWf@)JCxU^w}Br0 z9v{EFSF6{X5ABa2!TEsNuSSrIzz5LYZ^q!@V6<Qc-*BMp;7?&ozSSZK;PPSY;VGlv zlBrUvqOajl;Iz<G5ucm1*?2lV3k}^y$f2~7V32qv+9|b_)s?N4jiuVtK2_uCoAuB* zEQTzuRkEsYYZlf~SWUe&C)sG(D2SUB3>L;q1em=vT5BdVPiBl~z_h^m2)?n8B&rPH z?5{aRx0BYp*ALehI=MUf?El`w-;>!N@nYz5-dcy439Sf?kNk{ui)5AFm7W@VJ~%#T z^u_Tf`5NZ|y5XF8L%s&{_4j#aKfEm|KzILardAw3O=(fZHFmd;b`@I}53zc*!m!Gl z8=O-xld`yGwYNAmyPU)ubDnwi0`~^@5j~PvjMd>pw0B-p?Z#QdYixIkeofn;A6z9^ zeb9;2L2La?Gf7ba+!^USw>;_=Z=7%Zx*%Bpen)m2>h-~E>!JD)_!;yh`XoP}1Lf{N zb9Asx$3#O#|ExXA(DhPy6K^IseIB*BsAsC=YRT!&8SoUskLYt6T^!vQ75?~oX-938 za**!3((1k)tK2wO@iFvK@BwZnU}gu!hIlS;-OShX?*G$8+@;tUI6WQ@#SQg_$W35f zp<F>z_IitURT{oXut?9Y&0ZW{A3l%R%ZKV-bY@YR_uU%98qT_R@#gH?X~=0Un<fVv zo*JL_0yJk7?nqoU&yvf=gQrfiu!<XNcl!<m7ctMxY5K7N0pMO>)oc7zb>3=fKGmYk z;#Ma=Z89x#>3J!rWwd3hQQv}h-EMv6-TK*PlY7wx<H&3VOOHr@w42F=`E1WLJm2J9 zd87E(baRdZgQRYc2l@4nC$+1}<=S?G&JEy#+fB#jgA1pvJ)qmlt??mkxH@h9uyy9$ z{Bu3iKKe3^H_c<syUJ(HN8?`q*yXs>b@}14*=N$H_3~}=$`AQ<$LOo#GbkJoUKpQ5 z(Cr6!^n8_mRGFNAw@{w>kw+^~`=a;sbO;(9bQe++(rN(F>&Y@i;Qb*vPG}JBVxX*_ z7FQO-7Lyf|``v}`%&Yl!@!F>U?Bu3Pu=uOWxA5-p-XJbuGdCgw+n?5#_pau;`~9s0 z$()df5}YDWfm}f@VDgLXtNgQZ@u-Gz*Fd6VzIU%D&2Ro=>2ve#Z9elL69-ggG^-Je zifng96J%=<R45W6a19(p$#{!&29oXS><IcDf9CDDUC38DhZLkyeX12a5ci<w=QBDr z8F+$s1Zkk0-0;hcR3tll<}yh$$x@N4`62%vf>Q^G?^#}ErhQK4i+VKt8+Kq^xtD{$ z_fUP1hGG=CR^H=B+iSubq%A10DL74aau5*ETq{*gS4}xt9uo&U1|w4kV>1R%J4cXz z9zIW=zePJUS0f@%J6n4f9#4Lf|AoQxxBO2tBMH&}LUFa>C()EsBocLSHX~wZU}In+ z5r8EkBI0v4HRn+lllU+4zcqdmOIKG%9!5qF4-W<pRt5)W3r1#cZf-^<7Dg5p`o9?T zE?)MoMxONcE~Niq^1u0rnYoxaTRFN~IoK2ZQ#UepaC7A+A^9(y|2+R0$jsB~|Bhtu z@?T>86_D|t9!6#cCdU86`yclIwDKrgd79a3idos2*}ME5Lx7oynS+n<f9(1nNwxlO zKNmaq|4XU$-zfPQ|0U6X)W!H;`VxTUWBfn57l1AGl?DX?5dx7G6IS&EJ=cTGS5sTl zYt<L*;1v@SLsk?P5*BAxJny@l&SaLb0N}U*>K~R-l+H2hiy`RHnLva^Qofyd`<)rs zZ2Ro=jKKAU7x;g_<gI^Nt$%EP0z51}PGz!EBFbQpAje85X=+A@M`IFW!xv~pA5yKP zgfkfj&cqAxg?W-q7ZUmQa0Lqx?gddjL)By7fzg2z_OV1rqL|=28KC#n5kfyB-wp4? zkD$cA?aVLD*cb~xYlSu6WMPBR9hnFY@a!LP>z_v7Y6oB|5rk^Gg_2%Vhl~;KH#?=l zUBd>9=1fhG4^?S3Dk`c*9Li-A)APsrA=JkZ3Zz*qRt=6YIBm~7u0TDe?e7b85+X3A zyZv4@Fkp)-%c>~3fonXk!t>>Hp@5Zv{nMrdXKL249dvJvBS;zSiA?>-`I{RSIT73G zVVDhSo#WG!DGYF)mGQFaK}AC&G%pd0GCnRuguO<78N?Px&&vCK+mAE*gI26jA~qp6 zH$(_`WZEa6hv}L7NhsoDVtVrTq!z1^qHaV9LKZP8FIo@L)mo14m&4hL$tQ^QfvIzx z#jgyPjUp`-(-L6Y)d}Mbe;I7J;%GczQdaipsi=r7rsUKh0z1rj{hqh3n(O@dDv<F| zR9#+fGM5!x{O7RcMjP{7V`Bp5j>By2^IJNP{m0?b==5+*Caa>Rs%h`f^%tFEO8-oD zmKU9B3z!?50dB;S!IAA#J>bhoDSAVL%}(d4Z*E<D@4drr$wPLX=_)Ln)dsTP+oQOW z6G|SZ@8$E$hGax7sILIj{v|$9g(Op+=nYlg;%hFMK5g4>V|ww6L|=ff{4j}c*o__u z@(#1h3*O;i#!)6#4AH1v#*CxjL|b_Kn#p$*f-`9Xi%unhqmTF4=o9JMhIcu2d?kM{ zK9v2=@Z1Z~T%-~U!+{Y(6JSH$pDHgE(}R*mtn)W{&rgkqPK~X%_}`hS*+Dq0J)+W1 zV+?OP&zl~sD2MNyR$I_GC#&yq#~+SZ-jo1-C~-*NJgW_e{utS!8_f6O?Jt_F0K#n@ z=jZnfad@~WkM1Xtt5(OQN$&TY)zobmi^Rc$!pyBV*7+AcM7yWAs~NAS%9yWfNyK(7 zEzK@V=7L#h?Iz10*`EDlkLkHMQX&2LZwR=3PsfGvx20Q2#D>t=U}1s(0ev&V`Tif? zmc4HTmYXFA1-qzXqr<|^7yG=GR6WVRp{Q2klWci~1;zy0Tk-~c3{npC@brLEEn}1T zyY8U^ec<L5Jc2M@DP|#6sv<Vy2PnIgQpDfeyV3f>Jq1t^ugx;eim429P;&QimVSw# z<A#dl;{`IllYLCy)hnO|mzNuQLkoT~5jGx8_n$6SE>g?<*PnHAfyrgD2@i%L>`u(g zM31~ECM0O$n(}Kj-M9l1G)9#7c}`f6sBTiPGiE}D2&Ku(pC3-j^S^j%i)`9vdLxVA zT&u~3ZIc7EpaiXTAYT$Gcx#|yX)6R%>|F|>vR;p0$CE17%*yP{Pj(MZ)%6>cmI^4b z?o`8c^sacOS;pjfPTJ-RWI87Z>T%WN726U^IB%}mVoa?Ju~+>}x7j~jSFV(9J(m0% zADE>1e9qesbBBF{J1i`3na>fwq_Bsdr-|X}_e7G+1qJIt=yyi5U*g2v`0ICF*e16V zkQJ`^Bl!4lrbVXg0cl<&XOSM*JxGavM#_IZNxrARJ-@)43p7^=EHTQOuoch0p?~or z@U38Gmo^7}UV8%@IX?8c;e=bNEi&TFQ2Kgd;ApzPpZG<J{2Y2iJu7lkW1^yEw*p+O zI?VWQId3`S^z3z+xK6aa{oZPXjC=cFjXD32(w+Ace7<;Q=eo#XF2w6c!aT$(gF6qE zo#bZrRgTz@uqwbWvgDk!4|AoPr|-=LV|hZoDW=O(D99+9OyWBOhP^3eCf^YkLTM$; z)Rt|9JqYcoUH0$iTG0%40LE}98jL8lmg2)L1qpvBwO}NuW&)dP|0=#*K*GwIesAXJ z7e^9r-6u%#DjlhgTaJlZ1wGLi_}zlK?3~?Vzb_29@p*62u@ir&o>$x|mXX2AF7(uv z2xurdxrWnU0V0BpOrH|{md~F?{TnaZe}|XwzqRguNL^7zK4Dp11NEUg7TccidI(S4 zLM)!AN$5L$!1oAyijH%laC$VMQIgy;XYVe;zoZ|NuOthOmGsHyy}IFF#Li#*(SZ-s zY-uB}rCA|KV1Lvkt^}E>m7iyP1Pe0ysTGQJXWx>y;_qoNXiLt7R<`2L@spmwuAqEo zI2eq5V|x=jc}jsU;$UNaZk!vA*%91?<nQeob4a{|V6Pkw{yTp>WCXTJ&Wso1id^yz zRwPl+EsUOY6OjXv$eyV7n_1uu5#{<^!`M6BEs07@)X|PYMn~caY`sgk@*I|^3F|Wm z)VrukV8_-{k8=6w2ooZ*!<91Il`?ir-ds__bF-_aVDQ22Gt;hvYOXJhj->eGKYW>@ z@}2I{g)I3xB1|msr*-9z4wB_h+zPISLN0J5!V>kf&IKB-vOWlITIc@Jruob#8FA|q zsgGd8KOdIAg4r$aG{Ipph;f)Wzo=L1idQn>1}Meg6*gw%9cnV8>i%>l_BraY9UD#Z zDibmTwK^)#icg4uGD}hr!7~$r&<9RV0AO%m>fvrB3JBom_~hg*4`x|*;~Vg;9?69x z5~{+{UE^krjESx1wHSU>f@a1^7vLRm6!a)&o%0CU2?L7slPsc$EN_4JTx%|#z^C4y zS3>htrsD<27^p+Z|E7oH(ns?s%DssElU&CPz=s4ux%JiWi*H2CcO>ew0Se?(m||+^ zVN0{rW>`2YIT{l^3JCp*d_TdHIG2d=b361sFQg+1hOH7E^N|G|(`2BS=M6`BEAKfm zTOW*AreHFDkZn*zmZ;h^D#G@b&q^AKQ0Z&OlBklwh9=DvM3#Jc9AhU&Nr_`*9z#3@ z<|6QRMJC-nsl1^kJTC~m9VfRF(`rm9D-A_37t`9~X7-=9*S05@5OZ5FAM(nD*GcEP zpyCdWGBvzKY$LqYtX`qyAw6c>&9L*={+-5Gl5>WuZ;9Q6ALCb&PBccty#q04H$Hnd z&Y7?D&TH`kxd}|OSgWW8cgae>0q(htVj|SW(rYIX-hf%1qGNOFTa_#uaj8q`A@LXV zi_KadDFB9=@{?BRtfASfI1)o{`elwQz%7|)fYAKFBT-NQ5L`1CI)?2B>WRPpt5z#! zcH1uzd0_3wg3x?J83Y_j7+GHA=k1@7cPi=**^gDW&f(jxU_ozGiMEJGbp0VN=?0dF zlaYiWCH1#kMwR=QwrIqe`Z__-G_`997)AgF=z7{u;o$pE-x$sE<kU%k061J4ooG{0 zL^noZdO~mxF$0V+%o{l^<b$->a;g#YL;A3p71q8lHIcmTHVq8I#&ZUB6}!Z8+UZXH zHL}E{nH9xS_Wfouvgq@;C9x2)8TT%e^YWdxWJ~7EKG&HNnW0+I3(@8dcbdieWrQ7! zpohUVm^isc0N^?Bf|}fW6dwlMvl{L7x{Bn>29;blAr%rz{1>b^9A1P`%6kotM3=(F zf2PQ)Lks`%`9CIk^f$dq=za8YXBv#hl+!L0Eq(O;NqMy2`EeCg`;o?7-IgYMAF>B; zs<n_p8yY<w<tqa#T0!kR3I?;qAXopshm*Oe#HCL`Ne=@q^&6~86ceN<ZF*UziEWSe z*L4W44`eb5?Ljjto)p|ZWzZsvvwy=yL{rZV)6;4T1gMd<Z?b^(X^K?I9lc30%eq1a zSUqBHy18DDEy~haLBDb%o|2xef><uTX*Wu!nK>iL<klNiU_`p2Xf?1{Dha>+z^hcr z0~4-F=kt*)y`rFlY3>%i(PBnqtHk&Id<%cIom-lv(qEee0v=Sf51Hxz0fx&GLU{7N zhi@-;*ZW;BD|S!rs{1O`l*0!Ofd3`=XgBFIEapyWnqJ8wEP&F*E+E5HcTLqwOH}xG zcA<HiDyP&`1>J_<!sHLp=>f76?Hs*!bl5ru6kn9R3<^!)&>1P&f_3<M;KCuz6i}zg z4GRTn6kSgYpuI;m)<y>FZyoKH%oThQA$Zc-^!`qol?&}$oNa(g3X5H|>H%xQNu)2i z8<Z^Th&So@`FI-Lw1CP~XB%^n%a$t=99p7nVu<LVh@fnu__0w=5wnL*b%0?j^v1tl zD1Mg)?G%aozoU@<7rdt-L(kLjO677nZ0S08gpz3Lp0`df`%eItNS~+Av_ka`_is59 zBy=Zr`caF9Jtl_7!n5BZfrMq$8Yo$F(SmO{yNe1|K^v{W8ssD9=p;wlDB2luspfKR zq|x5o1N~soOgAVkO0UM?j)sI#NVYRY?#%K=joa0@A7Dba_=O5xj6a0IzRS~nAM_uG z&=uG_Z+pcktrg_Gn4DU~$_(J$w|~eEj)49NIqjiK@j-KSzNr?kQyYd=$B7qS1kdt4 zJuo=kN=P1BNe}x4+a=#TR$Jl{rkea;#_dCXz91$NH;ct>FH$^EJdo|B?0M7yHWBnA z(RhBxSY5ECl<LsQ%PmsZ_O$A3Mk6&rOsq>!xQ|My?8@s$CoxL$NpcU!H~^RpFPb6b zLp#aKT>5T%<>K)$SOu=|tve~5m($1Jg<U&w^FW@U?IJQ6;PFb35GFhtxQ)RZpj@m% zaf8&keOi2t_JpuaE#LY^Z66jk2UV2%_5mk`^i7g#JJwXXZ)Y?h&LfOr+t$!^6_-Gq z@eR54Y4ZFDM<~8HUixji7Jn)ME@7?7h$P+qM{7!;AeSonvI)v{;fJq_zi8VI;+Zn| z;!=$%Tr1wH(}Od*OD#5;WJHOl)ge<FxLO>L$VWRnOHqf5_QRud2qN6P>bYyl(+1a~ z$0UJ7*H7T-_x~}KAuM#~9|CoGQ3)-ZqUe^$_;m%&R*#jaVHl6izE!kEcGX2AWob!q zRiQdevNad1Qb<rJE|lQ@3hPRF(Z<!OX%EnT&4=!;f&!%Fh~=ff77LfY_^S@Bo7JQ7 z%=o{M!v85Pd$S!J$(Bw5v|{X`veYTuKE<od6BgF`1g3#k=(v<N*du5W46ze<pxyGI zdU8Wax%Tyse&)%MgI!2N^bsiDF~;_EFf@X!Le$ORYM_#8aZq9Jwip(*fy2OrGS!*> zOHuzM2{l1|Q5dwk=#LktvCnCmb-LZH$+Z|Y+kr@wF(V7*D)r7l1=Rs-$QB}8Hp__V z9Nzr||8Sygbuf$@_7P&~{ec5ZSZo87(ubMvVYr$g=#4SYn#GYOPD2UV1z>T}2oS7Z zQI!)@K6tx4@e$aUNdWigZ`<|Ok6J~#i8sT8Fv=Oc2P=H?RXVl8V;lx3tHa^k0UMNw z?rhmuD2!I~(#4x@+F%MKNP;kKs${ut9pmlrc}#Gybj}|2-Y<67NMnp=sq;Ne*Yb5j zd$POWFWl?<dC06~ehMb|O*oDae3S0JEMKL4LN#F8mkNnjYB_81D&HAl3DU)+?V<22 z0uMG;zt_=gz*R0actt_(&>?8LPj3)1T@KD>u=*f!0PRHV?HSfux4}Q&2!mTL)+m3= zO$1VgBMd`g<zCU@jvF7OH5M`j8l!AMoOk+uEz&P@U#3WRlpFZJ09h<r@d#Wdnc04p z*8@W@aQ?0QK;mmwl+l@)krKJ=gyiJ?CFSk3(;+K>v--F;gT>(uyOu-vXlKEJ`U3I% zcvehw)TU|=htWnjHnTAVw|X4u!^7F~_C`^fZ61pm%kS9l;rsEt1W*sWQcd=(2FY7$ zw(@yI->(x1f2`6Ks1cOP#V3>{6Q+%B=!mtbqFT{qYlitDHgVxf)dsB$AR*I?Tj-Ee zp-^HNZOO}@rITorX-1h)SDjokAh{rsLKaYd0705W0O!;5Me2ubuJ-F()e^)>jBflM zQbns;2s}fPQArWsaFFGRkMMRWEayfmsmG<Hg1vBHKER*8p!P>%N6Je9QLHn3AtkqD zv)U5zWu0c%mK=<oATaO{p~*d#-A`hTNo0<KPPu^fM1xj${x{U*tDf7{1T;QmbU95T z{<xF*-eCpWv_h+W^OZ&usJ)rnxoMld_S79>8l%uPGA*q3bRv<DsJiLE@gLC&isa#c z@FK%#rFM8ELf?C#2#1QKlQ$4@Gc!+QPdV*3BH{&b<Da&Cu%Pf)pfq&-G4#KG@`d$& z;!gMOfIYUdNoaS7R6_ni6lomosq^C~6HrZwijLmI4mGo;p`#m`R}hSC-SYlELSREC zi1B@$^WVE^P+oXnhufJh<eIsKg@cRPo^ND^UDI#*TXsPW#pooBSE*ZRR%ui5sIlJB z_Mv5cuM4%2=F_F>kTiOoLXW&H%dG;)29`M`P1P9jXsq2v1%duxNVw}qUI(M$@l>we zgJe7dm&?_v(V16Y)oY41b6!*?)jq47_4eat$w4tm{MtncU)A*?i7F=j29*A34U)Fy z_Dj>M7vet3beFuYG=PI77roCZ`XH%f9LX0Mbdu(EZ+h2Zw~BDX*StJVjEOwgT6?qu zT<NB5!Br7Hn4YO>;=OpN7v5nJS2>upRZ7;&P>ka!Upa{9SN9nK>cxrWToKIg`KG-X zm+1n}Fl|R^N3mm=w8`D#;&`P2lw|j9Ew}_**1DXfMntX?2pFd3dzv%fJMj+ki(Lq+ z{GRuZvGMY*(i^@f;C`>aC;=|JUEBlPSq8TW#pC%xVjAjw^%3^_tpk>!D@%TkKrABL zD&O!KMv8(<S@F$*2VwrT5GL$g9qacO$l>R+SWe^3*9XhZj^<<vGgH&HY+dE*f&vl? zo?C<|shX}=*aIMta#B-MgGR#t8<-<!Mkr;M&I;?Jr03|d0hf=;v7D7LEkX|`v(bwr zS+a-x(ATO(-eA7)$Ymf!0Q>Lm5Bv@SFCuHDgnDuelik*NCYw(Mp^K8^E(Z;^X{ieX zwHF=hADhutSy4#lM}~%Zo5~6<z1WSEazh&!*$KZNz3<Ok)B<Q`7*+Ic9s7$sm?@i( z5U<vn0ALugo3z?$JsOBBO}2<7@_F%YDHY8pe;|FDtCA;U3>T3EcPMN6>dfpynMByN z3+&JuJ63}8|Fy!L|A3atq{=NUsutK2QX_Z5ofSA?Bpudy&Z283mA-Pn;V;E0A#d^B z5d3r{X}(jzOUDtrco)#)B~_Olrj_=QO?)Zew4ZOGUu&_Ktl>`8{@kS#j07|iBl6`V zwSVWPS&yz4pmsOwzkq<+3&3z(qZ>IN8#V=Ad>iiFGvRUUqH|K$GEUTeL<lm6s_%-R zTQBS7T%Qo`vTSzQ-a?U|;JU}=_l{8^qRsbJldeRM!RP!olIw}bZ92x`q`i2;_RJ7S zKu%=DqKl%Jv%p1u5;0n(i=N6#DRTZaznmMp>2lTmY`-MiWW6|tvbELiQ_i6;=i;fq zC(EXpH=lIZwIq&y6^HU6hAeoPcs)Xe?AU)xWf$4m;u?<Z3kyb)^89S}gYnC&V##cc z_$EYz_%9>)?AyCPZBBl41|6u|ew=U@Pb-6Rj;bQxBsM*6z*fvt)FHBLqEOgUAf7DN zVWEldd?Ej!efv}diGSZFCA+9<RU-YnX+n*_^L^8MJelN{m#iv+Fp&Siy;6+MO-=oY zO0Zn5gETx$4l}vH8IHfoT8(7dPK4&C^oo7uy@tpYL#9|Bu~QkXt)VPES9Uw6WsxIo z_sPoj`Mlo}eK6y5WQ6B@{yn41iRW=jZfhuUxb5t^+i|`vmRb%!_D04)e4FB)y_`l6 zSTWamc60j>zJGpX-<S35Rt7YaINT=;_xNqM&*5d!){VN2DG<?3rdsw7^1|lmX=Gc+ z2(za9aw!n?-FYNeSy=5QvH->R=6Uhh>!y%e18ljM2ki;aL^)GEl1%A3C^vsA1H5|c zGnMV}-c~+3|97alqK16k^rRoKRHJv6(zfL!t}|i<uurWlbUM3Xr*{5;)trWFUc=!p z!SCIW0v`KZ^`3D}_632@7VmF4{*apsyqo65IypHxP#?yAoNVmkh+@d$N&GH;GtKL; zzv;0(D3H@h%p1N0xhHdw3ThQ%Mm^P_ycR~Y)1)*~x$=FPI8jY+T5wE(hLaSWyxwA? z6~lm7vobd2(bVf;5NadtIb~#wbIiaaaQ;W8@0>K{ZZu=h%H$KxfZ7o`1UA!-<G04r z*Bre~OnF*@E9joQd~xWmyft$KAu@idZEqfhI))_m*G?HUIb}TJh^I{-Li1@r(BV{8 zr@+JMA{=F|BTJMFEMQeE<v^F=3D#SPEuy_7yiR6-M0F8UMnc+K8rZG?HtD^oecv^d zxvMfSmn(1ev*zG|?c$m>$zKElMVQt4DxE<mF7|Bsmr~&?+q$Nl!Hd?hP*N?m`VKGU zrqKn-BWP@7a8MndNGS4GCyTA9IRUKi(?{18v)h^~o820E`@Ku=>#2=mv;dVj$=Oe` zzH^;r2EF>7k(cSBBKM0mbO{uCSUy0VR6Q7#><$Q(nsK0jbfPOgBord_qX?&o5Hpx7 zt6BmZ^^dWsLuFJdKB;9;Mg+poFqi0rl*&ETnE3FGkP$&oe8w*J)ZsV^M4h?dRs#2f z&qq#+y)cs}vE71rM~Mml=R34yCZL0#lG<ll7OKzBXn{e|c!ZJBfbDn~zEp0eLRBBa z?EvmEKbfxkMJd1!xwpBo_=45X^!<RsntsxemcPzuwywkUsm1qvtI2o$?80#N97EsX zq6MqU@mO&;(WK6Y#+kU`(fz6w({Uub5KT9tvg|tSMY$b5F`$qy=SnS*ryj`r`!nLq zdr{PgIKVN3#Vb$q-wCigIYbdLW^Y1EPkx}lDYf*7%~F+<_Ip!P6KwjEJK(pLY4Ta| zbu*V<OU`Xt5$_NBHiPrD!?!%Y+j5l@4!gCOtT#VP<{GnkG~a5iMstS4%smjQu&n2- z=e;eTtB~5BPh6RFy5A#teleuq;E5WO8#2(R+abit^epK2%u*e-Ir)x6syoVEA1Qq| z%=#};{M2O-f4?{3LbF{2T{kJ9WC|eOV8A6h4df**eJLH(>h}{g?zlT^Q#&c}1K9x5 zX4NtWzo#+u$&%mfxxE+Z%<4X!-pK)l10vQ}<uO~B@@F@rhJoj*SX@>Rw1v0p^)e$N z)ZEuHJO%EVPurbW!!bD91zvZD(~R9dt(Vh;1#J;ze-qynarsrPBu!~mW7TyP6op1O z_Y^M}=}406MtS)%d)Qnvp>Hh{)kXXQ5}O(+-jL=AS6z9^IOFh1L>1mBK&q_d2*y1z zObo07|B%<1t~Rhni-36kwbp&Peil?I<mUu3oGQv`?+;f_MK(W3u#{_|#2YgX#@1jM zG>Uxn>d=~(GSYZ4dv%JRnB;iumB!mZm9I%wh5h|_L5bwwv5*m+IC#2r<Y#Ey?#B`- zq2hM0mV$fxG~iut8**3snrz{z<O(5Ic4{qkbrGm}$ufG6{ZNElFd9IJyfnBW%FYK6 zT|Xs$zGu&Jnz}>--C}(x4@WV+R&gYFt~QEK77J$6A{Dhy^)TMVhi4}z0`Jc|iiPKO zJ?vC#Y~;-7BYW)FL4xOvM4#q$*WQUb*VnCQ6mIk|)x=u3@gl|1aIl4bIZnM0kFO7* z%#HDpnt@cKMmMuaR!M>YvQz0FsJ1a%{PAF6lY?0UT)6YDUv_vAz3z5DV+@&tn_XmJ zI9n=a<o}(y^%8;6o=h-^Fd7@E(Nr#C&8DyVhkQf$q4&dD+*?$B*iJQVnMB$-dkMyz zr{jly5y-jA(WKjZ?a1dFF)oD{iP_z=w!J;V60!O4vh4^8ny(z}{)f+fU&OAA?)4og zc${n3gqD0VT9m<SxvCq(VOI;Ed^S;!Eh7NQKwWRdZGSiRx)|7TCe4K(?*bOx^#J|& z4prUdqQrG>t@tV|k0tgT)K9hcCHDN9li3y~)<q+KraSjD$dMR{p8A&}xpq>12;b2& z+4_?6jlZ+OE@c5D2A5rbWH=Xn^{JP=4p()Z3$8Du&^4S`@JM@piyp<z+#YK}t}n28 z12l3W<cYs6bHjr98n8piZ_cLgdn1lzCXkv?;Y=RH=6QXxz?LU2$H`m4LB*sv_$tY8 z{tfjYaDeP-u4zI!Z*b^od#1l(SdhD6GK=j?o|cikJ<pUkL>RlF(OI$6Uruu2Y`HdE zjaEYm?MiaJ<pRJR5<ir6H_fb6SmVBW7C|Ouo#X$(;FwP$SeGZ0#^5G^GB<uD?vlXt zvHP><Qce&OgjD}~+|B+-XEslt^dpLG&Wx#`F<lWhxHDzKL{RkMjCTP8ED3FX(~x9P zIGKo(`{*VgSQ+4;4n<(>yRJA3E9=GxZB1VQ4Q1ZPxC#$q`>8wLfXFWQpwx99y;|4i zFYsBILC3d;_+P)>KI$%`u^d<19-hy#yNPb~)%?rHJrh<Bso=fhiqfsrqX}>NHwSn! z3w~;jF}qD>M1Se}vfBIl(mh`K@YK8=U2t_G1yDt$Yvf)nCO6ovy~)Dwh6^IB*v-v* z(vim#Gt%PwEWQ-efU}(DU-h@QUF6fw0;9jrqHOPmxwIYp{yCEmu1B!M@Ro?>8~Sl} zT_Ro5_{j{0^lA486AO}Yu;t%p4vaBEQ(5deyti>|v|GQ<RFb)3tNJit^kL<0*h|GJ zA^+gsl04Ip0x2`G{ss?Ir~+&@TLU*Nf+iYXz8C1$t$F_58I=MBugcHb(U?<~<Am<Z zl2&1aWC1QHFKXKMy9IcES5iVq_y}~8KbPnbyn0e1+QHY$PsA;^F4kv_dW3$e>LXE{ zecSg!5ZVNh!IHJa;U<3`wGmb^zGY%<XTO3v{#jk0wAw!iiNe~6PttJFdZNtp1S^!J z9?ku&;gy8?g#N8T@G`?B5+Y>A0lZX=Fg4i8DiuaGu;gCVnY9dmta6n4Zl9!q>_gx% z;A2X4)K%m_8SRj??p8%3WteIrUGB8amx@9*fAuLdB$EH*y?8oZJdi@${En=LIms~7 z9)i02I?+`!^GX5E5U5Z&n=eh8<b`4mCTbIyp#q#=Fo<%LS0$ns>+{S311eRh*4pb; z{hArIzgS6ozs|&(Z{yNz849{)<V=d7Le`Hl$%hUs0-%+^C}R7?X=UviZ#gD$j1CC< z@c>P0(20^^^%<>Vf0Ld>E&0*W(G&?0gO=GJWK0s8eh6)&rL)<>{s=V-%&Cpp@j<&R zpiP5h2d>bjJ6FtYiey@)NN3u4??Ze`Y_mHyJLYheIShhg^MFzVI<y;~btmn0DO19w zPmlPLJU)_J5Pf7+UhkNM8{HPR?f}3IhE8V!2Fws>W_o*|dUY{MNN^8WB@7{7fU*3| zmTE6GwsqWbyk}A!*j=G$K3z>Ow`fRf29Hn~AHdGbjbV@O;C`rup`jy({@4IPM8U;( z_`(_iLl>`g=6`MM{s<5U`!ygZ6KVA86iFu!N}oF&^2?<ZPPjN4y!z5T*pvond1T)U zVEjZ-%6-LiJ>X@vZ4S*9y{L^Dhbu>x!}vb2olgv|&@;`RwIwJpDx{V1Oikp8>1^yu zbL6j^+aO^7CO|}~RZ_K6qtEI6={1}l$~}ljg{CK(9_Mh5y67U$U^vhZZIFr5q$oN4 zU4V{*$0qmuK4B3s1BvR3{iY`6cp68ZmooHC6Uq3k8X_OUxbM*>ae`qjuj{|9Hv8B( zL<ajEouz(|<0D(8VrtiK19^XWMKq{@A73%;uj7zaC-v5)kP%PHP}V;tSvE;kC6PgE z^Xg9!l&L$LN_-XW1WsI8ar0*qGV$TJHel}9^~IC+b*Ts4{!Q<q5we?f!QY6sp;4{H zSL2g?-!$XZTjRr`cV`NC1Aq5@Qr!kbmync3W=ra&5OyUK)q{7eE}+nCtwIr?SXJkg z`9V%kSnPzm-JdZUvV9;kVk%h7kb?;sah*b7M#T{pItr<E;+h@K9HK`kN>B@Lfon(2 z5Ed7Of2hHO8|~gD8_l~B?fuS#h;&Pl+nPGFn>h3tQ3Lt_Y1aK+-!j``Ke`Tro~}!i zI}AVWQMjHWXqoc+={1qRkPbBxw+kA^Ck}qXE$!*#PT;&lU<wBKi&XkeE4`y$#rAH# zFvxeJr5+l*Kfc6CrI$Zq@zMd9;d5rZAaO=EBI7T4@eu~^ZdS}jc4}DH_E&3OxLyDj z%zlPEJQuSI59JDZA4-Le9=iThI-0I8pq9jq{{KF7?yHRmoIDp_N}uyyoqtwe!cX)} zWn`@AQPKX<JXw?vG<(U~E0rFj`9vc+x(hxAI*dwAb+mW=z>EBT!+tpt`my2iEt!>> z@@Fk@p3y*hxssjmMK{!UR$(r0e3@piiOi=fYBCvp(!}V~yOXr;%}@+0CjVPng@`-Z zAE5ToogWph6IO!U;;+Uo^$C3v9dpR_aVt{z1W7xdY)T|kKp+~nsRK*8@iry_WsTo6 zN;p~sdJNf6S?GL4de(e?!5A+rt&6kzL1Eg4c)(E_9zgnL`-AH)hV>e3>c)bpPv2ak z<ZgS#qt~x|wZws|Rz;EfNx@X3C~Zh<Ih<R`Yr!!&9gWX>&4mP=k4Ojx3HWVVOmH%o zPQE<8#Wv55(`pf&{)3*%^pBX7vgn^?vj8-bFl<Z)?Wo`aU(=r=x_dRy&8G_@qzu21 zONxdWw>^e+=VfozBaXeNpx<bIg`pKHX4gb~2s{?MovA;Esl$Q+8)qo@{`h}vM1giN zV?_KJl+yOEtrdX%<}05y#N#E9pDhc9{38%GjOv{GNLU&5MRBw$FYr!mcr5$+bZN(7 zbI;qC^ApY#!57TKz|S<8kFy<b2I&PihcP!41HDEySHUO>D>mS4yp>0#P>&ODFq7_d z%Iv0V;~w*PjS*|cj!xpxzME!hdHHr(c3a_nlKpE5jnlaIwWCyfZ(3u!&*$OI<Z`1J zn$srKz4Ih|T&DTYQ-TR{K%C~BWPnfIt#w`Xzm9?xH=&D?-YZUPA~t-Mt-9UY>7mN` zk&;z@N?jMZ$~h7`ld^DOMaNQnB7Em4c<57}d~rhTSiJbrBT<lYV53Y@I?LlTnn3)# z+<Qqiyxfy_SEwVPupB)kxsujYEuf#gV^#d3ttC%;=W9@_bBsDUJdr+`FZ2r{QM@r> z>&+QLhcNQEgdBQdGrOn<G%9TK9IWbX4hJpp@-z-9c`#A6gII>3z8avOqB61142!o8 z@h#66mVSNahoiQ$e0xGAXuXczFzvpoZE_82FLuZ|Mj=_AA9CW>H~BLd+jo*ySSLzU zyiyKrZ%aY;nOm3mIjg``c@u^L|JM_Xe3g-IfV6i+kvF;@G=cZA(ShAsM66eK9Wi4( zp>;nThw=RHSj}E)BypoKo8*IFF&>e<$|c=85fl$O0Vwo>i?B&HF2u*+gFLXny(E%@ zBi0JipWu*?KdI;p_26NZRCPl|800uj4(Y129?)1stmrf%aGM)ui-^a%lR;2qANi|x z5S%IV$-%NIV2%u-0YYffPZPR>vAj{aP<T7OYd~kF_tfS3y;3!@QveDixU6x}L^`8R z&_rz)*s`t@`#SwfOky4<uH@mNz6k16@+Ele$dRVNO)<n|W{sygBAqga7h0io^>Lw1 zm$O;zcH+J&&{=EVdr?E}v!xlQ0J%TB7L!4aIyXF(5J<YfhLves-0)rv_FBAfJ8^FP z(%GGm1}h;P*~l|Gxf#l9y(pY4*quI?YV7;=^2WFI-Hp}D;J+ucC=h^kH*$d3W=fbo zkmkp<n8DJd?_w&f3iC*cYPD__=_FC1tJ8Q>tIyk}p4jJ%z(=TRWXA`3Psv#k2xbn= z#InH4Ihu!FI3oT=k`FQJTS9O}bmwjI`11IElNA(FQ0*fqRofRB`i37a?AH}ZN|!q? z$A=9v32ij8trJy9<f4V&xeda%UD8@Kq~vT)g(%N*9|k+5($wO%lp!UWOrV^itbkrZ zZzSl#umfCzWL#$?UrPjEYeH8;!UkurB^vB#;oVqJVGL+Ol#&`i9Uom1p5{3F4vP{e zPBEkgC#jup=0`%Gyp=LGcA%Gd3JJjf)yi|XIGxGv)U`EiH#D9CIfROV?@I)1vVpAe zCVz#kdH-G*DY;9=hW?hpmxOK~0-5aQHUvqrQ%>uLNGAh{EZC(kgymR12RI#`nO{_u z!GLf{a^1|Q5yO&$W^`CgZk|RP3_G@4z1BVjRY|*7%zi?~K;}^6SlOQ<GHKz5(H(Ar zImfKo5i^0l7Clu_SS)R(9-(vwz3YosHnJmf&W{HQ1~W$%?}tlKxFC3jbdBJ635CAs z+MdatKi>k~<jhuc`H_ecQmQPw;B)hVAV6m#$7b|ACe`n^7_<C@=}WyyjPsZXJs_1_ zUO*ZKB{g~abJk-fbX_-4hEEHg8iDpsxCW17wOW#oe91oytsDiZhi`R>=4b4@Iq_(p zoH(@x%EQ`MCq8?7Uj%VjU(Rd{c5Gnj_*<w30{$T`C~d%)9=10teJ_D<){o3PD+)oJ z!6UhW8@t99+<ZKq3PzyOic__t_<f${%cI#b(~hdTA6^{S5k=R_Q{yaI0OlpnHCgUD zTsM!K(82G^=b0Ql9h<m|9n6f6Ls2fXQRf<5N1C-FSjdXn5cTALErNBT&{URsYOtcf zN&tE%klYD(4!@rEmi?w1!oY<s`txX#oN&)eat#L|VEZ!TdDTL*)tz4e?}Hdo;J{F$ z`Z;S&>78TP9S!dGd9AH}zs`PB`$)dq;mMv%h5SIB_*Oj00F|B_RI0VY@Cd_c?U_Pb z1E~{xmYj8Wf;=dFpcRw-zVeXt{e%{}`D*VuPltt3D!`Y1zI2F2PdQvlCAF*Gma$Z> z5crIyfMAx;%^W8~VO{xL8;akMBIy37-gN)H6#=l6t$^yQPNyu_+~G@ljB*uG3pO-1 zsheew<=RL8B$1?0!28_PAJ-<I&9Pbi{fm8>A|{Wq(FX=f%H2yZrD(O<N<n=Buk@RG zp+Hsx6gMbC7M}xj6a*JmmlXgIbkX@uOWp|tJ3(0Bm1QcO&{yd2s><i%wYf~CmEcDk zpFuTX&2phCQs=T?yyXbmbd6{NL~!wuhY|)JX+v&O(eFOTa8MR@hcYva@AYTDRcTIG zYNa}=P}04K`~ceE^>JZ*`}ZHpY4@)52ug%j_g|JP`NWUwwY=mi@YAK^3u)@GQqalA zAu|Gs5xdDcfon$F7zvD0(rRW9+u7J6YF4-7YTA~Sld5RW`6H>K*XBx?-#&n{d~Z); zy9^;;vFTqP<*bFZG`&nI(8`I)JrC(yl73yixjj=lb3p<Am@|xoF|0M*_AWzjXJK+f z+wqo{uxhDSBqv7S(rOt^U#emJqj7bfOk~cAM|yx=ts4IRbnOcUWy3_1gq-L{1ir-I zx<2v_#3lEOYjcIRUsG&Zj6dswC!F-hSEf78`1y=MANd09Z2td#7fnPY(oJ7Z6MO}h zn~WrFb#}vk!!t}j&vQkx^C<;l<Xo&sg+D^Ti#!+}-zTLVOq<{pkmP&Q>~qx_jukmL zi`AQ;K6hY47>6ItOjlYw8P9!a89F!CL8XN3fu;eQbUfmxTa$A{v)}Y{W;1Yd@h)hC z$90B6Bh@f?X>YVVWb|ACCHEaP_@blGv>!gj_mM_pra-Tr^yMJII^x3x734EE`RWq6 z6hVS&0eeCy_(1C5r@rxpSVSZ*DuL&@bX)v)L4pxH53n~{pxYu~sdB#6@iWPjPYhKq z5>A|AVb6wS=oN;b|JKHt$_W`%J;{Op;x%z>$GbM(6WqY>h1~mr2P7Q+7|8&|hr$K^ zkz0(VvKX|9E;kGrBZ1@t5JB`41Vuh;@&VtHM#j#6LoUu9IoBeY<V#yy{t~P!FbNIS z^wHr(fi|(#AN;6{B8&5&0cO^?g;dqk1f>ppiY6FBcn(hki!mLZx&Q=@kFj4E@JVv( z;@Fx9uGO0S!%4b}Q-6e0rL-Wl2Bbkgp+y&sSo#Mpx#pYeSy-|>*R)%ADDKNG)7%v0 zUagZ1Zb3F#p#<WgY~D{lpYx+&G3c3vCZoY`d=CrrZLg=5$_nY7Uppa4yBjVutJdvN z&TtxT$~8#mwizO^8@dl2vK2JFvNsioq~cz$+Rkw<?dI=G#g*gRuTciKvJlxE(tXGx z=JsLP`^wdlQM&#Sn8?7`YE>;>rhliEkPu6?2JwrP8V>eaCC}{E3w;t<;S-@7G7qPV zE)eUy@|!>QKZjGOR~kiqIvkUkC|_{Zdg8ih1+;V-w#V*#-#l#38YA;e210M_$9i;I zR$FI;S4?Ie%hVb<mTGiDR$Y$v_F)L`a=Z(pdA3^}1aGJG5A>S~-0f#oWoc`0yzn;< z+JQZdB@B7<-|~70+&CFTf9bXl<D?GFj=llrv>1S}6&iK9A9AFbn8HRm*%K@RATW0N z=J*GC&%OA2P5#cutrA^7r43}=_YHwCm*pG_=@49}ILRrS{&?;yMqCFwA!BaI?`^R1 zZ@Zx|F)n|Qdm!Pkk~A7oZ#<Hm2tiTVQ-{PspN+|YYn0@Nl4}muJBtjw1t1986*Wag z*u(e45y?%RL|$aO@-ZT}-=V3c2;1@eR>_ND5=NtYqu-+;M%al9UfCM2Wmx)p#55&# zptKA^XU{%h>2{W+$ubYcUcob=>t!<r!jtxxj?@Pr#$qzWmeeShzu(Wo3ezqsS*B#j z!ZJ&}aT8drnLW-pIpLwgl1;nVp8H66Q=~B(1lRVw;znc9i-0=Z0ygm29JcT_JKRYf zACzRzf~d%$Q;iPn2|puw_zFg+{<$a7ST7iYR#IFgkZ(^Lxg+>``~|T3u_rqm(9E${ zoUX6T57E14PB()5-<-h$x=OcwF44;gHPN%0>X2NEA^JT%C53BlJ6{-_v2sEE#lW8% zvhzwl*g&@~vo^9;Vssenz*5P7h*^4*<Bna>Yx2qEXy>AJ%bkxU-f83Z?hYR+Nkol# z*17CNUPfl5F9^I|^6fEB!P{4EV+Q5NAO7svG4ep03T|;%F965KiH)MoyfS)XXXJbb z+1{uCx3k<dwT3-?`XyJDRBQSb>>Dx(6h=Q|&rafB(`%D6(1zowr=9I>RV}x>xX{u% zj10OZ*;R%|ZK{j(iz<Oiw!{M5`CxhuqdXHfel$+Gt(j?}<ll>uqG~E-=1f=s*6gXT zH@Q~JnrgLq1>}#u9E}KQiB-i^damX)Stn3VsitlQwFiWbw0b93iW4=M1QDXUvVq(Z zEyPLq<c<vaK}#v6gp!(^AqkX;>572>z&#*O6Eq4tlds;C;7vk=u@Umc({dFo@jWAh z9}?ZDh1~x_XkXdQ=|=*3Bohr9a#|vC|IAGz9GxUw*dEtynO&`3CuSVa9`x}yQ{Xw) zTOZBe@RF~(qsI>Wr==gV$p=hKlNbauxdf0r(S4XJ;VKf2MM<AH_wH8hU)Lx81J*+V zCnwLAYYl1|6is`@qcP=Q%7~6I{st!0&SNE`%|o%MzVs5ez|va|kzn9WGxQyQ&!I(K zySttHpxd%R_{n^U(c$D(o$;{3w6jneL{!?gQ*GRFlZVBKLb*MK0jYw_EjzuFJnB&! zL3ygqux!*}6qj9$@G6i2pKJt<i=ZUVTD5A#PL)t0VkO%9E+AN_LwAH(6rFEq%x;+2 zBVs;j858r6H18udx=r?D(SKo3iWauWSvyUJs-}HYLjJ7X5egsqAkqo-1|-P21c~hI zVEMd@<iur=??KGlewPTLEj~0|Hv1w<)&{Upmh2A&iOY*iF-i=nvr`X76frlEN?Z{L zhi91Z|FQCwVR3EA+CYHd5;Q@BdqW7pB_X)Gy9IZ54-njfTL><}wHty%fCP6McN%Y? zk&iQX?wuJp^Y8o9{XD&Qt*Uxg)vC94ueGPGuLQ4TC7trkR`tOA4X;<T*f$J4xpv+j zE)Z?ffL`!)OKlSbC<Gp?pXLR^Cf}8*DDs~(_6wthKvHU)eN{;%VnRP4H}qqqY+Q#V zFboKH%Q4X_aL1dHhpr&dZ#!&}iSJjjCnR@b8PdEK)%2~Pw6v9w`i<XFRZ8Pjb&~RA zt7-?%3^}6dpq^T(R;_t6Lcqk{M|H7%YX1IdKKI=q-xl{G^Ncn*-5C7ZkiA}s{%OgP z{^|Z9Ca^We#)!`k{?Zt+B_?oPk1w*xV&CXb1#TmWo|!KmX)+5m1ltj!?-(04o$1?s zDbR?cSnmT=ibED%d2NkFRy#;D4PFq%bSpS}j9Ex@h;^I!u~pZ#W&S$b7$wJ+d<JOe z8{U!{6DuvCrJ1H#cvBX;Lpl_7BjXKN{+wI>O!wKxxGkUZVEm=}650)8)#2yO(bay8 zOL&Od_?c92lK^vtI4w?Cu4fWqrY*bJONPKN%Ljdom`6&*BHr-oFY-kK@P?feUVmf^ zaQJh;$m%#W^Mi`jIhXe8=L<siYhVaM!rP`HkMPfz%v1&JC0JiN>X%Fx6_pTu;@!pv zTTAMMpX@@bMyIBf$D{AONK}wQZ58#2*5%Ze#Y+D<o#|cg!7$)be^hVo{rY}_f52qG zGQuKge2_0AGi5=sa?Q_anW3V;$I`5s)ej&~f{UFDYvf_Q?^!&q9I$NH34M(y=|Nx^ zTc@dvw<R$ubrPQ&6&<-9wNQ(L%03!lx)--WOY69<AwgQF0Oz=T>}5G+`Lm;zX0AM( zLdk5)|8=(u=aJ^OIfYu!or#yv<3*%hL{PB`dBzs#**An>#L8qXDMVMUcpON?bqZ|@ zV&$ob;qm*=+C+W6G*RMV$eH}Qg4D*5zST@W!O*&O&JMaMuB5y@qy1%QKgkvEEe=W5 z2}0JfCB|)}G$HJtUgFF%ME|=uyBwyZWUCE)e^mEs4iZ^)8^&AVeu`M2nika;nW^$| zWdXbYj0`@xn}#8olRge(4%g=@ua+iupq84dAH%Lg#OuXEzkukUo!hq@vAj9n2|j3O zszS0WBEJbJcfMcfrQZ?Xj*HUl;-caD&>W!s%)MsN&(ne9+R;{ynPy-K_$G=v1pmSf zl~R-LgLAZE+zSe6gBc~)Kk*)7f80AElG~GBakmA$fwdTleOadB%J6&yJZ11~I&jy5 z-J&mENz%Np0Pf2%7%DoTpuQ`8RzTeMO)?&x5a9N8Vm$#n`D(5#{BN^M4M$O+I+}#r z@c4$}r4b03_qFFDB;+5vzz?xe^|yloPI7oIFFda<m|yvR?$&$-h2vV_c;l5O+s~;t z_A=fXsWg#JZ|;&fmJFvRnEnTLLhfl5^#w<~8**LL_*qUqoYNNKN{mtu1x<6Rr-1d! zISpiDa|lCdbt<7~%D|7<M)CVCnj(=2#Tv#Gj!6yzOBK?gW)PxY7M-UCqTe3}G<t># z2eSgwxVOhtcM04KR={#x{AL3LIK92p&FmX}+acqQG>YnSV}#3XKAaUz0*zcgb|#jX zT%-0d&2}dwU=EbJb;z+lBrqtHCzRlQ%&bxONJ~KA8(bp;Uwp%E8Za2e3;}OL(`*N4 z1GqqC8lNjPxZ06SB;FmuIe^F4C;Zkw-Zd;d-iG9c)Z^_7C*rHGMP?XksZ@N|p}2b& z?5jq`Satb<3oHytjygXn@<=}B-*)@rn;A9BYzry>g5RPL4U|`P9`Q6!sXd%=qWA%M z73EdLYgipd2_bN&*vaPja;eApW&i2<1R8WB@9>-R<yuk8_v;hC#BRMXn-=tdYnY(t zz|E$9`=s#%>E>_eN2Dc5!(N%VJ0Ht4E%~(CbATtf2{n|r3k4H#)+MbdQW<q~j<2AJ zrM$|rw0yy{v?%G4rXufGKfdvl{|LY(6Mlba_63lz+fOIAWtOfWB>%I|(05-t;QOsm zf=b$OBIX;-9Ac)SxCL0|m5>zW0JrPDX{+|{hmw-Xj(ZvFYv`G5hJI#Y;ZJt8@xzCu zpE8){!03hlRuNzp4(S!HSV3&K)EVQOxI_>NSB4qaO_u_f5k9(Dlej7V`Kxy#1-;R; z3T_?I3Tt_0fh47$*xWB21L;1NhvF)n0!DY+PSQU5TnYEyUC}mCRx)i5I=;|jBu{K< z^-VFZ|M_`(x1hyiL=Q43X__yv_-xJuvo!X+kJcww<bx|c-=MbVQnE4$OX-EAXqH)6 z$TPmpu%=p}WTTw*!Ig66CN-bnkl(Kz3(JCsxAVJaJoP`Ib}?`eeVk^mf%OBeFT71b zvo~Z8qb!2%`_1N~e(l~fuz2rxO+*6Fi)5eJ8h1(Wa2LSTA!hsB^6M)gIb(#QS#3U| zJyj}9@Th+IP0_h-$IJPc{Y<>oU+X27(`(9snEh*6?=<>25<J7A-F*^d<%%TVYRb=P zr8kDB9gK^4O(eu!l?2k+)5WhbDrs0cou3X__e?WzQwHL{EWB^4>t~@Tnwl!&AMJTY zxr2X2ZHdW{DICE~#3hm&^2!wrZe4<MtmIVbfuZl=$S~CSWhx7bOB!<T@G7hXwd7jY zmm7TPL(8S#s9kubTJ{aa>A7Siy)LLe<e7Izi>YA8?qvzv7aGman*@ph?>obrYC24H zl-|*_uxKEy;KY@nJBP$85Hr3Ic|nbee8#R)Em@%qE(#I*iQ0?mGKHxf^MT8o*wVKX zQJiW5^$YQ6&cV>w2P&c-(cd>U&qoFWrx24`c&-9}kt}2u3tJ_J(<}%r;b~WXAl@nJ z>XLM3U0~F4C47D2_dBzd@U8G6x#UETT}eh;Y+aD3F}Ya<rNE8NGCNgFSp1^Ig<kD4 zb#ui-!gw3bI1gvv{&k>7!i%CFTA;Tl2!r-c`;}#;U`wYWOzS(J+j1n71=!3;b$!E3 zZFZ9d;49n6cr&fC9aN0pMP4&$W`E9lyLgkXB$7+}?8Y>N!>U8<^5fY@W->;6r4-(_ zvPf;+E0_xP{&b6{bW51060pDJWa49)tO!QRfrLkULHWsKDg-DQTX#*B&ZkZ$kCI2I zg*!AvtUFx7c{b%9^c+*{4$1^L;8393T><ttv=AtKeO9d>6VB7GCenjJ-PM0c{nxp% z_*?V&|8wR7%Mvo%E7slhrRu;c({1HvX#c>#d+=acW&3cNyG*Ri3pPAgf8}v<+K3db z`k;Bs1Fy7k8OTBYL81`zSUbXMM7hi&iQK}0>8R;%A8b`P-m7VTTj8hykj^VpC3~&J zC|;Q;789rG?{kSda8eB}J#P+Ts`Yo5JfpXh>lRjTY!qx69G6FhqGpDE8Th6Qeib#u zZIIh!J9U^=i1$L}^kAz5`;@})NO1o5T>#<lk<A>zMd}M;t6RJgaNo`~bb~&>nh@IC zh&Sqvz`OgunG+=1=bq2DzS#etgNhHC^p6vm2h&@1QG_gRh{8Pk19`^Pe^<2r@df7o zEYj+Bpj#D8EfI5r>9*Wr^YrM$|9pMupuVhAYW$m{5&zt0<BIqNd_QIJ``Z5RZ^415 zzH}q`Z_>~HlE$L@6ZZ7lU)%rt#3?Ham+oh9X0|c^)|bHL=Lq6Q{uHO53jW5=2WApX zZHRb}?e}cv=x+z`qd+0<y!ZW85dHISfx?anz`YT^#5C-BvU~j>!~0S`3=idqeTVk9 z)(P`GSa%QR4!~Ug+u@;sA`TW<T@a|K_3=((dQc~2`diDOFietsv!Rqv)0JfD?`$JK zy^TadCp0`<Xx40TDS<uo&@Y5?0OwAss`e!x-2N6gLzJ69oS70tVZtb02F^EcNF#{i zmrY^?f46x$zqOvi;If(!k(ZZeZ1RR49>koUoK(9VXtU_I5ewg4Qg8lBTN9dt?y|b( zk^Pr>^A|z%yWXJ>=`y-(d63j@*OxO4`S98WvP356b@tce{NJT&Wy+?0YrWB$^;QJx z<(lx8JE^QX$fyV(Zyx%^Sn=prd3K8}k}@*$3k9xwQ!6kCs87SdH*{18hEZ!iJeO&~ z|F^2cIw)`h>xJ3g#}S_Khl1U=f5USxy5PCZSFnzabCLoR7$nh!?U&ky=`N|xN#5Da zp!uhPr^_@((+-A0K)$ex5d_1=MK@79yGmvN=KWTVf6Tl+h-~h^h4>9Ft^?vSQHMOo zAK{A`lRrO9Bv`cBb6!DtzaAZ1eC2a39Us#`Y}m2@`1_`TWy-2XxtD#`*y6<kWN)Ce z78GYY<9+dWcegN;Utc*ckGin4a{ROm?jz@FPXCL45LEck%CZZF>yxVG=#K)gFxO7C zguwvrI|2yk{?6P9Kn1{Tm)I5*X*cv4l(}V~%o!Za0k=YcUFd+e02x3#evaRD2_9m< zcE{hf?0@A|xL618QeT-tFd*@oE;@tKUWFWMZ}J)7oCjY<h~k+6rQ`>4R_;>2U794! z+%2-Aq9STePCO(eBnC#tPHf>D@Mlo|F>~655J68QG*m@vMY^Yu_30BIj6hpaa9%k1 zTtm>j=5A?O<y>!qI)>c}FVlD#37S~%=<x7+N1jMh1H@DVH&kgS5^BQe+|o~eXr<Ft z2ErJx-lB~C8d}!hyn8bWnJB?)aor0mFK3xH8-?h91GObtG3MUtB~N_UW=`Uc*%fLm zTUA_KtGj-hW~pKwDlJ}9vr9j`;#(l+gUnlG-W!9=8QQ%U%;LFosK9Aec5vVB4b_?b zG>(L>=QCrVi!|P9a)M9%Idf&xPo(L@y6+aF**vSCsed;+TgYa-!&Lb$``*YXZ~9~5 zH$Cpqy89(Ll_fc<z#x`qrOYL4lg)xszGp)7&U&*o+JPd>*bF>IW;8(c3T->rXQ;A+ zY)YC9^8D`};nhG8sG;xWsS|ZaH+Z|$TT7jLPl_RMw_!U8^iX*F%9Y}PIimGjiqxVz z(*CI1YsCXZ1Eu3ay;O5P92CRhmgvh<Tv+}J<FwO<9RmZ@0fQRT2pwbvnKc3;qSjBa z$QJ)$u4(Y7{~hN$+qv}->yR4!-|IvK1j+nhLFfYBb8?Sd^!}oX5F~BCQ5o0WiO#=H z@C0M=^=B#jyTA3EmL@))P*G?G+REtFC@L<;2wi_-Ff?Rlqit#*u!j8>#qQaw0>$)^ zd;f~RIoVaxVin!?ji~#Q_w<-0J7VcG_+w7rZf=3Xf<D2I+l4p;^y3m}(pjg2sqN~0 zDGk{0M(PJjXZ2@`yOU+F4SbM#nT?9?(nCoc?vW(ce%+uL+b@p}d<OvO+GYI-6cw~L zLeYu%RD9xZ=IX82I-gT?BN6EaJglT2h7K6HKK<^nZ8vd`JK0)|0=VHqH_8CUWh9bw zw(-|n+1^<CI&)0Rt*Apwl7pw;WJ+NADod_|iOlca+#1RhuJp4jp>{S9zW6;7yC!(s zxw>O{quc9qkMl_l4%7a);VtEP*+mWbDnDB;EG?05Ei959RH$hQm1>b6sSf#2l?1q- zryBYHN9P!d8%KAXG%mjw>itQN^Wn!>XB1RNeA;8?gGRf>R}Vd<o3vrpxW(1UMhwi; zYyoLNc<H=k%Le3x7~)ZncheI^wAM%A-+kB$iMhE!K%5;6E2cOIx@y|W4{Tb<3GC<( z$7NayX!^`WKP3~{0l;&rum>1>UCdhW|70-+9Qe&Q*phV;#S?N&eJf)vtXbFSOQe%? zqS4-P@#%eO!D9`_I$N~oLLK4bjkvTYvHOk-;JVCQz$fs6H85;&J2Ro71h&NWYP6zp zX}502!2g!3H-;>#{bFuN3s2YOkJwjXe<AT$@`K2thO`#QB&5EgBe=v@37A^s3(-au zc&KW-pMmW4|F+~#eimtCKJ;Eu-&dmVL8_*qSXOu$T?Qf6j>bGNRNG&^ns(`#c%IXt z!LKPcJ9Hs<C*abBA#l;VUZVxNc047QSnX)2SGmURxuzXIUXfVN^C9`2l)qp*xhJ{b z;P$3>L|c!K+B0b>pFU<sHH3Q^hP>i|60I}YwHrEw%hu@9L%;X?=Nq6C>Qu6-?&kC$ zBUf+MY{VDwZC6SA{aG3ggZNcBO@RaSFBuJRBXKYba4To4p8ld`G@o(DYgnF<dXSZ^ z_B(XEUZ2PuztF468?sqHYVj{=TKXDgx0#opn^J{J1SHq>Nk1~ye<_bDOiG$;s61BQ zJzr`bp7%h$*q^6>L6#Wan^Sv!z3P$p%44mSFIoI9o$D-KxN^})s{UYq6`Gf{Jt==w z_&No26E8tNAhnA4Vpy>wJh{j5Y=o)1Yl|Yxdhgx)PJV1k>q*@Rw-<9hOBiDdIqplI zF<&A>qWZ0!#8ibZ!NJ4YpHQ(MiWzo4nTX65qbK4N*-@-}@OGQst9Xb-jxS+Rrc>nU zP7bHV$YzEexFe95-4Ko@GtSL_XRJ`4iw(KsbvWtjF6^P2EhhNue-FVe%JFMKhr1l0 z&uJRpEvws+MnmE8I5JEH$ONYv_|2jcPNdkG*PlW`_lvBrF9(^cz!CJ>4(iXHNN_r* z(cmS>T$5_U;+TUFDRzTX*Izgsbv|EvD9f(Q=*0)BC21$?>A8N}GN+pv_Qs1XuA0?` zff}K<|6+8x+PIRU2jb120qHRj!sU)!)3!kFi$ixb@d>#;$LU*x`i6$~WF#yej3P_{ z{9&LEmVvMO7o8k`Z0}(|{Gx@sr3>}?=9>T&g|0xLf}2!Oj#jNuO*Ltbe6~WpI!<8b z_4ZsL(MWMdl##uxG)~_z^{f{?YY~U`q%ESV$k8*)dc`s+981d1QJdfbY<?WP9Df8( z^hSp2hRXV1FB6h)ujEsYugZuyOhnUu8QfP-5W6e8kC7aN*CM+iM`{?aZoB`8eBHR) zu>YAHcHZaNs?b+G&7(0NX)iz`k?D>=*nYEcF)ZpDUExNbDOmmdglM$m`5GZy8rPo^ z3wsQKR$g&TZ`7z4z4eom+R5ji?sk=qlA_c4t7^_h0bob=*oCO5fe$+A-dW>)Ys}>S zDx^P>nKg_b*csbs>(qS8fm%@ka)HFSv1|_ei>Q;;;z=j_vqN8eZ7$+yBH?^mk0E`Y zd;>TDmT%d0Ut0y#XjcCILm$6ba23%1beLPS)vbbho9ZUL?Je@6j@FC5z*!_>r~SjG zhLJ2y-W9cpG`>vS3p{OmTvhvgwOC0{D`lW^j*xGrxj~4=+~G-r9b0|Hx*okUt3P&H z(C4!uBoRbCQ~%yCFGq-g)*8|cqr%HqFlKNLB0^RBMS9uV_Y6Cy6jW@1BRJF5JBa`N zJnE}3Y>Jpgw|UG59tkQ_IT!$atVD96#rbjgr{Foc@0n7j>y#E7akkxzSQH_zQ&ooU zntJ<g!P`An?K+1(C)cAf$3C*H5d2b&py0jA))BLaesp_O_%_EZ=MmnflR@TonZ*W; zD*dL5IqSt4X|tKYe{m{RW&~>sP$>T$?9V2j0%!{}bGncpt1x(VCMmAVcBh8u{zQgm zAD5eGxdzWZ`VfYEw2^w+kSQ~J`lscGj;%rHl@qFNhO+<JX{*C=PnBcyim^r%ekAQi zJ3_15UP{Zm!dd0k#$^}OIm12ZkHOyWZQ6UlP7UFGp9VYw5K1lZUTAhp>uWR57j)#q zh(%6%6Sw4#nUDlp)N%wLXw<mz8(cybtt@Zu!Z*_4V$SR~GXg-)l-E$7Em`#H^aQlt zUFM(LMqM}xz%4rK&E8SyFeR1Q{DQJ!_{AWZL=D}>RRJy7SW`!Nm$)&r0@&_hi$U2O zTa^}L!QgVdbf;0N8>4l4(GhTns8FKogGW4&;3^}%Z_kA-B_NZ!=%nU)U^Z#nTbi<3 zAD=_tS3@e}r}?G5Wuh-ZRd>>mG6Y8^`6quN^~Q*V^xahJ&n}H?edkl6HE3o@skh@E zS|jX>#8EqXk0(CA+*UorHW_kYty60*SJXBMOx<!Dyvu_t(ozvlktYt6TBiR<IFt(L zT-_j3@>lsFrNa*K#mLCH(f_Us5a@(?msM$}z0vU<RXG^~VdEh&!R!jvf7C+D^n$Cf zqFiL6s^FYXn4xqE!gkCuKHKSJJ*T%$4kp3q$7b`l@%&d}A)DihvUpW!Z-2DF*BQ`R zo)E;zbN7d!;*oM(>?*J_t%#JVS2+AcrRR}~Luq`wbmBPeItGmT7E2+#gw#7;|B!J1 zAn6we^Cmr!1U%3M=d1{j>~^yGNM?jLq@BpV{XB*G5OyG8NsZb%!mQ`DQ^>RPEiuy` z_OP_>FQ8!Y@3YgBDju~H8TkBRg)cS?l+I@FnwRd+jUCH!U)p&Ktx;^czk~gNE_sV? z!sxR-sOS{3_gQE{I*XMGGT}ZPKL4pR251II!sSx1qhh`#dgz5RYO&(Df)KGbj5c32 z{M+9jN2j=wLu_h&*ips9kcVPYxyb0>CrG4h6fcn2xXpaC*G7^#>ytb0>ak-W_`^-< z3mT%mYql$~JJi5&tGGFW`ID9Zv`S;XchrI@=GE7m-u9-eKe3C)0cD51YJK~n!%kEi ztk;?6%aJAJF#RdP6MLvhj?P_R1Fz4#l?!^Wn=mdnM$6B7|4vX&cL~f+iJc|$4Z_y) z+2^w2(H!!ga~M)JPt{AlI?29pZnB8{Q^@<+qi~*$!4TIEW+vztAgobcZ<<$jhcmGr z$1y`3Hjxs031mwV89Wgth~CYFHQE$G@3W>>HyS~+vJ3MU!dP-!F};20r&0?qB}xvn zdG5-Ax$t2!WgwDR+??V0mhe1vp1V4`ua_qdECd<(jP^xcF%q%rTnT2}hGVS|<Li^4 zv1#St<*je;`$?dDK;4&)o^lsL_!0-pUe3*8i4w*Wbv=hor9u|<hruQn1Kq1ZUNg0x ze7(Y_Z_+Jicg%*AtVb7>h9+Nh{=yD7S&b!GRMNf`EZ*J?Zjmy_(dQ(oYCo3p%+DG2 zEv?KtOVRrS7fK8}By<8bAG+3ZILV$AV*o3*{r-Sd#!bx;PlYK$e>jgh?DF2`*^AZI z0=o5``&Q3mHwzYOI8$uxzVo@~)5M9yba^Ig`~XmJelOe}y*+oFL9H9BNWPJqsl$P^ zad_3D`kS5pIKL4J^|Yyxl33z=ZqsbBd7Aw)qs=1VdYd2ovCb;n!G9+0l-VyK-DTf$ z-*t(9>Ro;L;5YK3!=kCJgCYydlt#n!MhCi+gfuPI>y_?X^y4vWJiHGn`%^p@>!N=s zJ^ib++Az|hYdMZXH8?;#&wLfgRd=9W*5kG+kgkLF230Zsoq!{V$Mz-K^}3YalIIqg zgdvv}c^bYM_K%*)n**!3!>;NP+NNB4iH{1G^zSfRkd6txd6fYmA0a!^S*RUum44c| zOc^U{BT93EMBL*0lh`^aS}DCP=(9b@?=~|<?>$_hQR;Uc?wDUE$rGbo)>G_uBEVV! zoV=;y?g%`+>=WVJGZl%OdK-hj7_uJ$-w&yvr7}`<(CiDp9N!B^bGjOwru76FhY{W_ zo}J`X3=fl%?OwH90o0do+0u506b$HYN)4vThbSyj`DnU5U<Zw_-I0y*{3N5Q8q87v z?}G+W!h?dkyJ)zIbN1?P|8+(q&`Kiro9S%|UkRpgX%vbx>eTT8-S1QJo7i>Wr#bJY z&t+g;r#)-U>3kAY*z!9A75a*IZq{{Zu?rrk*9I;`z?%|6th-Y(p6OH%*VgmU`?v)O z_LDyuj@z&OJ6p%mek>pRcP(R&g3(p6Ge0<ie1775O3sqGJ0(2Xt&^zo?I|6P>uRws z@(;~xyeBfKj5ZlRgF1AbYw$Y>gEuY6nsa!W91rf7u8>)wf>@)sr|YK69==%(Gr>Yo z(R**aJHbN4S$y+Pu2hAky>7Rb&wd;B^w}-Enm$WFo@tzhA82tO`~Ib+(kLA3OldLT zd~E4-k+Ic?)AajWGRdL$!wWQchNO(9Tphck%e{%B;j4vE`q%EGemr&t=?C`72>nu3 z!MZKqnGSftE(tK6UTl9t(Qu&%j&bxq74Ae<HjVOWx>_ZUi!7<}t$nyL3!^tjnEKrK zT@rE<iMPn${`Os3w(`=^%(aCU)<5vIN1HMLL-Iw_ajT8|$!xi!;iD}*gWh3)cwcr_ z;>V6yJ6~@~0h4lT`|U)Cq3fcc!_9l!hQn=no^c!ZUJ6YPg43QTW;w>ou(^DLBCku+ zOO?t|K=d_My}Ny|q6hAh$DwceHx!G_=YTcL1aDQ<hOq`Wfm)A^4>tMz#=k>}Rxj_` z|5Ta<k2%X@o*7wSe@I-_@^G9{#PB^4lhs<rdG?$l8~;*`i^6O(wQ1wf@hdgdnXWCX zTNL`s@6#?r<S*nmN*3dd9x(@)-i|DhJfOw&<3?k8n&S-B80teRzYSV4?<;cpG4)PR zy8vK$-fOyrHI&wQt6a4G7J2n&Cp|b|q_w~=hMq$<<(oQhyZT~C0Ot}4eWo9S70dnD zir{`T_m4Ma95q3+H`nyQvSfc@>H3l2Bv_opyu0mei`!3*@T8mbQs7{F1P%uwNAf`H z4dVi03+fhB7LUvb#oqvj`w;%Df~2S2)oX43ogj`bALdI=@h)zt^Cgv(rQL~miNvXw z<+|E*Yf``<i{8Mbo;eEDfXa8-&SCE5HeQLJ@Rl`&w5eJ^lpl4M(p2Mo7rP0J5q9Ef z$KD8twqi+QmG#|OH?zrY9A$D<<XRa0L?FFZH@mVoFOV6Ia{5~nLXel#rx_ap`kSuv ztS5=0m0&IU9M4UE0+xNwb$ppwSX{2OX+_LjqOXf8c2i%1t_yh;NtQ0#gj%s?DE`&R z7YiX?{#-n%_FugPF2wJ!-ztn3OI)7~z(^y2D?fuvJg#3A>H7QU508d}gLFuY@wxV< z6GMb?##^O`DQ<SOzkDrn&+}|LKI73RamT~D+k+E;buRG~$73fR3ZX;4<k!A2*d}kf zQ=Ra2#qi2GCo)|Bq+wt1ZqaecXo%hBtc%CwSJ$C#ZpM6*uz?>hvP6<@a9h3ei|;2d zFh~~=t${wI8q2ro%$zr!!Uee(Lrp+v{C0!}Erp?W5J}<`a;4&6j<6cXyLcUgu6I0l zH+V<AiCvD1112h!m3MlK`aTt~vDKQQGJ#wu=izY95n3IaN(yJ%X8M9zhJ5<$X)?x2 z58lx+lvy{Tt#JJKnx2)tNkPL@))Ta^CLsR_EXD-2j}P0i7Yz5b#uL9qr)v)`qDyv` zI#E?kRnAzhRp2bo76_Vi)%Int(0hworC{?#1$!nI(r;56DRe59puzf+llmo5$7BcG zG~ek8$^|X1_EC7%CK!yD!P6-&RDmz#f1vet?{~6#O{>vb!tB?JVJ6Zsn%52vYWv;7 z@GY-%X(CAGEnUG8+si_!l?_%&!O@#02o+SD{1wY7PA;FtYByD{3D`u)IlOF@Y7#@O zHTCeVr`K&828*k0P7<sZ*GIdCVgc`m<g@-XcO7nfYd+U#FH%ylA4g{mwm!a|PfWPp z@{zp-W7f58yPVmiMgOQHEpZVV9I0xx&^BIcgxEJLMD*2);&JP!*W8fg3`;FwU!8Jz z`;rbjpPMbEC??K_$25sEjp9(?hX0WuoLHqUk-A!CTveNcUVa($XrrxfyYRofbY;m{ z{Mn;6?+Xh49Z&HaZPi!%J<ncR5=2rxqg^SSDu?LG*TFb!o5|;TQ?rgAv}{hLdj&19 z+2dPsqOiNK-<Z^p+v-P3F3kdaFOFmHo{kDb>ISIF(|>h`lpq#PXZmCt9SP>@+{y~* z)gs!nV63HOR%%XJ314!vh+p3f91UL~+-=le^#FRsi1fie;~NN+AP)_dgo&2mBw;I= z_t!~nBy!q^WmUjAu{EOEixKbC!ljSey9(TS{XZHrGbLL`Dzxhdvxo*XPV9^=e{rc> z4x7Et{e12Zn<unvn~urfE@RcA`dmI#DzbCER~7EFvHpUR2!12tcNv@I`o?ILZv`Bs zRP&t1Z?vpLULZGlvlzpU=AUcY-*F-$CdVhb@Gz5qd!Q5xx115>e~B_0Z4l~LlpWAO z)9p^?Wfut%wA66ZfVKe^J^T{lc5F~AF-uUsrn0Q)gx4n#&@gC3oMznbgny%=(ONI6 z_bC}Gi-4dDT=$1J?e7cm+yWLaUrS{|aqpZ5K<r#v?_3i%_vsolwOT(Nr#w5XxROFk zX0amjWiY2mA{|xOPr1^$nmGjdGVCrm@gZlrmB5n9Z{bH5TzK`bjE2yi)6o2v^7@Cr zd)B$Ew|?^xlOmq}^HErsH^#O^U>jvDCE<@TnwlgVvx3ry5_w7$qntSth%UZN-;Rn` zPL6hOV=3+Mv)3wt5Le?bAT>9<#=CPYR77PIviib^euTD^O2l>reiE`b(?+}aOdaX2 zeQ?NT=m0u%kjUWLj1TJzLP{&U*=dTEMF@du2K1viKdJX+wq)veu5&`v`+)ehy_MW& zSiP38ol@gpS1$NM*|hJ!;GEq#6^+$YemcK5(hUveq-%~nvYj-6yB<d?Si@Fe*AAsC z#*+WWe3bGUiHtF$AX}A-V&hkpc$>M@2g+|u(uGcgMEEw@x5{E=dmU>ubGy{!Jl+>J zM6I%slCkUF>js{DMQgTlq0B@pQ5-i%L3MK#j@=RAtDo<@S0bS1NtGYK_*ENF4%*}^ zdFG;@5Q#xEf`hwEYvxkt@DV)g!YuJ4t~3Lm<IpHR;ZMIQEe;Rm9E?xSPLoj9K$Se= zwtgrUbuxVc=Aj<m@5#gNRf(eZvJqVbvBZW5^ZhTRF$D67q<`XCcu_INCG4^QB3!(? z=ZA>iPxD#=>(4{5^no$7U*q2C&iUICm_i=fG8eHrz%bAUOl#H>_njLpyT~zehQgr( zzEVHlHf?Izv5#z9gtPjuJ$QQrpA`t<YJ~oJUCp90?)_z-aAsP29W>kg{ua9Io_=q) z*wWktKek#%j_Zf(BDR)V(w?uxgdFf0w5!reb&O{zxH1WF_S1qZUM{uok9!?=^z+~T z;@KBKoMO8R8Qnwma8<^k4#WDnfo%};LyE#Rbn?R;5zpC-&fr0ZIV*oKp1stYilUx8 z{&?{qx!TJxALp#bP^yVPV?I*i+-BV%M>b*U_E8wWozN|%t{bM@ny_P$^zF)r*1{M; zXK#q97unSTp$bfFPX=O&G+)|_+!nSsBEw+mw&%%q=d)+1>oAmaG}!E}rnolBU*QhB zq(kPVE&*^SpXP%IXaOdxIUZ>WIQ?V&g$+2lk~GhoF+9SUo?R8{r_PMB6zE~Do4*N$ zl-%qsrwG~WneA{Q^iK9-76iHXM;qT%uY4^+E+$T2I{uWo&`>(7P9`kOnj!vS>IV^) zEhnal|1SxtB_<Z=I>|8sO{aJ2eE*>5#M~)$tjU)D63l_+Zbj=_l|GVRKclVYXHB7| zLG!Q;bO26I{X-oe!wDZ4-K3Mqq}m6<`KR2GkQEp4PP^@L;^-SPNER>c!2OfZ;1Z{q z)ol-U&!4m7%dbhv<UbTP?D^<NXvqtbyyUL3E>t?x<dMn|Z6j1`?1XxKYBE!}<l^5$ z^Tr}Pil&)Zk5=91GP1|a5+zEOW1Y}doldrNb)@R&(+iis*%Bq%SXT@<Etv{k%$V3+ z@ynHt*rvUeZ{bfV0ZMw2mPHm!v=pu7$J8Gyk5V3fswG?;n>HG4kaOJIxs6ZJ8<%P& z&}2LBWvH^IYN0xl);BP90@ya*Y`IcPJv&TR;zcE|sjVe@Nf-~@%Jz1+n6+r7bcZgw zQ?NCG5f*%*i!qckaO_U&l0+^Fp4h@S?7LGHd%M%YN}eaN{@Z!sx^=#j=l#^NJW<G& zTlSz^x2<~sQP{j)>#*2qYKmS8DuwSEE`FLp(6g)kWskM!5r{q^0@Zec6QgEsZ!H7} z<6~_vM?OQsoz=Lt()fVVL)o-f*_v4vgm5R-pQ}pXR~h&3Z4cQ;$~^1X;d|kQs|($A zH{uX)wr%jPml^)~_N?I1x-i><F4PRe20GXkG3n@{T-DMJXiqjjmOWd!AL{adFFF=D z0EiVo8`5CU0-pNb@gWwuC}=WgUrb9lDw0urZ-+76*p76b+5;mqVwVjx*2eSD2kBq1 zX$YOWg006fZHuocI9<7RFWM2fbJCmKme=fl=3rGS2;W9rE+kjoD5#mV?p@(tE*m^= zmEM%g6p?GumryzXl{{^**o<VYUNe~fiSq83YSB6T_H>9TH6u4}Ba{mg5rg^S^rc~S zCG|Cz=-q-=vf*Il&r^<#``K2!4u-+g*fkJsT!%sahiU>vRQ(yRx)+LA$)e5Oc<U2P z4M<8I=(Zck*dJfxiwWq2GI1B{BIFU&qcMc5c~df=HUtm^Nh?a>ocJ%zQnxk-W@bPb zGG?>f&6lp)YHLq_!AAIZX00YGg5|N^x=ZqGIh_MHSAQx1D>mH|xnhN{60BWD6mGVD z{BRxl!<9NUJ?($rZ>^}On%$1cI2A<{F*9<}4s4X+jwmAC${9-cxz8UMAiUqw6=0fL zjd}OS{eCRc|4?mh2(~-8X;ExWsq@2CUPWS$c=$Xu4%hL=kQIZ1ymG9aty-Uqx8^;J zN#nrvoM%tswR)w-Db+Z+EfD=HphSn_c94ABUEbGU#z2GGUwn_P)ShVI&X$NBxO|<* zMO;;8mj$RcoDiPiyFzen{a$#le@o38TkX5K&>@6p0+Wp;sTv!AA3~_n-lb?I{-u`P z;<4FwI&!K_`FyR@P*$@@o(vMd$`&m{@?{=vQ1?7By+k1=!^L+mC;Wi<qP-5%-&t4T zX~%czH!obS5R&MsmO*z1(XUUx-cZx<uysIN?utc%Xl}B88j6B8N0rLlj%Dr@kDMdi zU#`V^*DrJixoKe#mXBK0A6zUgX83PAG`RWQ7jX5I<W&~s6w60kXolP5SZVNok{iD- zqyK&h(O@n;S`0;MObo%U-1O`IjH~bL?w-621>Lv11N_*d(RcOO$;utw-#6?9E(xYC zZA>CfA1?WFH=!d{UbXMFjZOkvUD&qW1@~HEk_%v~ExiihUiIiAv#{^AOI355PKtMT z&R*d%(l#4|I~VLw>zu;><_C8b`p834+Cg|P4&y!T{2H-Rdoe2s0$SBNhe5tDH;8e7 zw`>l{f?JFE9a~l9)DqX4`vy3Dw^ia4X|cV#jWPfZ0fjO^Bm&)3s~?|q$^Qha{d~yG zY90o)y6W@O=7+kcyX@jGPB*9C>buvPvPrsk!mhzAO9lpuG=ip}t-F=nySrT;IajU= zpz5M`mx`C&vEg}6wQlDSqE3ZMJIq|Cc6a}NyrF%%^p-5P_}2bFIS`3=u2pMP&a>|@ z$|V(pB^L`(*5D4HcMRGtQX8eHBR{U1ED#OfIoqO}_p#HzPv<Q6y#MW;gS}1-p#TVA zPXKLMjpv160($N9vj=Dgb~Q-N2Y1@cbVAAQd9-H{?sUYSe8kP`?elelYad)&7;`_# zdEQ%W<>k#ChzJ^t)pM7s8IC-=hiRTJ%MWYCEJCt4NylQBZeg?6tyvP;GqtUP_X3(9 z4wvqG0@aCmo!7}>%V9lUt@7OU%@^i+uf8?`Y@_w{KwbBh{Q^2Qp9QWO=|-hMSwmi3 zEBD*&u^`p(7~jcdUvpH@Xr1#(rXJ7e$qi@9!k+&W%S3(^o645k!FicM!>CquYn4~n zqQ=4Jb}K0mBzA}Y%ywU`Wo6o8*0W0O_gsBkRb%;u`@|NkbHuy$9R0Kv+y~fCS&2oH z+Wf&^xGVbi1QTEW&{>Rx=)rh~GiT>@BeyL7YuQ$D#nRh#8ExlI1UcHPnZFgpqC zn;MfZaM!rv+U~o6xg><Qpa7EhmN1yT4kE&Jvd<low!~&5w4SNXdx3}7-m$1A-oit} z({v2Bc*rvdAAvh-0s1Syh1<Z*o1P-;%1;#rw{5NrTHgh)jQ(WIe}ITC!=L)N4$z$g zuixBm?hm!?EPFS$O`swD9Lev1NQ}Jb>J3^xr2^_0IVVjP>#4+#TE*$v=vj%fe|6zn zIc(l%`|Xm`jNsxQJZ}3d=%#<^bn*B{7=c4Y`c&PLlSkvC@cl|SMc5`|y=<)^B8~_g z{KH3X9a6bDP|eyKBfGxcAhCw7uHoyq=XEDPnCpBDiR7-NIQ8}qeH-T?@4}SVzr3xD zMAUenc?E)=3a9|JYg4R@PMO{f*)7k<ajH~uKxMCUc1bE`kF-8Ta#vaFXP>KeZ{;D1 zMdMf7F4<gs2B}x*)tS%R&Z{jL9q#k)P8PX4CQ>N1Xj)&rH0iv-7M?+h_X)QuRfFB* zJ8wTfxL@i2Kz(1sDn4@k`hF`*2h+X}{#JF7@6Ow#43yA6^ub1M(g~VPF*t^;<vFe8 zl6|@u7bIMlKHNfomjk?avzI?T2~yeOFQgePPEnKfT+!nw&kAHQtlpALQ!-649tOaE z2gZ3CSyFHP@^ojJ$6Fg5b*22&1)bV@pRFUjfBG9}MBu6K04c<3BbD<Exk#fp@dyE2 zOZLW2bktM11xKChT3c%T+0mA26<N9+)|1*Z?gYPuPOG^g!?>J>nomdg7jt~VI^4(P z7>x}g>hHK~_W9QbY54a7uqfPt*HA&7Dp0jz>#3HL+3lw)wXo@8^Q`*R3*@E`E=b%a zy%-R3CwKd%)}jTyG)E)|GN9j`nk}-iPW|L?OOnf473vm}ezD=Z-TAy7EYuX-v>u9S zmuA;*Pmku8y<FquznOvuEMFLM-U%K;x3l(0Umc+UV%P@;rh-pSGstxtbaG%H5Ubpp zkHO$g>`msIQ?Sb&)jyXsUerrv)(*MhRwtq#^I*PN{<9@*0zw3P1{x8ew!9<HTk9X> zCEPZ@w>r54K|NXA(>A>J=yUH<e>M&@@Y7q05f9bCl^v~A`&CmOd<sKI_0`35we?PD zu;DKkZvb<(>PmPS1tU>~Zj^Rxgt4xE7RRQjc0PM1@m9u?M(D-XPmG#h03QYxTaT86 zSHh-y%Q<`bqK9Tg=|u&Mu~Zjn3wwZQ=!#=pSvz*GPp8M=EoLv>p}m6u@lccJ!a@Ja z(137G&yBn}w_>AC%bfG!eFaoVI#FIgF11cznlD}#Pp#9pNvY)drJY%2hprJFJ-v5q zpz~<qDA{_eODBT+T4!H(b2ed)hjC;Ii`J?fz%EYvw><8hr{B=vZJG>)Q0$P-Wt_qF z(T)V4|7Dw<0Q97*C>$_9yOH|tQp;!_2PoT%`_CNnL8`fj7T%rrSX>*Zk08NLhH<R{ z1cBxD^}?IFw6|2^CH@A5{t$OAJq#38yFf$P)oTN1$IPhr3l^O`0G`8!vFLDYwu+3t z;XOMAtg3Ac1^16@z^rs(>q0imjBinFygk+>wWq;qUgJnGCB7u7016fX_vO|-#lyUC z@{>b3cWB!4s$E3u^sHLguXcB&o3n9+y-|NZ-a3_!mb}$kDF3Wu0rU<Y^Dc{5dpn=j zUocc`UNx($xY=X-l{6B8wB7bh<WQ301Ii3t$WmKJel2=<C_;iR4Z-B)0T{iJY~FU{ zMBvtu?%<smuK92v?1Mc3wyH^_Vz~)z1OU4BTfCXXV@P)voj1HPunC>21N0mye9GrJ zM+NY_KI%Dmy);i&d;LFl{7(dOAmtxW$=2B_a71xX&Hj1SR21BN$x7UX)ThTzK?>Ne zLO<yWzWa=E{9Q6o8Dd(MOWIV%S4jk8(`)gFb#~s-ecyuM8e8qX8bSZodGlA0`Ihtl zE_?s?!5;W)6r@`2T0^7)^1J=9@p?6T{%%Ug-V?svyDh_eKNJ0Wk$Q>Ta~-$+V$NE( znK3rVDC>VM{O3oqH2C*4j9{%y-4EVRaW5EK=!kE@dDQv-WC+0JbLmiZ<yU<r&Q9i! z`$)M6Wt9kf2Ov@Y;-pe&3y-KDpxgAjtn+>~3UKz&R(p^!A$t3dN(~SrJkp4=PH-d~ zQLu2>IhyfW=>4Nn;R2}%P?mxXHrux;EXAc_;U0^Nq2qvwY(JtsMuVvh4&E;mK=tPH zBN3552#A+rB=HE36``?!A*Qi#AOs>@Ezw72<VptG<fMLEph(m(6_@(I(Nu8)L)cW9 zCFM)a-;JeWm!y-7s8j!C6zb)gw^FbHKK}S)oQe@2)F<c0^;13Z1ogoa+HRL8o&-L4 zLd!r?^TZP+1fUH`r1Vn}oZ_ztTUj%TKPHX0O{<Ivv70|UcE|%EQ2q?{D5_74>50Pc zBGp<#P_V|Ylh+!LXNxo*4*m|;F`oD_e36VI0R|jHp}MdCQ-D&@20mx;vqFG@4ciN< z$JdS#bsZpwUGyDQ9%iC3kKJHsfXmt^$cPMiY=x>WJcPrOa6={7z;Wnv<`b3QMBH-G za^OIcOfM)OUkgMkN6V4FU~;&M<9h6RBsG}pPh-dgm`Eb(?GvSn@Y5fcZ>c+~a*;kZ zJh3%J<R2<EwP~J!y^7XE{BUVC1)KM2WWiS<EbF5jMSY`!e;g778k9##0th#eIv>|D z9s|CLt{80K!>s%S(-lNrJYS8d2gFw*!!Vv;;{y-<EI_n^2PRtnlJvw!S$MwLvacH- zDxdgQ8896Mr2UQzYBK)z#0x4k%@9bC&x5I&JnN{BO*KZlY&%+#2r!TZBs{U_HIgoc zw_PssGNgm~F#yTR0dOE?LXtG`$E%HU$K--Dw%<2Y$dlL)L6~)_zkK_rDnv{o<#GP? z<5pjLM;)OaIe#R6;>8&1C8TqduA|C@RwC@NBnpuOE-<!lJv5O$=5Zz#;yE0*!zA!- zr8QhkpQHvUd=-)JKXl4I)p>&2WU)RgjBqok;j;cjG%mm$9oSCYfgR5t^jPTzo&&+< zLa@QrU^FT9BUIz6;J7ZYYK~q%K~&}eQKw|0X0gYJ#)`aa-`?U_dG=&INDi1DAaCE+ zD1Ad+`#50m8AR}I5iGw3Jh2X!vZG4COicdC3{Zo~6St5Nd_d2to`jz?{B&nF3Chte zR@;-f=0!qKyL?zYYcKn`9=nwdCwDfB`#2OnQ^8vu6%@12;y;45lo4!ojCxdNK3hBa zXe1?CFm*?4>4~YyqtQx>MH)&ahEgCiKSY_;%YSzUKQAy#oWVk53KfZd#Wm6FY{6wS zQ?0z7D*JDy<5VCh;elJhcXQTNYVBU<`Ss;9Y=}(XI<f`5>puOVy4~akmBd|9tNfc8 zA3-7wNm*oqa%XzOf}Or+kOmv09z2I-e(e#}HmBDT|GHI8s-tD*)DhcHjmfcr;L(Ie zB5jKaN1~_7J&L){e(=^=0P;kl+l^m@k5K;D98f<3MSei7Eq7Mn5o+5+)zUZHJEnl^ zs3_Ktj|1880c-RIBeW-rm_diPv_8HdUDaw-qUht`l78PINIOa>gXzaOQzQBK>Y!?e z*Bo^RK*do#>~VnYpx}U0W0++g2Xd|~63Wp~QbzKVm4@%3^cJoSDnE`$29iLV>1d&> z{bWox$ElMp?(5w$-ySKcSC7qcLM#s!e7KYAl9#53eCY04rI5v6q7^-hTC~i-Th4#k zB2_7p7^t9E;3=bgHl@RSc1^;ZRC8^xM4EHA;aYLYzDTm%Xq_<zy!-K)mgD6k!<o>I zzP6b#oLg~><%x!}f)#Pcoi}esr}X&l%7-RvEfn;;HjkBmy|-V@>$>QhS_`|s^DTIH zZvnc;e3D5as7>nElU++11Aitk{U@(&@3c=|9UqrEidc;`*N#NqeqdyrpR5@&i-ekD zeL6UqEFEvD9pSz6h-w{o)up_=yFP`UPxT(0gl}-Uil4rdw#v-l6os(K{b{7vFRo0@ zBu{U$JwWq4i`HYj+^o{R7zRv~NR^kW@w2_vyI$J#mf;6Aj?HD}o9%!Ur`_c00ItDH z+90_UJrb*8$I}a|rAtH-;aqHG^*s?ER^RiSDpf#9;#~HMkj3L9R)?RK21#@Oxpy0y zCtUEa=#|pYJh<X&q3kSzV4H6TL`{J1)nRY^6y<4e;mu4*kDgB~L)5RiUoO>AfEIGq z2p6V#i;^{-`48~+F`p;Ko{M(tn{?i;63ls4XKRNeLD{4VqO_Sggv9%@=2Q=KGD{#A zJ_YuiK=cgQeUi)7MhcyJAN}>XDP$>^;IF|z(V(gOn-*z3kaUhm<1^9;p`rQI`z!q| zJ!uCD<N=2Nh&r4sgh2kTGM4}lwQZ~wSCi)OXt8yu4Htx{eo|`E>N5Cx-%4GEVnBuU z@}13GiocD<FDatZ1EeAke(7NJx!o{pHnoZlJC$1Tuqn2Bu)eTT>fZczw{EM7tZbWA zUpK==6JM#?PwrnI5G^(5b)u^CA@|8!Q0t7*@jQNLZ<%KO@P*F6zJzIRaDizPOx znRl6s%~2yI3d8NsyV3vC*kJ@A{}6-FjBSeF*$}L<%@Vg!?@v59>Lw5&7w%3X4$_!E z$C&;J3i-sXA`Xfa0G$=q%`Xj|-|wzy>SLX>(bk0pS5;am9X>(BwX4Aezx%?mDb#Hi zfBp6rf4rPV2J9JENiPQ*sL)T8f7e@X?mg>FKTPiwIuIajeJQl>TWNWRf8iy$T-e$- zkCcj=4vxNz;TMyOk(u6XOeymlWuByTI#FupcR7kPR*)ZaP0cbQyK0ts=Em{*H$}kW zFMrh`Q@Te>*dQy8jf;MB<0^x*|A|z6z5P60;VsyH<j8jp`9R3$H^szsu_YG-R!@EO zwY5rk*>oH$6zS$}?lvsqJgMF}Sm<i-9;KDS-Pbg>dEV3r1gi=gv7A>X(se6b6ur+{ z@;x}vg>F*l^|rhEUHxbrA&%NNF$Vs5UZxS=K<!i#US~2ycyQ6c;UgfLV=u)TfAg_2 z*8NfLZoF1}m;f1J+bQuP|Jn}}ENNBPnLzhMUvRoaMK2%i9kp+pF;K`Ykp+xhH3}`N z_kz{V7h7JV*?R4%-OdkNIr?XHo9Cg!hwFy>y4l}~>CIU!w@qqajaaCk`hE8$emCQj zhvos}DS9Wgbvl#IG1quil@9e3Y)u9Ee#*+3D$eVAj$NvK!^qc~0@4znNvH_yB)SGe z{51|l&nH&)?M2rrtbOyN{qJ*t!n{gb6gi_lxacdGj}~Y#0u*tVhYp3wiY}JMU{nZJ zj*La>K~oztMn2c5u&gBmUEAxnIuF_?9Y5x~eS>p$R}Hb=;{|=+C8gMZ2Y9Qq-k*oz z+YXUX69&eVtK2BRyzsrPx0*T8Gw@k**bcZjsMW!+BClE#rAQep)nY&hMI#-8R{cie z#QhIWkKdFlFWRG4R>`CnOraY2V`~o9ItLSfULN7+5$;~ED?%o#Ib*Pg36jtH`GOQy zx8__$`Te_IQnd~$@#CPa7D<Mf0zfsf)4W^v%Js46?;QF8m^n{M%`sweXDmY^G1uMf zEN;#b@{?|f4Sd*MHTFQN&Jd{lpO7kvj(So04nPdP<r8)bekfuDZ2|q{kLzsD1K|S1 zy!ihi@f$(tp$quEA-egb3;57+o(p;42Y*M<7?En8H9xTDq#lXyk8A8_e9Dg4Gcegx zhEHjQaPx}G>eFbpU~&yk|67D)tqxzv0yGx>KbU|-hd;JoLuu;hu8dzr7Qg#czF3sY z5x6tKfJf#dTp$9{Ln8_F$M_F}gb?n$k9<$e<`sps3@aX^OzBXLKs3QC=J-(iqV9ft zcq9CTy1b{fI_#`M`MM7OcmhveJYWa#oQir(OHk1sXbB}<)RQK#9O<TgJIecL=vDUl zlX!WBFab^tV;XwGs=oY1W{5K<pGYJi%m#+yf>XaS4LwnniTEIdnmzesh7uk^fwp9z z=E=00!21KPXV3BtdJoI79{Z|{n~Mxm)zo5mjE@;L*y_mlf&$)e)}xm23AGao&_9z2 zO%8ox#svafe-Sche^HD2@sPB1BA9*=N;Q;EsGvfJfwKbOdP4)D{N-Z{U%bdoY=04C z%JF!Plm6<1Hugs69>*h(IQ+ffr2rj-_+=W|lk9vg0=On9AniwbY@P%yxVE|G;GtbB zST&)0Y$H>`LmR@ZY#B#{h~rJi-uu7r0{G9nVzdKZ-4uK`5q}~c7GVATp>5|F4AOlP zs}l&7^u7;jH=oK48g$%$6+pN-0iZfP?!!7bP?|Qc{#$#k9^ie%Z2KqP@geE^5z^Aq z`r_JI$c7gBs*TP6!K**x^ec;the2c4oDebWA3`e#?c=oIWtt8b1EZ7_QH-j#`4JXk zV&f=meyiR5t}KY~+3W|nKodd~zxzcF%FC*q^Yk_+-?ZmL&&QS&%hW60I`#NR)oXbx zH!`?x0Y&CmSX(NhwPzh|G=6N-;r=6o2GC7+){=yaMV0>_JMS6R)E0G(3WBJJsHg}C zs3@p3l_rFyhzLlRUZT=#KstdSa0C(QO==M7y@dcF35XQwy@e2zUPDU)guur+Z#%^I zyU+b||J{Fi_S&n@HRc>^jvZB)BW9R9QeexV2HeHR0I#V2eLhrP-7p?fb@QIBFB5<t z*mVrqzvM@X{8DNDFq`W%>Xj5>l@pRyKX2+9)Dq6KnIu6EJ!;g2Zi0k18sK+VLO{np zAWg>~fFrEVbLUAit_`OM@2kMVDx)sFm=2RMG+oVF&kX*hlo5Ef-t?r?!nYzYaJZkt zf9;N4Z*`avWt+D7swgA$AI2S*DW5Q@ihAPNJ$@624Rgo&jTATyn+c{%8R~@KvStD4 z!xKQD$){!OzQ6aP@61kNjbEQTGi3d*omSm%+nOcgl}MW0P8nlS*G_rFeS0xK4>6Cn zAG0dVFEPjsF#?_l7BqNZN&$#(<p@udsVyhg71ku6nn3ZJwq-e8Z$HW$4*qDA*%u2I zcl;I1>8(0F#p*%pALP_F4=ml_o>lAN`^R>=q$V?s$;6>z`1zr#IMTKSF3jC#;Ii6j zPUd~sBP=a!A0D2bYx>nAanWd_|HYvvHitRsv4$;MV`#wcgiB)%!D~umJSMvMq^*Cs zxuU-su;SS_glB)nAopz?Bs<rdU-sr?HIM052-D!YvWS?Afd*(&ouXtr-F<ShO5bTA ze^op|Y}yGczQ<(mc%g8|D@7RPu@LxUO+(K%N)S^F|HcW`mL22VG(<bcIaSsR7(S46 z{=Ag)lV6ru&6@6SOP^|^JD-J|rYAiVgyh2YWQt|er1A%b{8l6^L)UCfOrdHBg~F9< zC<yT`_JNJl!u5As-$Mqydpo`k>tnQY@^s*>MY^_Ao>SSo$&!oR4duR3+S*~BvTV}b zrC$gcf;fu$gTGJ3E@KTD@7EqtasoFrl?KrTxxdKEndK>gom_u&Pv{zvd~@>ph(>JU zejZ0_gf3oh2xis&B0TjlN#dbj2M}gU25v9xB-!<re_Prk+U+~ah&pe}4drX_+2TXk zB{x6^L4{&xxF!~@x(v6zt#QbiAyZb$szz*D_COT=v#4Q|W)BmH#g}!16z!6hkBq!< z6j`<MmPvHjx3U<#C^Etg1H)HL+hZb;_|>@&%nQSBO7G?@%dpE4c^!?3UrN^Ylvd%Q zfJvX{Jn2Rys=+du%G3D4Imt-db}-PpV_ceS20{tj0ZST#O8dkCi{v35|D#dE?)k;$ zjBi*NF6CcM$Gj19EgjA-9uV?$X=u^W9=4xd`I!vQ4c*(eEtW}{?0sMIExuY<0kM=m zCnzT)V_Gg$mT3Coi>%V}@JinkFdWojzchiTDXz36aZc#NR(C{;fYyf}=u}gr0E!#} z!se}q9T8gkg=>?m!*(|%H^uLOnCkyC_<23wqG(pZu!i7u`#L0t`?>UxXa?Gj9h6ad zv3}1TJ3T(rEk?+;iU4L|mvd}l5xw?kCdL?RJCFy@kp9vB=ATL4Ts*Vns>`1Z0_H|f z;{;lEExKJG&o*z};XOreBhG)+|NDXj{vM$6OqazE9>90UePGnMr@vs0c`=}b#eEHc zd^Mt87c`=b_zcZXhOTHKcj{EGk^iaykcL|1H7{`3-yU-p^IlYe*=njSFFTGj@S#T- zLFkN}4F>n&;US-$!gKf^;MM}`s-MH2ho2Xh{0`1&V;JMGdv<DI$Oj(@{FRF}P{`1# z-NOUNVpq0v=Y{~%S?8JTPT@9Lk1$Rl<GCrIHs)YCA+6R_XBB*HVB6DYvC(WY6yv=i zYbvtMR;XO7C5MBJbv*gDLzgyCkd{!gSX}ei-U>gLQZ+o+VY`Hb>-cjz^vbJ%u_?J7 zJX_n&^CI;dCv7L89}}U(^h}90^dPwiL;r2aeDqN<M(im`PEOf)<%=#Qpf-7Y`ejOb z_G5(nJw%CSQ;Ys>Ij7bv#*?i#put3&QYS}9p-ZgZ@+VvUodL+C4x`*Y@{;44Q~1Ep zbToH8<JHM_uYYnmk8cIk>_B}M<tCDBTL+CUZnX@1u)fVE$zi{NOOW4N5*Ak@J(ten ztdMVDR!#<WRv~riabIh}=a>7Hk}<m(h!Zy`S<B`=lqUcu%*DO+it1$ay!^v%zEbAv z^9Y+?bs=%rl-}dtYzCg7r9WH4qeY<2)$2dAsAsPyvLPh{ut1$sPs=q9fjET>JJjk} zdn&psZoUpTsNjFQEc7nG&!()f*h6=i>5Ruk`GV~6=<pLOKQO`a9QmP?ar;a#_ch=A zq)8gU?=?(KrKp<;2jSY5$Acs;RHdIy>cykLi8EjYX^dpFADT8_&1wfC{A~uN?P4tg zTt}m#qqBKA@w#EklvS>dfaIkdOJGrMg1TPEUjm@+tO!8`n54_q2?V~z-Uc6>qb4va zY+)0(ASALAa>^QB7HxSTk#r!fSS@|}c9q=P1D05~_-+{E#Ys)F3ASHAj~V|GKK=R7 zqQWS%@aCuM?>H-N@ooMSx@E`*yhPw8ncR80nJ7O82CBVy1iL{3z^9+r@>svI4*M3_ zqrnP8>IhS2+_pxz*PNiE&BFKx<q=@-s2K&Wb|)RWKyhjt_qoH{@*-s7g9*o38R$8# z`5qm=KyYsJ(HZ@4W^^&L=OC=^gj`Km7g;9XtP)_q))L+rS@dp&Q3ljV(E!Ui!faW= zVy=<!H7Bv1gOfJu-!oe)XkiB=Irt0H6ayv{QxfrRe9`ER=7kHWxB-BHAc}sc<SKNW z?9A43@vdY*UHO}@#Y6RIQI9zI`XpAk42|;%@Oc@AfZ2R^FIZJC_&vcB^=K8c%Q6#Y zUtsG|-!@UH$_;wi_pJ#!Xc}3ck5-fIFmA~S_jo%$RDm%jU6a;Fa9`VR4QfkHpAsc` zf`Sh%dcv)<LGJ!0mVP!L+dLO^IF#jzj;MLrsq_*0z#UVSv8X%10WZMAb99tni)>2& zm^5!di(qNxE^e6rByU0CP%@PBToK7XZ$kk{H1er-@U73@$ahDFZEt63vD=I|2>VPq zxjSGCnpzLl;Y_f6cb_F`dnWdCQ%%A%r;P1tKVOB&{&bmSd-zYD*yM$M2oqrQ*>Y3{ zIhW6PYrpI!BKXqEYI>FEvNXQ}U{z(MZY48_T(-5|`#rhJUG78$*d031QiUDgT{Kc# zl6YoZ8NrwxdhN{MZ$wWXGBWDOeca(Kn_P2;irU8ThO_0IFRrsqrf+&E_&nc#3u+)g z`2ty5lC9toIkQFFsh42`5YpX0xs6mp`6u5J2m_@$mFIb29wW?lULGvM86^p?#SQ~@ zP3F^1@(J|^Gu>mih-_RY{3bWI!x1y<V^uhtA4OM;D&JM_G3`{Q-AK>by0l97P{_=B z*LOT>vmn7BoycG}OJS^*r8@;&m0`=mWwgS4)IPZ{N%kUMj9SYV%ByLXSIFP`Cl-Hu zcIT2%rC!FoSL>v#AmX0)uy2>oJwwhF;$3}Z*S<2oq0Dr-b#(`COPhRsF?$=>-h4qK z=K$9EIZl02()#X`(H9y0ljNC?J$y|GO@C9EDB}jjYAyXBZZnp-LjR;3xjlYUkrhjC z(ui@COy?x&8nLDh?oO&sx8ht>whm5yQ`@3l;u=?W^QaMaZ{SqMTA}|3y-qJpIQEf| z0vY+MYs!95M}j`3KUnbAV;`SZT){L#f8o&@k~wCbHQ*A9bATI>ND{*w)ZYB6rGxdv zAeV+0t-o4DCq|lPJ!Jpt5;<AgY<7RK<ssbLoT(da$hzkD1J%=kB&}_{_<2&ee8XUO z9-%NjC!I%dUEx6pAM_2&Ri2P(QsvmVl-P4}cgZZTG)BqhqpA(X_niNMWG(qHJ9en9 z$1oXSU((`aQpoFw{l5C!e(Lc+Suuh2fsipgBB_u(+(pR2KAuy=P74{(C7+-hs0%#+ zD-BHCJ^2rF&^jxMm(USe?&)>5|0%}r9q510quUF(d7EH6j|VmT8HkkUv-b7?%0rTU zNXsMIh(=cXwL$l~TGQCxaV%cPEB4UKeiFZD<f7ox&DRvUbx`Z|H>o&#sVzYm6CB8^ zv^qarKkQTsYt=G@nVva!kh4qlDlFqg+$l4-8gPO(`_2^S$%^{)Wmj(cN2Xg~j{5V& zcf~k0*RFe}k)+!Bj`+dD;q>Z0v@U4qnuvx5&@~u)J}Metf8gHo0lpV$l3FYgRTwz% zth*8Lk1d&BZL0uOtcZ?vvrVfkq?VTnxX2oQIX`fOnRf$#!;*^SLvJ%nPoeXeNIAwg z%wk#>YksG%u=2a!KH@amtm_dpyCDm^^u)&f8ru(Q%sGq{0_Uq_WGHsJbdi+q!kzp@ zM0@5D*2gtQ<ezkfCNJ%pxS+8X8|QmTs6gyf%R8r^!QL-hl-dnXDY=(dxE#IWLPz9x zZ?f7=PA&ZrQ(s`<A|93cuY}kMnj=HiFP5T#(BEaO_=DYPG18sfzq_V*nCJNAA~lUw zx%1j|MRCh~^S-WOlp!^1jL<$}jp}ymkui~Df7}4wrIiiaIJ3^LVjIQ$M@7Ac^cCgz z{#9O`A=I}YA1;(Fn2pixT*(w@qx*wA3r<z8r>heqk|Wvv&_!IM6{^oYg?<}HUrSXa zKXr}HcW{b3h^z9Cn}nNm6Xu&0y2z(9*>sOK#uAF}lwJPYbdJ5GOV=$;F3KBwHPV%S zWO#XFx5VkF*Xlm6^P4oCE37(cX4{1ZwUxEhX+hp8ncF>P1&U)H<&uA-EhT9@S!HP; z@%$d*R4LpW<8&s1M@3cf_c1|K<GMqCdcDx1yt0p~y}sM>EEJpjYSr{q_d1`>dSO@k zo}oV_$fkrJZ|uSy+7hCyu`KQW-Fq71C;zBeGc`%+k=fC8V|ZOjwf31xHvj;@C))ka zRra{JEH-Zcl)}G=%kdEu*u4R4tn*6K++xsni1czBVxm*Vc069|(Q+qZn}=+HX_r*l z{eiD=B+BeH?M*!QPSp3R6X@c2u#@+)X)DIF_=9guQpsQ%`K<DV)K||YAHnUM;c|BV z4<wK4hXU?iSXb0%p$M#2JoT=?X;OGRUvuKuUffOk8f;I}{QL&<86d_-kbkJ1pc^9q zQZ!5=N|Y?P*SWb*n=`)nl3nC>xOw)4=8sk-S$x2%$dKn;^{s?uUh<ZnX7?;0uhXyj z#NC$U7soT`ujpt-L~)7*eFM*MwD41EpphRJ#fI>EiH!MQv858Rc<q=WBEp}?3RT$o zRK<c6Y`Jvx1;F|DJ4ZFSth#{hB!GnN@ApCnmSRXVRix3TK=Cz<szlfLSA8esv+1k; zYuVj$ju8It{=IB}&5#Bu@MnnWqFDtcS<>tC!NtByZ_rnnxH5GCt52WK2?=rm9#okg z)w*otl}f*a8sGRz`WpRoPRpc7yu`Gi4-4?_aF{%Fas27`>vmO!08+v)D<;`veba9~ zj6NlJ-m-PPR>iF1mc{7L;pl`Osp@R$qG3O)yY}6n!RY{r`px^JB6{Tn)NpVd+Y+~) z6aDb0aYtm5g3sN2b0y(Jk>P!bD&5aiw?j{FXfkuk(4g|Ib6WD<Nk8iVbN47#bLdUM z5YJYRzB24;T!qy)@e;!VV7)844!HwC*;aZ|6w?@9_BGHK!d#|}!tKx+JXU@gj~OAR zY8xq$>b-0V2Mz<`c7(zp(Yb^-Dmq2uOyt<~6>zyzs+0z^o7A_cDsO%8ja6YE2XAwv zRmVilh9hOKRhfO(^mblxB|ADhSATx+tu@{#mjMS*RO1*Ntk&&WD4m~No3)%y)+bEY z;A{++m?zH?i_$>F?3-pScOBA4N3lMjB|B4qI|{z)Uq@6W)UIqaGzYi&`bSMXAvrl^ z!zGIQ3&QW!?Kj~T=V<qj%s0CFS><zdKG7VwHN1fc4kL`7J*1Cb7fYR-g9t*FtkU|x zpUkd%){4pBZIgYVKhEmo<02@t5byG-&UYiK<Qh`QH#%U$O=hwVaeyT}aeS%Vcf_C< zfC?o8sTyIZ4>zG7HZC4V1R+`vGE(B1?t9Qp)On-#egog<t2{SL1vFi0oD9qz5r;mT zzj>1ZzohQe=#9G&hFq7RafCrS$Iv`B(zI{g<{eXMqM`dy1PV_LRz_~W#Z|&O#9ZOC z9!YzjggW<M^6R5=@t3-Fg>i}F_8p;Ng~fl-Ax>s`$Z&Xe+<#o0!Y(`bvR+$+Z(p0c z)FdA^d}}HY1-I?VWiyMJ^HW-+ykUI$gt%wOyx6ZqzTcRW4jBsasTqq*NQ~c8+H+ZY zIP<p9g(UGIQuTDT<Y}PJuPqD9)QprIKK}dwe~fUAUEo@%VTNwH?dZEsx9^>mo!cry zL|OH+Fk1iN#+k)QL6$f7kbNKPEz&ap)}Jfg2diw$?XY<D?A%$M5vPx5&N%T;U%>}l zowHTjwm*C-EIXt_Kt8J8zkR5+p~~H%)51`_ue+te`85P^*a?O2xQaRb!i#$UMofau zsPcffFIdu`Sk+Wv!h_%ELBl^}72>RDJQuF|+P46O%fpvK5;a$BmrP5|Xw>#J2Ai!V zPHPmWo^VIcVV(1RWJwauyw?Z$6-q};5DveY-|<+LOEhaBKpoOBJB;b_D+PxBxy5AT zoVJk$|LE`fhmR-+e5H2r`XXpk;ZBua5GL(+vBTC%qaB8#arI=YJ!VC#&V5OW(YZ;; zX{I{{DeRNJ4xTl4_kfC=WR<wZnlMGyJXz<d-x`4(#2$FyWnW-m`ir|JqM@le3HKd1 z4c|=HvOKRB9v6A5tk=T1#Xmi2z<Kcdjc^Yq(${lD>?D`IhtG2wvcfZ7uj5|m)!l%l zEB7Vtd`X&)UF#Q-F#DEHlKn~?6PsagN8A)7urS`ga&;!x-q0smh?p}6*?n$o+Os-8 zcvkJSdqpDQgPz}{T4Awd9pe&446Ni1INvV!KsvB0U)5~Dy$6*KPJzBwbu1;Zj|_Bm z1pTrrl8VF^MhH9hW{)`a^O^eRZvCF<x=JRPZIYAsk7&VkiB*+d_VYRgkdGkKyG^d~ z)1a&c?<J!XsUjBl1e=|h7oxU8C9GK0`YVNpw-}*%Z%dT3iPhKAe@Q07ybbIvC+>I# zR}lH<zB7m|N1BEW;9sxRdLNgKzB*0AdZo@^OD~Aq8@j8g0PJVN_f)du(+-07%B}5s z+3+^sfBT1=eM4FKwFe3VyCtyR4Ur{2XBS;AnpMd4DLyg5kOUTAJjl1FsG(Og1AL8P zA_l6CX)s3>4N@uJyNCT3v%*0azWF<hT{QaMUBz6q>%UMO0mslu2_RbSk`IeQP8~dY zaC6w`>P{8^_BBby7P#-VrE?Fg*VfCw&xeMS^#)>CLxc=gFcmK&SJnFoY9_Iivc{Jn z+k>xMDbRs@T)?2akx_rzkmU!NcV(Iy%NC$RrR3_JX-!@UVc(~Rj#77vK2ylbUC$Gj zSh*vHD;jv{u;(zt0s}@Pwl_~62OVX)3c)(h!_0zHI8Wb<P)Oc|OKyklwnjt0KFBMq z8<+xIORBeFW&^F9o7&9=J>;<Tx<@$niRm74ycxT9X&u}y=f@Ab@pP;qGDaPKV{$2E zy1PG$fg>+cP1SBpdl6B6Uy%F?d&R)hA&72S5skEx;LJuNolU>mDvZIR2TIv<epE{o zj(ul5qH-EgBWtib9w{U6^JksAmuj(BHcV)1&D1mYt-IQ$0c;s##wZ}{?y=gRQzd}q z9)2dbFXVgZrL~osC*|Tl(4`#Nk?0oFFMhrM8zbxehdm!Ii1@vWz-{*h+l}vl9aUt8 z`qj^OxX##2*3Y~oIl+3oQ$!Lpfly=NJ>?^l`VJd7OL|#UsF0Gb*Z&QeZ;L#%8CdI1 zrgX!;K03e3=MpYDv^fR`gTq0CuX0xpHGzX`U+F7LI}L@+k4M7vtj;i!)4C;Qio4jT zG>MJv>UQh6;Bu|-*_r96q(zxz!ET(nnFVc1!W&XVD+Y<LWq_ae)bO=o`jFKHnk+IH z$v0WM_W{|X9ZX2z=0J6Sj{y&SO6F5dDv1wt1Zx@otXg%2_px?VwfWA*-f%_7E3C@5 zeh^3A)ks-eTG|qXn}qdLSy~&S84lF<->J<A9^dr<`s865U6-K(ee4M|Z6ed3n&(kk zR-^a8fuo2L!GIpcXgsAR0-4Vn#JczzB9nhxC{QQLD^AcrbcOt?sd8%>{fu;gF`kCf zZN;CbsH14hfY&{{bUV7<!mlw@G3tHf`@%-g!_({hep(eYRPnN|>3elz!5&uwkxB;n z?86DM9WAZT4u4P)(LQT#YMOC0w%%vxe%6~D)HLfoIu^OqNBcLw=&QKrz(7TM*iNT< z6AdlP5-N-p2kCbD^d4Bk8O#2Vo(LU9_3dVXGu+hN<GsAtZE6N4pYe`y{Y!njDP)F= z>U|oG_a~s7e`KWFg<eZcxiUj6g`aIw>*U`TqTm7G|4Y)Ic0+~+k}V+fh>B9YmlvY3 zTXzjuzxqd4yz+eD_~IXJ!qn?Ze_AsLc;Xy4wH{S7iSB6cbZn#bsg3CDg&PgRCxRpY zAcO+6V+mTc`|a9BGc42t@TD_x*5Cv0HmqNy9zncThL2^Z8^n9<@jEpLw|-KOHkXsG zWpz9gl~C~GWoOvV-`Y$y{+=5nrmydo67&gS9MK4|<C5Zlf;&^m^8?S&cJY$NRO$W; zAC6ep5u?p4dp&lWno-_;t-G_G38e2xQ=^hEf8?S`UQp67thhtXBsGJ2WT~xBUi5VD zGdXsZXh-TL+N7o1d4p(Z6qXxiY2qGg!J8fiWy@qOhLX7lQw~Q>$NAsxQlAz144*5b zEw>~#rV<bPRfX#_!Vin{yWzN!tV37R%W=f0Jcy^q&^Div?ONmWC3iAt2=!Ar8>yW@ zWm6ZjX?3L<<Z9-D$pG`<gX-BRA+%*#y1o1Jq^nzJa(Nd^LY4PCFjC0%&bxwxNlOHb zu^U?eBq`w}|8b<re3EfiqE9ZbmRZiWkwSyr2nk&>Y-#k{>303TDCma!p)|NMWu2U~ zUw~qUwmqia@8%16-^F&s+y>(E?TB+7$v!>uoSse$*j>z;RQAi{`H;j;=DpWz(Cu6a zxxRcsAN&2{)ouS@vHx+G`|ksHjaK(@gQt|3n>rb2Z$y^$0j*W~w9!&@Vttk;X)G^V za1Zi<P<gp?PW@-B;X`?H(#GdmSwEGBL{Z%)WPE3=NuMe3de1HJ&BzYB%ta=}UzJ75 z8>2ymz&H=J1Ll<Y&B@5Rt!Qg^CuGIKpm0s`KDBj<(~txn)9!!Nri9kvT$FzBWfOCT zciE+u_O*?r8L12^&xlsHCKg$s+v^}mWjxzwYdn4(fs!%GfsLx@%B33(rB6R}<xq=& zbKfHvpeN*{IueShv?X~@kD&8^tph)T+CEd111EJS7mh-TD|ao#sjjDPjMMwRJJgNL z=~_8DsI^Y&-lb?0iS&3X<cN!vub%KnIdHV!V<@5qA{x2~tqeo#z~z6gZ6f=k$NrG^ z>eJ|hg~>{M;8~+{Mc1iuB<61g6q{1QAKLobzg0Z^a{SarGBrx)8!&ceJ+dph_K&`- zY5f2G&ZWD#Vd)RK$yFL?Gii;R=AiuUqd!n{R$vORfKxiEI{RnUyBCj8SoN>y57d$n z&2-wa!Kp+(xn=6FBc=@K_f1#&o*f!+CjH@U-d%AfO(6n!_aF>re}L}b-(M%y?X>w; zow2a8;%efxTr`-I4Zb46Pix5=l~fC4V`C#mB9WcFhFbR+E$E4h=Qsy6<j>4)jzYpz z9`Fb(ou>az%;rgrojDrdF8#jR_P6{~a;}A^?%cVz_&r*s<D9r=SzyI~=|wgZ*^M<f zX&WgmtAIv-wbGH9_~j011KB8Iuo28IJDUH%xM+1EwoWl0K%(!rvh8zp9Bd~Znl>k= zJUe|oTi*7%j>rIEkuQH7Xpr!zda1clW(Cmy+!0d^^DlPm%a99>AOW;n?*2p}4o}M+ zuvSaw+|;C@6E98u>ZB}qlI&&-vm1Ldpzm*1BH6KJ{3;c1T|4(BUe$2#@htPw1(dKD z%+Gcf-T34P&u>pfzW-Jfixkj*Ka@~7@@3XLu(EDew}#mCB{|t>N^U8mz3}zB;bmfq zom%PO)K>*DFJ~Yuj|A+xE~}YH^sili&trY@&ZD`1L?*4ZicK|d1we>X6TM0bdh;gd zZ2p#)m||a+H-AaFefoN#yfT*#To9@12V%=eqo<o6Tf`R{V<wZUJyMe0kqXnTks}#} z$;-WU)`Q6AyZB5!s}?g%7Tr(;qZwLuSkMAOr=mX<G$UK*vJ*R=?)NqLGiT|Bc}Siu zvQ&(KN@w4->MlpRxkh^~*7}Ei+JnrQ(n8~k|3lCMKMz&}jvx(4V;e5}qvREnISw^W zNURTX2Qp?A0=xP538|^f$g|7jKIZ^25mRBFEueSLg*dfMR4R(Jo~tTM)ibx(mk4=j zQsQ=adv$UrdC!xKyejae<bX59dw|txG>4#y)zwnP{er9PiW-<NB@i^!s@U(8&W+>< zPL%PKWtGV>pv&Y}PGO^Z&}P$eXI0y5yw8d*dxbfzV)WsYQm+QICkJBvgonSX>4@H} z;@&Nd@MIj^#EJW)dweMA&a!V-<)M&2s&PMZN$-E!6>@T`mh$tMkj1YEog-|R*@p$# z8ZI%%fYAK|l~<q_K$jPj<s34CHInl~n|yq>JeK5CI6S%5bCB;8G#ugOMQonS)qS8* z`eK9TR*dfkOc!vXmK>|gZqebfylO*sZ|6gt)X5?+DlLk4bi~ldo+NunsF`V@V9&pH zKGeQP7uY)3)@fzC)h<~L@;tZV8FY&XD6M|9Zd&v8aM~!PPJ=AotsA*<V3hO5kHJQ_ z0MptOB2at{90^C`b|>D+kfuO``8s?QpNUGN{Rz4|hr1p_%y%?KlJ8WC<(Y5wZpe(@ z&nPqZ*TOO24dfd9i_mX+r;Q%iSC||G6*qq(7++}T;W_<+!God*?-|du%f%MQsrkP` z7XtDJhA7*C6yDF=0Ii^8iER<fwf;{th^O-cO_7_a&E&4dN#IY$t2W#3yC+GmKlYj9 z>fRVG_*!p%l6M4+g0%W@8Y-3b^yjmX-vHLDnlHm}i^aMcg^`@x08?yhw`IaYM9UCi ztO`)o-px7O!<Ef(s*5RY%gJmfN{ZP>a&QS`+<w`8iTH(cgm#`=xND?S*>moC$Ep|S z^|OFE`p8^<D;b*(&w0LcmN%pD-r4rMS09JC2~NbY)^ilpwBt!N0-HajRP=8cG+)%E zK^2C|PzolOqBPYyluYays+zP-9;}dpP?9B3Ug2FWi3rZZ$>IY0uGDCD$wLv)+r0#| z-2f52(6=En)S#}p{D0B!#Ea>0{-=J&6ISIJ%b7rA?=m=awD>vnAL5-|!znD!v{d0^ zci3)sXULuVf2(&6FB(|=TfMV6S-(z$U-Ei60$!O}{%`FLUcPp^*jn^={%oDaC{MEJ zfx2V*)|Z@mQarq<s}fI`BWDt4hoz?29V@wUK$%Vblxko~zl3eUYDkB+25fyIccl|) zlvu5fm}sWq&`>rkjj!ahpG@an8pwqa9efl{)<x)zqt2}sfRo|-+uLr<bq$kZJt_a2 zbO)w)2Ih$78ZNCod>WXomX?;ul#p0HeP~H04iz9g5ip|{=jjC|zk5HKI!#~Ui8L3B zVbLvC6b|R~__pe~EV`2LX8f(#*4WkFnsF7+OH#J|kJD=XP;1HCCB!Ve_R~Ph?Xe9H zGK&3Em!D?mM2Y^0g-?Jc$x1G?O{>X@bC9?%e<O>%`m=DHv`5U6`%3oJaP&q5{@&W} zBqn-pa@d}%Z+-{>n<>drOn6U0nXG`-B6)jWEwu<9uw?%}xcY1+RYKSF^?b4-S7R?j zX}JgA8wC?T#_sV#NIgIeQ|j&MG4Rn4zw``4^6@PA7VpvBpMAJIiSNIdR#}5ftx`)S zEPUJBTj3uZM7i?wPLyysaX8KckV9=Ke~}Ok0_5cPBk0_R1Y4%{ZC)I$?L!O8IOD{= zGVULwrWSFT;|b5@l(EyC);c3HC2DIE20**H9mR2^(<gE7);5aK>sA<YEPN%<c4~k6 zU#cZcx$n%5M3~D#imNndbp4Ca&_?HPz77S$MqBCn2ZTOjF~`{_VLH5v(KqMENrytk zurL{V3YWfMsm-Jjv_J_nmlijuW)6~3Ev%EvVyIIeti^9@n=+;cj&T03f+lBH4ts{o zmAd45x9oAzyc`0d+I}h)xBLMP)Ew9elCod6liAk|W|dzxAbb{Qo1}>36q0uNUN{PC zdMp=;t?ph~!q)3Qn}Y1=!V8;s;4q<c2%nIU!LLuc$~3MOYto7>`M?4X-IFR#m>0wY zUk>0Fvl+nNavAeuKS#tApjs+R;d{F!U1q}^&3p@~daG4#YM|z3!?@r7XqgbkAk;cP z2!%@9TYepMN_%{HQreU&DK`WF{T0srV(Z{p{eBhcGScNRd(s*!bgh`HDZv(7a<T4k zS9$y`*@wU|XJ;2F;^>p`d*yq=O5IZ?4q)_t&1whhDWd8B3q8|5O&DC<?84)BG(ZY} z)l_Y69GAXvE8pNq){Nbf3trA4vZ^#_<S(-V=(W-xyv1TpKN0NKxY)<0`PP*v&B#7- zRfCY!ojF6tBF}SjsYKiKd(qsZ*@6IwhC$sAKsDD3fKKtM=Zy{kYDD`@D+G_wX(0V- zNPzh$jMdEq=x;xZgpS?E>vPx}`H^3G!<!rcfw;i7{mqj5j6a$W2QmAC<bBVVbJoA? zthg~z*<ovb&wD1kq7$>!WH2NvnJiCj!18CF$JS@kSFn#=qSqY#KM`T%{Bfo)nE<Gt z4qR0335FfiLz0-<j__pNpmYk)`|2goHu^0#r6m!K&G_FAmBUQw-)|q}g57#x`lF+d zkdzH|(_fes&XI|#Y<rKqWo5Qx#C(~MUsf$=ESCPnBA+Suz%ujrZeSYQb+ci;Ez<S7 zExUL^z*d-$QO(-TJMTK;tPK-{CFkQk0-VDNH}gTPp6vOS7%d~$rn}9}t&0s;{W<C< z(5;q98pFCqv<JAjsfXyQVePpNHTZZ>a_Gq7*v&05=Ot;Z)V3?&m1V~V`8B(pPcx0| z<rezSP(ttIV!k$(nAMHn=D4(S>-{TL7!L<cjn6HBvAb~p56G%mpWG61Pg?|e^7XSj zuO<xHrAoqmK6?Y=Hh%#yAuVkAUbJIixDTsEL2K)HWD45jus5f5i1#P$eA!JN9#u7| z$-=9#dl;nCNwFcd4wQk0U|Lba8N<m`WlrPZl7d!4XFM_dHP6g{DZ32hL}86%f)2h( zhkiM78qtExPnD5a5#Gi7Y0E>jWAm_{A;GS<g!OJWj2s1cU>CZk;x`jzuOFG(2B7<N zp{<I2p9YRKC&>M3`e1g$WNW2^K-SaQ9<7S@0VVtIrRlIPCg|mkZVaaVHF|Lz8wBk+ z^9zEp_VZZ&1Xwu*da_~Fw$=Y4{L-xmRKR6LZZhM(te2ogmU!1C1^dF0AAYX1iQ%R> z4tIw^0dn_BPu~^kI26q1-0}Mf{o$XA?_JvOonfpa#RxQL^t8tv_B(HM8wMs`yu?Aq zF#hm?2ab)b?zDY_%pe-<!ge6Rk6K^Uo~9#Z*Ik^iI4H`>b=-Jvl!_aT`1-K!o7rbG zgRSxs${LgX6?X&|Y7xr5(P=#1+v|T6%d?7BZy#U?mwGg|yY(lsJAeGRwis0?U-q@v z+-!aSxAaiYyuq4faH95=Hp$YWVvnY^A@h@5BM<DuSAxIf!0r2V(7KfGkVsWAPl0*| zy3C`1-MMOxlK!gHXQ;}0x+OJMt?-V|WFQ$zgcxzGZiU;M=?X(Nz?Fe=e!o=j`c44( zE!-u01pAFa$XSZ9EvZ{D-PI4pmyzpPX0+dMD<3I5al|5q!<hiZ<;kSPmWa)YJ_MP5 z66l$HW#G4ypt~iqKi>0Gf`PZE{kuSljrfo#20C11Qea&i3gN+#>z1SCb;MIZv0}4K zOtt9&mnR~h4!DM|be*1j;^4l$XiU+e%==DyJwr9ktH~89aEQ;WkUbJjKMm3CE;VDA z-FE1U*ORU(W$e)Iu7dMHU0cN3GpfVj*3sR_gZmBvXO<-0!-tEM`-<kdboBvmeBbrP zs#IP!3<y)-^@w5}dEr-5Qo2$)zu36T{Xwv2FQyEv(%QA3v5>&m`fi1}N_uqrXLoPi z0BK)XlxzPyD+zu>l!r&xD8r>=xqcNYX;CC@h!$wPiE+aEyl${r1~m)apzl@__e<tV zElNA|YUPMzI_x^DCg^j!20fQ`j{M~3?t`~Qy?E<qDwA;`^3FgX%Z6uok33B-;(v<f z#9<D;^?oMC#bnd0ppNIZQ#&xbVR*4rHL^XTxMx9Jb-r*wXWnpmXzGGlz!dD=*_Wr+ z6n43{9-~k1#gE`#@755Yaf2O@uo1g#g4$MFuYEBn-&*udHsZa`I^M;5HieK7_uh}8 z(ywpmr`c__z%^*PgBqYIc!hlu=>+cYFJh@Ww_3%YvRvT`F=*0${&|kHHIh|)*y`QC zGhg-45$*x0(~I3>>KiVazBR{${99W`8k`Jyb-%OC2QlK;pQW5EYV}2`YAMI|>bX_} z`~)QhBZI#BdK*=jKp2%#?7>WL5iM2*!NZbWracfL`^79OVO^<Sy;0!MKEs@An(X;1 zt7s1KESo5qQ>8UB<8`X%p=#uCtbgryA+An6G>w0?@T#qpa33UZ`nP+6Y3hH<>P(od zyI=dAK8G3yXFii#zTg0(f5pPUylr%Qo2~c0v!X1YnEC1J;qnUrb6m>9rj`XqL}?GA z>*v*KSL<Y%5pZI)Z;Y#XKPp_<xYct6-1TIdBh`^Fri3QR{-(K~0&l7VsmDKWvGS_D zxq*^;qp#^ZoPwPlXfkcxUJTyN%PL^_n(W5Pl)4>!730Xq*7(;i|0dxHuGw;&V2RbY zF!v9pmyKmha@~D)GkGHxZHt@4Lx$acpy|I#vgNnaqW<dG?)MXPMEe6N7`H)#<=#&B z$<aP3ped{`SqnqTm>UyBs(hSn0_kqXNWgr4a=WG2pYf{69iOrL#OaiTlT_W==HV1x zB70|b@c8{aTjO`+A?Cf%yM9I<I-5ni$pq~RsZmGowbQ<RWqid-e*RNwqnqu$?WK0Z zz4z~S6NnE<zu5c$ibRHsDr^N+B-vkISWoGERU$2GqzP#!_LVMobdF0Qlv#w~XJFGs zu9!goNd9f!=-ONKMXfw!Q>|@m5Vu+3%-^CyW2SzwCNm<`%jn;l!n@G_)D()<wkRE( zPkI_S#-}vcMy6#@_AFie#Kyc-ZT#Hc1}#xPgL*FGu2ZJ$W<w*%lk2%(EQJDp5SpGO zUynQcV2*ZiWfgB<O>tFt`YoppUkx5A9_XQMbS@I&M!YZ=eLBsB1co7B^@p1~ZMCqc z`d11~kUy?6bRbEx;FoHf4XO^(k8zyr67x@rq2}CUejAb12TAk`yMNvGz`aZVy7po3 zzV~0jHD^5hH`eE&v4}&UlwmPBHM_QQ&aTKb&9Q%2Z~`?DK&gCVye$0Mq}qv7M4wcg zvaE)1=?trDH7z?WdWI>-orOYL&#u)vMfd4)8zs#}WWNZ9v~wNuTaqaZNw1oFuQ6^N zs?0Z5=#P#l^e?FsPs!OJVV7dS<gKWgfJyrDl`VilZbGT8^5$a-c~V3SzR^Rm4J;it zTx0|ZR;hpGwRzXh;WH?e>ei&pIRTmMFm4eq-LM(m0Q6Q(sv69c%grOE`;~mTSDs?& zz<Rq`zeu*-E4BsJoTrIvH9%LrJ+!jYmhseVXyScg=O@ryQFPyRtb|2of<cItYU;<d z#B=@!_uS!A9ZaNBUo$epxxu1xl6?ZwbDmAaYQLND2dWF%gJ3)R*jfvM7EX|EG|eUk zmu*2!Y&k9yDCYzM<YxJL>v1o;isTfUig^YMf3obemHRECW|Wr(x{oLXxy<UVj&KIl z^DVO&LFm%Z|A;8l<W9IPPCS&Y|LI>ZhWGT_ulf48wSIkz@zA6`p-#R8U(Dakc*>+W zw^c63xX9c_B6aY$2X><F>+gQX0~sNLZ$+T?73YhAlnZT%jtcoD`L~27l9e&V14M)J zDP~N$<)Z<klNN@qwO%9T><Vs-US#!z5m&#p{_b<4Xp+=uNA^@st(8tmD|upTR%OZG zUdELK8Zs7Z=^PjsNqqzR%C_6R49s<ZrPuq^5qW@_J*ylGI<<2l;2W!R>od%oEv#@5 zjz!|(J9w9N&QUaiBk|qho0RqIMQMmd>|b-*;_52*uf#&Ou)B%(@&jP$<*f;n#g^sm z?Rjk6+q74_e_2N00w0`v9{D085BG73l+%W9y;w|mafx+{?0q}zw&T6iI~_kwTRqeA z<B1IqORGMpzTFM*`+hZ^ymL{yWQHOm6iTT0ym`SU-8uR9+kb?e246hh8pgCDYkr?{ zY;M0EdcW#D96xjTEs5N~hT?QGdNa^8;4_U1QmKp{l{rX;;Mqvtmu6)Q=9OdkKDNgO zGGDmsLgV>Tz~=4_c*@ECo=r(v57KY%uCT#ay%J;v-m1*R&9USn^(B@ATKDi)jVE-= z_`={XeDvAN1P-lr(%g#?x2nakU5fO0vk36a8M^lT$F2RB40u}WFUboK6ff^%1rMiH z@<F~=Oan?k4NvL!{kE#)k8OZtJB<neW4GeHW-cmQj%#jylD~6dv{a*bpj{C0Xyu|N z!Tn%&9^=~Hv2d>L(n6Hte_bB?)942QD~;U${yOmNpI-;|F^XzD9-`f6@0$oa=$n4P z_eVNS?Z$jSV!Yt|4C^14?<Nd;;ubnVJ*Yo2R<o?@7pL?Oo?0+c=Y^}@_wbD!iuRTE zgK0RZQ%X#<CGoN}5Yf2X80x!jcl!M+J9Im`p3JX1sP&7=@7eeNH@Rf{*$Y$pW0}@X ze^kiusdDJFHm-i&kyFM=HDk*g&U0hd@r_0*{#QI0QOnPOS}apas*Q1wzRFWncj<YT z%7nHT73B(4;=-x^x-74qb|MHEuL^af$|2-!(~gz+p_u4){+}-3rKwg_m(@7{S@?sm zp>zpMi=kRL&3t+j2C!R&etuX~Cw1y|if*5|{o5%h@{f$Mig1(~3q=JO>_EMLLs#28 zn6_&f&~|t_2N|luY}R!}toi06xV@%!jFs=cW6AfiQhh1nNY2Z{E8!+AkvpsZEg1ds z|B+x+MQAEg`ddLLB*DY*tMnKs?;sjb7Qt-NeK+7~;V*YH&F#SIt{NRzZRX2qWu4j< z-uCV7RcIH*(!uOP4sK)l?*f+D<V1b>z+1Aio8HV0(0r5#{7Sir#26GF_)ZA-#Bz=Q zl>EctXP1tfROacOmGgi92TsrbFB$#cB%{hVd}w`jdR~U>EU(47dv@yVb#?mB8lT5U ztY*GJVD4FVJ$E#ze1-O!hq!|`D82($_`NVG<}aB6jC%IdEim>W2=sa9p1jM|{kr7e z65MGSBEkD(IgW!%`V6+6f=zKb1~3jHpUfEPE%vc{I@f~R^P9GZXe5|s5M08|Z~*D9 zt}HL_%8q&nSD}1*Nl=xjy1kodl>O@2yU@$p`EEBAZ#^y1`YZTM_NAMqahck3@d&jp zM-C5L07Ck(XTCOdD|I@x@{JX4p1jxXosQo^LS##ONRr)Ta;-1acYK#*%F%k@@NGv+ zYEBTof1hZy-Ss%rBlh(xhw472jkIO3U3uYvKey6>2W8X_dC{duEVo%0Sm!Tz^!8eX z!FGJ)4_(p$+#^s4RCgO@=e6nhxskZI;(Hqc-Xv^9#0uxnQV@8r2a|`vAW<jrZFN#t zD_ZjW?!5R$p>b)bz0<B@{bCO^0?V)tQtMbDL$0$zHtI$XI^+t{rU!&;9z{^RDZww6 z*~B5!Z(L^YAzFFyfQQ|??J3$P{|Z>)0AnS@P_DE0T`Y<}`(Fg5`Mi3${~K@2JoW{8 z5$Cm<wbP1;_-qW>2;0Gys(;4Fp;Y(RfvWiLy*-Trx8&cSprNHZec^`u`v%urQJ5nA z0d)1*b)Apgj5_ZrjrXj7bh60C(Za4zRf`U*Q%W^zHWeT4eldO9HK79DsoR*0MRS<u zUT5*#E?_H7{E04+l`x~s4w#38>y>iO)3bPlyLy1%yzJ?k7;wS)Y%>48!npRSu=K#O z({wAl+<vz4OHzc0?@pe9YnMua7?8hf-kho4(F`LMehsZ-;@p|wf*I0pRm)dw=<viy za8X89#(7I8RzL1E{Yvy;81t`R&-0>;c!r4$jE8&5K0?(IGUE~or|}}sTfnjhORuKQ zKxgHAyR1@zhDDfA8Y3%x8;y8QZkFM~dCDw+`-n@`ik9RjRbS^z;&N@Y`stQ?P1m^I zs_ve%nSk^G7$(FbXgq8M&bDk^c)UOcD$iew9(HfBm%HGn&Guja1>mdMSyKwFBmPx0 zmn@lB*lZ`(+bFHWLeVn*A(>k*F<cz)qSCWr-D)Q%NmRC!K8ygi+?kf;24Y>de8%;_ zw!W6_xzm45Lv+Y1AO3qcj(#X!Y<mJpq2GboNWC58f7_mfXm!CKdQBwKuB{2}<g*<b zP2;XDS0`xBpV~mdhS@We55IU37)R`}Qa-eUk}ewvAU9rSdZe#*?)y&TSN!Lni+yy2 z8}JdK#ij}n`3EO!t2jpe6Rx%Fi$AV;gD9i^x!s45ayi}|cLC}>Y3ZU?Y;|z(c=@}S zIevAxG;IaS%6Sc=zUTBQKtBvDBz21@y-T{+;8<JRC!xH!)lafr<;SrJ`yS?mr*I&d ztF2~x%6qbu%bU*QKPfLBG3t}Q55BO8?A6-#gL_^W!&1K$TB7j5NLgWQ<w&$P8@?CF z=IPNAlMgJ;_6{+s<7>u{cAvkp?&O;CS%^Q){a@?y_X3q^pE+lmuU&barE>2tjUTq$ zUf_CCRP0;wQdt|*?3No2>96|4vWjk3<aYrZskzYJo{W;d>NyvU0oJRKKCL|=*5$N_ zd7}ACG`jj+HPP5%i57Oi^<MwiJD01Gq*l34rs`;+^WL)yZiB1SaE{_Dh{Gbb5|5S$ zAV$#RF-c=%&vSy^AB@SJ_79#Xi@N@Xw;tY9-x=!KXz`UWPjP(Pv}0hRZ*SWhOI&+7 zXqABKVZV1`EvfD|3YfJ<16niGPEnOmvw8*Ov{v6$|BSC(G9=fWOE10`IXL$#=T!@6 zH6^1&^5M)CrIruYXh*{q&J_f_hwfi%VBk&HU%5G6bPDY$x24bN<5W*(X3b^C9}aRX zc{;H(IJ`5z?m8=1$M`Ff)lZ0P2Nz^sX_PU6tP!uA90s)XoR_H`K6^vhV11$3W%Q@S zPzoeB<&;*f$iYBSwt5f@D`oziB8_B@l~NEOR~Hsb+&+M`q7jknP_mPH*C9f#Whp<U zA*EF6@sKE#RcRG&X|8B(XQ&yvh>eU^ZQSAXU*kGgW{n@NZ6qyTKk!QR*^kFc2&C6c z7d$3LpV{bUo#iD9>O8_u$NNW^3oo(_f)0@ANT>k5ajDLTOY(7^HM<3<8#q144_a2A zk;_fJ%<SMUugW%38heogC0o6-#X4Qk!b7)pp0vMKP;-yj$mZX0CjW-+T{B2*yx<hN z!slBk#PenmTZpNjoypc*B|B3iV49QlWdy)O^;?d=rHf<XP1_j?zxr4{j(uY2a9+V> zjrDw}GRA>(y4CXsWr)*!<P1md4cQ@PW}JX5WX5OXpvvjHy%~#04vvka+uF>>KEGxH z>Jt5QKy>NTQ~FWbGj7@Ih=@(G5}({%zlL62D<{P1|2Qns4fW4%Bo05eI80C*4waE3 zCGYGqn{j~h2&O%SQq!xg{*u)gM{<p5w&lw9qRX<Msf&Rs3uV}Bhp?NyD#F`x{?L6z z_7{g%QklmDDYtopa8Kv$eyr19w+BFnWlnnp)*pHtU17#}&cte&uXnnT*3i_1bONk| zD8mh&8#a+xQ~$Q0QL`}ga5hJWfpi`HTmVG?Jp8rH+^T1<7G}&n_E4y9gA;2x;g@y} z_ds2Jal)~mxB+8=e`1>3m&}Rq(J=ApQ<s?+Q~IB^J`oUamSJ|&C_l$GTVuI0s)4@J zIyVC?;%<ls>tsM<1r0R8qL}r)kKRa$7t2<;sOiFN6y7h_H)4VhMLrkgfWe_m)4Vln zQTC_E6IUt+Y<AO%=dU|#jn`$b4qRb;$NwRYlzqqYNjq@uIr?Res+ztWhrpNE_BXH0 zr@mJ~Y}0N1N(%AtiM{KPCsH2z?4%6Yk3eX=?4|!f4Efi0u6hxSIDV|(RQOg!bD&}( z9`pSDzwwqX!7zhu3U0`~Z`qAzI`c2IIkG0q=`02q9CHKgs3ZR9DOEkK8_X4~wELEW z6>R^0eso4{=?m=E^~Wos9~^srWBoGSQ2{hCLG5@y4J!Pvqmc2{Hn%??>*BNk;{6H# zv0?}1<6Y|+(Hu?1So9M0R7~aHqgV8*Z_6Kh&Yvw0(M&(#pDn;1dh2*m2X9mmS!GYc zZA=`v3$I&_0O%h)Q@MF;5JjT2DJbX4cwWJt+c$@*T*WB%DJRgTXXlbG7x*2UNJc$v z@<JkfWj6KLu*T&x*hVFAm>a4U$9t!1=PSEyId%g)%kL@4`|q*<ahANS1ynL*@Mvoq z+s_{xP~6K5+4l4kXp3ec#Ig15b)wBDqGAd*hNj@gjqS|GYiVQ{U71QO9i07ge00h; zn9CBC#&m*k>e=^&k2R>N5-`C8d=G5TOtd|=l{S0<Dh1zJr{FrF?Tp8}(UIrgf0uwT zVL4_=<kK^AyL(e`4e$0d$KN-RXQ9LZPgH0eTbgFp2W@5>9h&D)A6wuV+W5;@{et*w z<3i^FzP~(IW8!n;BZ0o|DY-Cc+VOX%XyfA!wg<#%AVLxIkJ`E<uB8`lB~s>|H=;kq z{JXaRYk??pU%z$e!*3^#+2x6Vc{BO<hZBhbm#Lmx-_Sf0v?6m-7IEo#LA*jnGGfX; z6aDUT@GI&{ycwYfB3qRb$B&CwH+{d(=HQgveD)2RW6Li;m2^65%8Z2~`<{`zUQm5+ zVq`kO+uJM98eAu=F16BDvxbk9#_+xKJ=WmefQH^nGcNgtCOcEBE^CI?&4SFIKXQ_A za=b;!ct2^(z|PM46Hpl5kNojVy>rv3`ytYt%vwxwfDUdPH)tmMcVh1OC-*-@PIASf z4=FnY&ai1U@bzof4wXO83eNRS^ZwwANVyP++af<+uHt#C;=qnrLn_rj$v{8tX#9E1 zm}~+rW9J!W<GrGgA0F-&;?x@{`#YoXh%i#g)D(*Fn+>^f*peFokg7KG(l>G5w|rRY zp6z`cLLPjPxBDxdJ5K*M`~I7aMiz~T;!=Q|x~v!a+HSu@>l3iXCxZTqt^MJcUC@N| zE@A__d~kL8faJFUlYxin8tbR<Q6az$&EF^Fmd}N;g3$V@brkY6JXRy}n|6kr(|7Xk zC_lYtQOE}e9#~12_8DXIZAN%F56XSd)!Fq8Tgio#<8XPCPK9eqqQfTMYqf+S7aC&T z?kN-wn0Mqbmd1$f9#X9Lf5XFmXMEF$Oe}%jIz_Ob8v-1&g{pY@wIC>jZU?DC@P4>x z&b<tqF(j9@cl_?<F(VdnP6iy`p4+sw%#gi%8#lmr?%9kTgS~+2t8I?oU7dv+K+A6v zB#)n7aKNB6+GwqH2IhCM<HqsxsCWa`rym4N_@1C~ypl%1#B(6`K2gB9_85u=JUTOT z`l#Shd`<na(;#nr_LY6)&w*!XK}P+Y<A+n4Ha;&)W&i7H+%HblI$~ZF&_mdT4s-$} zkBvrJiPrlZWsnJ-oHKuyUS0J#e4dt82yje?zbSfT@kMJJ`t=)@%CEQz9Ql>`niHw% zRP|f~u20VA?4B9}&m}}qfpWS?fE5}{bKt5+r~Z=4!9>cJG_y_#bE_)dJYK6O^gZuh z&lyB46&}nAXPoliO_91qb>`LSMEm^JN7Le{93Jq<vuzUGM2}m2Ss?w=^aA6${sY9o zMJiBHI6^3gJSko(AN+*Y`#n<n%=+?qGb*QklfFQUd4qoEgMe%(@9|k6>5oiL#+S-T zemL?)D!w$3U!T+hsoIK^KflJqlqKANfA~=8_*#A9)AUz4@={)R_?nNST883{kt2x2 z(Y{SMKKskBZs`BE&jj{<k99b{08#YsoT2<jgEnk>cD$Rjf|?hnSnKw0AKzjX;V66j zR@N!>+En}>orLV@(m<Z5YE=9&8(kI(*Ev_J;eMpGjgtvlxl%rrm2|wVs?)FDxj`Y@ zji4tFsciG?J<TBobkr<wA609*8Oi@R=ucm$kcgh;h3UFjpRhravJjQE#2mo_C<@6} zZa`(LXL+Lv*9ncn24AV`Ea)HkVThpsRV<{)a^zS0R9^Z}O}$V)Tf8$}Yui|@ljXR9 z{XR2ullb&Kus$&M?eR_NHNFv<RT>Hbu|Q8BZ>^k8n~@^=@&DBE<?&E<|NAA<le7`C zmn2H_s4Qg}eOiQ&rN}Z<2{ECuGiI1PEs`aYvW;X{CY5~|$`+yQ`^Y{9V{EhYyFI_Z z?z`vP>(xJV&$-Vz@8!C#_xl`Ey@h0xd9(;(0HVISiur+2h7%oPO;IEHl6JF0)koQn zRMf*2!3*aJ?O5da7eewy^g`PDOC5D){V~;C$WFKI=(3$brNcv`py6i&s5J5X$_z;K zt?X|)zzp0!+AC8DNn$>sfU5|+kXZ*bUP2|gvO>^siQ$U}Y<x(_H2n`7tNYejhmlq8 zK;TH!N<S3&^WmRCpBE{<wVH~DeA`AIev}yd705`ukU4Zs4mI+a0)Fs|t_9%jBZ%8c zi}lC0ffuVEN|Tfa+wGCKO{`bie|-6xAKu9A9jpe%xh}r}eiDpdd9Sk-M~^W7L$4`U zi;pI7C1bE)iBhU>;Fb!+POXsn5@ZJ%vzX}b-ZBvJ<hS>yAW6o^ToydR55BSuZ0fF0 z*8Yn|e<YyLqV7>*jFS>H1?}VoncZDNNMW32_(6!NbnrSgh@$d~K)|Q}5%30S7C_)0 zqQ8I!Zkk?G>SoxU`6F!qvRbL7Mc1E#OmhP7Ch6QRkEvHVoeLRK#lIwv*)$u&f(~`P zx%?%T+hT;xgANEYv3CIJ5z4#*!Qdk?Ni$M+iB}Ylet_6O4$pR6+V!b-Pvj-YlYq_i zApXbzmkFEcQN-lqB97=mJOcm(4tOvYpCk%_4iCKa(6nJF^1poJei0b+KQY2Z$e8j_ z$zW?fFqYlhw&@f_9#Eoef21q~wj=@{Bn$verFCdBxa3IMVU?b^o?Gh~H}+B(9DUgU zZF#E#qmn0Ky<is~<&!Cr1(v3vY}yZA*{7Wol3bnKS{U_!JQ+MlgYRq|Pz;%%n|FZ4 zl({_oFbsaoEEL($k>CQ}lmcF-2|(Pz9DOHH2bACFc#I0b5DCRAPLM+KlDuXoFpsfo zvmkgLOZo1R=@%;k%*hkDGH@kXybnO5LD9_T;4BLl$YUJ}bXznI7HB#LCbj5LJ?6aS zD=%=tKPlRzx&o}~^W0=2cvS{zV&v>OiMvE>vy~}0mj2-@6U3$RGkpb#kSP1e7Y`)# z$45%PArDSoGt^z|9<7jsaLQW&FF9`1N_sf%ZG`z4SO?GXm8~I!as5O-7Kl{wUxm8d z7A*hS#J)?)f56$ZqiiP<{{#V?Gbdw`reWq`$dx-Uap0`oYo2SR{>%RmBmvTetkMtH zz=94L!NFd!1ArQ4w!J@JI{=d7kHq!@qJ;?&EjzjZ{RIW@pWFF>XgqfDCIqMXf_uS( z_Z}<P@0Q10g8h#IHbSgWMxP!~Vm?ntE>ZQ@z@{7JlZ~@p<a-$mnN=li4=(>Pr24vc zZ7U$0giN8r$ssMaVw4(2^Mb7Ll6cd$c_3qgl%b}vO^eN=Ek|!5btT}zibMaGK;Db> zOcj9Mei>V^!7~Bi@W-x;_1&N90utcl#axJ@GTCaflC*yWve>NxZeeqoK0=E^HUY5^ z7%dlAI=$3!q=xvX#||{rR&61DtcM1ye8+{Qj%f20hn<i>7UqAR4&c=>2wr*MtuO=> z9T0j9CwT_=*#o>N+2F}hwgBwXcgSAU@z4GQ#$%uKJyJ<Wc=ytg6BaN1z|X4mJ<^e= zEM(AMTOcc&;p@(m<fbRQT>)FZOu$W@c>ufEf<4fr3nm_fJfpTfPVYYwxn`3tN*9l$ zKtdU{a6EpuI`iaqNC@4<4_zcBuDkx{k^$t&B=K(nJ4}1WL?TBgwpx<wcg!RZoO>NR zPZ*wU-z26E1m7uBkjdud0U7g$WC+z4yW$Q2S%oO%<5~fg+(>{EMjstxftT!s*ZG<% z$&E$wL%LLt#G8s3fiHpRdjvB&2wvGKAuAMM&8@gMFup)=Li+7(+V}5n3?aMuBm{VJ z?YRCrI7e0aEewLOi-YM$oF0O#+^llVGmW?hce4dq4IW~`pLh9}XIw0l`Kt64ua5&I z7Q1B&L|WXG7i5&}M~43C7Wo){6=i_m{=;H<o1cqU?o|Y1=#Gg^E-Kgtas2}TJ!*xn zK?UFLg?#pC#oirIug`>$cV`~k1CBR+xjzx$lfJqlLXLYlA?*u9O&qyK3-c7kif@CA zDAnIh2g;^^Lq>XFTyjWD9Os<z?IJ^J007HGbLttCOQFcRjyPusSRTG+s4)N6qMiN^ zNab*N=Y%Z)Wc!Rw6Cs<nl!q(9O!&CvVb%~UUBMgWRTHy9{!<>w;*Fj(PORR0tpHiw z0f6PrjZMoT(_D~`{y41`cv28D$$h+AUKQhY<(-7LT~M3FC<MQo`NP?71ylkhcxMh? zBK@pCMu(ENe2u>%gcc7AWr(pUaCPRTlNVeeXa<OOj|}2=auN7r{+%a)vb}p$ymX5q z6i@g&yq8{O$f+|6pnLJbTRnpP7ysJIGf3@b%_5@->{BsdDg(IEEk%xH5Q<!hh0y%5 zB7NCgusxfV&Z?9AGIXvX9k}&xp~VP9YzG(&_`60cwnL0oDBvZGQ>@CVh54N|0z>Lc z`!tOv1d#7bEl^Hg<SWu+x-AMJqfUYCGbxrcHNbf$$@M}CctN3Prm4Nj7|tFQuRi7k zURbkg%r@@c(FD%n7!1@3>d~LFx07b-kMW@Di2JlsdIGhHN9Q4U^pme_UC$y0Fp!U$ zkq#t*<h#ke>whh_;1rv{?hv(2v!I3mQtaoWKjKHD4sl8DPkQ^J&)d|fLJm*&Lu?ID zxZ-x~qJt3RMKgTL%>W`*?ad@WO)xl<Ew>d{2HRE!M&pM<U7S%s4IrM!LMEBzb6a%y z>kq!$-hceTZ$q$X-g|GS&zbFgK!qYo2eT0WPL&uGU4SW|s`DMvZZiS!(DJJ`WYeXg zlH7;lX%k>>{w`o~7irkO8O+>s&}zC^-ymbATJ0yI(EIQzWW9BK#$G;zqv}k>>K%8% zNj0D^U(d+hjSMAkzXUC-ytclZN#OE9X1XT_NUFi?6O;cyc<7cW@6)TwVDOp;cVvu? zI4%ujopFMGKSr=``E})|SJi(Enb-o~0FYnfl8OR&MYecRAn%Or*niM`jNFUtaGdtb z3>|Rx<qEiA7vlhPS|GQdf}StsFunqTLOL=D_Lh-qj3gy{1`&#!jnJP0$32s8^)ef% zbQ3b9_d=ZG^%Tek)+Kokm>9P6t=?d}$LxcOcSZ4QVaO$+KgD=17MEAkdyzC+4;3MP zc+p{M7;-J*Pj#T8{1q6Y`pn`e*!5rd%EGJ9uNm2KAtrM_4AeOJKxO<Dst+nQTcDqi zd`l2>iERp<4#EFur&?@+Y}}UrdXgqfw&rI(I-v{gGpq8QZL$vgj|Q+wn!;)=F$3Vf z^!Vfz2$>@IR?XM=nN`<<A=a$l-_*M7z3G7)WrnKYbed6&3BzC)F)x@9s(Ge-&CncB zVRv4oSpCtra4S-&q4oTI0g}nbVv=S6AJjaIy9-eOD%V<d7uA1xDyo_NF^$Q-YCUHC z3GG~n6@>9a`eb>G@GehC%I5Ipu8#nfoT?55GQ<}j#H#{oAgG@CqMvCI&V9G%KWpP$ zU)%}99emtR$iJ4Lq#+UOC0_#zR%-@3;^j^GqBbHRPfj5PmLTbNDCQv`X)vOh_TVHi z+$_+!3N<i_fczlXI(mF%@qn_%He3GDA7GCreEjJI?gS55>C167RBigf=S&@c0c=@* zIN>%Jl9cdn3!wn5q&%}ifZzU{?*IT|g?*Ed*PEo>zykw@pIyg+2i)h&<%1utnh8S| z$0i`b(;Ua!hXGRC?m+Gj@V=D=EdD_nZgh<%d|GjWv_>wa-3TKL%m^(GW?q~O0|Sk6 z3}<v2U?k-TWER+E4*Y;>Sl>5VVjK=_^jPQ%0|Oi&17rlcMoS!Xn?=B1HcES^@woaZ zJ5$By4XB*OuZc97tmqyk@|v$lflY9iFTP8Ue2lGl+@~KpCg(;zP*jla#4CWKFGauL ztJy~2RRqNd@ff_aVg9__7l7-Bji9!+2fztebhrj)o!bJ=*)RD3Wc#V!WP#o91r!9x zD6dz>V88g|xiLCnb43{C7CG>1%JehWVswDIsq(c`G?;%50et24^0PhoymC-T;x2JM z!e%>o4=Dm}x{I9=TSzI!H%Gvmm={n{eiAP_3^=$t$0-Kvd|P<~rt5#5Cw$#G;SBJ| zS24mr5abEEMUabEs_|Ff3;vu>Xkvil##X9<Jvd|pQ64#2J4knc8V4$#iuIqIUwh^d zY5_r{Pc^YCo#wv;$=wh{+zA7$@>TrpE^vJJ3(SU558frt_2Ri;vX<JBQ|lS_zn22w ziA(es!bkz(|E*GOVpHQ1HoB8$#r3oy>XyG*IcAKrSz#n+Lff)_fD{`nxZ?B_Jm4q* z?ptyFMh-Zz%jWr)^f7$g;^Q|Cf`iE7FRR(I1EUFfT~1)`88F?vR3ixtu{j8Z9V-h} zfG9c+RO|xpU;D2KF?M{;&c(spYm<;3?y;CWTE23fbr|yNrvxW($ie~L$BECC1|8+< zhx2=h@T7+TiDNbM3EVKB2S}uU|7eLzfAaxwieJ$WMW%m!bsao`8D6nlrw-W7+6f29 zVSUFApA7Sr&XB~JgseIz@NwFJEr7elClPNz#U<WPyopC!t@UJByn=)0!2s0|5*Pw= zJ_x>i@M#AC)vscqR|t&p_85ZFR@`vyaVUX>ZUO2_C2(B;Xday!#DBJrWB$Li*?H4v zzX>>qf;JE9JoiA4ByS6x`31ZG%TNnE@zbAz<m-?y9MDhe-#`fCq(rk$fL{{63H2YW zo~I+njP-jU7|d@W#dBi=#gxoWOUNlz7hn8Jn$A{SE^O-?XoEUqiq(o^K5CBur`^Bj z4T(T--!z8ycHH^BHaI%2>HndTFXP?Rd&xqJEjDXQ;MS(Q;<d<n0KN0~$Agc&j=j@& zkI~)a$r&h5UP<d`RI^4d-;6r|mOIyu;@x~QJeYt!h%bX&`jFZQfT*z0^;cjMyySB| zf>mc`o(OycIiJ{{li|#Ek3aMVa-||u6ew9g^+74sKwei7miIOs$9b8P3}xcH?x+9O ztj%M8URXN>AV{tjBu|@<{WM2y{z=_)Cm86WvHZ`=e8v_cyrHW|5uS#M)lJaq@cVam zxh+PfBfrK%llwScbadK$4It#}xy`%4*$T+p=ybv<)f$-H_ZAqKtrGN~EeJ5@uV;9H zRi~4vjYazxN$x4JY8~jEx{Rjk{oDId1ip9?uun7faTiBoMaS}MVNUdxGvJvb^d<Fy zto2jA$^u8+exZziPq_Z0`z_i;$6lA?{_j-^v?JvKRD>1EKOn(7w(~@;`Y+8U1lsso zGo&ZAf2JvHE>jMu-giT?dXaCl>+uhi7xKFEB!d&SLLlRlzDFW49QVTb+5mI{o7e*# z`WW_Tg){^O@B%6?F83M3`M7-I=^0S+4IpkO$3y0R1{+litcP7V3;wQ`kd?ND0(P^X zzz69kj0sug8Gm(LdIpFU@XHj%bF%gU*t@;|ILjAODqefA*;(52#YL3&P&{J-+L#9f zA<imw3u&kqKLkB4@mj3{h#v6_+K-CW&&=CSegxgniED-_iwRchzhGVmjUdg39O1V} z^Dvr`Jb2LmeH$|;=qlnnace)c!JXriu@}DUQ}1pkWpD%c8UpX8S}8u7z}Ok%4bB`P z{LqG;nT-1jsW*`M6%RDwvAgL4OvS1#cay+)aN(ArM>=6$WVFN}uvq|{Z&vb}zla%| zM@fdTE&X8JS=-yBF!O(%P8-fICuF=7S`@k&4CR+ZzIcgPX91?k9vUQi)A-8X08%&Y zky1b83BWMqyxY)QAEs%Egjj$t9!wssg$$6}s?Ox4*+A|(Jv$7<;w5Ee3goIw*bb|u z@|E=MA$yPHg9E<C2p02@BRwIsXw8m|)d!>a-yeahG5?$R=$@;0g(1lmsz1AVYPx0e zNH}<DxBkWtTv!4G(NT7o@=eH{uNz)?qXLrI=5b7XW!e$2=-#pG=(Uimi0h$niCACA zOEbl<?8EI|>K-MoC@SJ14{zb4MEj-gdft*lLDKmUznjU5@F(l1pJJ~-_LipqVNI{< zUOHU<#Q}(MCHT6nBH=zg?{C&$`CtX@^PBB&QfKBq0tBDZ_dl;&eLQmgH^46+{}*Qu zp75v2HIpJnnHUoA^dI+ouBOGZ$<_c}e6;vuoPm7r==1<aor%2_4Dsuu{a4hPZ-Juz z+0{Fcn~k9WQVM1iK7>qkLEd^yXfeY4h6Uux{C3fMYv1G^Y&#CN;1+y5^41ljbV+VJ zDLEqs;;&;dsWAyzySJ`~{_h54*x?-+yP4f9X2Q6AJB=kFi__=J-AR_mZ2N6v`foSo zk($fY1^Q^%>38{<{to93J@2Wy<nw+u18k*~w<wSK*JieQH4h6i-AP|ow@H`Gi?tJ^ zKFbnhK2NRtXEqHCl_{$#>v~VaY?V6{_9^bahZCQI9W&2z+H5$vAG!A7vSQ>X%`cIk zjvNOTU{k=yAV0Vq%)&70+Gu38o|$ARO*#LYy8_1>$J0tkhtF|zJHIkp%%Y;rQUcr= z1Hxohrq+CDufHeh)~rb(4Pj8XEm9Rx*o#IFc@Sqt)?x4=*zStEoYLTCjN@H*%2#Hq zt6*J1_K+nxi~ULKcdX;sBx)CJB-=NOT1%=gl!KqasiO=XIpTHVZMvt6httY<9Z`%2 z_8)tnj6F`NmT{@#T-xWrs5_)RFH%yJdL;Ara{~6b21V{|p_4Ut;yq@JtF%-#k?NWq zj%t*(dmk_MBU&z5Lmg2(?Oa&@)Hb^?H8Qnri2LLYq0^<YM6b;Co4c~$&6NP|y`>BE zZ-U|my9}q1$?Mr#!8X!G)6Bm66P--txTS6gVZygH`0prfT4AYbrlXBf``49`vNaX- zSC4VW`Rtd;wGQG#n2_MLp11T5hOn8GhuJUIwL`oD=0d(c)nb&x>Pug}Q+>VmnfW!I z+K3jcJYhR+r$O=eTXP^i%U?ifjxb({uT@n0{^ljf?1Ph;AN%}Uy6wa@r^Fk&a!=n0 z6Yin7IACDq%TEZARK!|YA0v}jw(BJ$kRH(@`;<0PQOX&h+F$~tH%5f-RP8gPj7iP# zx45&0-b6Qye`~A@GMm;eAF}wZzv<{efpaR?x2`wa=~!G2t?^b~4593q6td>sN=7%I zq(_Gg#k-9+Hh3UeekaQ2zcPQCpC02X9Q6~NZ}qt$SFUVY?qijVVX3QmSnalTsaM2Q z!A+}Kg6NriuWKCrU^M}Tr|vqp&o{!?a*=y2`BSIhIMW1XL^Wt^RgT%P-#MX;_~^I` zCGEo&HmJ8Qz+SNTnt!9Fp_;UweR})?P4D!{vW4-Y_Q+OAPoeRtWs(dkWb8-jn(sKO z#d*jNJ;(li+Hv^{Z@Dw}d~`zRGJa3}BxS1Ra->4m#mmpvAK0r+hP8-k`O`{{$=<vc z{*8e#zkl|W-HB&68F~^NhqWvB3n_`N{js)tweR0Ult^dolPR1%CFguY8ryL}&7GTv zZg?wI_j&-gJWlJ?+iQ@lsoFLe@=hs!-eM2$WgD4u&!JQ9=^h6y?UB-XN%Z<Z)0%C% zFpuh4yw<&?uF{!pQY$03f0~6=oV33di62loQGqnA`KC5m2hS`F&O>)2Wg~gTKYINg zjXqdAuWFL*HEJ-KryYb+gamB{F=*@FuM(%d(zLHK>fU0wY9~wA!_2CrF@&rKgzfte zo>1^!2+|T@#A{88Bx!maZ4IZwl4KJ$$RhN@zfil1sXLMWG~v@@<*nA?VH(IX51sc9 zb|?Yxs1N6BCFO7*&j~gj-aOU0hMj3(jy&H}_e<NqzFH8mpP=U)-FK(U5j`1Bj@HEf z4%I58{-ZSwvs>Hkw*TfN%k!x>iSbyhvXGwV?=CvcMF*+Y5U_*oV=$3wiN>i>J+qYd z=;&0;l{xNrWMgCY++HEg5rvc0!Nbf3e8@BDDW8U+*Gt_=V?uDIk^kSMg&s`9+wl$L z(BHm<02luc!SnYhPBxVbA3u-zwnkI1tqGnYRR7>p&VHF&;6?wFSP4M+)H};*pT>Qm z%%dmbb$LQ6`M!SS2lvjdoNB$Xv~26v`BS3e*Ycgl*CLuGDI#_r2+||;awMantVH!` zZf-+RmFR;I-;T$_n)??@S4Xs#*eu_OZtd}$J?{I*4bDVsYU6xrSAv9tt;TqRnTuam zool%V(F?5ThW6<!F@8#)NQr~C-nqB3|E%-!48~~G=g%XK7WHUHKizm!>dJj^XPLRL zy@!Qqi<zFPuaApsET(4N%ERTqt;Tf+bPpmV#ML!%0YSm@?7+gFhnMIr2CwQ~``!q@ zfYd$H#{Qn1I4lN}lObT1gIuXmRzgzrBq}ZZv?ui$C0BDKh)R@14)}g!M?U9<@DA~I zk(Na_Bwu3(51@JfD2$D5bEz*NRGwTjQZ+3PYgu^XQ_#b5M!3-^&Rv&W8i#~6!f7EC zDLUS};8}QzLg&<~-|@h>gCSK%ck8b7*`g9u$$<fLpW0IBWb1{4o^8F@>5ruxf@WQA zHbDx`rareBpRA~(8_4c$Pg<q+`L`=L-Z;gqc_Q~zq>X$3`5SgVvjb;P|E17zys(Qs zK~<8Lw)6aGOYEB1(;32fSDH%=RO3}DjKeEZ_ZiT%^vY!`6^ovp)xjNj*V%MQs$MNy z`hXqL(o;CjPI{Nm5S~Fzp$(g!)$q_`ywzg%r387U+O|p;wVRE9bCH!8?+}hog0Y>0 z7v}8lT%9Zo_>C}VOz_9}YNC+uQdB4d_tqaVGNji?qlJ`+^w?^ouIi=B^?tO06UC_e zBkDXddX4;~p>ZVHbKjKfjpVbeaHf8F*5xdgH|+Jkl<;Yn4O<&dfyeT*LVEZ-^@EbE z5&5^V+_QkW1p%~OdD%<5@4@s7QVqtJH9c>)8EcBH%Vd-7Xt7JN;*rnH=5-2gs~xY_ z47_olS?QLHqkioROflk4)OMYsjO40K;|nQ4Fr-jqIcf6(!!G$4_NaA-8GIu_?v`K# zAPBDQ$LEId41(`PZ-fuFZv;vQG;b|roy)J!F(1EEB04k;NB0gpXTRnR=C-7%Y2t#% z9O%DG?%NEm)eeTpNL7AP&v`Df&K0k3k>$9sPY2$uTvH{QIBYFXNBJp~E+mR+S|RsR ziNDz5oR0zD+w2<Pw8X+))6q?u2iA4jRjX4g#@dMHal2wExs==xoWJn>or-y#9?w3L zmdjpiq3>J`?vzFM%h8Zo-qVri?2^dsAvzvrEj?1#H^y;&>26%^f>Ce~$;5F<sV7`` zf#Yd^)*Uh5w`VxWOd5@~4)$n|ytDLHs=k)08r7a0WUX_<Zt#FLVU<>@^*CFS**ebU z^+eqac`d%j&)<$9lby`Ia&_>o&(-ybh;eRJ@6!<S;=N@5-nlOfE^{27P-j<iu+n*{ zUpqu~n=WkGrLkSypwcm-XSCYI*W05_L}-k-$ETh>_&!OeC%PA|29GKoBNetA#0{r9 zj;{@-J{?SAnc=&9{VxTtht8GbDu0J>G^~s3{M51fflWWY&RhIZ>Ob&ql|VT?PG+b+ z-zXlDr;L=7-aJANTf-v#=hyRW9EYUFOri+~G<BI>9Cva^TlCnB!ukON`{3)U_h^Z} zX55uE`^#nMmdHZt!yQ5CTegVLZvGa)A(y%*of^Fe&S$L^-_PSM*$#=e9bF`;l$7WO zUo!hb<@(2EH!8fSpEf>0U5NNSju6S_j`m4tPRXE~m7ip63G}cp+xSKA@!9q}*7#(2 zOVseuf_0Ox6qnhc8F6|FG4&vf$7Q(HVt-Vr`>{t|##WJp{k>UOCArTRg4ecj>fmmM z5)-9i3*x^LX)=gP^z*VwJ9>o}i9+HaxPHs-76S_F!2=o0F$d!F<G4Uq`=EJ6I-7)5 z++DhYEb5w;dV!6s_Ur%ftN-k%Lp;t)rf~g6e*HO$WdCYiNd2Rdb#2+y!HN?VvPg*% z-CvcZ9fvIBcyJTXFJEk4dT8mE{_Sxv)$UscZ7da4_Z|)xLy|JrO|VDY{m17W=xtp? zAxm$Q>ckP!^!U%T2m?3eo1&!Z2e!#)U2HzA)=X^ci7?4(jpV^R?ei&py?P(z+mhe( zWTOIm9UAK!H6`~Ghy7ZaU4E*nm)WiHk2dSGxB6`FU&q*rC;V?7)xSmI`|NDxcz5Tn z1rjS<A}&doaXL~;Gmns2B|glGBQ{J%_(!K`y01NPfEAmzc5+NlA1|r<=I{aAjak<x z-<tc!CVSe^vA1!&A>_n`P=XsD$){<ekCP))f#RmJ=@#?YNzcLtF-*fGoaf3Nov0f7 z`VGE6&NC$4Q-dAcrvANKi~U7=tkY$9p8>(&U@mC(of;<2oF0WPlhjjJG}}5U&bW&G z;SDFhb#%-Y_pft|&c3H9@EcxLc-$}0Gmm1Y;HiDMIB0NtA=YgwWU|V;bM~g%WVlf< zZ`-OZrR@c(Ar%u9-i>l>y!^vZ6OKC_91vV+9?^G}%|bIPF4vh6zdPq{e-NOESgNd* z%z!6Nn;FiW{-A#M-uvF1^91dAe4mnlEkS1<S?I}T{g~ibYDclp_;FwN<@%|95F-wy zDU5K}R%gcr-m4uQdAaoE@8Q2Ge!Q6m;ok1C6w3CR7{Tc-k1bXf8|wuIQ}t*|+3+~r zsdww%ECsZ^+h2<|?i+gH)M>|sXI@M1v>P$V#1`lKbM!~n4QiI_M1rcI-OKceRiqf1 z&B7NNdh3M0qH@=%u;(9kYb!^}yg&^+sV}#i+plCgpe1Xn30vw?cku~cnP{(TK^0NH z-HAvci=57G&2`syi+rJ0%;rjHtH^ykeXjAw*n(?rk7kNjk;&19X}gBXrbahY2Zwj# zx{U<sL633|_g_3~!T~86pBwDt&KTQo_s^-dt<R{?!^m7EtR%BEjMl43c696zM~F0r zkSNxkPToveSNo_Ho-U=sWbA#HOwLHb?faFh)a<&ioktDwM58O*E|cdPbNmDkD+Tsv zy=adX>5NQkH<geLsYd$+b5}597p8|rqR%+88;bh9KN^|&zrJLA=fm$@UlTXo*v`JP z%j|+G$BSIW;cNL0B@~Ilg)g{qPR|?L@9zn=^b=9X7p|hjTc0gwTaPylOO0QBE+Hew zo$0gj^5@w`2G1S(Ha2G{)m1Rr_BOxab=N7!zP$X4(?69I^OORocKmx!M0z9}o@<m8 za!?5<Mz`>_lONn4QuDrh|E%j(u5R~x_l^?f;Molf<4Y}PCpqL>Vc|x}RO5H}0;OW4 zpB2EJU87V9ZqLt<q$+wokK|On_<8WO%kX~7PBJyAgdhG{&Q`jj((hYP2)7+!-%=lw zAh#c`cRPDQACLo2-}wz_K9*fc>04E7mD&|1M?^-ot&aDhi1P^bS>S!AqqrBO19&`2 zDU6C3A^-SVAK&L%p+--<E?#e#pu111YAF!?Ln??onj?@InK=IFY}%EOn%;+tZ)FPW z%g=`1H&qymm-4NXo66pzYm&cPP7<YQ-93VN7^QQ?!S{ULu-+sxcWdx~2Jc5pE%oPZ z<(Vs*vK?GGOHKR-O`@Pj)ox2pOdI`u3S6?*cKkg>XITvPj5BTRc-3wGZ?9oBdZuAn z#d)J??pbuxfn~c`>vjwx=7U()mK;5GvXmT(>W!1q%zhm8d_!i*W`4WAy05iF#dm;E z6N2^*er{Bte;1LXv9y|okS96LyM`Cia@yV;+~ena*@-uQ=ePNE<FMSYoANf;Zm*w8 zA0$OYG$_~)yW|Edy6YW_rfts@ytv$oqu!n!wtrl2M`9Ietr`n9oJ86tcbrp;f=`V$ zMB;lsNG-R%8fQ69zb<9iJ*iKH&z6}wn<a@!(Gu(qzSmqt3l77IoM@*%RJ1;EOnDde zyaK*l)fX@jiLRfCZqUm;8`L%;NtqfrgjsmAV0+#2c)ES6w?)FERm+4VtIFKY`hQG< zG%abUu4$`nA=2km5Og*-&Xg0dFtT(-n!QXxkF;Tlak$;TrW<}Pu2jkB9wFa%HT}># z{j~3nJzI7frOA7rm^er59XdhEMy;+!qKbSA|Gj=_qk)g=ayJhp-M>+MSU>F|AJwDq zX7F+ovVq>Xa6sIId+REPdz+rv7Sd=P&2&lj8vd=u<1Rb4Z1{JD9^Oc}EWUAZ_X1Jt zkOq-wjv)J_SXb-HvL=x4P$lBNf@7aI(3V%pUd!v8Qvaw3e-GxZA-@f7U+`z=kJ_3Z zuf04gXHvd74y)@)!+De^Qj{y|&ss%W4bRt}6m0y-Gkxw^$$QkAseJ1oH$Ycvw_fjA zl|77-FS+XmyjQRw#Qm4+X3O0rzV!wLL1z|>x2`iY=M#Ig;p?=dvcJ2z>Iww~rP$e6 ziQ+))bfAz}??c9d?4Yu|hiM=`+bC~R+i8RT{RmmT$+CT8p?LVtz2Mn|J&g;>HM9{@ zwYg8Gb8Sjsrwg4MY1vJF92I4l-~P0d7;?-MgWB0+k+%8}-Kr|qV4JJ{t@BOL9)uQ2 z<J`tt>o!#n;ZjK<DNWPFq+QHZ4{6?m=1Lp)A%R>X=iqAV<;<QF@vdlA>xQ8T1@j2C zP1c!mTs8tDn|QFWzf%|SEL5s9NBC%+OIy`By||#K<iKxd>4n=0p61&&?z-pEH(iBl zd;fZo<=I#`$RIq%M`<&0MM3i;F0(^gdh~@$XqFr;Vt&KNc8>YRTar9k@cQPkim4Vu zsw&mu=Mbx{>-J>o6ASraUd177ebRA42c~$o|Fic>VqyEBbK@!;c`fA3z4->acE<6J z(AcW1smP3muWsd>YpAE4Or7_W6>n&^L+b<|p8A5YUSh+`Ce7bL)lZhkU#;*=7zeLz zw%Zo11UeL!yo7NCa);UKv0|lvkKmpUsq7A-s?w`1I~B$Xs^tBGaFSN2t{e0!>h4G- zoY%$VPZL;radi<}{c#z37+q1X)bZ|H+l<K2boaMLlbls+Jtcwv6)6iCE6IAHE2#=Z zH`ekwqU&}g*PoTqRf=r`jQ0UKg){3?rn%}I@=;9_Q>?pp$ROK{7vr5ZB0)2)<*5+Z zrorRG8<xmEUir&$U(eptpKlEuP(yQwb;G&a3pFy&gupXdlXhJw>k8Rqu}<fcGyQMd z?W_6&#xQg?`c~d99qvO{Z1D_jJg=}d;z?bgrR=?xGBd~G4RXj>W7#GB0$;g8+pAYh z=G&|3zZ=>d(A4XnJ3_ryUAvg(g>98AGzIP*=@ZrSq@k+BG?Hve6l|e-miSeA)PC*b zRCbA%asrnFyV%-y7?xgfOcw?>@~+0nxpCFF%Z)z<UFu)-a<fO?pC#Trqm4tO^A6EO zbXG@7NM@^IJ6({=w1xPP4c7aBJKetvZ&L$y45K)Nzz1$sh8S{D=Z4R1E=zzAZrr9@ z(vz*rK(#Mhrxbc}=OQeFI>`Qw+04Kc)e%t=cZ}g^J6_%r)+2*kBa8*+o@IVAX`Ppi z%7>K~sAbiC?3;_Xt9vaPx_e|j3-?$U!HFuJoDmt9Yem5)7pCNp!_1SrgNJGvRQRf0 zHHyIO|BcBuxLbWx&jvGgd7!{Mu5a}~NOT;Li(!}wWsU47F&%jfgW;L?uX~uoKh>8# z>6wY<1r#&Vr6vE<3}c&SAK#$lNe-+O?)&SWhnCVwk{|B53?cDr_N8wYjOa$$*S!wK z3@$r-foALBdJ2Y3C}6r&wPQVQKVX?n)e9l?^2EOEk+O|M5pf@XP3sA_`}eL4FapM$ zS(s!G4`E`1Cean=EuKlE{|LCVdi_pk_Ja=^mh+o8Q=P=Gj8nVWqYNw8mkt*<uQ~oa z{PA}&A>1>vN=2_?+Qsp6ivJapnT>tosR6$Czi@t|*S5m$_kVKns~zrb=q)fk@6z~< z{>EWsNG91MKJj}ms)Hc@ggg40IVb2J9UeK1C?ccHf}DM2i>l9lC|kwTix|OrdLJzv zqwU{mPIjuQBU)9LIbWHR38Wj^G`VUH>ov2r;aZ?8;WTb7(sr5Rq&w1AxO!%nT#04! zN`HkT`6b~B_Ko8Wb;OIyOM2xuEGz!T@mjItNm4RWaN~9zxnN02VhGI^J!u$ScfeJ? z%HOBgf-#bR6S<Kt(^y|EZWf7+-Y{?sGm`!?$h_=5a@~<!)mV4irTw|XhSs~{b;WVZ zu*t6bBn@GQ<54);LoMbQ1wC1`r(rhtFS<x>`+_+pJLzzdtB-WRJ%i^29o^kJt8HDX z@{`AV+1W4Z%=$dz66Zf-)-Rt*^h9Ogm)91adZxgSua(c!7hGQWXT4Z58}STQ)h(-C zRw-H#YEAKKU+Ky1SU&6I{awNPPVe}}L24E@3$}3OT~wr|N)@XoGt6`n_R_L2cr z6R=82s4o~EH<%Fae7fL*6pz!ZLV6Py7{8M$)%++-eeOx!;oripl)m5(XR>-&Q=jl7 zNrMH&EX>%Kc3Bb36!oNu42&S*X`~7(cQc_=Kip(TiIImihfSXqx{i|kuj-uMZ5p=n zf!EhQt}8+k8!zsY&*J&I&G90aw=>r-68FtKiN>IU89A=>7cU>9?e6dUyut33;I+Z( zOHjzjLN&j%@!jRfjk83Z4R!R)s}ywqMs>bMj0-lut7;VG(xA)19XXo%#k4XwY@@;5 z61f+t#b_Fsz3<a;$e=Ej;{UC*YmSGXT`M$hcI3Sgr&O@Yq8t7aF?*J85%IP*t7MMF z4Vd`)<PJG5kz6!UwYJFgbL`^&mWnhqn|dva$)w$>p6ao~T#*zeO}95*xAgvr3E|zE z3%ag*jb`uCtyQJ=mG||FN8e&S`oTa+pruo^e`G|fTSfF!|Ai{QA^$anLaO_!6o35n zPXEPsQfottbJa(wXKj2}qe_2g@2MktNbDmIhrHX`g8s<0HP}3U6`N^NptL8S{cNt< z*>*Et6VM(ySbV{XJ<Wbk&zr=<jDJSVHUa|MgVJJA<OI5w^2glF+i(1Bn$d(=ddFHI z|8iT~-Jh{j9N3_Op2mi^vGCznv58x){aXoALgLv+D-|%3^tJny$EK$Ck)A|9f1yji z+&<f-6XGFB*X|vSmj1PC!S2R%|D}z{G9in&-)DY0gbeCXr)hD?Q>??n`?Z$d>^|~p z`IVcKL6l8q`^{&I=-ce5UHJ|u$|qx*(D*}5niy>TSH0TX%)yqLvo~KC^mchx1r}-$ z$=Rzirmk<|3f}4U;^v3KWc_1!+f4&Vs3ls&+~0W`4{i}mmdd}(<VK~Er;oWVHkYYs zVtd)7HNZD|y_4K0V{tC+hS6(7M>-PJ#MW4{Jl-?yF$V0QIL1@s$OnYPw+=?>WUqn$ z{;4di_q&c43JJImQ|^N2Oc`5S_x^ih^~rrsxs7U(50zn-zCWnx)W4@|HmP{*@)0vu zG+i`jh4BQv9AL)c<;ud`$ucK=2`2>19U0-?#Zr}zKVp`%)jH3nZ-l1daztM;<oY$+ zUWTn@ay>m}RJILC=g5uSgont*)wcJ#jAvr)jYeJ-bG*y+qPs|)f>F;6pJ2}x-^^CP zd5>9-H78&XpR~&w)yodHDM#3O{iLl9e!~6i_j&i0ey>r<U1J6<*iSPQlng$P(o9xz zXIYV2%+BdMo@W=V`b&MN_DiGLs>_;aHhIklSO3*(gcyVsJ%5wH?$2IRa^=PK^z0e# zE8%>zaAuSGOJ1hDKMH7zgZvibWkZ{PJAZJeo$S8{fBLoj<x^K9;Oq3Y*KgQL@5^c< z9I2|di5}u7VDm{sf#^nujY#peWoCQwbXlidWFU%o00o=Wv*WOvHh((oMsm%e!K#xt z%*>SbjS{uIU7$bG<sdJ}e5d{7;H8kVmUHsplWH40U!W+@D2V>L^1#ytE6CAtnNY^t z<>eU`A9wO3H5Br&{;!Dvj(r5I28o_(gB-QLs;G&z<yCD7Df{-vj4$|Py8rztoCB^4 z_J2%hbzFu$3iH1%2>lf@n>2-0Qv0_#N*L+k@02L;S?dWi{Fyq$E<^L`Eg^w<=fogW z*7AL`cz`r)T@hd&ml&Zy4*8cvB?ip*ENC~7?u}0d+BZV%$A2TH=C=r0;@e}N3`uU+ z#gLhgZwu+h8g}Qi{UrGy8wlJHtRcWqc)UCOka8(8<NTTms`A#nn<D%aac!tlvGDHq z*qI#RLW0<o_Ld^y<@@e7)nBS5yI0~2X7W#(4rcRasd=t?ZiCa<4%wo~K<xT=OTD%9 zOA+a@sqG1-FN&|UbmRpuxY;IT4^*>~%l4dSe>V|cdK{QkA6O9_wGwOgf+O+V#_8g7 ziC+h0SW%Y-;KX){-Io9~`=&&Mw`AvZ<$J&9KB<bX!(*3>$KJ{HXZxAL_;>6&@%R0{ zk9cdb0F!xt1YxD*B-OLJ?ENbCBdfB26&J#2P11zPk|-rb2Cu)Qp4(Vxw&ZC#IqGes z=JRgkhb-`H$)||O*pL^~$fqoSWGZn!ZhDsFm_%#kq3kAFmtieB-8giQ3zf*r%wn*) z@aTpSmN?q>jh-*;-u*!xkL9Y>y{^?RXjC4xWw~4@bK`m!F1xqA*WMP{%YA8<G)>JW zPLo!jw%&D0STA;UcojVq`<Yvaag$Yo-ILU8AM##zJ~vxYbkZ}0rZ=<YbgO$3c4pSq zEsNxm?VLD^T0(3yYjxBpY2p+wSR=_gmfrazv{md9V)e9UbboNW-875+f;u?Sn;gx~ zW|y<GQ}?@OW%%Y-I#I32<<rMneOtY!)mMT4t!2(eRO3X9X77|L$L>{vX7)&<dsZcb zo;Y|Wx_hYPO>qySvY-r0W>piC1}AyckVC5z@5|iRC3~wMx}HZ>FR?RCTF0ju*{9V> z>_GCA8oLFxtW$)vj1*3CZDlntW8u?|Q@MddI^>~~FqG`)vdZfBEDj9jK72T&z^pYB zOXd``6YNU96P8)apLB}a{6joW{O}A6v+X})J;nIqz5H4|qVkyPJ>46KRQNQZo}xsH zSr_$~v))*kbX-|C?JjBAkZYnYT_-R+O#^SH&W0%VMt5_HaMkP^SY#4OaklXXado^T z^$@L7$Cy{*sJb=K-0?HF1V__ddg$}MVX5-uMs>TTcf}M&?`rB2X5IB<JB^iHj2zec zFqn0Hb(K=|CZh5^?j_rviW<rD)6EL=ldC8^zdjW7L8J2pnW|>iPD@O6%&L++2rRt0 z(G_>QA|dlp(WLA3k^5*>**xv(*5$6x)xHI(`6E<RlD{VbuHI>D7w7Mpk?H#`)xBeT z>;H1+W8#upa(%OVj?1f>QBml-#BGfG$aceltQRZ6?}LVH;OE=Rq?G1XdwzH#UK6Wt zB(Q_43#jZscdT2gZb);>64@}YpiB?uX<Fo??w8{puW58TF!1zX5vyVMYPW7<Gr4`L zkm{04`0UrjANQo9g`+96j9F{`?T&RHslrt@yuEY96oq)jKyi&di^u|JNiviS7Pcuy sR4Kdc_JzlFKXnLxO<Qpz^o?zjhJ0S1b1JA?fPaRUOfMGv@7BZr2QRu$jsO4v diff --git a/docs/images/extra-repo-fields.png b/docs/images/extra-repo-fields.png new file mode 100644 index 0000000000000000000000000000000000000000..0e036a14fd0a97cebb5d0a3f9b2560fcb70f1f58 GIT binary patch literal 67472 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 diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ddd576cdeeafc67789e3f6bd9510494c91e999a8 GIT binary patch literal 5430 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 diff --git a/docs/images/fork-flow.png b/docs/images/fork-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..9f30cb6eeb3a6e73c786b6048c0bf03421206355 GIT binary patch literal 37977 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 E0PHX9^Z)<= diff --git a/docs/images/gists-acl.png b/docs/images/gists-acl.png new file mode 100644 index 0000000000000000000000000000000000000000..c00abfd4e88c266fe19b385208e837f5251af831 GIT binary patch literal 146419 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 &I6minh9fPv7Y|%KgHYuxrJ~MHk>|) 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 N&LML?eHfXefr@0+Fxb8w{*Xa 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 aflU*Zjd~82+oyj2G}Lrdiyl0C{oepe3J|&g diff --git a/docs/images/git-flow-diagram.png b/docs/images/git-flow-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7442ba1c027c31ecb8c28ec0a7557dbdb06d89 GIT binary patch literal 43386 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 Vg2*J0)RqAFs3>VFmOg=n{0}4j<4OPk diff --git a/docs/images/ip-whitey.png b/docs/images/ip-whitey.png new file mode 100644 index 0000000000000000000000000000000000000000..75bf8d92179a858d1cbf07038669888df9c13a73 GIT binary patch literal 60529 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≺1c1R2K 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 diff --git a/docs/images/lab-setting.png b/docs/images/lab-setting.png new file mode 100644 index 0000000000000000000000000000000000000000..05659d2d133a51934b67b79a95afa77e061baecb GIT binary patch literal 76835 zc${onV_;>=vQ9FwF-a!ogcF-Pwrx&qd&jnI+qRudY+DmsZ_d3B_n!OKpI)m`wY$3N ztFOCvsGN)_0xUKx2nYy*xR{Uv2*{UG5D+j%XvjY`lrRy&ARw?MW`crp;(~&Na`raH zW|l@EAY!43Nl;3PW*EcWkFz*5M2^s%;+KS-L7VB3F#*UD@V+?)g2K4HwK>FKV?Kz& zUvc3G^Fu-maKL{olaJ)&MEOJDP`&zmKmWbL;qlPra0@)jdi`j<^w@HlA^^GJNs>ze z9S4n}96=F&@nG0RL&ai;@d3d`21OjHTV4^EzPi%8YQEl~osArzsW+?azI?4Fn%*(4 z2leSgkvaTX&xFDo_!CN#Vhj`{ko1>!EJ?;8V}Kd)PriU?877+~u3`?iB%A3wAyIb{ zZdj1434>5qkeE#pClT88;NuuGXiZplPtZPI==NGgb=&|rWSyAQR?oC(63c`)I?fL7 zIjJP`IyG*}>8^39ZLg=5KKRA5PX~?<m!HNVM<0Sv;`U_}gs81^u`K1Xy7;6<{Pw2H zxVIck?@Sp~h#{$l&P^`6xDIN({0={4qOUUylT1I<frw1*QNrUSg)i%tTNI_d$yh%! ziAa>jC_Mp(xJQK|!;^Nj09MDS`ni0+LywL^r&x9cPKU4&*_Wu)mD~DS^;@R>0uiW* zX$-nd-~RjS#6<{(S)hJYvXWv73hl*_@ss4)N~`>=i9-wm>#$ix&y`!I?a2!WT@M5p zGUzvGh%Xj;a1}9d`?jhwmuB0YS}hU-M}>#<+_8%NM)VMtw-E3alGGj`Mbq2o<Ukjj zLrZ?gH&5vRNA?4f!Jy|=)Sp3$BgXL?%(_fM=CJG_Z6KOI#xg5&i@oVbMw1|zbHJE= zY3ad?M;sq|AY4Iok)iwen8iROL2(NFqzJ*Nd$4Ojzxo-}pq)b;<iO&B-EV(m2i53R zw*}RLT;eBa`GOAy^9_`)m;DKZj0n1q|7!?rDW66R?@w5D!KfIVeK-igSUIo+@M}U) z(x64Y^c;f{aH`<4T*zb0V|Yi<HrRW?$6O*)cy~B2UwL}0qTWCHEJ3;YvTTuY5$Jr~ zY%wyRFniW^7+WBDVVip}x6iKd)WEs}$mKwU1!m+|DVP#S#&FPsB!micgi4%Bh?OYI zAQuA6MelR0b4g27OQubKq=gyhO#Y%h262Q>i<}au7PJve&Oe)>Ikvu|xkGlxea92* zEisg0nEFOWhTq>`(eu?nf}t^GE=4khD+Of&>Ia78Ft!0+4d^nsCAKq*GtL7@6V_Vj z#W12Fxh;DJ?9|tzFu49&TaFfib>O=Ey4yO4HTWZpY@fwW<u&k0r~{-MMK=uKciDrq zoxMj6V-N1-$3zs-LsUV0PKZm^fM$&<0v#{pmPa&`_)S`h#F{V(B|RiLBs%0$j5H2$ zH1sR~Zv2h7QNdmTbpg?=Ngdcqz`3-J6h?e={Mkt6{_DQWSJ*+HU4HR`eYqw@Yzj<D zS&HnRC5(rRQdm(F?y0b;7^$GCOLgGtUh1+dg>`Oqg>~dcHe+3JBqLZOZsWE4i=)aT znXxzt=`qD)nxny^CSx}70Ag=tpb}`YUe0!Tk35AOdx5RIeo9#0sX}L|<tf>z{^|Eq zXaq^70tPd)27^@w4LU0=dHxv{1{J$PgTP%5VHiANwj8DttUJ6rw7d2@ItgrvED5c` zN(pI+FA@Za3kf_4tz*JtlVdIk-6ix&p31Yz&ZP}y+$zH5X(b{hRdPHf?&9}}*wT~2 zk(DY1&H@*{oE6r2_@!MM?=de3_b>?32;K;}L%_&z>}uwdH2gHPG!JGj=HZ4C4Qmb0 zN*;})MjiUESXmM9B3Sw93{{m?csVqSRg1qDvgR4)LuXb><|=O0l1t7?((~Fyn<ZVe zWF_f@Y$A2?H@|rKb>#!gK6u~p-=iUeAnhPE;WZFM5E2nmgWQ55gQ6oSM1G5?i?E0^ zN7fES4V?@@MZ8Msp>f44#lyy@7uA$@Qf}S(n0<mxfE7ddL9oC<PL3F78Mhio8Vepe z-s;^(9#$S!)7<?)rEyljQ}b+YsGq3ewtW62(M$EqJYTteLDK@wqRA=n-U=ryGJDcJ zoi&}Usi;Y7&A;jKyu_KvS@XQ@ylaJPIs82Rd>Ho*Hx8Ey4-(HTYA0$9x0+o)qa$OH zE7R%a-10JG&$I8D4wEU_F`0xm9}WT29ur@O{k&{%%)Zh&v4vqhZXIYJ-(t~TzizRf z?SAZT%Wck+<$>){<c5Fmd0}+&{f6`6er9dOqtc}qX>53_c%*nqwU=$EdHpdoJBnbs zdd6mbYs$OP+XRG+kU~$jhfvXf)R>ii_zND`5~MR!tbd;0n12>zI(WF>n&5U!Ps|2U zw7|U}L~f-%VFXqa*STGbzN^YpHOg|xRY+KfNvuk&1+hn7iTrq8l#o}*L)a$DJN*!a z2<{v@HBLKw6VZcVhOCx&2I(d-(CY0Td;uINph-;2z*@^{XApat*BLH?u|`9y<>?Z- z6PGAiMXRixR(rS3xMEacL>^BsZYM4p*Hzc2#!?ab)7akVhJ7u)Gx|MluXm*%Yp=~- zvSnIPOHo2W#I34hqoY>oaej7Q)zb#Z@hPprr=h$$d{=YVc2^qF5^*TyX{>OF<?BbN z{i{>U;d$)fT|iMkS1#@#qmj)*>nmy5WKdo5&*p<)$n_3_mZY0M@W-6SD@WcNh@A&V z6K|*?sBJ13)f=4_Zn?WVvQ_g{>s4JUXLRcICx2;7H!hszIE|jQEuK};sR80Hvvs?D zTZp{+ZE$GVk}N&DDXkSfd`0+yy;sJclaYapfq8wsG_;y!K)%nO&s>-C$;EfgZcMwd zDs)YZWDM_(p-txt(Q<-uV8&`zU8hU%dz3#{Ef)mW<!}2fWnE(3I90|DuAeUB_(NHF zJeQBOYaWgBO%3J*cG<4k1wUFUthzTpGGDusij%fVugXlTl&aS?p07cUdV2Vy{iT($ zl?Rn|fxDlM)vMiYg+n<-cgPQNzjIB34Urz-&Yv6vE6uI!E}A*{GYfd@y4rhlb9X{s zV(}tv^IPoBk9YIEhCQPiSyEY)+2+#2qy6`G_vnD)F9*LvbI`QO@nl&uX93D?Y3^+$ z5a#L&jGJkzRA!Q<X8<(UqVkQx_q*!D?#0XnUQIih>-8u^15y6r`R9&Xw9LLKRZLgR zp!Osuo{n$c*Um0NE|-NllB%??+Fi?gD-IuFXNmQynbldXhpv_PZSVI<IL>S`pT>`C zCpxd2N$H4eYcClutFM?3F7Pc#S}g|-XE#=d7iTU4mv>u{tsXYE*E#$6N1Mm*5wAA* z`@AWhDWA}{CC9bvd$Z)HvgSaxk4|+1Iu5pdCdWOq`MKc!^PObxpP$!G1>0B$>L(7B zM+o_g`6k0}LoYf%+!<~Zp6qXwcd~E1Rk~Q+y-w+(yR9RJqoX@eI#b=-FEYp4+a8-P z+sXRKvph%M=$~tk<Hw3$rlYbwx(2-5cw2X=e_O1u?b%#x`F8=*#xl}S>x3$>sC@)b zWyC?Zt?)n+z(Gp9K#+}$d2Xcm>brnJJzLim(OED9$@6X?^i~T3oS-HAzac|pV+9#; zOGQ0EmWM>rJ|oV*;+(0|C{P<nOB5Gv5^W-z!1pxwmX?k#mX_Kyj?^H59KX?@O&0tA zLgMS<&O7ly+sH!tAo&0t`2yx~gO#Tb0s@+8rljVmCN0HjXk$gI|I^06h}PB07UZvo z+m-XrtCf+XKB23XrL_a6D-ZEMdT{=E|ErpgnD8H694&Z=)uiPJ1#Rq&2w7;EY3Yf1 zVF?Kdx$S=%b1Ddl{P*xbUp&O7j*hmRbaXB*F0?L8v^Mr8bPOCE9CY-Ibc~ENe|pe3 zxLG^uyV6)Yko;4~|Hu(Caxk<vvvoAHu_pZMTi?LO$&rVc_`m!7^ZBPDBUiKk(`4=N z-_!atLAt+M=oo0}>Hb&tU*i9&<&-mXHL_F_GP5$WcKD-%mxGCoo9_Q@`F}^M|6e-` zE91Y8RR52W+;o4N&_At3_uuB?h2^IEU(@r#9*Tl$f`IUWhzs#6xq_Z+L+L3AFY$=8 zcA^QO#_=6@x_pJ;2ZalxSoY`-y1;BdHhKP$-T4?qsK<{|2$LsfGh2R#4PEf~=3vZ} zo^0e&PXr3H?wkC$dB<V1x#n@WnR<=2Sm-i3<%6p<n3#}oyx-dDwtWvr*A>Au#f~;O zICyn^ZI|I@h1>7x<uzFuWpZQZS_W5y;@#VO7n(Lt5Ed5Z*eDG!*)W;T3XDbi$o{>= z&+p5*{-TrOJf@C}3=R&;&-XtCyE4jEYo0}RoYlvQvN=GU6vkXkjDq*|4UUwY+#ihd z{r&9?mo)w{$QHXd69NZdqObjS5iM+6qRw7Jpb2HF=FtUZtY<v@fY<V{S{@r8kASLt z1hlcKd_(^?J;>lP(%_y}T|i}X4j3gMzb{!Df!7-hDq1`<f8n-O2t}a7&>lYkUxc3R z+LaYp5%aW05WX$vU|aLxFt;V0&FYnH_h&zKHCmi~^4QzK^`J7Q`>)dfQCywHteejB zXLsZa`1!GEJ3Aw0xxZjJp3Y-2A1@4y4Xav2IpU&A%ga4c3TP>4<yGgtNx27|yw1{J zHye_&&;P)k$bsL2ahUv=vbg=RGW`q`5*8+*<batgk`dO^1Bp+-DVV{(5&gRjAy8_R z8z);^TTK_r&|mI2!j<OurOY->8^nJ23vf#NVA5y=5CES*yQi}v8!eWo;)ih?ES3;= zc6LgNCj!=*ZK`ih^KY5`I!A{y2Df;dRc+a8ZRy`L-sdMoS&X~x_HG%cBkF6XIm_vW zny~%v&z8*Ub&CMlOYSMeEx-p*lK8HI5h&_z1{ZsbzggWJ5sY>6M|577$aWFNeGra~ zUw1bkEP;|F&<=mFP(vk+O+nB5?Rxn7<*fQFu0-8@qm6~O{haacc;?H@%#2#6JBvz{ zR;bNTWPeJnp;HGOT?aA}?^BLoO>r^G!=$?CSMM)^SiFP5H9u#gmlIq;Azi|PDicUy ztexvzf7t5j7SCOZoS;$u(B>YkR!Wzk8m)V-TDJUX`Tc@pI~~$qRv`VI-|Ku#Q&O@a zI}7WbSCZ<8oXyXNkPsRg?0*VAX}%s6bcUv!8e{})R-xgj%tSqF@{)$N!WbF;jH#t1 zsLRerP~I1Juq^i-7A;=a938b#{U8eZkJcl^f@J5D6RfA3aXJR$iEs1e$r1Yf31wm& z9-gmnD&-)+`Hw-4<$7my=io-6S9hYT1tFP(%PD{h5AS<-aZS!W$<tP4C9?Uhg@8`b zzWh=#=Pl*3KLnb0->I(`eTzc_kawU}p+&i=Gci;*BXFZ!)j-yjI+ACGi^#SfxqWOg z*lQ~*h^)(~T)|?tY!m4Po%&XHh>5I6yUkJ99}=M!;6wm6&o@28X;kbJu`bN%<|=oT zKPfT`1NQG$_~ZoZN^8b7V!64!nW-0*wJH<iU;lw?I2i@>{_F%>(sE>l+;T40P@|NG zyCI_ueCg=m{`vD~No(Z_g<LrOiY2h+c8cp)gPG#n^HFxxxf<ji4l$oTz@ned^=xLR z<z+Va8>i#9s*YzM_u~R;LFon{D#B)ZY$v-LYpdgmxJ%7mEc7Yq>G#{a0J0(*N@#6v zPG$oMfwao_1dS~A=U7uS<Mr)lZ%eXHA7=O*^MfZN3m)4Xom&ypt%6k(N#$uI2fgYe zPp2x~m3CPeHO0gnT#6kLnNB#`-+h(}tclV5zza=`%r(Z;`C@gFA2-!MQHU{W=G%gb z5-A5UG}oL%?779GiRVyiw;m|(+qNJN=EC$erb)I})9MtNQ0x|=u--V_WrXaoec0UL z_Pu<zf%?Uq-O5#!7$P12%hdg{5^mJ?tZ;bcwNu|LU}!6keU1qK{XL%kcn6bVBrZ18 zCL|Pwlk$yvZF6jhT&*ymifp&ZXdJ_+?*mdKq6LSNlJdoCxydU1q5buDyIeQWYeQCC zY=z*7_G-J+smi?BdV}HcY=$!mFOIRYqqi{6L0`X$xHym#yL#~NOUr`pOQOuJ(-Z*4 z&^#+9A)#Pgrv*7A!%pcFUt>lSw;TU;YHx3^md{KvUn!$@jmZ{h@Xf&g$6-vM@Q4Z= zg^`Jo{@zezNN8!KP+{$QvkiepgK4ho&y}wDwwzf2L_3C|Hjw>g-5HM78vp0x#rl_b zrDxJ#X&~t5!+zHUyXBPQHC)4(JCr>1`-kba*70&rF_&eA!^a-B&!!$XNsr!P#jCB? zm#!d&zr8@1xIQs$bk;z82chVX`j@UJ^JtbcWiAqt`r_Jm^E9mobBy(!KQtYosevzF zb*0jxX->*yB-XyAucN+OcS8v(gw<RpBVBI>a4g5=QlWker(NRleSID5S6%3ic)~DP z+Q+=QTN=0X$<Q9O@S3`BxxJYRk(Z6R4zqXOo}M8vn3z})n`|cHEF`kT^6@sqkxwW) z<8+<@EXPkty&-RO(9xd%jz;f(_dQsfmH+lN`oZ6Na09bhfStgsw`r_#iG$a^#%*la z)#WWa>cOe&!ES?>hjSP9b?RB|?!NsSmkCW1KIsaq@Y<SAABl;uel--ll2GKAY!58! zJ09nc%dXd~sn0=7-M&wrE1xdl$w4v-GP2L(mIuM-`=xhd_H#dQ;$tYkWrWu|(Wz3C z4HU-djF{#^FOaOeGKjM7tieJlr(4=g-l35!(db~!9%b7^FrE6mU?D-bVgf?NOVJI? za(4Vb5;Z<FMHOFZ>rGWn4l+Zd0Wv0LbtuIsXlN-BbO$;Af!C2t=GDwF0SP$?UUMVt z;GQI-owWcvXG|kiGBTcTtjl^3nA1k7pvSzl#Nvm?!+Gz5s`kN%s7Dz<MDhevnV|Lw zZ5*f>)``%bA7vzwT_q~cs^a}Ys*|QIiZV<-!$S5&lDs2$I_n+z+9r~3SV14)yzTFr zV}mEW=83GurFLLLcOv#V>oe<|%Z{_AQYENyW7OgzM*@Cy(bs3wJ)k=69pP@X75UKH zx_osX@A^`#<=ExOPHTY?x$EU{bq!Tt`@#oGd-V)c4QzvMr0YcbJo)CI*RU}X5*<K5 zony;XRWN`VO9Qq20tK0`VhW>>{OR*J+!^$k-VqtxCfw6ZiZ%`aqS{O$3RhEK@>l-^ z6jWvT+G&0jXGu+1yqD`7zv>Z|MoDQ!j0e0yW>-oIU6xn%f4TRIX|nyn`|XiRq!|d; zOgU>~OGb!29kyDIRZCUF4D4MbxE>>ilYfo#xNb1l9o^v>2~iAZPvtCiIPdvXTps4A z2`2u)Ii%~)ddh8aadi+XdG7swpQqH4J+$5SN+%%o4fmVpuRFYmb8Kq@WVz?mk6~im zdw|FX$wHnEf#(wuVnLDLegZ8s^Vdd01KV+$=HnY_yokdDJ6EeWHyJs99{E`L<!VSH zs<dPYKld}Y_teP2L_#K)WWo5f)OMUDBzDQb<a;6!;O7x#60<$!zhut8ii{NKl9lX4 z2ay(9rL=jCMsu@ztrx7`bkbhadNB>GAsQpt1+7*XG;f81TZy+~H%J{V7wD~vP^Bfl zTSP6_(gcts6_ed)z)5+R*DJm}e|$BKKFIG@Cu*ISW94-YIuyK@j7ZS;*BrqOJ({fK z0=nLoEyUb~t0UXN6ZzHZ9U7?G?J9<pT1u$Q^tHgJp5r!i-=a3eoBjBsq3)WFUp7=2 zTHQRHE~X(M4T9yIuQmI*Th~iX+>T-|ID6h3k(`*FJ|1*dIem$c7kX4({g%>2VRZ_z zxy*rhn$7(6B3dn_qbTe(@VbLi0*aiunr6Pz3dA*55AP{W_5j#6QDQ<XhOYF?D0fxf z$Tg^iz;1WQ?=<-}ZikE&w9@@(76cjVh<K~43QlHG%RJr&Cy$}WPR?`<2ntVZ*TXk} ztie<CQVPo~aPP)n(bPv(op|X9(U+#WYtE*dDboewt>+{CU-Hq$^`~QD4^b7mzi>7i z@{DV#`A;2Z8C;Sh!hdXr3m9zAd#8-u#n<7Ut1cW6<c}OzhD89cdZEHtisOj#|Kzxq zlOde@u!SF!9Y~(!6FjeNCzlnHa(XqyW!Gw*Lmv&_jK8mO<{rpq&88KZ*wj2FbWhMN z7jnBMw1&joEGGw!B>o#^@*%V}AktGDiWODP7cj~jR~8SKRK2J9LFEX&I6q}hq-iAW z%f(LmO_eh8nEKO0J${}$V5c`}<;hSKn{x`Ww=yheL#-LPNkKu#_hVz}Gk8uGfS0SE z>%5p}ZZ=Yla^>auC3gPOx?|Si+u~Gq;E5vH_OtF#-sm97^@vgBcC!nDGZmxP@uVjG z-Q>+=1Kx;mED>t}AKuing(>%Qd6Px)lm<zqSeSR^OG%(5?gXvCW>(^|2C}bA<{5Dg zGr<ta<nC6^kiV_nc;M6NXnRersy94$Gr*lW>=$YLbJ7AilE-0G|IyZDZ(1f)>>iFE zh*7PDMG{m}Ms^#1yJX(4N;jH98zqN8r*;W(z&K51_J-)YGLVX;Z!b}T@e&#FpqwLq z>}_=zfND2pq3xcO#$N%6pK)E9(`md$<gdxsf6LHv02Tq<mD%WWn8wLjE0#`GMmS$d ze@SRkP1Nklf(!;b|FFR2eRW1${9R`dQ=LU3UxOylQ~}TCAro|k2j{J=8CYCB8#Q~P zT(uG%+I~9xW39MBHyv0`!Wag-SD$M!TR>SPlUY<v{gN;30cYm2-D!wz_n+){y97gK z7e88SxrE>UtF%BV0%MvINy@F1H|#EVH12bbMrAYBrt2QUy4T~zSOWuGC+e4L7b*O# zjTHX`WmYXYF5JgPs@}`FB0}$JnRV|^FKj`Qb(}hVAC`}<UZ-Dmk8%y%4#-ol4=~)^ zzwtb`-qE$nh^fLNs$6(|$FU*Pex9ED_h_J;URt+j8%R!!b9mR4j6E?~hgKs<cvp-- z!AQmudyL5`qoBq|XR;<@;KW4m%XS4%jT`IDA_2B1gS&?dh-3}te+@y?erJeKuetDe zdt4B|y6`~z-CD?ySBuu&bpv_0QZHXfNnG%uacdmYrRtrrR(Mw0_YT$~T}A8`WKrG* zNl~S&HL?C<3ITEI!l{7%+W&N~k9<osdG?|6`q$&rXu~whN)*DlgR1OHa{u-s34@+< z1yW|YXH=lKhDO?K9<byvuE=b%w2TZ9U#dTN4E$+G!HVjYH`DE7(IQfpQspmJm$}<M z$fL}|fjUK~sV(}I_t~!xejgoo7U=sSf7Lt#uAy8q4<pVZHuCQ&dRs`ehm+^mS(`nt zxus>r;)m@_0db-7ck%D_wX}Ikc`4X|j#(DvgE2auI}nYir_gu5H*l=hng*+QJW%j{ z_QzXE+G+~WlC2onZCs|;ezsy>_m!A9VM}+zpUD640Uv;V6B#Maeh@`Ib+YtNv5UW! zH3tR5W);@XHe0USfU+~8xK%##w6}tmk7spY5}TLMbJ*V-+Ui?hCZmp@3-EcK)8#T( z#>qu2GMrrfLSg!~nx%j<3$}Tf+zm!(<Kbv$@xf&0PWE?yi7uJpTu%E8)i0T}m8uRr zi-c=q!*$*Ux>ez_hQVGj71%?!GKxbq<Tc#Trc$+9S2ox*)?XLQ2PI&RJa~_!w0BhZ zOUg8pq8_CdoQi<g%&<#gk4o3$C+umx;)nN&RW>jy&vz85b0#<m7%wvqb-=~gsW|+N z%PK>Qp&Fn;^;^PMNFs6lp0qlx_qWh)PFJhnlh0~T(FA~AemR@26Ef|GVe{WCp{LDT zz~V_@=$Esez_=$`+bfYJ4Kr2g%;V|zpl6xFqTj)~ISV7|qAqWgDi%c2PY$hnS(vQ% zh=|9l(9ead%HE9!lLH*o@}|sNg|(?F8GlF6JQBTnR5%-I&76RpkrFY|@8o8=>EMaw zFAB?xU~Z)tiO=%LNBqNsKR?pARBagQ-S5rkBcuDXIz3`brBwG&<82N3$qqY!SYTXD zLxF;{GiFlmCUyLu83=pVAM;?$W*g8jvAz_e>%M`2_pmR#k@R9_W+*Etf>ULICS+Yc z$zH*^y5p<RBjSS(j*V(^TV&91CH}_ZtWufJ2tYGN<a<d4JN7oXDa+HL?%XO=oC8As z!i=dInZ@|3fN%4s5#eoKp~<4%ezI@DI}Jj5kGoqnf`M$RZePzcqs_d(+@B5;*4P46 ztj87N8S+u`lJJ_E*a*97H3&~lq|)f|<U6s6*U6PDl`6t(4RJP6l957&4YvT{nBjDy zpR9IQ(;DF$4OdF{L@GhJu`}13S=~HHA2j{yTk5-KJ#{biYOQroMi-62$9#C%7wKhB zO7D=3C`vU*)J=6>=J@sIy0w+8Y1HS%@2nW{I7oaFqx`sGzayBi6Uv;%7Zec)=W7kG z;`<19@4gDX;P>Dg<g5y)Dky}!GwBZa6I}FS$#(dhr9qZ)e$^Xq8NNO)0D<@T5YNcY ziO3CSs(I^-b=6l_jBvfSc8so@PN(f32#Y>ClcZ|}-y@gm`7RiA{Jb);cbIPD{FG`k zQlFS}lNR;C{bYGcMoKKvso4H_E|3Ei*Jhr9XOqc)lFh36l>`8gy<o63$$jo}OUtQx zdKqb1bhM}WJKqX{R+5O9Aj+sB>;|dSY!uPsi@~Tnu>rR!ubFNU;Uf<{xLzsF-jym8 zzgVoqNut#bdum}95wy0Zh18~3OC1l|8)n;@1xi`m<U?IfraF8|c#@#Rv7(~^(n=1M z8A-p@N_%XN4Ob6wTr(RX2(F!F5BbYy>z~gfUC%z6BO!L%&Y!vAwPi1S-2u)V7d7QS zzb4XM-BU{@NKipu(AoseE#&djzT+gqz9+dSES6O0yp$#Ql)N}$eSllTzJQ~317Vo# zzaXch7B?nzQAOwVr_(>KjXwQ|yoIw05jzPh7uAY@^fkKp>FkRTwEb~5d-dUxz1wP5 zhA;*ZFqo^pVQZvOF?NF>GDn@&w}+yucefvXy(<)l?#*)4z|lq?Na0|}g=N6m#)zAF zDY-U`tug1iwmIucRXde(k^Z>x)AM(p7w?#9>nqAK+n^bOG+xEM(%}lMKU5VU;IZo+ zd|LL;2B>JwWT}Xg-9r6cdF#hTQ{jcmGj*I)HzV%3(aolpcRiX1HBgKF979+l($M|I zj^R71Y&@WP@>PF~{vf5kyBnZU>T-J7y-*T3i;UwP?;?D({$@Fh!Q92Wf-anF`?u4@ z?EvAPqqN`e60EPK2rQkpUo*s+6DJ}~vb+$Bvz^lf_e6-+p|{DX&v@n-qek}{<~(+O z<qE1bnkQz3FIDRTq?L+go)@e+D;Vv_OO}3q`d#eVeSTs3^^m$`r-*jOy%JyFc@D?& z?514wQIuJ<m0nL&asGL@8gOk{fs8Sc9sTKX^{MpvICBZo-(hD}MZv#Rq#stWy0r)L zY5PMh8)l}!-9Kvp<=;1rGssu&JEXANj&5$xrkfoQtEC);cROW88dpuw+a1MoWYvWO zN^pCHtKSI@*laenG90Ejj%V_r;^N~`aB%~~<ImTomL(Oi<mw9@>|YcO-{5L)qf6CJ zaH0b=B+gPBrOhzB2eMM?Z9VE3Wu47cCT(n_y>*l;yv@3Qel7(x++{LMr<N1kt_Iv* z-=+b%H5x2KhazzdFIHL1w}W2qlgw<emg2|9^B?BB`fA=+6)j=@ei|gB1)k7a?Xrr^ z>MP)&;>=3>%@MSZgxIk>g3wB=f~Z8qVoa=~h{;Y&4a??qzVut(Vb)@)BGhHaZBtY~ z0G`bbFN<ZSn;oisX=)J3p=p~hic$U^L2#q#X!|!;aITr0`nXKmLlTR)Zl?K#JrENb z>|M)D4$F9?%uThguitJ*7*qcmE&M(Q;re!{bR)aQvpjX&LY5!!pFB;7FZDI6a>8ql zXK@30sG`EM@Wd>vdCLtdmnc^hdV5idLQfHz&97;+A6Z3EFJmv2dtfUnU|X)<R?kX$ zi*+d|0=r(P3(k0)Oy`!~jIqAXc1gS0u>a*A8UbM@(j<lb?>?!--&3`F_e(>N*6dJI zPOapDwv&LU*Lf$^j}^kS^F3m$UwxYun>ZfoGLn9ZxbnJE8QGf)+fQ(^&$rR&lML&i zo`mCIB}R&gufHCK$;3m__o{||-R1KAMSG7+beMbK?<ZBouwY>YZ5TcX{KUv^&(C7A z(>*2fviV-G4`ac8Y?J7e5twI8@16^r(cI^5t9#3dd=K<{(+;t9qK;7(eS=%PlJb9D z9i%+=-WjGx`m>W(d4`uTd^c+(xZ7)V8<Mivy~6W2EiJz18g`K_RuNJjDGL(#_#3|N zLq9c2TC-D44%0%{SE}%*EUj>GxYrgW>v&?lL&48$5Yu`JT_88|X)u+|Vp*Zw{sI;X zG%n(=6gsv)jA)3Ic85+kI0mtXcjF=T<_2xcm0j-}7z|zG?Y=6AU6kE0d!>IIY8$fS zW!Jytzo#>s1sO}H?<DJb^T!g`e6ThaDxAFThLkIg68wEV_62fq#lN5I%gf1yWUS-< zG&$PtxTWo(uI>n1v|2U2AWydew?vh5umU$V>@p2W6hu}9V|}j(Mwf`+JRP>UZYCjS zpNGd?-g>T>@aSdQf-%Ilu?c*~V+6vRU>ibOdM|!AT`nP_Z8N2xMZ{NlEv8i!QmqUs zP^$_n%WUV>AB(B~8;6lYL;3YuK+D-74L3_fM07k`h_j1^`m0otyuo5gr?La*47p{6 z4|d-1YssVl{c8SQG*O|5S~1~d|2j@?Ca_A3ww~cy8auxGX)P8RS4Ij~3SiWIz(348 zb!4=O^O6d*x+m9XF_Xf*1uiFGI9+afskJ%6B+;se@pw2J?({vIBU5S~O+W4adr*V> z#zTNgD*#fS^H)PeU}npdyCiao%!sEUARsh)is&c(3+A=ZKy<j^7KgG;j_65h=Cc1d zF_T?t@j_@f9zyTVz;JH|!J&F8(DGvL{8psie3z?RRHS~)6W)!*?9KF{obfQLJmX`M zeeq2?^*^sgsKCs#=NT_3s#`tb0`*|KwVnn~GcK`Ibogjx=`T3c9cpyf<`SYcd9&-7 zcWnkM;4vM(KV`5#wYUQ&9O|;(-`Lp&!8BOK485Ydx(>Fug0Q*`#vw~QRsZ8~mmCMo zNa1F5k<l#rZ)@{U)QA-16ElzW_^F`(ANN^*z)uI<(%iYkP%~nTHQqrLsn}%4Rs^H& zPK5=+oVVOd|9d*45j^~zsHrV7aeqHDIu;~g9Cv;!>H9SV=>I1U2yUrGUs^{?&W6<f zh&SNt9~_IUixUdtgq$}*AzqTIIm}ThZ2o=wJVWbTnkQsZ(}k!=h4gf2kdT5tr%qVH z^ZyYF?yCp_S}1<MiB3s#62<cx>rRh1iL)ShJ49*Dk6Cp!9+*_ZPqXIk-}+Ko6H+5r zD2^b!_ae@o;{2_g%~J5<*p`&iV7%e)9`Zkhzt3y|)e(f^<mC8p+vJ)&8!rYA=b}H- zXz6SM2Bw>g)Q!2pz<iiMa|!ghl90>&3ytY2Jr?MPyRW_?0SDaQ?fnk~>4SDH6rUWM z8eE-R`&B3Yg{7HU>+)7j!Lp?I@i=yV_WM$#psOjgO2t}4r{*FtJzq%KBZY+2za&-_ zXmALqe4}yJkf_p&rVxK9g<9i#*!{A5_CJ_Ojs~`Q_ZeT>Ih%xr2|9=<&bomnV=lL3 zy%~mBnNGw`A%`+wb~!b|-4de^yeM5O^8T&CVn&U*jNF<aHtl~Ms2CoMG)EF+N_1Ms zq|J&6#=N+SN3L8YVvQY@5PDt+yyN7PrB++vC@t7$)o<v%LvD({Fw|z83}L}Ql(fWI z+SG|T-i=|p2qCW4d2i8tvYqpk-0lA?(Nh}CM^nf@IXe2VY-=tTnByKG24+F=*H8D( zH|sLDQ*n61Igm^pCIF3oE%?3MP5|R%&=6Y9y1*i_WX{Pnef3N4KKF=wVSaDRol^ck zmM)40jMp3xJ1eM-tE@i0WXWCTD78=VTH+8BFpL8#te~C#VxNvxwVRHNS&kukvpJBQ zskb{2`t*F1jkh-AYOW-&Pqb^X)R*-R6{{<EOj#E2_t5g=LlE?7xT_t`?%9*&-sugx zU1knj-|u|fT7s(nv@(INZ@=x<1|->>KG-Y@(`4+w=-Uy@7g3J7Un>4~JB>8-*YSRL zdV89a<#b=o6>NDaE1!R0&YF8IxeB`9t@T>cVJ^#7)0gKMn>ft&{^;HOv$0D|EZhqY z3L>VZMMS`6=Br6NqLTU7SlEl~S*+BoH5i0FUu%}d)Gn66YcQLGygyq4Y%0gzfcv6> zf!_ExS}Yl?)ETw$;;>rs#gj=>?L#fdyCuE%1``;}7Gyg)Gh=lf9HvK0u4J8hk5@M9 zzrWnC2BcoIBh;DA6+LagKXQNPI@BKscY5CX)R{5baM|i?i$b?+HI!$#FBwacAx_+v z&tWbuHJ6<mp=gY&-V_kI@Yd)B*l#Rtxqg{5nfN8dz`=p_XI8DMC*kt~5-2-6%ii0_ zVPEO9)~7PLuGeh3cdmB&L&CxY@<k$JQc_9)A2@8*1MtcpQFvV3M!w4BD*AIp()fG0 z(|mDOA2}S;&nzDmaHF3{fHzyMGUbwnwZ$8?YP-E5{nZAu;lj80Lgd@GjBE?#wc)pA z-6oqYorQ`h&i7jLHF?$JZ{*Au2ki_to80e)XVS56CDl5e*y(IG4`gkBaa!NKh@OtZ z@{J_ZpTw#rE}<B-S|OB*MS4qB+R(7Dev`&?OLvB9k<Q;amRsNGCe~sQFE7r_9m8c$ z#@bIGm9KH$@4pQU51;LY({;~!=2JblN|sB9qR%jzpw8=hzoXxuF3dqypP2Mbu4n^? z$FjFVj3?7_-EI$Gwprezl-)M>C4ZQTzmDWb>j&*>aN`5_<u8WmZEi}Y*lCXn@MWe2 zETtM2^W1NP;+(p#htgAcz1qkk^!4>QSN<4LIbF-bJo8q$1FyD`IM$hBgJZ-__C|cC z!(yq*T`A5j-g4G^I*SJ}uG#h4AX+F<VDIDo74KPtjzWpCx}kx&ycyrl?m(AzR(`#P z`@>cq`tUf)PR0A>{p0nLkRO0wC5E7&Hoo^B0E5Qd3cxssccjtndMiNPubiHK(JKD} z5L7_IWw)JQiM5O*0N^_uPLw+0FD$Sg?ww}ZAL%A?s<y=@fiFJHdW<L0h{?KqX4a7| zY>^^{VMT_qNLBqwCELp+e7+Wk>xEBG>Dkv)$$;&%&^ZQ+O~#)``v$+`l-26&y&9GM zu;&XUll_vk{UH(h&{eg3Evi~YbQNh0zU|Gcsb)mtQ77qdWNFb<EG|2X4MtOgB`lb| zx0o+Tyjx#sZ?hb@*l_qYqZ<PgEdF9RFAo>NpkE-VtQo(+z&Q2VyIrLL;SF(zjM7f4 zB!!(0UHrzHLPDUu{#1V^8NQBsi9~$!WwB5xzujm#%0e-h14eRg<@ZOCizIZOzZS$j zXyA&QUuejurIfPc<563FFTv#~02xNQ+wS$p8<;U9qpDH6XvfCF59-HysLR|lF)=Y5 zjr-32em94Lg;jbcLSt@hT!aBac|L15AD91~w5-v5K|o9_#6boBk`g-Jve{}4V`gS1 zs^#|^9!k`W-{BbP#2;o%lkCs+X&);Sm)_CA9f8Y%s;cY7g3W4qtXwYki%d2vf>yij z7=<D}1U%|JV8CZT4f|cE)BOa+YN*tlU3&7FVXet3{Uc|lqeC<rA6ki8S#u-w<Lznl z#(xCK*+|=|adLy}V5*zSsmc=P55>RW$s#bdz}wgO14mTRJ*+H&rl;qD+bZrucuHS( zxK(VPM91-lwhmgso`*RQpk_{9?$3&g2~us%qmM-`D2A@5&YQvAJXFiJ(v6lI$iF~P zF=>jyqozBFW?SE*D6ke;g~iqr%5_33)qSS-WqOl8UTg%@bv-Fa55n;WBjPzSk9FR) z?>(&XJGhpUaM+z3Tk&X#fa!SMv(T)`4PD>f3i9#!BtaqJbC)R6dmA3`eFwWtJ#5G- zZq+OrmKImOHC|DvaIH+lE{aqh?@}mLe|Wgyy4v<fGUv|nwEucIm05oK*Z-k9eEwk6 zmp__`<Kp8SGbGUEMn^o!g69+D)2VsLMZftA`cX~9MY`WkvNeWU#g#F`5Wx(`5DD7; zZaq2`Q6m6ha$I{>Qq%K6P+w`K9WSJ$6UFIERHqLW5fOp>6aIzOl`vu&>SQpmb1{}# zBT;1Oq>CA{7EZt4D(z$jEgq`7KR+}-f3=$fSnA-(-3~&&N;7dB_k4^bcT?^Bh$fq^ z==TBr;<)v?7Y%55cKiHzA2;ihy*nC4dR#HdzJTq6egCLzQZAfAXB`s^@GkGfFC*pu zi?V})tw{KD8ZCP6Q~0em=rgvtm<E=F(Et2tyw|Slz4T=l{ipni9_%LWlfws(iOAOh zti!3W@z$ES^T-t5Ya~k~n=o20cVe;@a1N+P0|LKoI`9Q7+ExHRa?aZ%r5h<bSHeAk zH-Pdno}Tf%LqR>F?yJ$=nN17-t72|ULDBE~^A$9&m%Hl`bSiTyH-xRm*UN5QQ9Ks& zgsi$l+Kt8~o$wB=rS*R8wD{5N=|KBiG+EwK>Do(Wjk)RWCjn~1Wf_ff-cpSA-GnKw z%MP?pw->X?O782{vfcg;ObTkncCv+0TM{||f$zu1ueGTb%Fsx6Nfae#ktrAi`Ec}S zN>n|?zRM+D@5)h&D)-|el=&#zxI1zJ@AIpA<4M<#k0yJPtVP?jwwr$0dbOyaU;9yR zZT9Uhmm<Sac!_Q9k(zO1;%gZL(tVPVl)CU|NaK0J;XVGpE9$3at@a!10gX+h0?a$P zNs+XytSa%OQCYJypMNH~gso%l7iqYX!7Tk&k;d-wL54SN$#wKL3!gl|{r$VJOP2LU z8%G|))Sn10oa8LsFy_kk_|4H^y`k~iS*^lJva=h4+PK-gZXZrI5e1(?YdZY-XYuoL za`-H`30${9t(+%K(HDZPh#|9qFQr+s6O5N#uhv?&y%13fn;w@uS2-SssU{8T%}mw< z;RHOu0psbc3$byy#qgr_hRY*jbjOb}f?LB8UO@y;<vwwHMMXt^0gYyB?aWWJ;>;p( zdMN1>KqlL?tmuz-!AiPUbSM>ey_q~=ILFiZQGWMO8tJ|j=b_NhP|z)!J+;k0nXeE) zF_i6<>g8u<+STjHp*L5h%{5Fo<+9~f%rd#r?y}_MJk`J8v9r$F)$BRl@(pa<nB&|( zLz92_Wp*Ia?#a`1qsL{E)Bf~L=GrUA;o&G+&FF06MZtkTLLI;>*c86%l*O}<>11n7 zx3+gq<qnLP=9P3H2f{t=t+YCr1TXLjf8$IhfBehu8Nj@0UU1Y;y(|`M@F6qQAKF_y zCm{>)9;UQD)k>5jq?F|0VCR|)T=ePF?te$hz_5DUB@CJBORFXLPQrN)cO<UaQfy)N zHsa*&rJCeeY2|2;6+j1nd_VxE)`FzMBtCY;%s1e?+6xI2NL5pRTc-lhZrRTJd?&yT zPy+UO1?_ag>7UAKE+mcjs=J%F`K%e<1a^Np_YmHNG-75o{#NyD<wWBU?t%_8^FcJp z3Vpcd*Gdyw7Z3Eoi8O|=@;q2jMJY>A={+scZf{CrKuh43dM06QYLelxJeH%uIaj#h z^iF?X6U!4am@SsIK`+j$+X#N8o}|?F-DPxKpKBom$m+Jg^l!O&r0tdWkwz<gj&r=M zto`otIzUyr4myY(?!3E^JYH-}KLo4pdMJxK31?2$f5@o1d%>yRV{QC}R>_a=eoQ3y z0XVBDLm+c4bLZCw#rUD-GfSuYT%y%6vZM-H2rj1@6^UIvGLulM$Z~C9GEZfWo+>~U zXll+=Nni-;@^zk@<FHpaL5m~q$KfzHJeDJR^lJT3B#uR7d9j<}S2@ZCCRx~JQpRK* z_tJbk8qKEpa?4tHbDKzq2NQQxQ<5hI<l=2fMWr<ETZlqKZhRF{CV{ldxEQreE^oBp z=Z@Fk?e0I1osFpY>rIk|WdwIeIT@#*2t0il42QOj8^hGgRVp3TgS2M$cmE*ef|a4@ zlNtg({Z#7d@K9#H*;%5hPU-E(dHr;QItZpx-Y;!=uNK=0i|Wpxv+8c0_^(art1jj3 z`*D)CAJ0b?bb?ozb|laH{27^eqnzT+3khLgARRqNOG3*fTHKNrK_Q|LXVt~cg{Ni7 zYu?1g#C{!aP9%GU9*$MGNJxYYrR~R(M9m}CXU{Zja1tbbv(pO#kMT;g`iae}8b|ap z$DR6I_v1`2qBLmK{~1je)$q(ifAxHw6;%&$wgwO@H2Wj_vdgaG%bAS97*L>(Q`w6x z>QI}>Ev=r-sb~ctPIWfye4EZ^xs1pu>txd6;Bj(v&dmcrOWx{!xLC7*4}q%WYk}pM zQwhi&6`cCBZ3_bFcEVM2I>L9`N8!1-r1HE?$~1rNFvwUeoJc#3h8VB0UBOnJDIbj9 zvZD3u>vcT3{Ne5YgkuEsr>6Qv#|*h6=U-<rkNdPN5@OrrK|MNL#R1q}y59*)(FuXn zZ(VM(B|DT#i!7mj%>~BL381cR-+^W#W2;3>Tu5HO`jw`jyRb}IeS;@xgr41$){Mnp zK|i_^=d-orl`!zz(Nys1y!Gypl??w?qN#fq0w*Bvj0i^ZhO6APU>=5#hlZjN7ey2P zF|eNPh2o$Ln1^$WYr&)3-&GRW=J>AJ^}MM0!WPxtY5ZNAc3{kk{DijSN<cbfgnU!A zj_Ls6CYU?{qq;0g%WpV8ny0KD79PHj;~lC+OVaNKwm9`58FjTR>4LU1(=!Rl$RqRp zMD*xf)~&b=Z~PmRbHy$KfnEtVvuQ=kK)HlWu_Y=VUM_m@kN7eCv6kvm2ratqbH;&E z(BR?(R;SCZ&X*6hd1;t#iB`v+#@1>`fiJuG3G3^)l^n1t*bK0rL)V-s!8gsEQA*1f zy{W}#p49G;4YEy~yi%}pq($KA0FZObH#@?dEFY4c9E^mhlTxCeA7778OxrB0+-$^R z>$_(vVk*AP8Zq;J9WhfFg_5y9Ixq1mtn5%OA7KCeChfi$k6nmk(}9w#3v7Kj4A$Fd zb4s)9db=6d&=jYk-m~3-G!Z49_K(80HWx2#y%AC<#bZj-TYN4`x1J5hLm3V`?Kcq= z6_AlGrXDsC=(BRFvaJu&tQMa-hR@w)d4;}QA(*)3UbTIod9aDY-|gv`<b!@~wnP8p zf72Q2bc$?Qr3b}1@p)oYP(NE*Kw!#d5aW9k1y9eHp&~&B+-Dk6)o#D^9|_wJcxDEY zTkw*W77@fNr9Ji)*jcAP*VJnX?n(nIxL!$X8K)D|OlX&dA{$N~r!JL*FVjZ1GBy@g zOsB-xpMk$nNaB?K`2P~hJi*Zew)fe}+%41f(~nZ3;{2kNEdgGFI3=4?{hL43)0T>; z#|F>)OUomtcQJ+Qjpn!wX`mKU$_Z?|6pNk+79nwkB~hG?_L~22t^J$GEzY<$WXn{* zvvpj<Z1mKc6Q(E0+IGe!)YbTT>65u4^C_E6;G&gAj!r`NqFU0v<zOGnir6_5_(ocQ zY4`G``tsX?XT_$j&&wz%bVzA*5W~ab&;sI+uajY|d$2~TYOGRzE_8`966L59?&Eh3 z&6=xA!I0nXST9axfs7|I2a08a&=FQ4LzEB9PW^~`+1D1e*Lo<YSdrD8V$UA1#62!m z+ON(ndr@oGf9R4q4Ia$!{gSS#3>h62mC|J$67S2g;agS3E(Q6P*Q0h>bhC=TWL2W_ zW}i53j}63;{4CG&Kzs_vEnD-bP0P*@iCFI1h$t4H7NoXo>>*_WUjNt25>0a!<H<Pt zrR`o!5=DdpMT|U1_lcD1O8K&jG^gFiL|or5?wGos47-U^0;v<m)E>8H2NI0a?%sDZ zq8gh=^~9eH{)h`IrLz%gY&RsgnN-PuNoP3a9ag|<0Pac36IJ8qNw2@z>99d(6+0I= z9(87Va{2tDn+%?US5HFGV0^y&(sVQYHw!JlAuE&Pl9_yvv0!nc6hCsSqUSwfRDRT9 zHv-b^O?I^D7+jlK*RX!5Q36@>=8)jTfpo{i;G_T_q`tohS%%36bX-P!%QsPC0sf3z z5Q;lSM6MQ=sL=7-iBzV>R{B8O#b_%w(h=<Gjm8<dI8S#)g1GPIai-J2DUKr_4MmcM zcIrK$+u~40aqgpB;PXLpo4awtII^xyR<=XCDWpVSA8`C_+2qOdB!q5@O|~z^0oZW_ z73fA!_khrqU6IcK<(xRQ5`BrA=|-p37&(yO^!j|1&4N<Mx*4O42v3hNS(hnYA4xXX zI#IT%c{Xvg0%ZDjkkMS+##B}Qz<Jc`Av-;-?8ys<>e$6rp(}iEn;85A^ViKv1~1<k z>4(a-rr-tDBWi<;m0h5)tsLPjQ+<P(jpNT$r{MCIg#%G){0~G2pR|EAM%XR8@_S4u z{}n_g`jaM00-QX}hyDZUcKzug7W1(_gSWSP&jA-s%p+&%02)KKS*6XDIY58=-1w1! z;$i#uE8&--z$b?p$aCI=P=Rcar_yZn?x#A?g`3iI7vU4GSdFiKL8B-KFlFT<W7BL6 z7y_};72MO$ZQ`_><V0Yksdx(>eBWUzUx9BYq8nRu9kwz4m~xBHzuPYvo|8u<f}&M0 zyxGhgw#!hJzL0x&!`;9&NC~Ttq<o~=o~7DFHyV0yRNo@7NXKnKjKwF6M!=hm6`zZE z1DPm3BXOT|U^vN4;-v5^pro_RI3y%j{rm)mUBbUWla|5fqZ2@VgN4(k#wjn4>k3Pj z+fn5tZ}e>PEz8sDp<pDQpUE8?mUEG?C5s21RW>K8m}C+MnB)7CH3v#qaZ61<a}r0s zSl;+wl$n83XeMHPRTEjRI4Ld7RmYuXHeo49(LgnCiug5700QgtMr6osli@&qO(rdD zM>Q4?#=N%oCU`d0op+Pb&(rBRKf#l$gE0lgLhZ)$@w7Lk?%Kij6wl|j_atC{x$t~@ zWO#Qx<NiTSUVclWqCJHyELfI82aqAX@N6x^o_bSA5Q*@Ee#IH(VM+Tc_N1R%etw%T z68QykUO{nOjN9$<ykl^sfawd#qNAtrq6ga2#tOF~+V3(e+!!o&+Z<L!vYDd8M1PbF zH0yONlZ+k0s-fu^aR*&(6N^k~&5h1*^o0#&kIb`^i(3a7lg{cA{KXb~8t9BLXj|&! zqik;-BxrfPT`%D(`FEioA07zCQ|bZX(>!M(#}KE@y}DlAWoveNDgG_gs#T7bJi@Jk z*h*vMxD*-8W^q}o3PkeCiMO?ZB)M*?q|9eNP2t_c0TA8#X8F{=gg@^fbM(96W@wr` zxh!*gDR^t30kZ0d*-4!VBCIkfqk?J-MpUe-^Lm%S*>U^pYefw$mdw%#(JF9InzP5_ zP3iF??~mtVjhYE-X_I%Jso6Py;>Jd0w#G)%XMQL4q~6|Va#5br`utWK@5YUYTF?3< z{*}li9hKG@Y#r^T1kpC<i@c(Pjp|7Y%IKTst(6r^BiL@y1;-!^8cikj`g5(Ic8{@0 z5oc2Vk8S@)r+H25R%Il{5<StDcJ8wA>@DM}<Xr`2Y*bvIFJ|a;KlpxKcHAO<*JD!! zpW_`4&-A}V^ZtV$3QgKMA$}aNJg}o?!A$c%&u)zSihAb<<UtCD=1rx=2gHD45^je) z<HbXXcF`h=!*`xyQ+SJ+-KE+06YjPjFpZsuzMB1R(id=Cr88n_wk{v=Yy<HC*Yowa zUZyAw#klVu$O=r7Oacbm=C`&}vIY6Aw4vO!-$Naoi?~g^k34Kn`<W|{nk{z1elb($ za4>q;gwoW~r`aF9b#@*df4yb6Fyu^2tjn&8R$^J7_rEvN8OT6;59NR$=lp|31<hH~ z>Efr$m?g^f=8Ml-A)3Ost(9*0<rXggMaw%z*R@A|qiq_sv5m&IoyNB9WXHDc#zte? zb{gAuV`GOm=RV_o?>TLsk9U8`9^;?6rhZdv&$TQGaqA%2-nG8r9PBR+fuYw&XYQ+W zs=~D(>@9h$a0QfBf8X>;;5?`}i#V@nhh_wA$~hQp8jt!!Y7AQq<Y_7iw&!R@1C>?+ zeQ0mGo!7Wccg`%|5Oq$z`85mvaoEtZd>LTelXtk7<R&Y!*3OEu<DDLK-<j-lo7UJO zp-udT%$z)Qi((~9nRK<u>}~E^P^KSJ;`t>$NeK8rSm1@&^F45u%IF6QLNM8eN0r(Z zAQiljJDHHH3k@vTiCi5s99BysM_bdfuWz2;0hlqZiF$&DP<b^rFn&5rwP*x=i458% z;KM*9wMO2XSJdsvK@(9|rRbFJNZfl@+#I<+oVFf6x}m@UYjG*dyEuH}5)_+)hHE>S zHJ&%cI`|7tj14Wi#q+_Y{FiPT`6pGlfvsg+=XKlQ#KIDZ+7qd`2P#ReqM`h|6o|@5 z-W_bX!Go!9wsC}JZ4?<#2^AYHpCXSI93c(PD1`JPpRn6s#yQnX`;@%MBVvo}9Ca%K z0H7Ssu9I0P%k^*g%S`6K7%;)4X*w9p=c(GiQHI7GDyHuUbthl*LgMRu8TV)WRx$#; z=5obf^*Z|<14OJGu2KtVA4A5GN<g3P$A0iC=VIh}_~27sI$MLp06PZHzHE@r=^ezV zL-VcIE;))Qx?zjR2pcS?nRw{QAey_tb_<f4IbRb#lomwFm7Srd&iGcbqE2E)Lw_Kt zhfQCXI$G7;&ca#f_J^!AHN^o+OqXoh2!kr>XXmg-ITI{Xn&H=PH3Lp+w%3XfK?o9G zK!}d9@i*;rfsCIiE_FFe5yu&dw02CfS9)XYzJLj1ogD({%PCEms>&EwMtGz=A_##- z8O8ZTG#;q4&>B0*O@mh_6_$Pe;oJy1cZ^@OknuyAFALRhL%CLjkXYx_KropHMV=~L zSELgsy!yMb@96Iojz0tywzQhlu5>#`S&{%NegRWj7-(kbbi7I*Xzb=}IGk_k%=V}t zAwecL;AnFCHejqZn^MEwE`gr(XM@G6t(SP7sxx5V50oR+w5n;$awwI+3?jLFk~w&# z^_h(&lrxQh6v{6MNs16LUjdDQ>7N#BEWj8%Q7$9op(;QNv+eEct-4}|lDB72%8!D2 zEAc-;*aLpJj<7vYB4S1Dsdkvcd`q1du96{{zRr+fzsdwU$x%K_YtnsIkZ8#fYO9GI znGp0+BxDNXVCZ;&1j&To#HTl^<*IKv^M{M-0~oc)ET|8;nPk~Fz+N+bKOwhv*2^n; zE_Y0RqPU(78}&S`o7ak(JCK<ka&06kIWJkGdf;Z{^0`7Nzd6I8|3=9hwnjyy;aP8+ zg>=a{?q>NMHJE}eU5Qp`xM4@b@GWxAXdhqYbMI@IpyDnWmwkd7;tWjKs@#);irJN^ zyA<LsjF^#{D*)HrA^xeEa8{L`cKq`$zvb6%1BgOC@vRJ!x>apI+vou~NaE(aA>t&X zf~qkTc`*k~AXe<K3lSz!-ibrI`~CcF?R@tpUu<tL)i=ZKrfZW2%f__=752Ql7<XP6 z6`XX-SIP345osyC=lmq?X`<-Mr6`1wTm`zfyA|u(d0OmlBXwBp)n3o<v#2bZ(y38- z<D+Z2eAd*_8vQPIRHZqOlTjIaa<yV2H5`ChvcV9xV<9BNSc{ITRoLLX$nnhrYl??n zISN2Y5x?<9wiKuB{`HSi0Gk-?5O@~nSW8hL$x_bs&9eh2ns+js6lPNmPNQHB;pgpZ zx~P}vi71VX?-x@s*q2MVv<DTIC+B6Y7`wXei}x@j7FeMyE5bQr2a|kb<fN{9^`*`w zInHA%EVVjU8eOk~Im37#t~(e;71n?_wzp9=;~u!ruiq_dUNbZCMz);8{3R3$B&U=P ze9-Ps_xPYQTHSu}0SVs`3k%vtTtvd}zbm-vbeo^txNB{(T!Rxl!x)o}9-SA!=3uds zvzjAL5_x+<g{9UTb+?>SWVd-D8msQ74@!vdPMrAM0lMTC3c{>I)q&uqIf+zG0CYzU z$<y|?wfdQr+<D|Isa>`|2LvZ9xHL1JC4lv<=hWk?q#9M{!irN~K3HAyBSgR}FH_}G z(jL>2;(F0f$9jg?FHa5}f>Kg{BV*zqM1YCjkcle96koLcmR<6aMRNO$vuC}YOm9#h zs2>)qbm&yVjPXl^Jt#3aFi;4VT}s5}GFY+SmhBSN{05)cUN*{es~@f2+0Zb4Sx&d8 zcXtsp$s_Pf1s}0Nb-R*fEwi=rf>23$-OVm0wRPu9gTRl1&n2;A<b*F+ec!KO;5ag2 zP%ECLl3Q7ngF74Q+FIN@W1S1UoCUqo8qTKEbe&D-`plWzq5;UEN9xS-J>yFPpNmv< zJRJjx{6A1>)boG-J_YD+$|F45KH;YZ1rzjI1%gb<nUW6W%oo@28jb^1_A_yYTAXuP z&B*B#6h<uBMj^k<G+*D7$b?>>6WTEFcE;sf5@pSfE4cGBoQ!8sojNY?T%v)3ew=`O zzIk!EIb`j!%uAW^?g#Uyb;Qz^`%o^;7U}<~a2wPY3C1_<v6J;SKVrOGTvT4HtLbc@ z-ygzU`l5XKhoArJY+_6v&(kQQ2$@s*$fiEW$byAnD{AE0_{?tCg*>y3G#IQHEDk$( z0vcC3POqq9v#>ZseWtKcJi)lD(p~21)?LIonS^3X>sbrbElPB;^o)u1vEXVDELH)v za&pjcr|pJEZd~gX?>rm*8?{CQy8Q-WFcIR80o`eIzv)yH56CAAZEm*IdssZLH0|o} z)c9^RtvumRQ76dClXb!ZX0pyF+&)g_X=?tf+HnC+N^xbbvrHoLBho|t&Sju;8QxOn z8^!86&J)piSgCF;kH4zU?QQy(;iLthSL;s&%S!DtOqFHQfn%Fo_5e>{t|+6Wa|KD` zf>v6e&OciQ;J$=Lxw%9AN|*qd=-KR+Fmf-yuFgQdxyR1RtW>OWs^nBw>mZ3B&7Asz zAS6xuu{k!Kaszs8H3++W_tw%Pt{{zQLffy+hqKlG+Ic?*YsY*D>62cjOIIm?&n_+c z{n3~d<%i~#9VOv=kKAtsq33Xb4;x2U385?*=JIOfb^qsG0B>QL3CxA>y%~SlbW3R{ zOa+pC!WzpM)@EftrR}^K&RUduyi7T+qwVJ)=w?-SG-W<njL=;4>%_8e!ShmU6(<@U z5viUcQn1Y3OwRQj&ad-qcAnb=n`b~<qKRb1))H>1$}wy`l`T@gtk#AMNXPe@`l@Oh zka(R16cDQsFKdqcUg+zax~wguDw_O%m)N-wHhV-32BW6@Z-{(}^afB$Hg-kpnP<xz z*K-my+MJn_t+!S7M}3WPnY&}+_YdBl9P``a3mf1Z_f~<eVH#Rq@e98^D&+P%tYu#2 zjXF-~YSGI0EF_Va>lKYV=bk5vkF*;A+zhqX$Ovb<Re?@w81GHhzn0?I@O4?8PtF_O z0bZy$w7Ot9fQS#7{sB^P_U$c_B9;+dWzC~+m+}A!>f;l%8mnVYVy#J`vTCOhM8nxC zOv%|u>2f*XeprjKlA6=W;JD(2E!Q35Ymrr^ugm|p-P3g`u(|20Sih+eG6>Sl2DKB4 z1S-w)&x*{OaGIFp*rjzmtr4y_sHPRaLAkI`r&Kxo0tT;ST5dz|kdK;ZXvtQtt>RYf zGmUmNZs}ajg<J=FGDC42&dt;=rP;stT8bz@h>EDy>+h1K!V}A@UADM(OHju9e_#5E z-tU+P9H1fVADsw6LSBiSTj9VXBKzngDp?Ov3>9<K*k99|ugfEsJU?cve<tew-?pC! zHm6n>z90<kHhZ>wRX*K#=zq|e)fXw{-xkNRwc^etZBCSSm^+-UpGswb-5FOh<H6#^ zppV%?w=q`vTBPi=r~a3V@^`%)byQSc-rmZUUa$yXliXIB0@Xd(9!dKK=auh=L_^B+ z8=N48vpYMbQ<HSEm8-`FDm)>oyk?|Nma@W>rH*%wx=je#$R?HUwn_ioX?sUq7~!V9 zRJ0ed^$W*VkuI5HTyo>tqQBJ2y{`AsS3@%SRF#%KhwL#O%kNlz9Q0GB$=Jb<VwY8F z%KIE8AjC0$+m!1Pi}V>=A<wUn#Xq!A<dws#=;@dFn|AL`f(8LFm>K0rX#Ulx{F{qk zH;?TdIES!XF~!FJvLOZuQb+}&U3um{Oh5#K_BR%6R*=7>#7)MM-B!QE`~5H8bB6pi z=c%%f<A6r<`d2P~UA6*UXbhycO}^A%f2=qC^T$P)Z$Hm%K;+wB7y6<ILB7dH6E4cf z|Lx*FCZGZTztMJFut(*K$^Bg|9|%yvxTBBQpAr9RyAH_3s9T=mjt(bW&G%1*(d+B0 zsHiBPrY82$LS=M;R9cSJS_>HkMbAIGR90&oC#%g0cu)7|v`LAqXII<=IWB(z9X{kN zI;h29NdXTJ4;eYR@7Kca?rziRyilI^3J|rsYe+;){FRFfTTf4Kuf+E8u<-b4bW{?X z%LRU=(Rz^g?fIXzEWp*Ud7O1~fF0rAa4nmQaM4`w-asS(A)>_yi>Obh^PyUt&!e19 zm%kDd=VO1Bl93Ss04VOx*1|oX?)3gyP=bb@-DPHBLA|`Z3<(Y8=i~Fq^)fRvTWqo= zM5R^_V7K4b9ZO}7qHF#;mX{#08Dp1ogrK;dFM3T^n_>tu`7!gk-S14Le!W|&%In4L zWU=~FtMmE5R&Q|q{M;AfF;_7~GZ0DpP2;gtGir;Sfyny11lwY>3|4F0OxJx3LqkK= zxRLt5?xVs8ZYHNZX}fF%{_{4I25TV1F>6_G*^+&g2hfgta27?H39eu#rJ#+gNN=y& z;ZPn&IFdpP5DbemS*k)SrTKJw99*nWs6P;a!9gt*@y9;w|2Rq#G-~LmBi(vgb&Qvq zf}%^uoOP!=7`K0SC=LfSL0#S+-A>%j3>L|FoC#~+(aVcRxl%iFDp$nd;bQCIdV-fZ z#d4`8UwC6zi4iYw_OD59Guc$0{hq1XilBy}*2Za~;-ThgX_3>JV$(z+uSOI}!g&%a z2LQtwP6P%9<}2dl)Id_kghfK1FGiOUY9ggE#XO_Zcz3J1t0u=O+4S{jZjB_aGyRWn z*qr6lz1;5qNy8Q43c)Mnwq*qh6w0wad8q<|lEEsKH6_avp_=GP+<jw$I^Wq;3M2+5 zSHF4xq!t%xqDEaa*NT?ap#JCgdCJYGP?EV0eQUC-FJTB<3IVNW=uzoE1^WrYO(%}4 z_20oMoW<j5GbM!Piz&Y^G^3aL*kHAWnZfBSEGil@PDn{9k=1Nh^*%mVbH%l#)H0t{ z<J%_;&CHI>&V83O$Dy<zt7#|iEZI{mkVaJb!(;$lkfp%jD!NljY-P|n8HAbbSP+PX zi`&Z?n5#e-ECv%j%SWdAR`O8F1Rua-LD&crM&Oepu38{O8~A4OcSVJktYL0uPPiAW z!JKm~xZFun$c~bpijb18Qbg&_>#n4TNJzE|TFyU2qH)>oSM6_)y3%J_bh|-zcXyKs zm>{FD3ZWPq6HE|U?OBX2CFMs^0!v5aW=6QAFfy-<uoY+(RMy?&=9N17qTDC!y2)i+ z1w};6Yc?7zH3kV3E3S}u|4cNF2+2uz?9*QwzIL&K2KKu`-i6Ee&B)kCz5ty{l>rJb z9?#VTFD54wD|x`ktZ0}YUi4&S<AI&lbg(EVAlFy(I7qR><wi|c6;rUdT=BkxkIsA- zdvMuBeQ+IN2BnD!rMXkDwla!V^a5jM+S-}gU@pBuFii)U?*A+-9eEteh)`3`sEL&_ zD**H-*mj^j(_QydQZHh=QfdHmC4n-$FUbE)zC)@TxsD{KJ|90_43TEx6A<(mC<kRT z;2t}@0uOdhYA1xl7!p`+uakX=C*#M2@<=3;eVjKuRgjD%kOzr(>^}HJ^(|^7v=V;$ zPZG&S_D!?y0LJ&{kTkZFEWDU<tQOB}Thm{GqoqDP0>J@s>o#v3zpx#fTkZ!RBh(%U zZ?(!s9;A?F3G$gOG1l>_eIu1Fc{rpGevKgPWo6IE=ccMPO{|oVubt4_a5|sOK4sY* zC;Rz<?2@ZvW~4>kSK|46O#y>UdtmTLz^IZ3FZJG2+1Voyd(XM4+0$i70r9Dw3)=25 ztZNQPN3+GBtc(QE(9jAe_SfNgPm5ny-HyxMh;_%ch}jv{$0vB6pmn@}#Lv&q4r*MC z>4&Z)Vs(f@JA)n=!Mo#Z>uLU%q7`c1k5g08QD$X8I`34PXl!;w7%Y}q+lSzl%Lpu1 z*z@-L%sWO`#`fD~B08_p7311N7DQGBo|S<*s)^bBsw&yw+KK_g<y}&fztp)9zVFrn z3@g-v$=(Dlf;zr*%$*LN1CnLq4@%}L3&xTHR<_`nftf)hdhI9&WQyWq{oJ#ivKr7W zb1lj#k5R%-a+uEvO685?%9#XiX`}XB0D(8)0Und(vLdxzd@jj+;->BoICb!Xo$|Et zUPo~)?5E>W$e-K+`ms&&Ai@L*@$msae~LceF6aOpHwiS|PwP`}`UeM(=X|l40eNB+ zLl*wvFicDOY7Ruk%64LY!q>V0T@2w^r#U4Rv+|P~qme4tYh#=&qNrd_6PViliHEkv zM_Vxc`4u*Eb^EcFDsCCB%Yb<RjarSM^^aa^_addeBJh>Ia>p{DMy1s24dY(Sq{cbM zV8G>a{DhNzHF=P2rTV`feX_BDubQ)p^zt9?O*zH-;q*OLp=LJoGTgft4#|740Q$Zr zcyRe)wg&@_*EfonJ7PgOUds0>c|QOWT5x1VyH9G#dUK1Gg`9Zc^DhvM?Wltw-P7v{ zec>ZH9=t+hrCA6MLJorm12o-*w72g26{rk(4Xfy5`+I)f>BFYo8vChQGfU8Hc#PJ0 z{j+%M%b91Kuz1xYM=qM^ZhKoTOC7;mFIWTI;|PI`bzk!htzeG@g!)SB8+MnS>sNGp z;7hWB4#l9rNe%wSFGl*K_R{LTsjUY?1Aeux&o2E!vB*1e6e7IkIAgTK{R3qi2{}_} zfyCk{#iJgLh7${hP7>o>Mu-+!!NbkPFamBlLVZhYwRfk(C#*V`^g3K&*6o1&a>cC! zB|~dMIfX%B?k5OX#RR!sQTnY9ym%)=*ZiH|p*=i2@ifsC(CWP&@p|qm_^ZSEI;7Wj z-di8rUKm!>ntrY#9HL^v?rjzpqD%*(uCX-Mg;WtM2>}tm{o$!BSJ~31el#83#VS3w zsN)vLW9%si7|ejzmnVPFr_#!f>D@@P<iyioD~*-oJB=G&y%W4|C!!+M=X*&yQ7o3r zo6)?lldnYH1(`p7{Ak(^qjX?n?sy*<=XR5gyO~<^=Ur!u<f2Ypc^-cemcQhuT*Z?s zFs0;?+qApgeospaZ?-=Gd^4x$0=8(H0{X*HT0E&%N~*b!%W5ZUO=N63D8`DsAGRR! z^7HjZ5~)d`{`E`-Up--Vz;pby&Bmt#LJOdv$MrDjVjV9Ue|6+k#{~W=I{|WK8{OxX zH%p-6=j5+3dXRNkK5DW*MfQJCAvd9xQ(f*(bAxE#`HtQuGdOWE+$E5+uO7I1eDnCG zv32xRDR|X0aXD>LYLiWd?3i}n*Ze6s=U`yra^)4NuwpJOL<jp3+A=s|4-0<!T)yt< zNR4W==rt*u?Zw*TdLDwUt+zKjfE7l8q;9L80EOQntnBB`)~Catl|dy>lnOdKH-L`E z0U0y7URl~aB&U5U1%K3(pX3}7e4VmPkcYk*%_Fm(Ec3?FGtb3pi)s`d$AMN->*EIo z`e!5Gig37GF0x5dh{}mld;!Gy+(55ic!{B((U|%Y>a_(2&JAL!T*}lR7NixzQF8NH zrr8iBN*Po6W7!b9T(9@drU%)^iRR!H9@89VXYI6)&en!I)Dg51d1HUx9xoW|4JWu+ znGQzb*zQEK5)cv!(5^E%{F3Efh;#j?jZDSwd@Pv;rL<pqFICcUd)A#VsF7H#!uMxu zjxS5vsc4<AkH;-su>wKu*W;W``>E!2Bnh|64VGynMMQ~`0=35TF__Y+61CWwkyu<V zRV+%zT!6s$T&s;E$ROUfgu5?Pe)OKSD$#y0n7Q(t*3CFzj$;(q4@kNX|Ldu_B2175 zqIB<Tu#n6rOyNj1{}cH!1>t#l$tMR4FNM6SB1NB@NYf}^744wf6=H%}QYg+Oss7|j zFFE^mP0{2ALul7$IcQN?|2yY)UsmM~|KN4iu+`yRJ<AjsI(40EDl4l~>sz7j)ac8f z=GQhw>DIR!E*4J+%Z&MZ9H)9*YmSJ*9WB`E!J}*waJ{cXrQcnQA$Gl=px4zD@EUo& z!KMpnL<~y@LQ0XMi&hiR-|kG3YoqP*X$dr-`}UIVgjV`&9uCg?r-!n3uF0`vKO3p` z>$<E!fW%F{4R?#Xw_>_Oy*CKkST?}JTLeYTkaX^mi{nMx<n~$?@K%?zC9itT!Hv{h z6h0J{X-DYJpUAUttDz|h2L|EuWQ7K6tJZUJs2i+#^pD!E?BI13xlHB2#l~$k58$n} zc<I3S*+&ELRyV5=<j1YC$+xf(`YHp0Z{H(v!b$aRR2Zw|?Dd(YDu>vcTpyNxC1d-> zwujU0mq%X?u2Uek*N}8~cDpt;bsKv)uB?c9yn<=Y6M}~q7I0KSiyj4U5nA^)Q|HLm zd1H8Cw<{i^Nod)Saxp*BU}rWV*Dp8ny~ML2Q$4^}zA2&kLpbt@i*r9zKEo4cy&!Nt zW9t73!K!+$=wGbXV2(2DY=J7?IryP`pe!mbDSVm^=JIx#ba_0^plujtm+tv(3ivv4 zX}a(s7>)KS=^0Ihmk9?#)8pH)(9L#`rf)h0vo#|Cf+ZljGE18;biciv0KBL<_oHeY zyU>9mZxfWd@XZ1g@f3D46iK;wR)p!B;p}IN66B<Oyl=F__3TogZwbWu<rd*nOXZQo z8HQXFg()$zGj}t&bZ#JNyCT+Kn|_Q_tIijZBBFXk{gi?_&G5mL%vagd>CeFiV}RpG z{bV15@5f?3PbGB*J!CJaj7Bs_PEL-_U>HJ@r`eyRK6SY>c<eCiHy!P2Q%%SL5P$D* zBi~0az4P_<rn8pgi%9{ve;$J2@R%!6asloo)eFa78?-u|mWYwQ90tMRMM==MD<Wye zYK*h)`H2!WY33asS9Z>?9NXBEb08`-gqv_68sWaDexjmT<hXb{X6;mvT5cwT0@MWb zNvh;)RWbF@`wq`1hi0M;BA}$i^?qTdo4C1IF$#%U13=T!_uucVECKtd@lC~{xE?3Y zTkROX$Oxmf+n#WJ5ph!I6kxMFPJ6L|098Fv2-^bPDgqOWwv~cbs2g4Ttks0G5#<K@ zRKDLq5$&5Wlv_q14lg!1eQttZfBRw9=>e~A^gL<vdvR`WXDTfPptZ3dxF8gqNA7Z+ z@_8|#aF?9IYt}1*+;`-1zH}!hO17@!%uJIt8y9tIbP+W;^Ao1t;KSSIPJJ-K>@LVE z<2Ffp<0E}UEv@^u<q+<U>ly@AGbjsAnEA40KPOzLU*r-`h%AHMf{hTLCbx6KxTObY zVB@Z4^GMGNKqPYQU}w73n*YZ7y2@b>^Es}hAR)z~$W~E9@^0}4L3phZ93zA;Jp8Qt z;&|rrnG?!JG_bYb#k?3~7}&hDJ*9JcV!MA<dD+u$ue4DascdpD(#!F2u}%X8TNZ6i zV{bcmL3n#-75xVL6*4G&0TPN=Em%{bk|IN3@^SlPi25t4vGs<}h1k=@>!eo^r#+QZ z)v)iFP4D&nkDcwe?I4KPzV&S3U+y!#O>AW4Wr}ZXOk}A+B4^$>YV@Bjhm-EN$3MYs zz2QDX1`D)oRm+HM=74u@ms=W%VXJ&}oa8d4!NmgNPKy&v-gZY{b{R?09ebCqHdeC1 z*z*8kTU)h*Kt+U~E_MdJH+}9sCS#`Oz+AteiK)lD=BlF~YPO@5jIn;;v`g|kusj;2 zHvQ$aTV!5ea_;1~f7B5;+}9}d@S#3g9%<~PiK41;T#fz2k|X*OI_00O4}ZSt=zy@@ z8J&a{8JI6bpbxs@E0U|O#*7v%59}7$&rCJPje*f&2Lc7<<6#vma7sBtJAP0!le>}2 z!m;8U0#`Ruhj@rg04ev|qx>O__ZaDBFMkh)>Ab1$OaR6d*7M@XUHxyfv9ZWkUgPQP z91&aIuf-hs1eK@D^)pWm(-w)K3F>P5dROo8$5cbSp{#6^k5fU^Mm*WwHO$DWuNYro zn#gBoToFPXj&v}iki6DS6u365fF5O$PG^&glhxO&>&4-4n0y+Fg;ro3v$P#05StH7 zO&>{c|5t6|0BNXF4M5J**GbeWYb4eQk+bdyzF(*2UdIlEinF|sIrHbKPuwZBg_^_f zNbOH(MY|sK^fjt~%#o3IJuPTeS7MI#!<o749hTqD{z9(Gh%nRWHo4wZDoXrPs%|Y} z3tXY|oaW->XU+s`rS~2e&Qp-39q%5$h1kSHDhM#!n+4=6XuCtj&F7KZ@9P^{Bu6f_ z`o$nCwSxz(-+fdt%9OaOl|xUBP#%k$Eh!=v-ME1$sN_1C+*RAbmGU^au{wupFqjUP z+059OfnTviKl41JZUbf^pwAP^r3F2aW(9iHzYQ$Jq44J?){^0vlSKBb=bN3N=gQuJ z8x$VwXU#%*8YJ$FRD0{GG`OK%-5c~z=;$3KYI3rVZ$usPjw;(XCj=V%e$l9ti4+Q0 z%qm_9a>3ignnUSz18&pa(%>pzQ#eb%!D1oN_60_=9sOVf>|9T=KFGAaZdsft`hN`! zX4PFLHK<-6{(jw{zaQba>2SS$L;Y~jMML#q2?k3ZA#UfSFObTc^KBKrzRfb3-iUZQ zq>v$Nt<3`uWSd}^slEkO<aKD{8HYzp^{!)|76^^RqPP)pE|ub~FECFP@E~NMFmGWo znqIDQJ+{TD5>B#*j3eKtNd2u8Huc5sEAeA7igz8mO>GsATc@IxP+Vb8yW`vwOJX7b zl5hxT%u8(EltaQ!Xj|;;u(E;?N`h&`tHJCexG>u0mU`h<WzZTzwE>2{inMUwWAg=h zmA@noAe6v@C}Wn0fp#2*+h)_JgXE)=6OkJf8qF+83rPfMl06@LaGbro7?+qRv#+u% zdd-k~EFU6g>Ub*46fY;IMx0c|_6RVeEL=>+ZrFUk*Q2=$Y0Ssf7?-H-`e0%KG~SWH zObsqb!C&Ir(2X$<O(?_6Ow7&nd;P<cgBop_>Py-xu-L~yLCL>1=DA;U&dQ7v?-^!L zMa4NL|JSpsC3wC)qc1=2tbG?{iMz?J)SApGv|Yb_cBZ0eLa}nSfCusP)C~_25gqta z-<Z9}%1(=-!T4>GBvxM?!_`4$gyKNX4qd`4IqIbxf&kU*;U&0VJZ`6=?&!L*YJE0S zDUOo-N1%4G0+dU^O$Vrev~@ssTkqmqbgF$Z6IqlEQe~Kl^^;G1^7GinX2R4bn^(0) z-C3!apDPS_NS&C`&8<}Gk`jKy1C2!G7d1rIc*>&>!gxFlrcA$hAXzmz5$msUdrgEs z1MVXqo3?&{Ck6&S!*6Fr_x>nJ!h<eh8ff?l8jyFbRa6Dw@QWF157&~T;_bV|2y+6! z?r~GrGLh4WW%z%Vu<rE~SlJ1G8x^rN#P*xsH;7J%cN?7_cP*2nxK@{wyf2YK#p}zO zEpYn5;>hduXvk7xHb$#;oA(_y%)&`|0ib~)B&bp-BV;8Pv~ME>Al5O*8FRE1i&>Uo z{&pVsII?cSR7_1Vq(b@OzNTmE@-g|lVxnk{Ad(8rH^Fk;A;fdB2*vMqL`6)$sHgTj z*8mWD07Y0~YwA7;J)G)lerHhJ^`N3LdxZK|+JH07Qs^>!n`<dnfE3YKs98g)y`4aV zYT{StAkg<zi9{$IG1(Ur5OeErAnH>LBwAv&XA^@qBWd$~^E$P@126->N7PaQXw9rf zPpzB6Dr<M{*d+z*wQGG4cUHaMUfj;74`&LGl_HQ35t+#I2jVqGCi{|sc7fVw*Wx*& z{##UWt~G1HunA)XuFsc)^`GgF#~YIAz7~(m2%Y_(Tcf^5{Mk15->A4;V8^i*v7y*W z>&YMv&GIQPODut3inbIg=se+SdKG3hX>~i*idd^y<a=tXN!OO<7cvKc){eWEZzpRI znhGjd;1{G{PhbebpdiAERMDDPD_Y7+#{uRVooC$j5~mHzMsplTxJu@0?$*caP>p^T zOW!>Xh(LQGKSN?}HNWV^rnygWA9&M{TaSykcVN7wTZHS)Q&!Q>j*@+K7nW>CU3)t@ z6+-JWT^b<JNFAkYz3iNo)S|n;x1_iqkXTz4lGtK9Y0IEc-#OCP6(B6vXeQO0*S0_R zr3wxGY<-6P2r<(SSEePGJM%{8W+<VF-ife<aUZcXID*>jXQf|*O}fIgDl<!*BNpDX zx8`ji6gPk_+l!Ry=?ssA;;W`JF}@s|Y|EWi@^WpNj%v?&aQ=<|I&0&)jB@92eNOLG z2`5hFZW6qhflQ%95bB59htvd)5X)*kQ5y;f;M!DqaP^q=`Y0REUaW=GX{d9V5G5e7 zK#NhD#WtjTS}w?PIr&unnPw`rMPWE3vl_MtprYgOgn~pGnyqBTqQ9M2qVI89AJD5W zDo~;tTaX_jF>Om=g#wb!5mM3lb-M_zZZP$+@S>AtxG4wP$FPcolqI(IYFJms>JeX@ zhoWzq=}NAlL^$lQ5RqvfU2P24-7k)=SfA}#+<nt3*O!gehCmuF)la=rlCN?6tEiY% zZ=KmpU3VfEZzc6pBNc;eT$+Vvyleb97B1oakgj@z_^`4nkWIJCXH?>+Z2<#a!Z{AF z7ngkvQA*JJxFy-b0E59aY+E*##wx<c$F~oxQBnfWuc53<KULvLqHe7Tyw7l6pOPLX zf=e{ETP<daH;~z5Q^C+2K~-FGqiB5{R@Pin=QR8Yf6Au9Ze9(oXoOFpQGLGFT4*VE zI+YuI7w)&Yse3v)WY<I9oKiD`+viQj_wkFY4+!$lP9JoECctuMh}9zp5BAjOTZ#m~ zT7Sm267U}fKlv|Y+QUk#4@KLnVKj1&^+h*?FHjX6C@kBjswQ-2BbWUwmwj!THPy?Q zvuFl<*jqTegr75VXhboW;u6Y>B@Xnuw|hfIW$b0{9H4c=#ZsQ#q6Rh-=eAC_qpo1w zb5tUkG}$mnP?-=c`wFhgrTGj?uu2kU91j(j6GU>e8R#mJ>hy$bcvMuEx+pGDD@5{4 z-!7yhn*%v7_dUOUXC_9f9BqTZ&CBueoP%{KkYcvP514fk6dGCgScc?(-b$=r@8_#+ zi}wC*(~-5Ld>l@X#M3p|P%k$%gApa2d0{z=vsOa1(^E`Gw7wWtPJc_+w4gwiAL|`X zxg}do&jIRceq4w@P)sm37PIZF$A|Q=7|zz+f(+p0hQ#r(tgV~hYo#+z-;`}-<!}$) zu4E0;t$Juxf3@T`{HY6#$%BfeZ=S0Yd?ngh2hKUYve`V|(Xv$4f70M}DzKU6I8MM= zp$r=QbAFbWWaof<#r}<9=POOIa=5VYrH<e*3U)M5WPyUh%bzk#m#M2Bi6XSR0dN^g z#KD)Fld(ujB7Nlu`K<*#nnFYIMQb@X|6oMl+r*M%-#A~CM0#3B6WrV`jln3aVWje; zBrQ2PnOQbrFvMMhiit347GKiC)g-rO!2Bb@!<E!PBB%4^0W<TNGI=<y#)40zKl6Nr zMx|D!&<00IyC}`u&kqWCK1bICt>?oZYMf4&7fDDYV?P%1*d&PkWHN#$ZG9ZZmz9ns z@)vMzlPs0X6@EBtJ+GrKt`V|ZYjJ$o3dXDZm@g>;?p2eo&|o)wzuPBn7o@{ppy;%b zu%o$WzNF;3+GM-TtZC$I3M6F3@EJzkK3!=v_t#zeLTv(;7{@v!)i5ia!GU5jk=dUk z6n^pgbZ&l4bWKcJ66+dYUT$}lHxx%|J`rbNw->#d=Wme@0|PTw262k@91Mb-{Q-=O z&-WYhWJpD7>BZ@yY=8qA(q!9=h$Jq-D{ne-)O9fH&frAjW|^rRvL%BmFHl7l27}Ca z1}8sb>gMhe=E3p`e3fB-MkV5yqw|={4ek{)PQ82};4|e_mM{&mRC_%dr~Q)7rdE#9 z#aZ*Qjr$$52eT?N&lWiB3pd8K%yEkX!JOjK9(rHg!-oA19nVq4!xcBOiIouHSYa3Y zbY`-L8T&pquAi@UTUZt6J-j_H4lZoV4_UY*ySv)4HVB7P(rv@)o__9XaI>Ga4|T!8 zch);~AxNt9<|@MXW9heEj1xPx2ZPTGLuiTm+pFWhmTbv*&^Ie!xD*Izx4L>lRjFEg zOLqFX@3ELZJ?-@3iFAoGT@VFl4eaL^*6Hw>e$h{Ng23|1gbqv|*=r9a?2}yh+yvYJ zjIO0p7>3y>w0te{rd-4UetgU9h%BO_o}W^!+XgSV{}p(&y`J%UiRZG{{yBMu^rKw0 zTvOE>;#q+*WzT3zmV@{&@G|B%o7(7j1F5}zJq5A40H;|RO2P%n_DmPmK16X%nFpDt z4ozAm=>o%i#Vz%1@9in&J{-VlbfXr`DLoJ<LSJX=J~kBp^Eo}P(!gkv<P%}@%~0cp zS1F9V5k9d7<(~WFy^()W+sD0-kM(RkQXb|+NoBUxsB1y}m*o0XzHyMa0@mx@zoux- z{RLl|2N-6n^aM^Fqp;ay_uw($hbwApm=zm5hWAW%0|f2je9Kpz_eU{K8JO*|EM6?; zN)lKq?Y4<9@Q*5~HDp#AETMRLc`aqhHF%A5-F{7ewKOm1(kUP%RgX1L+e6o4$5qDD z9jWML=!#$SHu^x_3NfOq&^eSSkC8X*C~xFLyAgMsaa5^Os!V+fw7Vj04l1#rPDsPP zr-)8E7<#Wnnhj;cG~-vQR{sOs_f);92ew=Csm57DY&CPYhIh!7_Gi2D^ssqF3_Hye z+}RWj4&j1C0{>ykVq{Z#mB^E3L!x@<rXumYxfC*E;PE!w5+%PAM1xSs0z?i}RYu5O zpP`DrNBap0_G(eF+R_ZOZmOecH*D<366l|X_X@zTcVWo{TGF6-c)1h`a}b&}x;5-- zUP(sOBuJuY2kS^kpBGib>7kuiL`4<CjnoFrJ}G*BPg1Ec%uZe*`6Tp0GFXIZRfARK zHK5z9vo8f6cqP(#culD@qO0L_JVz_{UKsi2ZB}Yc;C7?8NIp5HL|K$4)ZXtm4BZ>u zui<by8M<nCdjiS)rGdE{hR0Q2apxmG@%+Ww0nz{0Chz4d+ou^Mt;ZXlACT(gv>|-v zFFQjlDCsk+i8c5$TLHX6W&56hha2(7<x^h`lanX{Bj72_s*8b7N;JItN0DoY1Qc3% z>Av$kZCD2k`!Llf1`NgVRA#7=MCuu7E+T&wjG|!?U@lCXVYE(j=%)A+{%bYT$C7%s z@%eFF-jIsM8l~Cv4@#M|(Q&*>ti3N+&20@^#!WJKhQ|{z(RNu|#t)gRSsHFj(J_OE zBbE=D9u*rm3q!9RUY#CH9x|DQ-qcxG1+>>h8zY&luGp;qqtpLYZwV|`2&y=}pH-Yn zqK?;&WqXD|@WPB%UFNjzIB%F3Fut}Cz?Woofrdm#94;0QU~3SjrUz&KO0Dib&P|`G z6s0Dmd`zM`>=n7HjppjC(;GhgL2SH%Q?Cc~v?aerNa<|G`6Xd+c;OLWGHNT{HzD1@ zY&tLNVnN5guF`07BogF5w*CMXCcU}h=ntQSN#fSL9R7g`H<JZrYV}&Enx;gYGiCbD zy)$Ibcy;Q>&C_!Bt@N~-%gQ`FzZr+qM%ovQ>}B=P1X01`lH6e=JO^!4Wn(<1l@!N^ zUOb}K%Hbsoqk9#0Tm|sFM^vTW4@zfoybOFVFZUZ5**sj_3jY;@Ot*p0;9k$B_HGJ1 zWj=?}+QTiN!ANPq(vBhj!@>CSSyzi#EEAc*L8W;B@{a6z;jy0vMs`b4+t(QeXZJk* zl8&e1^dEOS(Y*8EC3dKq%|oaPo=_#w(njH>=_exKMKgsm3#f_IMf=K>(YgO+ePIJq zb6Xqpq{~*?CTNpNpe|c3q*)NY($^(^imt?4IKO<>b|t<{Y|ap5N6{Z34ye{HVS#~* z334>6WxN(`eLAwwx28{!X#bh7#Nl|9r**CP-UzEEFfI?PIqk_)U+<5NOoORrf#Z?? zi|apMvmZXI&Qa^^)mGi~iD)ytL$jjOj$5|5qe!zssDhRvDJbS?4>QLumbe#nUL;dY z`}^<i!!7PIfRZ;Nzojm*vy^K_4%b|`8PDK+_>~)7Co%u?LxPqE-r-AExZHnGi0o1Z zQZnf3_=2v8@y|P56jx#?7H+t_p4m(;J=0No%@uz8cS#TmLoI@vYD0ky^%nj9u+ih= zd!w^Wq~FkuOm+tn?clVbUpWLK|KF4BE`iT<qMl?tnUWuWqY5O)_fv%Wb*_<2tgrr? zeq<MYU&v6tj3K4D8mIq(-6Wr|uYk)E*~Fm#9Q~x&oZq`I<9raOgm2$B3XhldlPeKY zhGrD{&HO}PY_{`aRgb9{|HG5-BNU46cfb#nUW?!CMivSJEia*8UOW1mC{&7k#Mh1w z7kW@*xV1vRYbZo;k#98MYavD*yKJ2EyNa^#9})5>zS!YT{P^&j9AA)Id?4kU!KHqb zGVuRl?C&31pHM?0Nq-YEn@<jsPL%qKQi0g-f`B3Fepkn5$rSuU!mnNU^<;`EB!37X z>cbE4U35YG;~?-K$v~y#x)`K>m+XB6`G3z|mt4UAr29weK#G~X-<0(Qc?SqJJeEw( z?*}>XvUY+1xvD=Ik%fHFkcY|{u>XyTY_=$9d^$_9sAdY;9|G|Cta(ED3@H3TV+y*s z)@Z7kLh&aFA82tpNAU+MuE0M)$j28UwpTPuU}F^fhi5;0Bz}5A<%=wo{oO?|kaWV- zh{`15f4B%?6Ojo_ZioGkixGjm1L*H0?_Pyx&J_3)ckf;mRsD+%1mC^NKkEYf$3f@^ z|5*Y(qrZU^y!d|+3tB!rAR+Ykfal`}jSurn@BhO$?{eX1&-&;A5Skdo{_v>JJ9L=A z*#0!x2e2<X|9EaAp8OA1AHn+i#7@pM_&76#|41)X@9D+qp4w1>MC1?4A;TNUH~$_# z@8K-qV<1nRi<=DfyL|8<Ijyw6SM~R%#ppfc>Lc8AX@1w157Nd-XC3@^v+2@<h?B87 z#`e#GGk*IGhXGJz%^*^rJ3py<{Kg2CsB6iSx`-he<+lT3EuZ7O#2ZeZy~5x4@V~p~ zf1z0Olz7DHy812ISK)uGhy(B^beH|^n!|sR-`^>~i%}IZM!)<PxUn={^u@$4u)4tC zDxd22_qhFEq@w=cC>F%(vxjw+e=~5r!^f%E60$>ZD&F70tQz8DDmJGos+<h-2h0vZ z(%FjhHa`AA1@)dH{}=5EME8<sW4(~7o_~jn(7V)$@<^i)zl-os-e3#8|M-V!K|b<7 z$U4?M6=-EdvVvfyWZ!14oi!zg@H`&N!O)X!z0MC+zNdE1T=S^o_<!Ps5gG{^oAT~~ z6)d{ud7kPl<-dx|NWSeK`L*)HEXaUP-3ixc%D}7lC@x0SJw!5pZ7HhL>j{JRjRB>! z!nhng_gt-QNx<hq@jr(6ARbxJ)R0HA^;~1r1W+AfRn{F^671!UzIWXwAJuTc{4Cm& zZ)9&vbarV>dOSB5!b683;MN|hqm0{^AnFO95*2U}&Q@g%J^*_j@KL9tSL#JW4T%m& zp#)l7Yce`;qBc{-q46DX!yV4TsAh=!UmGOD!yo6N&YZs5QfVS3%CUKx+k(zhv-zn? zkk_^IJ~~zsJ!$4z9C$%G)MU4aa)oa2W<-x*C|mjBOx`b<OjU|N`js>r87f9LDRM3r z<LY%#FP$JTT*&{&YZV~T3~ep}K>)$CtZ?e;7Ky||Uhq>V&nQ<`-v`U<D%Ki$4maa0 zMhcvmH|jna-ih7<Bt6k;JCWN4|BE9&Lct?CDy(_1orw^0Ma;lrJXhV`tn2EtP3F}F zwjbh8a_CQD-ij^t;0oR;k>2-#1k$Hecf8TncyNN$Cay0`tK6O_HA&~E3Jc%yv&f)l zJP~Giod%Z=p{gz?mHJ8&Y|7`sd)MC}{g0ag{u;KzF&4$na9gs1!qa=goA>0oTPC@k ziX8eAWdn7@_fxkS%5-^(gXw*|3WfSxLH<q1#2g|kiQghgwCF8vAOjR_C&!30>|o>E z;Cj+IA8(l09+b_Q0&td}*)aAxaT1=~JFU8$Bfrd0!E8P4>uy_zSD!jGRg7!E^^Lsv zWa&J^BnjP7bhbc41t|rzLCszsRJ#q+Cf7Rg(ufp(5;uu2#fkXNBS2qg|3R~6L;i95 zGUh)qLZ{Is3Tk`@OmxkL#BUs12{*JnE6JAGxHDC8;@N+3_$ay-4b(Wx_SC^sHQLv9 zuv~kB2@3VuZSc}@Lmsz&2CF=?W5j{h&WKFXmYfGqYneIUxhlZBRNvKRduv2vy)h$@ zKFJDk<~q^`y4MSd8tb=mK;()LZ}MBKGwah>4eTy37d2g(*Euobq7?5`Y>)1l=Bcsg z#&*)45YTKt<4nyhjbnMujdW>mG+7WqDc@Py%yv2}faYBT^j(s4AKW=1;V7GCPof$J zf5A<17lise&mb67U1oN_?z*!zTB7nSS3{r`$n={|X<BSggOj3d7B3kC1TCIG{5RA- zc~Zfu9i(~prfJw0r^JsWKXrah_K*iHe3ZfoP8(#^o4*`mORqzmd5ULlD!hUC&3Zqh zedOipz6y9<$(s%qXzK(A4l+I#&mRR#qnya`<ne+q>bEF_&u^!0L5qr+(C<)s`jqei zopLXR9zLT#Ei)EbV_Cv`V2<cBSbTEZzNPJB&rR)S-l;-I$QA~@={e4l=`zVp71$7C zd7eZFNMqiS1&Jp>_b?g-_2AwYsw2;cvFYI{<IOUpVqAXtqQn3z<Mx>__`dhMwNp6F z_(Iigdki{#5$(FR9WkK~Yi7W7DN0bi{SezGO~dmeO%Tr-BEO~EPGB@i7~dN-0SwHH zmHrZG)-j0U@dxNvH{5xP<p3r7fgLsPORbPcE@Lk?l)~Nbx=LVNj9bo<9+Yg1vXv}H z5YHqea&FC5jyvabqr@(wa-fW3h%&lIpzq2CSPv%A8TWujV64F~pV}>x=x7E7E`ON& z;%hzH-|#8eMt4wL66>1E59D!k?>hsuto<yQ^S|>Q{u>B^TUGqWRN#cinF-O(_Er9J zMXC?8A9#arqbY-uTYX>l01I1(NS#E`Yorkx_|EAE4NF9Fm3h4xEiC{n_2ACL=dT!A zssfYMDG-nMSz*V`I+BeGrFdQ`SGY$UAxXt^w${B?&zKaMNp8X?Z}|4!4?$WjFU6sv z30m%vtN~%H{Up;bx6u&}{Ui8|jEmRvun4*&1RP={x*iIPDubJ$aqzFJrc|o0EbA1v zq$F>zxCB9-;h#1-0xG!<Hfx>oBO#Q<W$Io$PzT(-1Mv>tf=36Yn#|d1^fK=bL>h(B zZ%-FoIyxw)D=K>Yc3PB$-&i{aN>3TpOV&6x>o1+FJMW1!TUx(_%X9`T!(hu+NE5o` zRR)&%5?u;~wt9a81v7#k9y@Mt3%6`gyGn>$jF}2JnmyBye5zqyt-nR^gN<C9bpDkN zQGOJwmOK7XLxA(6bwO9@5Ph~>3(9wGqsMwJa^cg)e@B@sQrTw`X>qpD{!#{TPL8^+ zt^(W^RoO!tkooz^Kz=>d_6ziF#<JLci~1IP$-owFEE5a^Go$nLrDc=&`5(xd<&5h} z%UyE3PBZJD#<$HsoEkUr8YB%t^g8r+vsmThI&?F;)`a+K`CmL*>wN9gimaV^4W5Vs z-zv?@5?~ero$q-2;svB-nNZdb)Dm)VF{hY6c}8RG@PZ(8YxuS%UIDkfo(rdcRGOu$ zm5e#G5X}z_oU=0NJdV<Rso~wOu7;MaKkwV_X(mH=NFHO$g~uCZl4y2j&rPfR;w!`Y z6H?X@D9i5N#iNmE@$#7M?Nj0Ja?%Zac+Gv&6TP1|T{a@($#RFk9|d4cB$Da;w}E8` zRTSdjp&Q%_a|;%xN+TfQ2^(*c?m=x^YLKfyi(KQvd)lxFX=vH6)r=;G<y10S-s=DA zt+%s#y~t<;Tk-tzMcb+s-P*b%0@!K&t&_Z6P8rR8kE()03N)TVbty?m_vzy@-qKa3 zoikoR2av-!18ppI=&5Sk6gu_zlYLB>Bk;pR>p@}>Ger{_RqiQI?I+)q&W|ig^v}`6 zMJ<Lji4{vho@j*iAHCcb>7SowM%Yl<v97gC69}8eLWjBk+ly<1^izr|1se>uY2`4M zVQ5_8j;<g?&2zWuDU?u%Z++<LvuGVuJ`oVK_jK05=l&|}AmS;{N<TI2E9N2rS|s~u zFx&Um?Kw8+;#q4daCZ`Mx#NxwC(CU6a9$Ymu&Zg_c7JJasx-xu3#RljZMt5zGb|2L ze(z=oGq2EGSA_?jr{^MQac6#)`uTBP!G@0UHLm5zVdur=+D#@?<NMe^DFc^~S8q(% zPAME=NpnYQWwJdx&9^eGG*6`Re)9ZDi(ew9<X*EwF->lE5U3GvUq&iG7L+S{^3lwH zG*m#i-o*h^|6BGH_>8!i=orDEIH*nsz^T}BXyt_JPFJAUAI};vfRa!v;hn6(VajyO zQPir@STb-z{li~PPwPK~_xc9l;OXx|B+=Db8mX@F1SHre9&qE%`3+|=Q(_WnrAIrj ztA?19MV@WEh2T1q>OD9^d^cSAVEyv?dD(SuewkbWLE^z8%g6aZM>qm~?MeDv?c&Nh z;_-EFOD`>~ijlJl=rZugQxr8{uc^Cp%>+K1>3c3yg3z%`-FE!?S^HEQ&q#?NP~f;q z_fn}Y^MbhL=f@t5v~T3<X7v-yZ0$BQuc7xsfh0I`8#7;oH|!U(UTmTpI=-52RYQ&t z_&%j=^perj&wZay5Ugv)k}!S^kAU4tL6Z})8Z>#~>F*B`pwH1EWh&LeMR_U7^($@b z7Sz$fa#uYdB%6>-mih0vKm}3)@d>*2#2Z8>Z}V!nzv+97eVTFQX72rR54FZ-cIcXK zYwJc2>=Kuo?Pq08OrHh7?7%giQ~!LUa%dv+=0M^hdM7dA*Zg$3yCHK4DY%soTH&_< zLULHs=Wc74eoJy~SFd_99b)LzXB=?Fq0%9lvO&y69M8<<NDPs^pIQhmnQQ*HCXA8{ zcoy(%ZqSd4@V==zAdeAv;Rb|*`UWmkcQT$b&xW`~o_04A9i}gG+&_W&yT&`$$R$OI zU*-E;LW4~<M|!`2Mwta1uC+&WE+{#l3A`P{hsd2fcQxFz@;R-x*PJ<fRMQYD(UZ)H zpLo(aDO0J`db2wTk$yFsQH(&~Rb$1P#hOJ@f^Ok5@yx3H@8n<))`!T{Zz#bQNK9#M zggk)S-Hz48oYX^}p7m`4|3#jp@$!5-F2}qO5to{`JAFf2Xz&99{*YpPMbW%5vR5+0 z7cUw77^Op4^v*4KSe#{Foy^NXkxkQ4w2=aAjvLl>i%oqyeLc$P0d#Ih7}U25%uF+k z4|qusQq$stHAPD~c<Vq<uvhf0tfle=^}2#64JHT!h(^E8Bp%3ypjPWoT-=ZDlHLjq zA6cpt69LimI$ZvI6A@-n8Kv263`zkJe!S85(6KHdh2rsmd-i>4FO1U{?tZRGeFay7 z?2(lRgXs^7qoQhN#MT7FZ5(etdow&en|F@=P3rA|)NO#eo=IDK`eJV(EliAqOW*&F zXvseMs&RLzYVItkCl;APzNBh=86iKPC|sI;6&fc7$`JyNIe*=q!A^Nu1#ViiZYMR+ z^cVJa$7$+}a{eoWg~G!lk?u{esuF~ae@nFZNPp&Zkc3XRkD1y@2g02??~_CUs{&Wi z6(7pLhms}*-vY*Q$(m=lK}N;>ult>ZsPHeSj0@W?eM$R!WEbdQ)4f&pugZc0h5CCk z=b>3AuC^j8aJ+&~@)%k%wVh)NzuzGGiD4Z^q(>tDF&wpu!vBnyI%qI<Nwvw1G)g;+ zujXgfbTc-96_!8itH30A7qh{gUO3HX#(&@9_<tyQ%YZnWWm`D7LvV-SuE9OQA-KB* zceg<T!7T)LcXxM&2_D?toxz=(_nx!wcQ)DIkMno>sqX3Ss_L#)tLvLFRW=^;K>pZv z^0cv92_y2qy1zT`1^lZPz<+;Aqvr2}pEaFo()lLv#uEJ#+ykqXwJ6`j&<dsR0;g#j zc9ZSjGyoMv2B|E<jVfxT-o(k7iVy|CvcCm#)Ic_GFa%m($Xu!f!nbj<VmCW9UcR=3 zAS>=$1my#?n7e`9+h0W>hTpFrcP1*KjljI^4F1nd+EM-*!5DgeWzM)X0RJ!eRX)An z`)_PW!hgkwsgOPy{Vk|q_+#ile*UQxs0#BI<?)9^R`x{u3r7ONJ8V)$lpvaYf7?;K z6~W(-7^9d!QwfeT`p926>pL0RUw;8_Sk=f7R2-4YOnLNwLtBbg7XLxuJp>zdf>CME zG)H#k*4l0(Kch9A=Vx0BfU2lE;(LE3#Y36U^dLs_e^E*SW?d*JlXF3an&(!80U zO#6Q!$zfecf607?p8sh@hTUWH*Rp&FP-XtqNBHfp)e;pMT>YaP=zr@*XrgLk-UZiR z+9ZpvNY9bZGpI}-c>fmpoP^<VRF>|7()9fsrVEQ>{NKS_{>eOHCdy33LVpWsiwwSR z5StT5Qh2ihxzNq>rQ&LEAKxIq*<X?VNo?r7{!fSWf7>E3*88P#)QCrr|GnYcPp0k< z4PWPkW&a+d|G0DcZwxn)>>nudKSQL)r^8GC!4O2COLXaGjI9FSTAE@n%=}O7Ui)`A zS#LCn3V~IsA%D?OKhxq{#2$;l#J&0M|6Dplgn!`89GqmhxBucdVzIw*EqoL;$=-{e zKh)_8YjqH}SPzMfv_`et3+lY97mh8U9O#Skvu|v@`^BW$g8_Ds0Gnu7RkVXzPH}jN z%Ot)MHjF#Q5OiwNjFG}vnCv7%xAu<1N*OI7y@Div)ch|f+yYX|xaG6#wIgM|gIEFI zPPI3PZW-l9f|t;Tnj^H!4U*gT>33c|vxr=KE7b6;L6CQcnMZ2^nr=CU!|fB<v2Fum zNr!iCW*asK7`NJU#Zi;<F!a-mV2(_<$bJ|Uk3&A=P$Of=$o6&82E|(q7N{2iBPhcJ z>9vU58AHjh%1gA!H1ZK$`+Uzt4pbS%Igc-pYl(VZV(BgLG;l$57}N{|kt7@jWk(ud zl&8B?<R5^ILTl+mxL$-D646UC(5xEw!%|yS?^*sz5_}T@YX=Mr5H^&RI&Ag3Qkq>E ztAq4<OQhVVD^E*Nq^8Knw^9diub;0VO7+zcbZA0G?0V^&N{elL#On)Bd%?2q?~}B@ zw2B`^3`@SX9oi28)0<d;l6Cxbv=Dw8bOM&)gy{WCbBDDy)KZ><-B4v3Alb|;3Tk0+ z!eYF5ow-*|i2^|-v3`W7-&p_Vb%+C#zU{Y}UyN^acO;O&GAgy{uml~HX{WXjm87j~ z`H1cVXK7koO>|U5y&$@ibfXNSsP8UQ*u~Y?0S0}u`-^A1?X3AokXYu`zN2hnZ1S8@ zAd0ukAtEx@uIZ1-bc0p!v2>O>D0vFk;q1mzSN$<JI!4dTO^swmNeMmtl{xeSmva>$ z_tVfbbpFAurE=`o-@v({8e~WUm~P%1SYzeux0ujBSr3)$JD3t<2>cM4Z?tJ1ko<0X z0cs74zvU0hG%!~@0(I0xk56|r-S^phH!)(dNW-i_Tt<VN4Ls;2*2Z$3oy4*@mB5|| zcl5O6$o^)29_M|mO<jgwJ$a0gzt{kXdLkq4I_U%XhXAab9i^fG*fJKrTqU_0z!w}Y zm}7<pv8>Y~$MtUCaz3m;EX^=i<!8kzYmMoP-ze%06~7@f2uQj+1FaoA;xuWnXC3HB z{oRO<x*PC<Z?r=10{(rpZW9c}NQ*`N%e~X6n1hRUMwsxJZr~-ZVnwR~nC`vo|2!|h zfj%f6Q_FiH2e(uHrHwz|@mJztP{zGIzQ2Xw8vb}V5B~DkIe;kr;VAucP(1BFG9)!3 zGPEx#tys8|L)oL}<`dl~J+}&}&2gF>&ct@KfQjdObH$Yx^u5vPoyp!B_XF*I*lY0+ z`Ws_kJ4~HTPsWT+ScFfaY&`Q&Xfjrt?KID}b?MWg0z9OCCv~E@vgJoK9jM3`q=bZl zQAg@qrx{C93f!INjS4Ln`@dTl(lhjs$97fzA5wy$nDP|JT2*&X^2fX3L(<LF_})Ms z<3_x`?5z+u!zSW7s}IXXRgYqV`;PNAwe+S*mL;J}60dc#yq-w`w<~AxXkf{Rs=#%_ z&#G}Q_||5lpT3t8!iIjB8R!QCcWf`yC()g4@OMX?0=r;lT^&o1w4&vX=CW<HNUsj3 zNM#sS>~(G~2G?C*Gc)FEjhMVbx0?TDNrsv4bd*P(H<hqFjG@Pv9&j}t+9R#ly<{<a zjv(=~cN<I4-5uf7?Rmd>53v_7omz5~9iL~LDlZwg5ID{d=Gbg&Ez_;Q1TNl(0+Xjh z1-po?o3b$W5`Zcv{CUz;j`}w^@~#{&I;@0k<^1dSotzs#D0M`frK?;%Kn}N3lsm%A zAJ&ybgLVY1Yp(Zg^IISDW~OYFrkHL;MEt@xOl0nqY&1IvlQ4;tN{rz7xai^9M&<>w zcHF=rD*F)M)sCa~+U^enj9nR{Su%r05nRE?ztzvxcRr4Ok?qqx$|M|abG4Jdz>*`c zJktrh4zVK#7LWtTCu^y!$nAqAt&bd-ejYY`+Tn+D;21&WTy&HC*d#mOZb$lAWjI?p zrqW{Fv{}=I<bbdvq;{8orhwfl5fv00QMrHfnN+ndE@g;9Z=$r_{=jP4`w-s+?C#|- zPLNm-nze?6BpS2&90^-|aiLD`VY^%pWA^2-Bh<NX`@au6pzNQ+6KJ0?y{RV7hyrs# z=imdAm`NOs26+<ebU@13nY?sg(%f=LflSy2qeOmOi&F+O{^Ud5`pScw)i~*zGt;0s z24owVp<Z9fgLr6S2wL*%3N+esr%=y2wy&G8-ed%5(&!)+!Eei#-yzkVFl;TDTlMNM zL8b}{k`^nIJD#{<k=xOTxTV(1bOr#=qWihqOs+J#>r*n$`!-o77W-WGR<HQW&gIu? z<}<PbI^+m2UZ3!%ykEmTNx6a}YTxag@{#n}F?VOl=KZcdNrHF6+ED37eY)7P(cR~O z$y0@qQn99kdMVe@_jDgSrBs;d-|DZTIA0!#SP&YNHKnxSvk&I|J#%ls!*#^cy@15* zxDlEmB>f2do=^lgNkPu$ydub$`3hNTl~#QzZ(x)^RuQ$^MskQ8_sMGYpioac)NyUJ zx57)vLZ||2nZ3)Ol~Ha&s7YDNGEh-PBetSE9P~q2<$m+=UpGG-)@R%-s=Z9lymv6Q z@S67x!7QgnC%t*0Q<Urdxe3itP8RC?M<S}%9iw={c1S<dd;(0pZw$}If;`H6vDBj< zp=dDbC=ts1aanDrAj)6rNo@MK440eQ9M@iXpBl}$-6~QeH%6Z}bQZ_1G$$j!qD&2^ zmPJBg9fY>#ecs|WH#z#&q50y-YLmxh_~KWy09jLhKi#2B@$g$2J=@D<{n&P%s#Tl$ z9`He%qZnBdY^jm$<cAaR<E5uMY$dor(v(CD_b@}&k!J;yII{%h5mI}X(R<Z%yrTY~ z=>^D5E}|CBm)h#ca#NleX~anaDBmk;4?bApCJsy>oHM+4mji0xS>1ICpb^f!Mp!<J zoqL<2jjhc2v{>3bEF9_XK3d1xAHmuipWXz{Gh7Jvk3RvHR1YF<S3MB2+Q~XSJib6= z4-Gv<OPP^+`_V`=5ro2U*F`yYbfM&FBmZhytDX!$Z=tp#mT>bRe8dPpCztps-_`=1 zm+6agMDBEkX1rZr-loF5KG*rocH(3;`y6yZkF8ONCbE__9#QphQCC0#7}nUIYvt8; zCka|ex^#E*t^9gg6J%_A3UuN<bzC)X`C6ptE@-FI*Zb9d>}By>Gs0ItziSRh?*b!^ zmyP<G?U}T*|9xFHmWK<Z`l>DKyfa$oA|IM}C8becFfHv-v{+HCO3mYTAfP`>Kd_HZ zMwN~*DnoYHa!smIQytl2C6IVdMX~82FgDXPEjYWe%>o5Oaz(g}L~<&90vv@7f0O9L zp0+VFI9k7Fom-Da{mS-*WiHUR)bLk-7?0x(JJ$;)B3jbBc%W}Th|)T6x?Q*?-l1HV z(6ss;l0I=*8d=3esjYB3#&!j99-&6JQyUzb2vSJLe8c{G;{YqerAbVYg`E8p`xuXj z8LrpF+yaL!B1U1tDx~%bhU~51B*n>+tIkK47=A`@V?7AO`o!U|B(-A!zbkBEMudvu zMim4JXM@Z|Y(2CXVo#M2Z;ay|c3QDFvK4!POIk#U!SNg^gfL$UNcRh5IlVK60a+nP zd|mT|oEc&chtu#Y+V_TIFe~7~$qJngWNl>6PwwX?4;qd6sck!Zn$A;<bfA*<RFmyA zHAUccPZAz5_xKS0_{AEI9?(gEq!YTvu(QQtP}9)pPZ->Yqlhrli%IiALfP?;#f3-t zC-A3U*`pNs5T0K)TQ_G|gx~}MlLt>!P{NBpS@rtlhvU>bGnlWpehT~%D62(DL-?rr zV-Fbd9te>s4@-leuZyQJqvQ?lldUoWGEH31sRvzsUBQ!mUCyo7Wwy{bavixV;3yo^ z3aapX{YJcLuKp^_y0-!g!`K85(ml*G(9vLHc4l)ULF;8lhgSD0AuOG@c(3tcSao@k z5ANffxl5}0jOa|~iqeY3Dq*-H$7A6qZR6ZxadVHhU3F5JioN4Gwwu=MgQLrncW59` zti8$3;F@n4pgw<hPqWS`)(QJH`t`lAeHT>25X6p7bU(=c_Ip+!BwZ8NR?;}N(RC0{ z@d<tQ$v(@uzJ|d(0icaSM?UkciD>k}+i>gfYvkRf_xI4stAVi@UsI|9Ap_k9Hs2>_ zC}t|J?A7iV)>AcJ5`O%-S-Am?uJZnxrLgLXWz;-Sl=v$Fs^WI6f|k6=-0;u2JCo#x z6N&cU^$;?^Fu<)|xC9ja=5*#%Gk}W7E@Qy>qK#>T&ZK?0^0w<x^ZLnQq=Q~)?xC@# zGbYJc`;1*`c#1BDJ#4MHdCU2HA-QDUO)rpr6RDi6ll&xIkKzZw6~!0J6+901mU0J+ zhTwwM`+OlBlnsE(d$5L^mJ?nN>NLmzN7UWO(n7*B=J1?~EOVS3`CE1#?|qK3H5aj8 z-c`AWJuR9(#{!j<bA38019|4WD`yJ&(Y!|w{Llut_oVzNOX4rXTqL2NcA89DmbjDo z*8}cnd&zF*4O)sWoz(QSrf;hc3qH*YSRnY?>_Cbys*MowV8I#aelu8V6OHx7ybS5^ zceZB+?xC<3j!aRKxr}lrKkOkAA*u9K-R|Ap2R5E#tRdht6v@?xJ$_!b!PhZbu&PSg zai>Mo*f6ra@v#ZEPON1dP!Vi*aCyaEj`$*0(r9nIOlZ5|V~~7>+r`b`D`Fy@=7v%i z()le^0e5|r-7Bh{)OnSEEl+K7RzS!=%s#u%Z*ywg%y68EA>R6h@qxFZkDx1ytqp|V z{*_YLex{yNyQ#56Lg=V`%y6^YNXxIPjoPFkb{yC)JLJx!whs1lH7{Ww!G+0`f}l!2 zLJ^};SihM_^SAa!Ms)iVZ+?aVA->R3-OPIVKs25%hh=P<KRy7Hn~Wh=OY$-rsFNm# zFRgl!+-uy=t|KdL2b(>&vFe?#zaqEGDvTyKOXf*vH|j^UP^Oy9JySSWUnEj20_sQ} zZ;tz-@dL$VOYhUD!CZD;H~pY4rh#3-;dAL~rpnhgEOQJbZ97j}xard+1bs_5@Km!_ zGqmv4sj5=s45LLVss)EH11hOd`Qw5xv0lHy!oX#w&OLTD%Mp@>5-Dh0GC~-Cr|^?k zDM?4R=kSSk%L#+U!vkQgCnwKnQx>hIB-X=VZDpd}Wu}Bqiu*DmV%h1n`cYNF>}r&0 z<%uY5>0ayB@_pSA+>=`yi<#X#xfy<Di2G3qdKNwF&$0CwZr{%y<7?G!!|FEam*h5k z?GXkFrbm4&7}Ndf0}wOso;t52ZT+ndb>)r`Y$DDAvbc^xnLB5>ld}rojf=F+h@Z}y zt>h#t)D@srs5I7^YwV|o8Tw_M1QU*|T9Nx-Wk&a$w^f_k3w!6!SxDfsHPYOXLOM-v z*;R3gN^><#d*<{QbhXlr0xBJF5xinTVWn;TmreSb$MeypkFoRit$5MZP|lJ`JrlMX zu{O!l_W~O{zP{Jq-y2^@j?jquZ-n7Q1s`1jEfmUt8byRabEdw>hM}C>kqXVP@3Rl% zCMcK1^6w@O_jrfdUa<+w@wjnQ&AUM5RDLF(PfU`Vc2n<im23)!$WhtKk8bE=U)^^< z`20q;5l)VM&6snwJYdNLTP$ny9dl+xPZD1*d2T)JBK>eTd|2t2$FYnkBUA|6pxtZ| zI)rZ&pB9t4hI4MUHjXwj(R2nh7<0QZ6QF=lRH`3>iw!V$Mi{CV!h?EinTpFsVrrgJ zcdQgY$o0A|gT1l4#`PkxhkeD4K4P9vtZ}moX`rAouB-I12lJ#4UtWq6x1bnww&C4S z>>2O%R3vjwLV-}%Mz2?geiG-orWrnc?C1Khbk@MV8R^4p)`DjsAPp%KR9UwW7jM3s z0EzWWwtJP-$6M_;$;OK9J4j-bR7Li&x(c>;eMj0G)9w`Ki`-MJTXQVnE+M^%*T4q& zkF!7M$7V8$dJ7Cfwpwm!443))CeH4SJWK{r@|V2wewM*U&y94q`>7iaXq=fG&a|_q zK6=lR2<1{(klSVOhFxkfuWyGb_V4&wFndoq*n+)1jMhKm2^taXGHC`}oA+nM=qGH@ z5fCH(u@17fL&1p#qW3<WB;>~8kCEz;A<`eMAuh(eXH8tIj;(J*$1kji@NZ!UUK=2X zU!E{X$J%2(EjD(TJ`OS}Af|S9_!-37uaCG>fEP95Six~hcpa>aA8l0*3fCS8SsE<@ z<PAuIi=#lbS|v`_Fk^xY_q<%USje~ZhNfqsS2`ipN59m-piTxW*OR~^G57iJDwox> zX7BY+G)cHN=k(P|>GVB%2>BD!XJHYvlpT?J&wX8UvN)EeTM*|y2nd(s18fqindVTd zI!Qtm(WSmGKyQw&4dm*mvGp}25FWang(Es@yiYL`$YLigtTa#7=-Wd~5^=GoFoVS1 zQ3;<N<kOdikBKAI_B0r0MTwhh<W{GSJ)0V?p0kBt#r&Aq7CP&4yV!AVd^Ut;Mm^rF z*jo}bZ^#W#Dx?EfsV>8#dJxd`s(}Evdn&3*l2!8npie)_mYrhXj9{hGWq9l@v*NF> zWSosv4^6xzAd!kl?4TWSR>hlk?LF9;KjS5`zb%EJDL}Mq@G?|wlHsLxjJs#GV<H}r z1|jPARICGx2|tUYWrT|I8_xJ~5UkFJ)`bx)3pXHe)4PlLf8s_D(qYxdt85!50;J^z zDIoTq7NxZtTnv>lMr^2SHo~|jc(NrLT<Vg>OKcF)2FvXGu3_J74o@jv1M@@M-WR@B zUi9R^cqJA@QVSWJW@$!K2<4rdHI+IjYWGo8;|4b|q#bpbCgX2)#hCvv-mV)v2dp?> z`n@`54htsIXM05&i0PCfT#A3A(d~v!XuA&Sx`XZXsj}LPq0!S(OZ;3ypZltylJl}l zIHJiXUS4Gt<Mas%e9(5Xo}lrHs0MSD#)DmgNo_bVP{31mC6b|Ua&9^9q_~jOgLHP? zodSMcPhx58Ym;X^Y}W0MWyIxr?iD)c1U$+x4vc#c2AYL&ePL0cOc7$*g2$%6x<}4h zz9X4>%?Jn^L~Nej4?r70Mb~rQA^UT=5|}AuZ@n%JNa@lQ4}7Um)IL*Hlua>992Hx2 zju^19-YhT}AbXi2t+ts=(yY7?DVQYpXw8Uq$k}0%l^|`WwRmuYK)dL8VtLXi6iOA| zp-dziN~Y=&YbBTf&MZt2jLCDwnBL<f7}_%7m?)P46+b^mo%;jNQv@WK#Z6`l6+aie z7kodx@G@R5j|maxp#Z30<Str|VY|N<W_7)gO$OkfpS|!2d6!WTovn)9we)$ouCt%u z*?5*yQ^A&~nfze<$<ZlR3oA`MmS8D3kL5sXKx~&g_gVKsP&e(B*munV8*yBwc<MKC zt&)cCYlgQFe@?(Ywf&*jz~#dSTz1w3^3+I{r6~RJb1cX5LF)*+(ns@Mb!yI^6y(`- zM=S$2=F%KXNRCnG{8E>v#t!Ki^4Ro!Y`d_z;_q@!GSg2O^H{`Lu=PfdVt#Y8Bs0s- z`mzzk`c3@QX$`-T<@d4L6(rD3%ZhGLaOO~t2Cfor(01{Xe5z^?TPe#;8V-`8<u>@7 zg8Jv&Di8YjE4sPxMsR9}gGX9`bHsYq-KpIRehJPp<qW(|)Mx(iH1t@OeVr#ezSu!T zgn3HNyfS(Y8Fap^N*vlA0utF#Q3BA#Wex9SRJvAXxn6vv+~bUVdD(Na8LMjnVf@3( zUj8S&sNY=z<IC@H_la!?t-oCm>Z86+-pgLD^}!z6YT|f2vn!j$G5{Rs+Vzsq+kt6D zbeiv%a$oFH5kY3af+d{N#-3TcK4poF6P~5ZO>wZ(96gDGlKDvDC!AzW?;q=OCCQNS zG;y?buqoL^b7b;qn5h>-)yob6b?;|YKv4>lz30w~REsUWOK(VBzrt)jyFtp3&hEEO z>F8DuE5=45k~B}Lf(>K!t&J3x28D|+Yf_nHeEvZOQlD@q#IHno$)c%YmsU>$Dx!@S z(jsAp+9%cGPa{dW-N#a6C7(*;lW@l}gu)1nf6|$JD@9fuPv?uCTwUGW8C!%($mnyt zauR^ma2Q4Yf+32wm8hn5$72rNFGF*8>p>_So>l+rmGv^}md)4tedjGb5?YsA^3|MS zJa<=)#<m<po4{Ct$yBX<$pkn0nIf9HWEZH2K@dE142E}80G-HXnZzaQ%C+GS?o|;B zUbO4qSf@NM&R;L$75;G7+KEL7iA<2LC-?T~rI&%;%f(k2!^?c6u2O<6ZQDc7TqN3j z#HtCaDW9wQu-cGWd94k5f!2}oN2P{o#a>o&kmHzEMt>araHzY8k8!b~&ynj8dun!N z5TJl!s}0~EikNLMn6(Ld$Y)sWT(=y+mGeyc*z`D6ZoKWO=v$eBhK4x@XnvUZurc5% zw$$Wb2akoFdr>#*mx;>_Hd`gR*w$pxV4Hm`y~Ci!Lv4XBZP^34wA!@*W(UWA5Ow(u z_`W*x&x%>zH=4q47n=<K!g2nuBqUH>Byuk8VP+4H?c5c>Zwu>-&rd*VuMi+RTv;4D z49$_auUPeo)!4+O+Gtd!T&ID2E=%r6os5|a=R&iNE3I^YVwlkT`{?p>PH1RU?`Yoe z`E}87_Q5%0CWiIZkRgrLE63Bt8E=2Mi1f}j3X9~5b~$PTT&~Hc!QIW7b13dv7(5Q> zRV&oTjB(BQ&&_aIx_re)mLEqi&INt=^$yK6%Pv@%fGu%;3axW-7n9IKy)yq9inj_t zFE;x{Pa%=RFU=7*=+1c-5dj`k?<*#zvXOnSbcR{^7xFa-!3kCyR5RkxNw+37P<ro! zEw>Y+@Rp+WJ3h+szNQFyGA_NS?+n(g;JGq*f@QqZpt~duUt(fNubhbvtvkyZQ_64_ zrA?Mf&~XF)md+)FoiCqTF%E{m&d1koAc3u-*4307stwYfT$gc0E`F*<+O4gO?{G>? zE}kHV@Epfl-~LX${WdqT+z7<Td%a(0p{LV>+`xQ^xab_?CbRQK_rSCV0{N9hlV>0< zr8#$4Sm)K&%jH;Ljk}yD&&)xPS5sk__Ynq$*jdcJ3Ilj9k$;h`1d(v-o-NZZbz+?F z9-q9^iu<lZ{!@PJxcExVfDG_Ck<oCqD3B_to7LXftV`|V+-7i(h9vzSV)0Tf6M<^= z_<cphMvKCeGgx@P&(B0uTSowsvGahFQ6bEY?fbejqGC5WG!Z1*LmhhPgC#nS+yX_b zvUi@HJsbLXnjFbeYtg-HO<j|u!xYZF;AlUXtC-z|-S^8Qfw0d!t}rlEYAQz{z{@w9 zu4+2O&Z9-stOTHzKl<{n!}mR=8C|(j<IXE<X965nBZ<e(o;&yw_iX*Z;7ru=D00X) z6C_Dy_LO2~0J>{2)@<s{Areq{3B@(n7yYU#AfOX5yJSw^Eq6)1I)6j8>Ssy{VDRYc zdw@N)mWgoMja4Z5F?aoicIU;7WUj78vh0Qg@A|Xk)9tb9h!1~EZFqkM0X{>VgM)22 z8np{(z6v(Gtrv=<0P4LekYTTx-!Z0(PpjU|?}qv_wS>rtG74E9^~O|UOZ~eY{STKn zyHiSOul8`pBj%#NFRZQapalcJ$qj9lduj{|&<h{%+_{U$9S7^R9U3F@)p$-zKGuTa zE0!>JMo+?1G<bo}T9i6Ml_{h#?H8$QE?CU2zk7E{+X*fZnQ2-ns@Kf#S`|EtRWm(| zlDSujz#OxxS3&j_59gz8F<$x$lO0J(Av~WCCJ3^8z0tD(TzE{KioHb(b^B}C9F@a$ z#D@gqF%vEok$$s-9JYYkC;f3E!)<3JlHrpuEX7C*g4}!O+h7{@OI~)Sz?zmvrA~9S zX^fRz4$IB7sgFxF8^wqfux=7+m#{6{Qa6M1M&wdVHOw)UH_Vw`{#G;3Br7nURR5iA z5=EfgnAh+D+a}Q69W6L%b*+zSv<4-}cQRY`z~Lr_fL-ck`|+5Mj2#IEjhzNw@b)+n z{7|aCZ_d!0InD#wMS%`qN|QHazgQSC;pB!iFbvIE`XhpxHsy6&;gx}@5spbUen<N0 zF;d?ocEagD*-n%Pr=2FzfFacx`4H^=XqMaXqeFSX6>fEg9?N{um+q%zd=-qTZq{gi zxC<IIC~Ua5CXX+5<R_}d%VoJrZL`HHGRQ&`h0chk&%_Ro5*!#9D!>t6xrt6`Q?@ky zo5x>bd=UzHy0#kM_0S~a?`{^ys!&=v%AnyUT7>UU*=$yv;B(kE)7CB;l;-3($gDw~ zU%P?<dLl_zc<D<u=#Qdjq7-J<&Lyg(OldRUi<;%Vj;W59TH%W9L82xah%<yuqRxKq zMq0nwcM|PS|Mh4#TM=4Ww8r77i}vz~ww~TR>bo-ot7{r!k59)1ZZ?iOUyw2_l2m@R z03ri1(g!0P+Vg5iAgdH7C3=tYKK?RB91jPMiQ5mHXi@81@|O}jJY_vb#ta7(Z}kcg z#I2A8y?KAUjujC`$LDhw6G=AU1LDY<Baxi9tJs<PL35)c`i*|*r)yZ_&2RPa>3nek z1Q{W@X=%xfo9i;=E54|m9af_Jreaper{0a?O#{r;7$6dz2E;UZ?_6)&r1F($xq>*N zD7?Md{rM?u^{}KGU+^bg<Z^$JrL_5mQ~1fl>u%=;!JJNaf;KKOik0$U0cSn0Jl`if zqGkgm!H}?n8*FKKen0#YC&$m?JgDWXVW9-XY|UxO)WXbIlJY?jj_{`rN@>+>>eRO9 zRb{X*vj5_~kRfR%e9j<nKc6|jx#N&_p>e+um8{7;LYf&paZiiQ>Xj+_5pg^JlYud& zS7xu~(|Iozt-!a<Cg>>m2e<L8=niA}Xo)X~*)<GN+7(NAsdyuC^g3b{hq>mQ=sYr_ zA>kIk*P+$Zkwq1CNcF5sHIF8$a^tvu)H}Ne=7n(6w++8jM@Uk>QH+qr-3DOEBygv? zVSnVZ3VG1Xi}Z7C){n-)L>Ix$UrhYux)ym9S_8pJc(*?P%{mnK<EKL!i+C;n5|`tl zYzfo3$ac@(B{q~>pf)6(G1<+LTP|Zm$A`oUsQ%{UV9xPSwvt6v=NFX^Ne<K3bvO}j zYrPFiLgx%e;gg(@^_E4e0?|mlwT~*MMl4ll+W1kaX1eN@y#rDyPG+gz|1Vq50l@}k zRROV8ZP+bZsHu4%@Rf^k_p0~emn5GP*NrgucKWw9<1hV?9u2G5QG$taWV_o4n6$on z{XpYQlq_EYPMcH1v#v+Ol~c=lTKlq!#Q4V=sb+VivZTy0o6+ff8nP8Zt+t<EQIS_5 z^-|PI^#)~x>Eiex=3<U}dt})Z=i7SQ(gnXl<<*Q1t>Sah-8NXyn0^_n;^)XZ*e~q* z{XvlJlUQFtf56~CWwNawgkJej)8{1E5C@Ajnd1mZnHh^nF1cqzOg~a9$*$!pgKl=y zVYWBKZz{zPlDaqjgtX;`NBi*Rd!-hW`y7eK0s)IYgnhE{syqA0-s7eFll<?|mg+dJ zXYFiwkNn*_mh##=U>%bhH-0X9xTj3d!&7Q$1SI<i4kxa;T+!$(@QcLag<zrMEq#?$ z@%xep3UR2pv=5ixlw`uO6RvfGa?_=YiH^=~;1&Apa#jJIX7kPI({Mah7vSFsUhz^8 z1-#(VIJ&&=&evwec|1YHMg1Jlx$kFJT@{(GY27k9i%?F*ri0qd6*j#-lgMRDAXX_A zMV$6#IyA+hr(zQ=>(#+#OLIGH&$})wOnqQFMZ7udfYNvk=f!#DN{Nm=TJpH>qj|xL zUY43>o-LO~>=S1T{P`;(j7gZ;igJ}F@_FynQpZ1mE85{brt%=H8R418T>&X5+QeN9 z*Ia2JnSrNyuib5>GazwLY~Y^j-`O~j&|;6qFHrR~1LA6k-$u*UM}k+HH7k%x`MoGK z8HGCimb^yze?SH$pe)mKiwu|Eqs`b3aej(ZtZ5%TJaTY$#n@su0UEC^Cd|4D7~5D= zmDOoJ&sm8TEcUgj6Ml#On#LhbWXVo!GVg{xK~4#&)5L=Q{Cr|`wjbnl8ofI@X5JWq z!Bt73NV*aV<NdQg!x+YV?L&RlSC-U*6Z9(=B(}CQiJJX(J2!)_^~S~1E_xNNfua8A zx0E@>NUWoLc^2lQd~F%mAu5YRU5UVN#7aH;KUouhYVGD#LpRG?8A-Df|4%v>qhe&+ zW8$`z>B1YPnLrApjGW`?>EqW~1ZTOoj6THT`r*>}`AuA<o|EU_&cz1kRAXP?GC~a? z8uM}1T1^MvGLRf07u1^pn-}BAZ`hsLB5WA{aBBVT6O2`TasGNl%_#K`jqyLfApOwr zzkH_ozkj6q|2Kr96(jA(w*r3*!v>;8p8h{R0<LbWGM$EUe#4aXhx{y}_JqYD)#^<E zhe`wjrm;zV!zStgC@~b%WtOhPn{L9CYdYbhz`BXSSYsB9kJkiCV_ymMaooKrdLV*; zrHEa1+DSn9-41ktGPkZ@h2PqE@hyTLKXz_>{dePx)X6kqk33a%qSn{9gxyg8Qcbz^ zcqgRCCW8Rk%g%kQbx1t}Gw-`;ivT;{9z|MUW`8<o9F8-IchhlSN*luOd9PfnzF7;c zB_ys3MLBwM1>1quS7vhdQ4&+@Cb7qXP6yROvfWKzn>9Zi_f6#-r>by?6YV^CI+f8n z-l}oIH``2`jY+F+qC7>;vd%}J*O?_G;-fga`0l!A7;aqo%=q<CFtl<RT~x9o6kQN1 zhqo1WNfa{&Wj*eUoMQ$pBP6=_5-PRtWC+Jb029tt8(Ka?`cu@HD7d$HV}F}42x@7Z zO#b<UrBL2mBG3~8RvBB#VLng(;zM_j40-<6>PuJ6rY47rV;+W`t9P!up?daoHD+@@ zqS&p7{rupMl@7jCm@HuK)?BQngiCNEL(GGM+V{G6r;>nmYV+#zuCmZ7Eke0AFQ~<r z$ywSh1LDf0yjWW1-Sle=z+d$r%n<(>UxwdYlSYz)Os_vxhQVX{C>)~UYiMfp`SYux zg4LMWSpD6jBL71VS)H5~1R<{bJSC7^`Xn`QViAbxR&pDgp6S28)#h-njEr?tdCqJe zb7ef^&L=t168J_%Vv)WEn~D1tNIF0ygpktHe|EeBls8_hT5i3gp`ih9!NVObN0d6b z1h5N1BBX%JU<cWhq-vZe8p_Rv-CHdx<Z96OmKUO!%!%JmSD<;hT8Hpe(n$?|p;(dz z{8drH3}Kt3CB?NAhUDv3;CiAOdXqQrEJ^$K>Si%Y8nKOmLA`lLA?#CqRQxzP!C!5z z2Ykh;ZbWVJ!DLz$pRD4O#STO`hG5kFI|RN&N_RLg$=3tJnV2xlQC9+-uMr)7hYF%* zI?UamHwFZ@G1x@RsSeimzh$EeD1Y1JY^%ciV0E^H=;QUvRT<52#;8TU6yv6Vo-A9B zbh?aDTcmFM)cPc9y(rCiJkd3|Lvrl&h|KKvBw)7lMv*eCwc72Q=sZce07hVcKNgRw zUGz<Zu2GR?0JU*T8cJDJ-{=g&&5))e6G&3qvmNh^f^AY~dvsccnk}B904sDE(O^hg z{+r6SM$yI0BK2?IQYyB$KH?Om8fm@tD<Tk7Axeqe+UBuu>A}VRKg$X=Ek;>&-V&s< z-~I9P-7<fRl)ej8m94<vjrhxh82-?PWXKRN{C6`kEP<4fC`r`j9Kn6-A!)k9;$-wQ z>iXZhZFPT?5*!`Qk+<vdlO~(qQ`{_!PVoy2$6)jInuLvz1Iz@XhAOg6bYoOmH?OdP zI8`QS^1%AXdk(C?K*1kbDiLCwOhn#EmEtyv1}??MF`o_Qc&V^nzdRE*0kV32RVEnb zv50x`xQ(Yoh;rGUFZ&m*=Y9c>%GFixTOdzAn6Q&ptfNn(ohZ+)+vlALN906d)_5H% z>q-srDCGp?C6T7OAoi#fe5^`OvD%I6EuI_cCjrM@!5^nR;-d1ogNj$xj2=T-4C0d_ zqM~{RT+1A9$87V9iU>R6|39u?BuO9lzvlXjzWW1b8JvOA`XH8~r19R}hKI?$T;P*J zFE=OLR-1HHPD)WikMEWOr*u+{*({M*ajTI(yz(V{MkI}L=vlu0E8LpT?c?i08(MR5 zWj)IJIPym*QAs}9P#N^<-0W=48eG*#wy;!^I%%#!yV^Cgx`nTCa$IeL)C=)ynAXN& zRBk;OZMlYL*x1-e>Ru^EyZr7JqWIckbmP|{BO@KR@vr!XtKLJvisE-yFC18jXsouP z%J&-8MysER4vC`&O#`Oe=9^rEd~4mrN1)O3KS!kT;~MuYUdhO=m&b@bj+EY@^~UL) zg}397<><!qJ1;u5v-uHFH&lo{LNr(x1o`5z;4A~b8SI)=>X-|x^ao5EaQFAFtU#Fz z$oVgqUu3b+dB}yXg)tFsv1${6{>3-_mWn`o#mOHnspJodqA3#BPGk`NZbo366Y#j9 zSsz#M!4b&uWUhr__ccPFgieZSO}4ZxCNN^xD9P!4Cg~bUqQpu(%xyHe+p2`Fyhg6+ zZ4MsJE<!{*WqEo7;#~W{=6!4h5|pMMUo>+{#OOlCdH=SMgWCQNM_;&ETi)O$CvF!4 zRw8tv#2~@i;HNpVzAFCZv&;dMBqI+ef4KNw&evHZ8{H;C+}euu6(+>MwumP&&v<6y ziHQ}65<zYJ>t5^+Cs*qICp<wq?6}ak#Nk4njS`;y<V8pCp$n<V+31kCPT)SYc9E9* zsWep+WUNI2$6hhJ*e=I6+h{WT#?`Bgz~!KIGUn^S1RTYKvQ_)crloUKWpP0COjdA@ zOj2Ok(rd)rOC##X!V^&Pc%PBpsi1nETf$gLrLA)T$pz20+W}J6^fQl(9NKMVAX~XP zLveu{ce(-4SG1+nfrTzm>9G<1)9~<c&12$xN(bbc{O~~BI7&#;6V45@PRLS*2`gjw z!^G_@;i3BDt6fo{@zp%&3v97+xEZ;}3HmBwonNy0Bl5rM_hjQE(MAd-ahbrXXFx{j zh-77j2`IrhODcHqEcU8fMtoE0`n<gjNy}8g`o8$LEIs6i34>q1Km%H4C>`M+Mc*O4 z`{j^$XMc*!=;O<5*0GO#pCg{!a7@yA{R*F>?teOl3U~wxq!Y3ev(Wedm~ZgwiN9@H z&xAKh_ytP0bY?w_xc8`1K>CH;QGe+OeThQX7LD5TM`efX%YiyuYoJpbm}z<@Co`YG z6qByL0C%r$>Q`oFgRT(%xjHhGVh&78YL-U|>er7XDZrgHAt;~M8%!bM69jQ3g>&=? zLS$!}=G3);(JS8hi#_Z+-}ZR}fIM;Mu$q;oOhyJGXZ$3Kd<&u#gREwvORid-fz<~~ z70vER<#d{t`)mA2!wA>;L@y-X+>i#q2faAAgrDV=wllCvq>f)tV<yv}nTPnLGCrb2 z6paj|&++xtrar6JmaY`IYZ~E4F1r6B{rx!Yl|G2ef9Y;=k4T7|&Q4^f;X44z8U;2m zlk8vjeVFH-6#i_6_)+vd{k=wmbVqrugf^)35a{#Y2K9h-C+CB7t;JgS=Sn}VE3$(b z6_yb%wRUHYd?tvj@^ZzyYtI{ElTa&v$+P1d2fl9gI9}nvWPu%YblWY`bnb)bp#J_T zp%Y~owMdl3%)IbaHy8>g8V?H-`TAt^ZhMRASHvAdA_!zMK9&Uzsl2Uz*uv*YRMEz* z>&89rs|wS+)yFLsC%C<3!GtJfpdMQa)-$%)p6pT(J9|&6sdlj>oz$uX%>(|0kQ%<A zgArS837ct`6m0wYfZMpjL@a4Nv8Bhj)<{xw)CsZ(fh1aSLDW)1CLB}<?~AE3Gg1f7 zE${FEs_IA3E|jG8g#i&UFXuvyVZ5b6u|3sg`JHI3dQ82mJuEuhAM7sqp7Od-e(pXK zmQ^K;6>&6l6`uZ7k$!yHl5W4e{48)pr;mKEi|qM~w*vIARZ9ckO%bYq=eWJP8`0tH z5$jS7E{ef5Dg5BJQ!;o2y5~dQL$xom%{qg+`*8P_00+y1vkH)N;7e%70vhw^Vt&4y zRyc0RE6LGW{EJZW=zRhSLxXHqm}b24L!B`X^DA;EfgqNjFaQ^B?M$O^MP|u?z4Ixr z#D~Q=&849Nq24=8=Y<!*?F;GKoK5E$hW3xeO^f^Y`5gUI+3NRiXw?ev_LUlZq+Woj zwJ&gNG~&GA?qSgnu~5zro2)TGOhj$Ehr$WEwJjxL^*3|!)u9L@z!S4EYq-b6C?>CI zhvZnhozybtWxnwkZ(RuA1Zw)%B4Gs7y;HqoS4@U1E}ruEr4t<LfC(r8;NrqO@>@^< zu?IEReehfrl_ATp*$5q{<Az8%_aRr|6?AS@T(-}N-QgTm6#tav>LnO$Vf+4iF>e1W z4e<nuihfvsE;nY)h7B|911`xS)-u8=eQe+|{wk_6ivbshvT<QRZrKs*r61M8^jRRg zXUY1<V?lsWiS5p%AE`qdpX)v(nlnNV%5x^cyAY<bnk`)%k~39JQ<X=_UuAAFhe~`p z%{GtfpG#as&!kyYYx5jCD6jKpUCKsl6q|r&dn5fG?l3MbO%BFDkjLYzki=s`R!)`A ziEp&Ec4whWdT$GErgt66qN>|W(JH;R9bfnMtLTFP&PGNw4!PvV;(m_Mq<V1`n4y!p zAHFX6A_*t@_7#2K=|sK_(0#CH_q({#;;HkZ_FeQ;VRTfs8}0~gUbw8jPK9l~!qgNL z#@VYI_IqM-m)FbMP462b<z7c*A)i(Iu{Wb6Qs^W;w?B6tmdxGivxf*^8zg=BczJ#{ zLx=50Z512RI|jpLTx}~KeK%Np5)OJ;B4aT^a3fjq-!Xr8HbF5VQ4m7SkGV<n<%wu) zAQJy0vVk-AYCu5+fv0DoHz#9&KIquqK+?sVDf)>WinN0rRsqmSijVCpRv=I-uE)6X zRc|q(px*VpV6Eq`A43`-Is6;4#DM|w#ye}^9Nv*CsK1oAf};v$zSf&N(FZGPcDGQW zw8|}^q+HCfT(r`mOoS=iq`j+iS#GX%<BY9LT*1mVI_L{DCyshB*~TnWJ31HG^C~`T zpfkQ#m_9gjs5pt$dzU|%XBTarQsVtK6=*YS99aTw0&1yaZOh|!FYed0Wo+#+6|%1z z88e|gwrJy?a9|G03+^kCFtpzSgSdpa&J6^Bl@a#i&-|JN2_0YdS-?3o?DbL1HzkVm zD@g_i`KOce-#Vook)8^XK-{A6f%+q72j7J@k8%a~@83}eE)DEJat9!lw8$3Bko62f z{DQNV<7W@Qc@IEV{->9Q(YsBc65j7B(g&1`$e3B(&zT<1>cy8)vI&W@^esY1@SU%> zpRqIwoYHbR;DllhJ_`3+j|)X_Jj1RJ`kjdA@f)H{LF5}fB~H4$Yr&gg34SHaOcN!O z!)C3i+Wx4?d7{5ekIg9dnC8SFAQ`F7dk&>fxS(=%b@S)?`5JP67Tt^K9G644cBEHH zELUi~>GQ2U?(PCi!}{3k`Gs^1ZJenKBBR74f}#KHA5Z@UKK{v<qoxbo&WMRr>2m&k zw-;fV@zPyArhFLmBlkkQIs(IqfyL!y0snNelyRB%w-~fbQ`6>DQ&&%AS`g{iokV^3 zh(pAZOZFpqw++Rf+%QL&)LcXPs=&tO{RU%HpFt+hez^2HkOSt;xnq(Ygh`ko7-CMV z4b8wu09X1PI8UaZ3sQqEQ-^TCSPRrQ_+G*9Zd`P?*lC1-Q?C2HiBC!pF~R;J{Yc6& za-i*1Ctwsj44z|k*43&*E{Y6>$IYbMnb4m;puRblL$6aQV8TsuI|cbPQ_N4fkOb|e zy%?BHKvq^(78uycSJOuY%4KPW2o`wq_Kf8o8uV~lX_O#y+AOt4_O^5w|D;vEIp(yQ z>kUs{e9c~QO$A`7;^5EqTq<Scvex9<o9>j1)|igrHj%cr`%t0oHi>25J*u@IOv#fg zfq4p<9wC)*K;Tj9tS#lW@ftEm(#CNw#8%I$tvuobhnN>aeZ^6bu)41J*p9*Z#%Jp< z&yT~&0<&7>tpL0OaoZoRHoO?el18CTV8kh}{F4W?7k3|lU7O_q18&CdB|Vp4?8wrz z%+fn+*9V|#CTqOT#bp0GZ2La%BX18$#^XY@&?RuBE3l^kF8pGaV(S+>C12!#;@o92 zctE2W`&qc(b|G9&xC8n!Yjwb#2GI{ae)e7%UhrOgbSS}R`unJ!=#TR8F9W8x=I8h2 zSv9*!?&~*4F8z9CkHE?y&cpN4FgF(YlIhR&T{|iCD=zL$8+lDhBG1c!<K-r7=Pc`Q z6mWLoNZ~U!Ek$4Q(`+Anj7UPc3&>t<7mW@lE0U=e`SPOAa;#)PD}SQKkMAv%k!Z9$ z+{CPH`oTw@=U2>!slQD(C&8+kO=l>Q2cqU<D939)5M=r!LC&j)lMZGeYD(Rq@A{SB zE8I22B<e%*)UQIBu|aY~k?ND?P<jNYEHR>PS$N+g6kaU%FslVWl`E#^eCy3&YDL?R zK$R~bB~R_~4pFmVh2&f2Z$(dQwCPu71AP3DOSq_MzJ7HhNDl7^!h~u^4EdSb*1Lqt zgTYUT)b9P+&jGzt0Ve^zR5Lc7bPX7S6O)&APsezF`rd`9$PnP&upxrfWf6I<8_7GU z^&Xu8)(c0%dG{q|>p;G1{c=1LcoqlBOS?un)@j2C(Rn2<>m)RSPiEN72kub$^&%Op ziQguJ_jfXb^_1-+>l8M|t(8Duz@ED=n5+d;%7B-XOON|Whk6#C$QegEMOSa!t$dwk zRo{^0%_+i#TY|>2;)L>GTW@Rd+4*wD#(ud#;CwS>_Rdt$i8hDd?`dD>I;&;5!Ej(f zd4BWWh{E0aZ5!+1*;%f}7~&V=M+9b+M-qlt9LSm%^}OW~EY7ZQr8JX*ghb(()3B=k zYov_k@O+iVfzaDdiFoG&7?czr+DzYa%wu5a)-k5ANggon?j;PBHPYYyBeEaBRC0jq z*S~53Pz{W)MR>>dy?<V<n}2#D1&5g8SEuq3QY@?exF$s!Z!s3~)P{aoFb(grh1(E# zaJSGZlwnUUsZeyV6?P*&3^yWMg(qMe`>p<9wQD_m{2BZd56@PwOLWTnuBxLG!^Hed zqEr)Qq2kQLV_Y}<yLT+!_K$B+!>D~e$Ak_%mrR?g3dXzZi9aL``{;;R+N<Hm83n^i z>_cyxl`=lc#g{!1me8lQ5%2t1aO*GjHQsTc6V@?saTo(uAY<kU$t;TVHCs&Kh9dd6 z;i)}6H33+p*Ie3gY3yxceLTKNHzfs%X7e^eh6w2Q2gKSM(XD<?BnGV?Kp2B-H~YT; z#)XXNS5%TY@-J@1f%#v$Lg-0`HU2L!gRQt9<-3-+G6SC#wh`T9i>>K=jOf(9h;LVs zJuKB5)`kinU0Zgg4%d?8PQmsOenMq2LR`Qp*6Rk6V@7XtZnY;&<^CMEFIHj^cm1Jr zCUnUcwgLnlVHCSedtME*?Qr}`=9@|K{md+M_16laqc&F0A_KC*^C^o5RWobzcRoCp zCrb`_pIVvaLNk6{{_i<~C!R#5`OSz)kd!ay2%Ggz_51GwV}w(~Z-Ao8YC?Ftg($m# zw8$R_KI_U)3tAgN2nIfA8JhhTH?;?wzS&kD!Semy_GtbSdq++!bib{Z;qH!R#@U=l zT>vRGff=u?PxsH##_%;fs{K8tTy!xkg%oFT3T*BtkVH7{tk=X>)GrtE90L7tHxjG7 z8il3CpKV7M)%ePSZOg7)Kpn)gHJT&D%r<jL$S0*Nh{|#&aHVc68t0QmhzeqIhcQ&7 zwmqk^W1%Cnp9<^0M<rlz&6dje(IjOqSCi5u$n3lD{VGf0pdhAL2`?N-^R#ZiJDCf0 z!$i+pCgNf`j#B@@oE1*e(qt!c#D_daH7B)GZAXPeBHI@JXq^8&4`le|@QPDkc0bS( zY8lzNV`G_c3s7jHwJCUoz#qILsbhRhx{P#-Z)!w*!`$iX3)}hXMc>)^4m#3{nDogA zUYmee<yn;NCAWa|kJ*GFE0Lgq;J?7%p+>l`NxX*kX}a~ov7I%45N3mE8YAkq#!O0z z7tP9om0RNI`(dyJ_>xeTaK)eZwQP}E?nuq)>jqSc(NHVii0<iiZqdMrGC*wAa|Cdo zx5kl?%R`4(WMJEdn?-f#QAf|shV`UQfJLGogv%PPP<G=zb3iZG&NB3XYo=V+SlTEe z;17vq5e$i_(iKBk6a*Rl4We4tmnf-rF}I_ELlun0t|uxst_-F*sO5}fi2q$=fZ5b? z?qAhLtosCogjUQt{d->^h@n@qIb61F(psh&=C0?o*Qbw(5-*>C7rY^grP$l@sB$Or zz@AbDNh10ZoCQoOk=td3u0um+YiQedrE1U83Wpk375HMegrMNtt_V<DhQqWRu7G0Q zT}jz2Gu!)h(zbcv$I>&EK%}4ZL|&Xh9*iSjvaQ)CJKF*7@`0m2RlDDca)tZA=Rj|# zb`lrO)v%_jkL}FrRX}}0Ppt2{gyVPYM*N__=(EsIE=QhFdZV$!oRA&Rag|G(w6{P0 zo`3N?f4?i|&iGPs3zuNWgvQ)Fo!67-<y#Lmlp39gpz9{BZolFMfqm}n!t9_NvS5|8 zAwytL9U&I?_-0}uuGldPmt)l?18%J8ocLA!VXTi6b0;5ucu_0SK$39gKzb6CA({QR zb38vln+x}t38wsgWS;?j+fT|SiSB*jO(bwZhxdEu)jMH8EhpAmQ1}gwed*?{nyc&7 zvcjiCQ`~tewVz8As#lP&=DX_YwDSQ-C!~_ic|`Q)?)B%y{;w~0sx2fdz4v*h7p!WP zJ)7zpRB-CHCK`ov&D)eyX!O=ePmjjh{>YYv<E8hRLz7iEHYL%8EBRAX87J8tiHyve z-_^Wo@-E!Uh4dbWR&jf~dTA=?7fX9<W@eM%6#XGbrA73ogxRBDfFrA<pKh8QH$MmC z(YwOYjBoeW<>4~QzB(n8gqNC<vPDWqm3eDy6)gxG?Tk4~ePmOp+7{E}sw7$t-H}Z+ z2Bt>Mr^S=)YH)H6{#?BHuR^BrnEMzQ!B<xtHj#Q!*T$OOrUqS=1`&~0E>fV`IWzn# z9@rhG?k?Oc5wCBk3%DlW9rr<apHes?Ck5l#HEy!=*VVqWwMWcFU}uaLO#wr-(|ky@ zq{D>`;J%OdF6QhT4mLR~+p@q09H4C%c@hY(8Pvd#UV(UaPp`7jr|*tWQz`qgPh1i3 zpkaf_;DKxZ5V;k)<TJ`@ubbsf!eB=9{qY>W8E?}L-=;NEa(;B-ZZGny3&9$S+vZuF z>A4v4*gg9HA?&Ne>PVKi1A*YK!6m`n?cnZi2bbXP8YFnIV8NZh!QCaeySuvtclc#@ zvwQcF`#s-3^PFd9&UE)obyw9}Z&y7(ZNXOvdy`OgkE!q(+62UX22rTlfrYlH8Ber# zn)umEu-tr`s@HJA_NSZiZd0>}iK4}vX!vNr>b+>+!9ZROa%M>_nZCGh&v=goSep}X zPWMka^ju`UBryL`K|=&d@gpBHX);Cmb>89|EC1B8lOLRmnCIGbyPAd>Vi<6sUS(TY z=pN+LT(pj8#4fAOh%nl&6mG_g9^uu3`WjrIEYP5B*4MNE6OQklmC%=xL5^&(rINwF zGGy#4v<ViAs=J=J4`v2R0G&H6bi<a1k(Pxg6I?PXt%4}Z{Z2fhF*$CJpk`N}*|x8% z{1bV=ZCa`cV)(v>v^eOBL|I{Vep>7}aSmKdwssZ;M0MSUE(ldy!W}j784i9t79v+_ z2b^Jej*DHWg1FWKC`(+==hlKR&BLb!w8t78n;4Da(`<R3Aa#-)-nyI^e=jfH^$j<B ze>WAzHlWve5o36Emv*CMlHA@jh5uup-DV>hX{G(g2~(H23GU5>2f@b>)G?#P`aP9c zsdu{D_T>_|3PDigj~ZH;VmHlH><Tn)VJ)sFD?6t%NNIv6NLxRGUBS@=wQNPGDvU9X zOqsNqCr;ofW#XXj;4OWzbg@7C%Xvm}Mkc!=N%YwN5dxGC@Hxy4rg*&2#x3N?IXxQR z(c)hm;f}IW@ZmX8_)4V8MRmJDu|$$*B=8PkUqaA1Mq}f6<=|IOhyTq$jhK?*4XNf* zcVNJ&Ee?i1vRw!#{Ux%&Op4z@KFn_XIW;E!4^e4H5A~4NbV!%$jf6V9i_}qEI-HFQ z+;n^?Ef?Q&lab8Sbeko#)x<wO89|Z{W}icP`vBHTdqt}Y+JUo!1p&Al$LSn|=i!6y z!%daTo=Nt$g4^_$pG&+j`1^7oDV0ODNL&FhONbgUomwk+eHEedfEq7gJOkd)kz7W> ztET14>MwI34}XCPH$<_BGCqfMpf=pY$<0{R*Yz54eB9MQ$?ZybL~5bjZV6*{K|_dE z4yz*x=Kv>e%Kq%tpHU1`MQ{VRj6)^$7AjmXKG+XF^EvbJaepLJ7-fMlq7Mj5Q!dA$ zV271ot%WHgzpTAIwfy;e4ch4FkvVH+5pIW(a4osE^JtE0P|S;COOGy6&<9WuDVXY} z=mTDjW%>nBP;IjM_7_mOO{_Pyp=3Ef!L#458IQ#vHo8DvUiL8HDf<V?><jbb&g``X zGG@?=pp^rrUetUFFx}}zdh5|Ph)tPIRegldab3UVe`tU%Bd?}2=Xvq4pR-5AN5H(f zj7i~T2tPl}M@u)M^7p*x@)-mWvoV@T`O;s0dl*?8QMI)-PuOo41b(&x$oM_Sd4BRM z8v!MD_O#yu#g{~F0WtevaT32}IA8js`TxgXI14U)`rrLlT*4Y0Uh!bNyYhbw1^v!l z{37~&V*2OmbF?*pHy+n459kIMb^!El2UWVoF}UjWR%VZCs`Qo2H^n+2QYYx}_jZ0a z%`F-V;fa6IwGK@AUL5CJ9Q{3X+XH5pkxR_AkKgg%JyoE%MQ@BP$Pn+7`1=VMlUgca zCjQr7UDd%AHz!$Y{a8}w%3)v<m@*Tn^$(UXqEU|4C?G@fuFM85<@d*JUET01?mLMV zHGKU(!->x}K$)Cu3YC@#C67J@|ELvn6HZJ7mt>BP)B>xQep9aqldFjL{?dnz2cc9C z?p-P^|IDtht)xWT)u)NN=zlqw0nwHM?x<JR;XQo^8lymt@1;GjE?{jb64D9WC_T!| z2LKS^cz#44%oAI&XSxO{&w5oV=S(6K4`6!5|0RPQkmy+sr4rWvG5$ML<HIH^u`(!; zo0BEqN*@<W3VOiZZ(I=-o{LMLRR+-9Gp)~9^JjH%d}@qEQYsXupvRy*Tf^r3j)2*a z9LyJo^qd*PINtJV=DJvP@rv0LK!(lMp!}|6A%y$M|8!EEor0NeZ8QYfJI&cPP2qO5 zWH?*K3AyYqN-PhNpASl5TNmDVAe;&|%|1IPej&_;U~WnXidzO+#k`L=bh>gvY0Kbr zPrkO56rXzw=S@BvKB&jIqniwIWr}eFvAHB@n~_ls!Z$YxMsWz$mkh(=ckyVzl_~j^ z>qtC>`EF|E1<7iCfIftWXD6g$P^Q)dU7XRnMkX%#UEzM{&b+$>$50Dj+7ywrx7{qm z0B;I|^>>dySey2P`U|4_KcswgGTwTbKnqEO-<Pb~Ua=tUr-=d&Hy8Qnp=NjjXzOc* zx(m2(mlgg>b{&_dvlh+9j6YXfs=rhbLlJ>?30Y5J+sh15P`xWfD+5djrw($~*Hy$Z zGUu*y2N646NhY&Vqj6E|s$-g{-q`Ow<BV0}CVvJdv0)$TYbfUJ_iH4*B7BiH$kY|w zDYO_zhn0#lS{m}3k1afkZbQle2YM|EH(gC<u(Nru^wD{&Kwc@2xtjVM|IsXFN4GP} z{!r1o70srce{1q-Qc^SAFOC6H&s0T4#3K!)f!FRrDjFG}A^(aF3i#$$jD?z1|8qS) z^{@>P&9|>H{Vx*q@C#w)(>$2<ZWY_j{Zv@|?THHp`K9Wu;>M6tx!7|wqWAs6Gv$3= zAGXUzzY()$^KX)3zH3PR6lOMV$QU<O{d(RE(Qu}3p*LY&T^rFljW>dNE)J?XFa~rh zSBho^<ZA!Ua5V!TkLb)mpF~>Zcm%!TmpyB@8HoK<7{qo&a@CbC(tr(XIXhWAn%m6X z<bf#6@6N-PF7B^9en(-V5b^M$`a;GsWRj&EsJ{f#F^FAX!LtOKeMoPD3;lKT)EoJj zd-P-IJ<IS*>Ya_0RKTG&&#FAnvg#lq0xp5?Co9}CB1S?cW{g8GLFBobV`{kq9*?Y@ z+@smLW7xx^qOQdW$IT8<*%$^LH2yNM=(rK)91T|O`V!$l*Y2it9FkZewak2q49_`I zG*}5^t7vL-&i&&F<Leiqh5=!uM4ELm;cQh@=1>3gL^T@6$1A+~+uP~mcLe`Ukc&kz ztpF4loA>=nQ|AlyE-EGEGd{O75jFJzSZ=S;-=B&BQ-0E`3}naT`K#QGDFL{m4-N(f zBs+WUwu1ijFE#Qb3Ubp)_iBeYA$IPU;NkfAO#1h~ss>|$2>a`4GOGN;X_I6NHAOFZ z7NX>%Mm7QyyPAHGFW4OXV7<8>LG~}HP++hu5McFbF^af?+-2}D=~+Y&9E%AyFW(Tl zDZ@`qf-9|5M)dLzZA5V=FBQ@sw`*|}d}o1#`z__6JwBG~dgE`Y;c$X|Qd~03h-kkX z{Kl!PlcPfUJ^LJjFh8Pb0YVO?I{eG#<yk2G9*l}o(Si!McIFyH*7kO5%3S&5rgGEU z=BN6g@wm~CjCRWH_aHw><9$}`hl&M@$>i6DxNxg;wnbwj*Xi_1#Bbud5_~4G(o;%i zZE_ekm>X0#3X<(s(x)YO43Dj@Ei=);8yD&^l*hgFZ_SJU2vgYd3^}9Ovs#a`ERWHM zwb*`~zHQhFB205@Vz%7E$$8+y3PbuPpynyv=fYeC?FIk(%<wd<?@><AJ`%6!-uvzF z7G^4iQd|EV79dDCvr<Z8_<cb<k1O(#=9gI^Z@qr@XYlwDb>C!Ok>kLP&sKwadxt@` z`V$hf*d@71k_W_UA%Dvch5R$P47GS%Q!MQ$sXL3`XTHQRB!46(?^vK)riC07hk9_N ztlQ;^_@FQN6zuM?!4A3HMmPqgXwVbZv-vYR@BPUM%9`nii-x_RyG6L*)O)mJ3ej~t zlpIwQu0+{Qu;Vc;jerr}<UpVT*zThl1r4Fzd|=L5sa{7@0LLUZUd#YQflIl~p67$n zQRr6~67c{`b{D!%zv{iX_%;o~kgG(MBf?MQjmsErw1R^56fWCUTdsyrEYjw{kgM0` zGm>zR3_2`Z$sgYy?9g?V|2bl+`N5<b_|hj1gpr$2sn2=i?%0=l1pg4glzsECazZVR zKS;ih?YCbN<J>8;KeelSqrTzXPrKMBpD81Zt*ONwTFGv`(K3y{MhZpJR&&EcJ3dUV z=h1Gq*gML<Hj23fbs+*pj&i)c()P5Jbv-%oS{13f{_9&vDy-3W^gRhA{H#cB2rJ$k zsuw@L{fDE1^-3{Hvn4^<g%ApBsDo~ch=;EQKocJLgtf>WI_rjO$Eh6>zZ7Jk{*|2O z>`R&bG?mslPS}oE4IR9m(;i2I5gnU}OFLT3eVa<AQ1>mqdhHgr^}y1oS(~l!jXLI4 zFV2~65Pa*gZ7a2RiB{lR9~eO(ocL`mqTxovQeBi4<cYNc_M-MCd4IO!UU0-QqWIAm z?Dl&Vdj9#n;@|~4*jghx=wohlFHfuRvtSX~8DeN@DPaReOv`yBe#eh|>R8XF2{}s1 zQ09)_?3mooa_|$qd|@YPu84fV=D@B>0{@^JS}HY7{@hacR<~tqp+HdZNcr6agZiGm zt<(L-)A^NY{qCwq>~lAcq5+Ho(IZWJS=vLZ*Lq%*C<RVdQj{Z9^OZT`)t>T+LxX!z z$mi+Mvy<;=$Ie?^=C~G*@%;7IT^?=B&yqHK4F9o_vA{%bqsuS9NC`<O$N1vyP{5z) z2OP#wm)rIze2RSgx!eoZ)@{PzkTc;;D{@df65BjChaDB+lMuOKju%+T2{63w$Yj)A z+IEPShBcO}5^qS5KRw-Scaq)Z;!{vItz}#dHpeBkuq>U=xT2Oi3NS!N5k-#xcuTrn z;PpdTdXDJwj{dn#tjpfPL~rlhf$>1Zq!)>{y~y}_wD?&J8bi(0(ZzXnfqr{!F>23M zfjF?U<Pk2fsTJ~C7`jlHcUwByUqN@U$HPmL|HE!>Y9#4b8}T_OM`*HOA{B2#+GU() zUS|{P3{|se<^$Y8ynB4iris^Vw=Q<KcYwwEGz1j$4(Xi4ro+gu4<oKdm<cv_@E4B@ zayO1u<me)R?_$C>41=kw=H9sM6FYhX>1wO@rv@KSIh}6k)C%+|ot&vA<t4$IwIHkG z-qT2N6%@|t^6U%hgGou*rQPhzm@xR!PU{2rX*Yujrq6sGW#+5PsH&?7Phs+MCYxz< zS4)39DwhM`R;&VYL6^_nY|$cYwbrC+KR=xKklfu{!jEiNGYzg8Gf4h=HjZn#)5dEs z|4c_FFp-#hTspsjB{&lUIf*W#vJ3nO7{I6UdTP&R*wPXp$7}~EfZ7u;C$iXnma8Ch zU>bWn`E5xHwH69*J4QfEW~?pT5C5fr`#_{GthZ$sy_&Ia*`>hZ<XFg@@80TKKQIT{ zJfeP&eneq4dM7G;*U^GVV&B?#vp-M(t&-Y#$ey=;pO|hils^}og#2bIy;gs2&CxNk zOmu(Pm_vRw`0H1_d>fnYblzpZrr=hCTa&RLR2-23rE=X^gd_ZpyWG3#%7~S1SPYK` zSfgFb(hshCwkFR^C>ad~>rJ{pRHF#6rXP_8(0R*1Ik?h)Fk6WKVz#XCgk|^%eZ4x9 z`g&jbQ6G3x%22kuvz*n_sD87B?P`Iv-l0HmaG9sn8+!UlyYD2Rg5p-f?#6DqZ+vYC zvVg-=4o|7YqVmwp$zAnJ!mdPfjm`Uiv0PZK)Kbfyb5yUG7Vn)9T0n+CXT=27W=oIw z7M%pKT(&v!xyD7kjVb1Q#pM2Rwd%K#e9ij43)=2&)51VCX9C@Sc5&&$Jj6!?1ggZW zkAI!ZUih&FT}Jo#i9`vMIjT*;oAsly$g%apPdZdIyfMycuFl>R>*{^3Kwgc1;Wr$} z?)!nfZWDCZDsa%WtNk4nL^s{{3f5MGoo$gDMNh9IKFEo@*3hUg`iHF4d19N;jxNkt z&6(N^dsDvZH)mv)d<p(N?F3>r1Ay6TSH5w<$8xJV#x^ge?l<|-)$Ev1XIrKl-h|u< zbPPtZJ6ni&pL-&xZ+CaKzSerUqWj_Jyi%FpEIWe<#KqJfvlt<M52C-j_y}Jb*bu5S zQNj0Rd`#op%tr9^8--Fph^+HC$`Zp?oH&g;GYanTwn0X#Bl_yUX(^?;Y%Jp=Hgkj? z9p!<~B_$n$&vCrPGh)VPir-CUJ#IV|7sg-Bah&7SSWNfLFK|Bu)*NoCaeb_@^uWPt zL5v)jRnIsIZe7zI`C3*$<Ccr-F6W+E0r32X?I`+g^ukX$@$F!7k)F2qqL%EDrig<T zdreABr%(CoF~wpr(Q&qSdy;%#r|4J-WPI<iq6)OeSnpUn66o%koV}k-nl2}J9y~6w zX<R{Z#Jh!3l<3ZM2KmNd_V!giR%$%cD~QQ6^xucGGu6G{{7B<MwNhR;dB=@5uKtO+ z&}1WY%mz~m=(4#La+*ZO7M3x?cn`$#e4fy>d^CRJ99&wD_F?r~ZDZU)@1#&nDs4PN z#itl2vp14JsQfOy9ryxIr^Q%(LW8yYCCQzyJE=W`Sl*FaPST~I3CVLN{{U^cSq<g! z0P|RWry~%u+6;?RS;CYM5C^02N2V4S+?euwidKj1(fZ@v0}Z1saFCNtEw<iTugt9n zW#HpAEN1Ryr&MX=r$`pg#DDUC4@qWR#OTBn)DS@8Ah6(MBY8WiFR7KHF|X3#cfqy< z?5T6je%DeR5U=g~T0w%K&F|tt{q$J6v3ohKd||I5XuTIumS1A~v<F{tY=j$Fo{SMr zKrxCA>EMoEH7-0N$>t?+iim%l4hT#(7`4rBbcDlZ_3J_MJ)iHo+24q%L(*;H?3B8w z>(`s2dL_#NJ2Qi&f3-o2aL(s6H)E%=0Zu=5P>>KfqFS-%P(s?ph;#B}!}OGt@Hx&# zwv%s~rlUZuG1DV)BbR5sLu1f<sgfPCwCWnAIkLX4%Au7ah}#cv;2lGmC<0g4&=CKo z;PzTyMXnW}dQ&AY!Z>|0M?3d;tziy0T~9j@UlD2|iRAbLqJ~g6WU0W5VN&GI3)EG8 zR7hN6li>t~lnq%fER*AGiV=$SWCK0j+(Phtw*vO5WdWb9I#|gm$#WNj>g&{c3YB@A z_CHHBxUc&i_7$|bVoL5d-4$J;e{<JJ?#Z~9A{1_`{G(x<iQGj~m39$_JLHw~wEVzC zSKP;vEnqWVr0dOp!tvv@g(%2l2v$YRw(j=?C|V60Az(TILK0mmmNwk0;)j+rKaOD@ zzl+@PYQ(bT8-yr%dtwo4@<do~e=FN;6dJ8g@jE?&BPY?k5i$I<V=yQ&>=$g$Fk1Oz zCb<52!?j_8{^p_5<n(^?boYbT>-*`F&b8@}J)jfO;MIx>nXmz=r%zZdEn&xu8)E|i zghtsAjKCDHRf_l21UNST-*7zk#ygy`jX%Qi3QLE+4K=yM(?uaU6&QhhGq{z{4QL<3 z6N6`Up2}K2qH?3sk*s`pm4<t$BZ1V4=M2#8IuT;qAf$c@AvDBXkMkLaL%!|lBGDkU zM#U1%k<ns1O%I+SuVQZMfh&3RD=_5yo~yrNxV0j9gWE`E)%mxTgCL(_23bI5^V!u5 zB(c5Q*Yf@z-P-GP^XvMzbs>cWY-t*ADlhg*f89-ro43u=q*=Qm?O5;4D8mVG@dtv? zU0uQLIj)|O`Q(t=U6|wb&X2=6XqjrSU^|pr@8NV{=rp%P@jqidvEY2;)p&2MREb}L z-#+^NiU(0eQ9eKl4E5s;gq<d*repB;9zq!rkMpe8{}nlwM=hghVpuCY$wUjo9@1gc zUPMwx7#R(5JvjoiWy6`3XXA#{48MQ%vH6bkLrG!;{kc)uIbk4QE1v{BF{W53N8KRV z)@hgHrq>zec8Ru6$2wwOi~n+`?s7<A(ATW_s=V--GVS*nTytUP1g5}vvw|#g`#Shr z2nUvx)k+Nul-9K-*CiYseYDf|g;G7A>=5?AMDD=WNBC{NC&0FM1s<sh0IYO<^W+_o zv&tzN;}J&{k`5iLqA{%0tU9H>Ve$HriDbx4@GqQh7s9CZ03-L=dZ$}d%@*@3ID*XT z!<>WZj+#4hPG(%>)*sn`Ket`%O)xrv_TaLR$guK$xv-`!;AC`$?7GO)zg3|nNPXo$ zDP}T~@*4n~^7Dc{k>_vqIwNI$1opElO@@C<ATG;KhbDF7@ISrws~omZs(No<`oe8Q zL^JH=+;A1zzqNk~+iT2(cx}}*)br)VZa7m-@GSEGQEnkaA38W7rtbHOm^gty2NO7k zNb^6cDwG@#)c#iCkOlka`31csKgi$8DvZVSYZQ3m{yJe!rDtp$fXi+@d0|WNclio_ zT1a#mD&Zly?)lr09|U}e_?DkVnXneS)4J?>5BN~Lme8x;F>&$i;HlCz`$UEKk4c(c za1s6qoAXzq>`r_`VzZk6R8&;-LCHil_7~W~04dzrojl4TZM*#!jvfwd8yJ9#A(Js* zjMLlu^#T#pGt4e?rja$1oiROX4!a7H=SGvcv#e@cg5jM5LHWSB%_pY4gXn|`sKS~> zq0wGq=!(A1MEv9^TS_$ddeoX_ZIriT1QCaJwAtM+3mSk><#&@8Qj~{e-W7%QJho+i z<(Y^4K%%!)!-ly~OxVFs$ZDi=<U*Z0xeN$INLE?}n4*Ip4Mlm_v7<8kBLi{)md5qs z01vPv@G+@kOU2h9DX_l<{2!PQ0L{{zrhJ5dsKbHg(cc-!wd;rpjqH;&X(+Df*qI+u zQWlk0%ymOda>#;7*zA`w?Jciby&@y2{2z?=r*p&1{^`~}0QK&|qRw;ab<44{?I}`G z(6+(LGPg-JKD!cD2FZzl1_Z*0R~Fe6)vI)fC3A?W&<xcYiK7~~?G;Aa@82rdAj)s$ zk*ewSg62yr(G-qp4<lu|X=QNXugYlZ$BO<Z)H_@ha$CXmGP0tO@lLt0hljv=oQe5s z*uradAQ0C}L(nY003MdwqPOyx2&kq-!&u95L~urHsZYE<PjxM2W_q4+$N(#}u-qPD zwG*Y067d(F`<5MMgqIV!*t*NGrwflxN@Z~H<VAz#L`3ZSHbvjp!k>|IrJ$;&2)ar( z3VJ8@GV94P6(pOGMk0zcFtJsR6F{Zb0dz-8YfBD9;Nu(Rx57BE!W2mkm#<KV7e&){ z!{Z8z^eD3o62(jFZ`qz)pe<f(Ws~$>v7Hzd(>Pp-svXDB@902jH3n>VNfqALAQ#>v z3av~VjJ>0r16}RlY!x~Rh%1v9X;#AoEoG0*{Rd>#_#0#uCI9gf{fAX1C-Pvmk9tZz z!Ub_h+*9)VnnMhy1A?5rTc+^3mi}9kRKR6yWX)Bow|IX;`9{HqtYyvptr0LIUWgwv zR+P}nrnTV2U~=r#%YdCLBy2*4RnwM9-*4*`42-R;Ihwh&>Wlrs{DxS1QS-CFsF%fU zM?XPqx(`cO2@dsvUUqL0Tx+S;u9om+L5mCtn4c?LlCqcj+uw%N2@cC3Y1KK@llA9v z$sdE(%NZ0WMNee3u2-d~s@UkqEv{Ab_Jh9x@;Xs`JjHX<7bTE~M1nVbxd#oSo;)zW ztLxy)PBfQgK8R-Oz1GsxnG@}EQ^R@Tf^Km*;+z_i;q~%Hog+6cB&<bU^}**ffd8tw zjw6Py2a?HpE%Dlgj8O;du`gh(R*ZW#L{451ba$TH0g@KtYU^#vM}XDcdj509eR~yj z&o<(0QvB;3ihy$&X-Nk5&vYPXNcyUsI)sr~=Zx@14jn`iwOW1TVcU8uje~|bv*3YT zOAUD&*sw!te64xdaOBJTa|&*L)v;}9!9PH?79_n=``8jIK4peo!N`<AhidzWDjHpc zM8DgnYrFfUM9eAWqwK(7fY+;ssXvWNXH&F!LX@W~2FH>(38}~?+@Nx&128Sg*Or=2 z{9?&c9Jvwgb;q=Ns@v+><nFZN!^iEu{@-j#r4W1Cp0K9}pi~=xvz3mV5ji2P%V8!P zlAW*W@K%DeyGBR}dnnQm)SGW07GKlYJ??uM?U?G#k>S1exNBqDpinJtdbPrsjcf_5 zYHOu?o$zI74L6sL#%IhyqaF!nzN&Jz(wJU$X)thk5yh(UQpBi?Sy{wa<$nbI$^@ow zAuQ!M!g1f?P~gpH-TSoct}1J=ms9u^G=!}u4eBNYGIO&LuPKsU*uS@IZX{tEL@`k- zp{Pb>%YI#)DM!r;J());HHX^l4{VpEikOE=<>p%3Je4*TUW()F<8b{BzSQj;RGYfF z<zEJdAKkS7sw5EJ-^F@rM~d$55H#^4x{G0f!8y{#-BU?OAb`5%x3Uj3Q@;Sg1| zWqj616<m>>@A!bd74)RuM{nM7eHN;ds%Kz5fpxa#0Qagj<-wf=ZvcMlJZC|NP>xYr zc1ju9_W?sA)r<DVJ5W9Dn2T86H8}a47TMJ{=vrr^2an!8;vhVq#A3vC)zeE*!!WV@ zJ-XWB^gu%F^Vv23z3jHFYQodyOs;OHahP*3)jk{Txt3(1>%^jPdxPsD5?*LuwzeJ_ z__URUVfoS>Bm9MeP@as)dP8d61|POuxT8PQ1}b7|UBF?JX9~yv3~P3o;eKRSaVZ3n zou33Oi4VdHUc_FN#ch#X9zvQL#i@sQ8pY?nv1k71cpBW5rY$z64FSS@i)FW)f!P9R z)~5uQK58DQvsgw26iYP^S^~do+r3ensQO`7a_3o~IhCiMiQG{*P~*!8MfivOnnr-z z1NybetRi5Gn13w^f#6A#*&G(rFo5}xSMn*OwHJco!K_~*zX<~A!XGA;#LEx;eq70B z)hZyuCA|6sF`IlWK+C(5g(2AB`dyURf4l{w$qF_qu9SKi_~_!mep5|HLx>(>O1SQO z!JH6ny#2{%_{o-LuXB?4aUCPSOMaytyZYgLyojZsCn{$*co|<?pO_4e68`}i<wInl zSSgX1XYA-APpCut`-)2LNrTq*VW_2!M?H(<&>tv|t1E&qiHqRYVBTc|t&w<2Q;Z7N zptBKXCBbxWgoM&>#Bw%ZSkL@*8t6_Z@v50WqQ`srtzWMMr~PP34z7!%E;rv$Fnu6J z*?#Y5ZC9legHSApkZY&N^qvL-$4E-Mcq)b7SltT8Am3(=je>^k`Hxk1GzF4lv6i!z z_dxc~6{i|=^g|x${S|8w&>6Ms(c;ce3!P*0t)KEn%cNfl-fl6T@Tls6<!9L_fe(1^ z-X0a~2{BhADBmWM_@D_zgv+6J7}0B0f3nGNTPxg3$Hgxk>i;y{j}`ykDO$kz;8h&< zSrYYloXV`OV+9?q8sbrVOAbr#q_gd%ayCDnZe?-RvC3BI`Jul)@qPKn6Z6AnD304} z{#IMvS(TU&9r&H48UuFNhTt@7J7R%o4}_qPOTj8`{)~A+a7I*86fB&9nXT_7_C$O@ z7`~ujtwL_y226Qvoc#8tcXGUcs+K{B&(HB}PoN!g!=n@qE!yXv5n5O|v0B;&Nz1IH zZfaO_YM_R~Ka7cYtG>h|5rP&f?;Anx1@kIUm%S34pYR(aSJ$<pOBYdPi(ij5n_$_g zENx2Xf$WPOc?}c3P@h!G1)BV+dZ@r*sd4l17Yt@+BPi0Q%|O;4%*RL*oa8QW+yzun z7ZbS}o^)n%Rs>4Mal7EAF?W=0pTSE)+nDnyM1QK78;-rk_I{kRBJSR4H>@d<!CINd zAWt}U@zi*XYpk^5Kf};rasEAs!cx@)ZzUF@ate<K2m8m_`*lnFjQKeNgXy)0o$x{z zg7L9{2A?AB5U6;k7kNXBL_9vjM7cL~c~?VmIiGi)((c%{Cc~xRHI0!xBP%jF*)k1E zV1!YA)Bf&MOzJ*Qogq<t=V@|EDWxETqmrmb!>Icwm52wTGi7qc)vYFzlM<LAc3}!J zhwX(EMfqc4gBo)2PP*NpSp<RxGNIK{SZCAq!Z~K$ld)*8)<j-FG2KbFh|3lI!xGen z1fQ5)z%?QrzLfAfu}htpd)C#*b!wyUSbxpqcyP%XMAL6`KHB5}1_p5m_B*^qp5#xS zr9^fEU%5FP))7<uV1p(>DX&+fn-M%lT=jjhw+kCx2!ckI#eCCyl^q%f%US6IceT+i z20m<=XG~FKA`4lBr{mJ;Z|ihrlB%taY7ABm)_?j0VAq=|U@w9dP7@0oQ1hvRqb$2Z z5Y_*z`Q$c-N~z72QOt(e7*Q)6t4<?9N1GMvN|@HH`BoJ&zTWwhjR1`^-YLH_`AimP z0nSYw)~omk+cJuWM$0`tazEpZz7pee#>+v+Ct6}DPM=S|SZV!|7xtlY?CTrh?+h)o zkxOwKxz!uLQypQWMsSlBrDm&B?7fkFr}e3u7gZHpF%Ma&e&JYTu{5OYXa<b#4ws`! zW03KRFeDyaMrY_&QQK%AG>*L8^Le37`RJDGPioft4CL14<XJNRL`9g~i=bXt>J?Io zz!^Lpf}lfQM(6}Or)j;I#1Oq11~3V*`kMoC_Dv;s>#ah-Jjs10R}s%n_*gbqyR44S zy_lNekce2_ht&1}N0bXmY8K35F4ILkNR5IzlkE_1FoLpZ5=FT3S)mitDt0Q1EjLMO z>CiZ0nc_SO4I0k>@OHkNQcpLPI;x1;L~CGB)8b$RApK$Supog2P`3w)5$P|yp%EVp z8kC0gNJkc~i4#aj^+OBl+OOwrv5j?KrfC}WkcTR7IHCVqJps=~`+6)h4&NHC0JdjZ zd1Mf?cmY)IJ{4IvZHI2qjz7RdI3x1z-L|iLa%y)2;mlf^D8fvJcQ9-fBvV9e{Ky^e zmy)@*QbP%L^SPa^f$Z3Q{D>Rc14eos&86A^^(7bVyBfNbR+s=d!Juo*!h7rXhfnQO zUS1t{9W8Ox?mBZ3;Rhvc%fp)RUb0y1#^qG$?w2Dn+cq$j(&ZFWYclHS>C~$8$iu}# zjHAFJRhn&3e6@YRVqG{Mmw~A=uQQot=g8@L9y1eb%KRri(^BWafEXe=D34D_Vx1+$ zv*i~I_D1ox7AsI4LfUX@_9a(8wVz53F`avYng2e9E5sk4_yaMKN3&e)Q=t`ZvZ!(H zTFWo?7xs0IWOX5(IP0?Ro~<q^iQRkmk#&yE%k<!uz%=D@xuUDDWuBztUFMOGQmP({ zuibRZ=d+dAWJ`bn=e*gBMR61xNdwT>0CceU>;C1aB?`EXj)#NUYDa`Gmf&OW^YJ~K zwDb*|+=W!!YU=!N>SAm^??Se&PobB-S!Xn3?czbnd8!h+7)8WVYwTj6rA)&rWIEQs z2?H9abmtFu6*8Hx&PW6n!_~Y_h0^DrQ57kaPV>8-#V+qRs)qyH8dw=jOXu@IJbLg< z)+pA{{<#!5gKI9%wqQ5ni5ggnEqviDu9nJ9$_{@{o9duQH@Dxh{>!jxv%#b|dh;+O z!5Rh8sd(RrHQbr@g-+rvjaQJNVB{UG?x}g?m`EX@y=;Diu?W2o5O{UX&%c8Fu2?Iw zF2+sX3HLQ0WiTdb253?FI5_z2>ls6G+iiZlb@sin_HU%_7yGdE)b(HCl<L}Z3V1ri z>Ld+QJM(C?WKIRw%tHf3m}xY#9BdVQs3ItI;_PDeRYXty{y1oR&I<HNhOO7@$MtRe z94(VL2FahM;aAMjrJhrK6Fm%6aKiF<{-+})4qJ(ccmdT*w2UM=nCrjsns6V%Qu>f> z9GT2Qn*3j``N6n*U#vNWBNm9~sP?$Xx>^h_xn}pU2J4`trn{HT;4}p10|m27U}>F3 z!-Yze)9Y`}Htm7x%$>ofT9_)u43w%$O*&yy=+q@irXU{!Z#l~10{<JXKdmTna0A!; zFvB-B^yxvgnvBgtTfxry{$oRX#I)W$s(*t*f?y&sa2!S-7-}p0s>i}>5sto)`cXIE z_{hrvoeBZwib#fXAabq-U9pGg1?&lJ8Yf+CjZUWPdQC{0(7>A{je6oT526VA)=(B1 zEOoW=_MGkgJk8=fQ*)K>{m|aOa%ag0_((%0Aiid75yI%<+0{1J6_(qc^oJVizxY#6 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 diff --git a/docs/images/language.png b/docs/images/language.png new file mode 100644 index 0000000000000000000000000000000000000000..75e1d652f7edd50d6a8da9d646e3104ea320bcf7 GIT binary patch literal 74915 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 -|G$W&Qf#RUL^2>!rs^VHl^qxzh+Sf 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�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 bV&(q<>bOK3!jyKs00000NkvXXu0mjfpn=k+ diff --git a/docs/images/ldap-screenshot.png b/docs/images/ldap-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..0283d122ae1fa2f69b766eb5ef83614161702064 GIT binary patch literal 281766 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‰{GW^+E3EAhhIQVk)_BUQJw)f4B1Ho(b-B3V=;DNkx>k3u9BIk$ zgrb~r(NdXSo^o1vJge68=UGUKdJWBY`+clX+9ZYN#CY^CydU=iHk=X9184!mWX&a) zPM+qY)iWnyb=m*3ry3#w)9|{I7odt@ZLWq$!fPkj2OD$$SEJ?Wlac951({^e0j$=O zZ%s(vKB4RnafYRwS!H6oT5tkvz(Rr4<@!aI_ox(;Tf$Ong;^&MRpX+8zsjLzQ1H5z z@bpfduOljS9xu3Q4rI9EyZXx%7hbku&Nx&wW-Fbne6_*5lUn<EoA(bJwZZKH3&yuM zAK)FTI`GNK?1rWRefdkq<<wPo8=({U$pU8UnD3l2v5ZIc?wW|sohbsQYxa|`G`i1| zX*I_HakpC%y0~)SBk1Q3j4Gla!)A9^NJx<od(};?QG4@RQll&xvCT~RQW4H4KvKYF z4ac+zH{x}rMbz}Eq1BE~x&o?6kNo3s^wOAtO!o!C;>Ozdm{>_Z=}4#lIDn&R(!G2x zo86qL$~9O2&y=<Q?4~thB%w{s2XtriC;wxh1mK|fydh&a9G;`-!F^phA@_oj;pDb| zwq;$pF_rnJon<k?BdaU8y}rk$(0v$6i@TX=K($)T1+78K9u(`nIE%mM@x?u|oKk^- zuwK#mPM40`xL#)R2w4Q^;Hu3PH#bv_T25d#LsT+OiV2{Tvi&ao{AdYjZG<+QD*8_9 z!<#Lp@;C#FHW&tnO+Z1_%dZJ&uRTL-*;j&>detM34Q9PJ5%amt_<C`>cbh`ANSI?f z@Yhw-Te<P=zF#g-eb`0BeW3NiGr=kzT)tb8V8|z&<#b~6Ii#|BHc!@JE(xNdS2@Ek z<LU@WKxX%BtGz@UqKw1U<00M18<a6jI}oIdFbor^)V?ed9Z3XDm*#%D8&5}!la|Yl z{|T&dG?SMtxE#X4+k7Lm75Z2btV!Hd7I}+m!5oI87RP4%s#Qd1Ak;B2&9P{WNK1th z|MCc@W9t(e@7mP{g4mdT*{bSl<DR?-Az-z8h+~cKN$Pe>P3PT)vkT9DhNHO}6+lGE z1S#T~uDe&J>-EfzY~&8qynjJCE_Sw(F<KRBt3_@<IxN&=@;Q@eF@2ovYSLAgMtcAy zD_PfdT7p{1V;FkU@DJeir;AZc9S^6OAn<k^?l$S9dG=};ZD_X@E7u6yzn}3$QO+j$ zkyR7onyk^oAWH=nk3?Wr+~}TqR!;c|2<KK}jdVel5ja?F9;y+Z$CSz!)Z9zZZL_u5 zp_)9szq<hPAMJ4*4D&}DixG7a8gL=PsY9IEhl>iItkrcri-6K$v*&9PWwdp+!xf6F zsf#qxnq>`GZ4GrrHxTx(ZngH4geTTgT5#LVmg04#fd#kKJBD5u#y=d7ZE!w-b=(32 zq(UAe1H&rOm5%KDiP%}Pex-&x8RLX&u80F!-7%Z41oy)dX?4{sg|Vj7LCAU`gtfy= zYk0|aY$-}^7E!Zyu`E}gcbB9zB5;2eZ6S5OQD)+OK4F_2X|dTwpIyH*_?lY}(i3<) z?XA}{30}8OvTHP{03|H)&2rg}!rXdL4JsK`fJ-Ovbzc2nIp4lc0u1J>v7I>yIb9x{ zML*tzLl;u&!?yp9_ccF(K>%;uCe_t4z6Wfy_-=@+33f!P&2WhDGo9H(21)~a4r;3- z8<h%eJq_%_>^SR&A_-k{PX;=a`G<CKPyf0@kcBglAx;w|dP0goAn=;YO{(tW`occ{ zZLm2wV62g~S$)>UcYCtcp@&MCaYfEPoTMJ+96x*%Z{=PtHN)wuR4&Z+p>>K+Tj{S8 z#D~oCasm>d*M58Y(Bc0FYF;i*qgA<a6%?;d)__Tn=Fn9+CnQ+hPTq#yP3hGSn5`D1 z`e^m!Sl?|{39FQ`UcL+>+UObeB`sy<j%e0&e*Z|d>0v!Xb?8llgeH9YC12yJk{ctW zg%uw%#|S_}4vh-!X!|5l<0NdhaGaa%G(cu|8pqnm@?L7&B`@ENj3>stXa(haIcS>I zF2Y-v=H}Uzr!iDKi3Bu%ZPB-+&~HRtbyw*F&*xl@5Bm>?*Z)+P|6w>JOKWWRo^ZS> zCpQU=zmiV+9<z1c6hq0y%3^0@-Qov$Fv8Ugl8%fj-tDVw-ZF?4U8_;E3%ujJPPeW9 zaaMc@FV%oN06|{YylAAZpQ)62fo^Z@+?BlTYTJ5jd>jUtHCUDyW|<`KzuRjH?wBHn zS3p#h;(JtTpMMpM*rH*ZrvF`mPjEEvS1VTa`ib|8&wco`Vy%Q78WJ`gwU`_>{P<Dl z?H?WiP=3j#W_Q}W{Udbc?<z$8SUjT=@CIU#nfvC~(RN1m(UL+WjR3gnjY0Fa;Pky6 za>%<=fKH9ie%?`&;kBV~`{A6c!+~`xeCG-LzbBl3fL)1S8isD;uG;vOt?UP!;NrR6 z*HeC?*3y{r_0&$#9VT;*QaH9ju>{Ocs{Nv!8nZT#$*gh7x(;0S?2dd8QU8IbBOIjc zuOlku&CP7@X;CDvy~`KGfAZm>p!HCHswsFj_=+VjA~ocTMb`=9q|SE04&-h?v{t4d zhblV1gxpSF)blwN-Sznm!cTQ7nx24{kHP*9W$9t6JZ4F_R_|(a>1<hf6kYb}zBUS( zj{_!vDe=Gs`#$`%%IkjnA$@rY95#s3$+xs^om2I^^wJm_!UxHVf4-LTzoLV2arKm+ zA~pHtvn2m!kGAHkI2+vQUK`U|=k!u!qy@#PUUWQbe|oaja9SRyHcgbPk=XLN-iAG~ z(6dJdycUf!n{0P6*2@tKOc9cjEksar?6+iFlJLIBkOFgtGU}1U)|H@Q|APT@rTcCl z3{jEmP(XYWa<dwssU-zZLf(JWm^e)+3IsOfL*Jle?|3WPTZuM13mVe+;;NdgupYa1 z6GM$CIl0!xZ)<0AVm~VBP{E%P98veB>qOC8kkpCkVm(<f=bHOge_RWm4p}Xm{9WtJ zi@%LpW80}KwE~&-I~6(I(S}5?)Fm39Xm_fRe6rT@iN3g<ZX|l$Si~}VTfEjM@`jL` zDCCvQ#)q|#MfIQuQ<<pBOFqN#PLqv<UNn|BanI;!Y3JCLQF*|A&qx|E-)l5E2JVOG zV^+jgW(u^1Z{ECl&#lSAH+!*LeX6s*?YuRw7ca+>^J~{~t}?Vb^stmdEM8Y|-CB&_ zuF~mBumO=!%|r}RNv|sbi(X|zIxmj4`**td<7>_dmZWC%TVDi^3xBQd9VY1tE_3lf zm2Wyl6%FBMg`i<Pr1ks%eICE`zu;Y_u$>|7P>mb@=2|~c<n04_p~4roWj_WBU<6cK znx(XD`9$+22!iwpzaL&0>B6C=kt?P~W-nxud0**rvaAW){OaQw4gBYt+XVir{fYe@ z!8m4@Cn!(TmTSjYy0;-ex2G%3`o1z>F0VQ&{&6!$jS|g_8q4tq*t2YL<gu+E+}2lO z1}A^5I}rE7FLFS$WQoi7mn*vKIy0Pzf?aJ74nwRbzl9&-@+;AQ=R0n=n%Wp0+b{bl z*Z0pw+tQzntn89mq|z<-L@kV~?+P52>Qug`_T1*G-|N6RO#%IS^F#s-9rHgwQz;lX z1S3Z6a)l#a4KQ(TK~q(4J5A>{-3aM?Gm0YIo&H*;G+Fgi8wf?*iB<dB!;}GdDR6jy zX-iB1wW~cO^s8`;&WbMVd(gjx3-y~nmp`a&D7mnisVVh%()?$usHoD)q4jL4M%0Fi zGMU7^D-_=h!+}dnA!BAAQnKu5rg$eZYI(o)5ew^Guq}zp9S;haoYO+gHmi^>775iy zg^4f0`K%ko#{&2q-v2?e|M|gcl4v%NOvO_?EQV<IBP?v|>vBeG8L6J-J0q4F^`#YK z*(29SzEwejxt-V6WLe0~3+J}Who(PLd?&I-Oiz}XR!)xBuze%^Z;nR$D)asoRa>%3 zHS`yZL2$aNUi*~FjG{AI?$FwPe`x8|a}V~R6jM8P_hOyds?;CdZ+}&oC61q&CdJNm zQ?knw{5MISkbc6j!l)BSfd>^as-Q}2PjYSd6Ni!}52v+J2lvL;s-84#!*&pZ;6_>R zxn}LgwClQ@vDMhd1|QctyoG2fi(Iy@)eeV$z6J2*4kA6duaEKi#%A7nb7Umn4P{+O znxtH1e(h+(^&WYHr7v#5+X{U!G)qd7jlFbKJ}hL=IV;b>Vby=%TJN;L=6g#9$$t|{ z!f^4?nXup616~G0R*QFWPm6<d;gsYh(?jI8vO2<g8Mv?pMwimkZ-5#upGZ?RdGbpx zes?FOWtSaOpNLBL62oH%2dmZ72mf6dhx=P#Bwqq?=|`$$hH3>+SLQ66qi(gDU<$Li zZ*_dtFf|TUpT~nrRx7F2UvE>EyW(2rq0f}xll@oAOx6Cw^hRN;+yy5eH;m2sS_*c& z&72^cXkj(ZHLi8?0=CL8MjM`a^D*aeK@2kvK(a>S8MqD>;v8(ol?>I<Cy+s0g?r5Z zMS|a-drGvjX!*>r6%4k(BJ2sTN7V@8XBNyP6vH1l#PkH^=dJb0k&pO8hv!~U-I!7} zlvOjWkF2mP-Rdg7$wph~!};%OdUZcr*bjxlOJ^;sDjeF<*Si?)UVR1f`5FnMM&de8 zgU+XRM)}|FhX6|Rc^Z4ioYcx1AnMEM52&KxEq!oP;g#_Jo|PZ_GoVwdWzl()tK}t7 z;_@|rTd8!t2I~~3p(F>EvP=2GAKB`t35I=M?m!^mqKx`JAtObjV)e)&M<;l<_WLR5 zssY>Nh5R!^+*E@9;$dk1=qxG}Oh(HUc`oer<gt~y<McGdh<69IggsnYHs9Ijhg=^( zyb)#9Gdj{pEiOkrs}?8JzMYLhnySg+<&Xz6-9I;eStK!YAibI|?<P~Y3f9>hajqzL z7H~z}B#7*fYngi1(_|MN9~;ZgSkxDKa(N90SFt6eKzt<TnNc@iXVTA0^hJHYZ~GT| zR40j*k^t<jI_bIBV}0YyY<rzlfl&UD#LODAgI%o!cFvleE<QKMjAqw43WMfp&ryw@ zBe1<_II>#N{zUQd|I%m^6UH%Jb&>33v^mWAj4>_O{Lt+*1mJqhXVAh}JiT!sJ0({M zRz7<MwrME?p>W+^>NTR;GAc7ySl%{4)Z`#Fuf@Utib)_z0h!3#q1XBH*2t6Nw2IbK zxlGpq>6IGKhMcVZW&}F&`5&yhZHu0WHWbN`K@Ibe`5wYhWTsp>VO_8Gt;@Jlus`uv zoek{u<YZZm@f?DE6m<Mc(4aSVj;<R585`(IDxm-8I=c}PJ>6O>Nfrq|CmUWQ{-j`5 zXL9*u`3CBpD{?-?FSt}fZz^L|$>#1F!v-phyC6?|N)7&&dgi~$Jt4l6^Om3EI#}ei z``PBpYI!}Y97@5<r-Clp2W(%}!b;9y%N1VNN>&Tg9E0P^vEz|~D#?!$^{n0H(>+h5 zrd6Dlg&Iva=$LvxhekZP^so3OhI4r2sk!TLHCya-z$L%JWZwdWwED!(?7lx=t+kKq z;w()7gZO*D9oom#(`1m7YKhaG&feV98JmAujRJ6Q&I%qRMNzX24wZwa0}tY7Xks-L zJ57I%Y&va~@Nbf*10>fkq?~pEr~PBD`6C}<_bm(<wbFQCGu5q!IbPQ_yS=QaK{a4e zT%oUsG(-p#J8?AbF%8L9>*rhv6DWyM_C59@vxsWh)aMMlS$*$*0b{Q)(F+R~xwfuf z3i#eNkLTk8$J0646IhwgfX1ew*ej|{zIgq@f%oYUQFN?WQx4Bmt5VmWD3Q62FZAX? z7wGVB;E&wba2V?sFN#;+cFsn#+>F{al7Q2Y>4~RQ%?3Wrru8LL+;49#Dl5&puJL>A z7j)@%!!L5Y%;wLzd-rQkyQ;^)Ui<w{ebGBJg=g1xdUWFThaBhAAuq@@^kOfp*87MP zQ#qE2ATD{<koXg|As77vsMy6;vTebIXH)*Q!EL~RkaaGbL4$0Ky;TfBCG;x=hsgVo z8BcaVD8~PGJVo@=;@Iu<1vbg#T*XfBHl0|F@jS;dzR2zC?q#xr?^R5C?5!WfxF>A9 zo5x?XCWcMaJTWQ;m2R(NX^|@l|8uRf+WSJ2eb97Wj%Bf<9;XI#O`+PKNaevqyu|VF zs1sOgf<X6GOez@h>Xd+l!?E6{v`*jrb;JK*=DWh0%%XNjN5`=;qJnfCno3ioR~4lS zC_N#7N+*O8Iw7E=f=ZR%5oyvw2?>NyRHTL?B?$>lAfXp&2_YmL=P%Cu<NQZ2&c(Um zf`^Co?Y-At<$d41Mz6ls;g=Fp1J@Z7k`?wW1R3}d*{#P3A^U557J>6>Yb{WMx3o1L z|9dmc?UAIdAG%wRyZlbDrESQ%BTq<|4yEp-G=svah09@J)HKQX_Ija<Fif9ITc{Me z+)A=ky2-GKrYKxM5G9Z;8qcXB(#30cTkjQ<*5Y?J<mosGXFGAETS{l`tj4+NioJA@ zdY+ye*%G&#(R_}68>55BVifK!rer7EdoZ{eOugPhNRnh~KtYXQj(Z~<6S5bn8DHho z^m~e-9}i<d8xY6@F$htrl<LQpT>&2K+^Dn-<Mn8*LweB$L+X1URvoMtje=fj5;6d{ ziIy`E7*o`>8Ja!nhe2L|#ECcimhVo>>;XK~?px7(0xhw=hK&5tkXaEPN~nv69a}xk zXSISlgb~+GYj8nZwcJ#ulNTM9$q|(8AYw;<52Eze{H1Mh7>CZt0x^Gb$C^sO@j0~Y z8sqHX_64Kx#q#x(o)L%s(M9S@>TJivZQFkOsy)YI(U^JDL=Jg3jMCqtArTNZb*|W_ z?`&{DXJmB?d$-_J-3>bsE=|m5C8jjz^%iwubxn{qf}Sxi&bVs4QrDmyBm>u8VfR&Z zPUOg`!DL#A#@}Xs+KX%Jp2!ya9QpI<#?5Z~34&AnT@0JnMsMTPPGHDu{3XZU9qdUa z>zR5W`TbOyWZTYW8KjjleTCPwNf3xE9n?MXHOfwK&JAzZm#KfUQXcXsF6EOpb&Aqk ztw)U!6gd1956C3otyM?+bmRxr{4<Xsb+m|bx<2i)K{Ne2)Y+rlot{K_-IiXidEL;u z622>jg|S8+=4CvRrcQ<lQU*jltl>&;7GFxo`XrL#WyoH*dsSCV=&GKA<k-2DP>1<t z4c2hu=K-Z<Nyc22G$W%7ujGi%^sh7sbZZRygI|SWLz-EiQcY2pj4ZN|oONBdWb%r2 zMC|R{1nlH-J4{y}T%YPT?o3PH#pijy&V;s|*EnB-M>}dJJB!&~m~~mVj3xI&*K=~t zRrJ{XZavztcV$b4I{oF(o9g@54>|AV9t%Q-5s<MX_<~>+Uh%$U(pAn#@)c;;t)k8n zh72wy@ZR!oJouf|Q3j?DH!3qBH4)|)cWk`g$bWOKC02sbZeVdq(MZ|QD7$PT2gswc zb}ub-$y@doazMUEHgxA6X&gu{U$rmri(JMxO$Z2|h!fajr0xd$l^X03x;k27Umm6k zVjDRy3tP)elj_pyOSRqu#n5%LlwEx1F3c6(puU&13)5pNeOt6v92tr@;8J%~2^(QS ze-#!@<k}-LM6QFq2}1GjdGF`E1)n6<#l2q6c8L~74k6l}o<UL&h{7+eFE9{~cK01k zNJ6sjys(4h0OUmfa)^@`mPe)KTMiXH@77l><%4BrUI9PfrKQAnZH(N~7KAordVM(C zKjcV67pxEYWUaH28j^<;{5xsXzAo_cA&Yc<w?o)=mD&}r!&6JN?p}e_u4I%oh4j<_ znbWDST41J0*pnpSac~QeuS~#`F!mfLF@vBxHuN(q>m&MUTh$@ltK*9fi`d0{kM&eg zPU{>7J`D|G79>Gu8zPXa#;%byihYR$*^Px%Hn1W#2rw2e7nLSyn4zFw$~+(Bwf=L! zd{#~e_g=Xnn>e;XnLD3V?LTR=J_ylaY^$$5U}M!%U?Il40sAFZW5AyDJIhQP%?(-1 z@_Qj%Kr<tVK_E+~1<y=$otYI#4kq(5)4}aCUv8?+m}g7s#eoLpJ=<#V?6(Cb%=ncC z^NjulK=n{)n#t`^VA$}3%rg8M0i1`-FE3B%B~tY@y4#-cAYYQKrYoCvpZ!M6K(D`4 zP<8%m_fNfn@cu4JC#8$>WQ+3PJdhT@L~GtK^0G4_OM6O&+{o7a<gOg*p5^OqE1Z=O zn^YCOGiVllOxYzpDyUUGrS|<@w;)TEbdJp&QTOwHJ;ILL`%I~crtJY(rj@-)aHDaC z_k@yS6t7H{F(OGJEz#C;WJl4VeHb9?{=sVA3iEF4uzIIDp_bWy+3m$`rFAn5&8NNV z)s27=iOBqoVn0lfe10=QLbBNaPdhG=@Au*E%GFrp{c=y1Hrbe+$ggp8H5ZZev!+)) z|IVi!$+t<>IV_)^RXxW55DX^p<qib*KX!)SMtIo`ti`CYsTk<Q$vu%USRh;BQ#J^O zO;LXe(royT1k6RhyV7VDl^gTTPP1e_h34g51Q_6E2H#Aw?F`4ro{yLKO^OK~vt{_1 znxGb&dJG9!ylc)?;#dJ{pPjkDcZL_&{?tN)UVDV!=D$;|@!_G^?DL1pn9&VQ@|bp{ zPia|*PhQv(w4t9C-JDR1o@+@RyE`JHbqKHTd~tWlRM8>dx7>Pl_4Ck5?{bENHRr;j zwMEB^fP`P@q$Y__Bq&@U_+c~5in;ZM51x8^e7&Key8jpd&fYBvN*3j@5e(aRd8BEB ztTfH9?9G6$f8<kbDO4eJOz$;WonQ_#9X6w4J6_7{X#y%Q1)cRDaRcmrsNO`{_$_sM zj)`+ff(=8pr8<*E`?`*1=np7OyDJB^)>5u7E`ntGqyml5hO0SS`88VOfGv-es<EWR z5ep6B$YgPte~xv-oa#}>DUwddE0>t?p9}Sf5*1xD6bKQ$;s-bt_6D+iho^tNzF|2> zeM}T0!HpY~;A}|;7E7UuV$W98#Hy3VXIJe}ix=E0*XdYOV6ytfNQ;$YtB-dkWj)Nw zYv!*KgiW&$C16zJW`e6J$Ld-M(~mevBbcra@kveAPt#4_#a#NfYO>i!|8>sm$pLp= zs++a$n3F3BDjHo)si0Zc6KC`bjYi55_U@rf%a!`Vat~Pb_LzD^<GiGvtFcTamd`=$ zE1;wIDm0TnfGiTU^E`rr+7WYg=M_z8KW@Bgfx7S4<G0?6)J)(u*fJTJ7wl16fJ4c{ z!4o#B>$=LW@2{?J9K<=!eY`H~qT4uxmnYpR=35Y)-rczYsBAJP`=j+XY7!_ldWZ>V zBQHQvKSr5#A!vo9Lzy&rj8z?$k5;-F!@RcLX&j8{^X-Qhd{oksPKRZW`iz``207;q z)%bPh`*<eyb@MKT`l<n?8z*mKAS(s3%|Ug?1T<`nl!KxEMeft@pzlWa&eO-&crexW zm2%iHAn7voHfGnv(rd%^GJSe|%eo>Fr<$IRFcTl_#Tp^pvWI0BlL%6AVRbW(n9aTM zbI9OI2!B{zq9Dc`Vf|;>Ixg1YY$t4|bia<Nv!BDk=QiUMW`V;a1w+)3nr@4J*?&ku z&vd%OeP*VGa>^NQ>Cr&p<njBcq&(M=;4t%qqK?08G#)kwhPIpgQ0fdkl8uGZjxW}l z*fq!E5qWi_7Za;0uF%yi?v;9@6;IFPdUW}~6;>amEzQv6h2a=v>Np-$x?JG0^JtRo zsn9C50)^k%q6gwx^{u=dD*6jyG{>|JR8O`2B5kuVao6&GN^Q$e-$EN#_sgfm=FAP` zwl=@E4zB^h2u_D5+$Fq^SWdqeehon@NlQ2*pPWoC>}jhnx-}bf17H4HXFc5)7}bOD z5jn{oEr@;PpBLV(rr*TaJQezj?boiHeR_LFvH4<(jXxkvy2`FQdN6bivc&iuXdBO5 z*~xC0S^Zr)T(R?fn2L_HhLdh>bMa~6V(tU9WH9alW<FegeZC@FW_q+a=+n0yKl^0h z=LpTXym3VXw^893@Tlqg_W&HV$;}bpbtZU2H~Aw90$7(D&Ei`j9KY-BUdJSImZk5Y zpsDQx<qD<Q@|RTC*OFfypH-6Pt8&&?skO1U7{2Or^?%?en>X%#z6)J5+z39Y+aZ1U zQ@sJ`fbc*1;!4dUbvoCIia*LJ^9|JGwsTei5@oG=dTHloA8^*`a#a+<&z~tp4y%w$ zw%nZ{ha*scvEI<+H-i&b_zkTZn2K4WhId{_D4cixzd{`Uk-&aBQWxuaG|j}YhpgV1 z9*PQab2)CAjN+=0yXovhWunH~+8hlw!UeYF5JG3E9&j6Hq5`<KkzquiTJ&}X`m0+Q zRp{zCULDScNca9DTB!eeOyjNxqh0X9+&7@>Bl^vAj2bb6XW???c)0-H^&(d;d0bI4 z2@!Kbj}qdXD${-c`KOR4g!j&De@_l6bdf&Gabyfx!J0JkKRD@*Dr;N{<oy8{N8}Ud zTY$dB;Ok^w6jIDq>w)6tnNwA3sa|8GkTk8-)|ndGlvRdm%+V_hrtfqpU!D(8d8HOr zErFW~v15F4KP&qEO?>!k-2pERjGLaBy0tPkIRtG6rcPI%^e$GiE2#1YU1*nLz~=?m zu`eu-QA=3tpC4mma}RzWyLH*mK5=iXM$~8e=v=l^4`&s13X**p!JG?R`K|Pddi$C7 zR==^k=+e5P5P&_{?e$4o>fHKd&A-7c|3Cz_--i9-m3b58>%LZIc{;v`VA`M!snAQP z0(MPUXBGr&<@a(|fHGz5YR&V8$~h|i%Rf*@=Un32%=T&~M|CfK4-kC#_TkCThwm9= za`jDKDwEf%6pOu$&U8zr9Pb>ByLY^EYJ2cu`Iv)y10HE!cB>Ci+UhLj4ce-XM!gA) zsdH!j06zEV!Y9q2txlB#ey<JWnG7W<-F2gS^%hy83YWR^kgg;$N-#xAS~F66{%(`} zrelSI4k2E~Z!xxzD*SN6V(7;pW~`$-&c=8W3Dq*eH`ddX-T@QZp878%LrSwC!O_cv z87EwyOaElqhWTQjj`Q=m%hL1F62O`7ef*c6@aIQyKM^F$`aX!I^~*g6Th5Uq(}0UF z$bP;l*a8K}rIb&GGbgUN=I2OJ9{7b&jpy;%E(b?$ZTX}vuj+GRb|{<QKW1k5HQk@E zjV|lvKFITjOEWg4fL;+|ZX2ECk2xso8}fqG>US8x?r7)Llol10F70HyR+${w#T8*9 zsodmZa7seQm{Z}tuTfq8(Vv7>x;)q)@^KYVvvW*9Ws|;Cf&u;e3Nx=Y8d6UcBun8% z%AFp=$Fk(D7f;nT#U1NE3n97ze}&Hvf8_Sq@q4795Q*ro=Og2(@o(9g2c7_+$Q`*V z>FE=VxZxAlq+YV1N!OTZ1L@6g1$_F2HS<be<0VV%GK}UPwAruoC#l9lw_VGzN@!mA z@aW(71Agj_@u^pcII1~{({K*wnvbgtuNHfN%D3~bGjj0Td+Ss#V!!^fNm%4Q<e{BH zw@Zt!ol2hZStfg1v^iKocF8~(S)4aad4OyRH2NEz#+@qb_yXkHe+w4+!0G1ya^jqi zfIUt1d|pUO#f<J2PUyUP`iuuW;}`57%<9WID?Nu88jF3ux0GQl4L|I3BSaIn*kf_m z2y4Lsl>+w_RjdgXOUSd})wN8KKVVV9-*vFxhT9Jg^!-HBvr4htD#nXoz|RSCI=r(s zgHRLQ$4f6zV}Fc3(YOi@_ywCLb$_XkD<yg>&nBmbGsRbS#9G$d|8bS!WUsgE@JwfY zOFBsn!0`id@Z6E@1C<3gw)RW9k_!T;T*yK_=Vt+9>94lV9IeT|Y&v(9E30qEhSW!0 z7~^awNxyeyiAC<@S0qo@k4t3oBkt)vux_p2%xuF{uhzcuHTITs`~fcL@E4=TF$<A! z#-eU~DS0NoK*P91&y?=CmX0;ts7=1JWxv%LO*As7++lxCoxLD(dQfj5`^|60{3$li zN(%!%*Zb|x9uTikxy}z6`ADP0*PKPPrUYL9K2M0g=6|SC%rsA?QPS`ga7xZF9r!K) z7^mGH;UC@-)=<Iaml@g`VZ0lD(`W98-e?>K-{VqweBeb=g5J~z?}0N$Yhc}z?YW&U zVbzO~BNzTz2mDLmzWa(`Qj%=D_1uIw=Tp&trr`PLo1PcEi_?*h<=zU4Lf&;MA3Yv$ zuqa@C;kJ!lh3W{qUNnrQ#>*`ZYoV|=p4wQZie{V#sDzay^7QK5)%t#*3VK8q!KXva z_>M#adkXHBzjl^zzPi0O>G8nu(~S7$GD7N@kLv`5YxLvm{+)BPOJSrM^hH%?_4=C% z_CwjHm){Md@uSB^_m2uhaeX)A#r;VzqkRmcfY71%0&<aJCop?R+)L`hbK<a^#yk!+ zFQV|#&m~w<GBIi$&U^ZV;Sr{cWl!>vDiw<sEo0g7LcKg2tpP5lV-+Njx5N*4&)#nx zq7Nfe@}Jw`^2nqIa%l^vsu1^{n@=PY;{63&PB9o$`&8Z^nse8CK%7FUce@81#{M$F znN2QZt(|-TH$dPB&+KiKxlQNtUVNXzy0$OnCnMS1yEn`t*PPkp<Mnr+_02DAed(k+ z+@!LkBwX0$t8-h8K*9|m5^s~ylfA{btcaGdy%wPp5q-q8P+sUHamo>;z7koO_w4)T ztiG6w;Y9R1`eK~IA}YWV8J7*ishp*H7Um=FWipFjZXBdv*0sN4vRx;kE@=x1X9>Jj z85Y~ft9flWnTfl>6twQs*f%UMX3AV~u;T1G{QaWk^Zv<`AH5$8*_dQHqpHVFy61Yc z<)n(9u1hOeoT^f&=sO1Xx3b>cb4|7ykz_3W@*!X!Gu44Jqg#jDHvV9OX>P)|UFSc4 zRE8aXa=<G-Oe(-NJz&cYF&O`rI#ni>4?$jO^)IzHAxsQ|ABO;kZ*2$j-q-5N89Oll zxh_%8&66Nh_^}>k4r}mb9CW?)edjm)lBNA&NMEpbh6Z54cBu`Nqg4JIzxXrw1I4s5 zTn}Pz!v~{~AyJ#0F&IlkuKrp9paJ-{9(@cJxt_~8#-AxCqUHCxvRcTD)_McyKkx%* zcJ5K|2)Om8%h04|JMkA6ggJAR^ujx(uV2i5OK?;~9(+F31-SO~w|?sC9O|S>uXY=s z_s;_*TjI!DuxdtvSZSfN<}H%DFYk@NGPnJHx_Xm-6ZSLYV$u=K=B27Lzs%f3q2!_c z^M^W%G?cvW+5Uw6S6#$CAx_=ZpH9F^*tib4*@Yu)dzfFGM3M54$hl|<kc%4jOXxPr zr~g`HZ&O6GHgMqxILUOiDe@dda)pRqv>MBTBb&ni5c-Ql{%ree$m+%TX6mT?dG@mS zgf#IM-@os~((8xViQjvpX&MG(sp^k$Vowu}Q;CPcJLi+<qW8<KW%QB4RiA-D1d^th z%5%e2UG%<A;My4mq9*Gr+w*z+u&@7Gf}SXR<pn}SOZ8tZVa4J!_6HNgx6T8@Cg!g; zJ*`5NgM6UO3J$abbUVqlPJCFy)GFaEslo&qFO+IAc;o)s5pY1{>wVw74a4+<yTY#` z=kFSHkb`1D+G=T1shL~(c3iJ#<v#G{89o{Q+~ESDou3zw?;Lxtr(>9@E`2q{PiN5d ze=8&YmVNTCL9VRv+C3G$KaH*fiRJJHFrgUbsXh+ExvV0k6yt8O$E?mqtEjA&;X4MW zFw!Ua=|yQ2P+rXK7${$j#y`8Ye<|XB;_MjP=Z?9f+D^PH9aiE^CBt}$gJ-QLa>fjH zG0mYKN4?HSg}bHVo3&Yl((9qw4nF7z6O-8|-*<E0eK|iN{7)udKxLNTAyFu6ctD>@ zPI+#?){ZJHA-v9*s5d=u3)Kp=sj5>ZIyMp<w|tKr`GHS9^ZD>6sNP5Dm-;+esob}* zm94*F#%m`vPRFEdo*bZx^`C<Y*0cd{n;0z;vTx-}o&H{q__NoD8{fCIQP_FL1#qe$ zcpRUnR0w;I3b^WTuGifL{@|E_0c98!#Xgj#;eEkX0Hq(u<Ob(h$L<*paV4NEi223v z<un{JO`@;xISC3YQTx3+ErVq4D`>DjvlIWk3uSKmSn&I~Y~sut)CWYCUupVje7ztr zrdhIgXL;#y0(a!|k@b11yO~9o4!C?*ZEX66LFz?CJCL^{TvqPzgnnqv_dfXTHSRZo zhbl!MP4m00JwR1}Zs0lF7*&k)9&?X|t*tFk=HNmwI`$A66Y2MFSo=5UFZT$TbJ`D! z-Ym;5cYi+kAOp473M@<Bdba2dn(MJeHkBoAwTUkGwNt>}?rGH%cg~)qaW%GONL@`7 z`+-9A@V3si#qdbXol;8!bn@aLx^8UdBH|^=Sv0y|%X+<>k<PKuYM^i_@qJS@@iXZy zz)Yr4<iOW!t9c+@yJJ>H?b?aYeUC4KOi)cXT&h$kpS2vu%fjFHL0jK6nt1{w6>V4# z8%)WpEwuUu029pCCjD%><#rVgl&K#d2-k7w72OlVkw>9-VHI4f;5#F-40`EmGPiZY zVH%+xTRCBiSutRaClsoKEGyjo-=*LAW+{QI2Noc%hLK#Rx!#Q?CYJ5s%;;L5QG}!V zl=6*8bgS?UFh(hIA_<vOqy#XjRZp3~Bg$?_{=ErIzP6ki+X12b>S^VTShhEz6#XCn z%c*>9-tW3!$y&@H+6e-<XmkWzI%8Vi11(p0j7Rq8I<W3%MxTI>wNse#U2WFNQQfxF z>@s<~0l$!S4D%1hHMg&x0+YO>=>7z>Inmx3r9yuk$()BQANA~PW?Pmn4XOI=`94#l zJLQGkdyp3;Ksv`4in`sjUTWc5QJmz86zjaDqo8MMlXa{doFt@K2NIk(&H8LQa;`nh zD?C#v*ET%^?1(G%>>TU!NPs+DEU#;d1gm`h2{SeNv%?LYh?<&}xK@c#saDk^r<S5i z#>ciXmQ;#;a)<GFNHa*2eoEGyxIB8Hd6x#M-Y&pbd-RC$_^_p9>C>jSHeN56=ET7~ z_8v*PdM1)-(rLac{ETiLj^vqiX;&NCs}L$J!ohs-GLNipeWpsOVSRYS(Rom_?n>ig zD1f}u!~+rK37av8;+0JcF8UfURgJrdp3LlqfpN*L0+qC#b{|R!QcTZKvphvILld=o zqbab3m$7Ntm*Pzx#MpANaMA0VrPdDZXfB?h9Xzz<pboBbO5l@?sspKIA`TYTr0<We z?I6TlTz@VDl5jS3|22SfBvS<e&QpUfXUQ%_+9jLvT6P+*G-wI#R-9Sy=GKS4+p@$( zgwNL}vHYwZIas!~^oE8nCFc5~D9*7pnP;7t^QG)u3DXT_5{?8p4~bJHHhNR^Iwu@< zHsM3^muw8^&7n$7M<zDVXIAQ0<8vS`@z+tJ#X0^6kay?2?6`M<j=bsdlA4qZwvhrH z&XHD_QFSAU9_UGfv5v|vzDcSMoEIZC72MM9ZZh$x`+SziHbj#IWoMQ%&`cls;XMpc z+W17X-iijicoej|v3N`()HA@0$;LEkEX&jazJZ#Kxjdo}#Ypf<d5r>VcKVCvqw|KZ z@lG%7^Xyc2Rvt7eX)|%<5N~Q9>4gHJ!gSir#^!#L^x{R$pUeMpQRzEGNg>s}YozT# zBBg0-rHCh`Mtwf>F*OX~w{`sY=)CZ*R|jzvLXm1gsrMUD@ViIQIZulYTo%d%IVpgd zW~vt8kCzIm+IlcPc`;&zAj!#;*Sy*%l6G>W5}LzCqy09rq2syG`F94CQi;4$1e#rc zeVuzYHZf(d*^<&5U9X!E^0}d<AP68AD#JBmA(?E>Jt1bt%y>Dqac5at6T5Jb<c(Lu zP-T8G=!r?8<WyknY?YZRY3A75P3rW0JYg&%Wr4@gWUvW1GqHOR<J_eVUG7$-+BI+1 z@cZDJJ0^^wfH!FK>U-l!1Hld0R2p@iCBxQj>t(zEDc}oU8t^$zF8ffeudc-5oa#?k z!W>rrA=`MU@i*DVVu9z#h>RXHX@i2mWofxSR$~-^sX}3lKIrt}mUT_%0F(hS(YUK8 zz$pIuiVl@Vok&oovw=ogus@C!qb<HsY)B6`_Fviohb84fw!i~kta9igbwx<Nd#`2} zuV~RVRy%$vjMQMr)zfGz2ndbY?K#F8-&|u_IWBwHm^aP-L$ks0YuJBiHuegH(;bDb zMEi>j>_DmXK$-uk*3kT$T4OKt1-Bn~Ty>Qvtso4sDRjC{(=v7x`gBR@$^k#-hV?QG zW~Js$hvv|Ta9-dyeNN?m^Sx;Q5OehcebhvgFX&3sHte_Pe)NM(G<R&^_yapoUtf|) zP+r@c)MFC0rGeUi0Y)&1k4he8nRTwwySEdXgA>Wrl)WmziER1d32!p`eu5-$ma~pb zY%;Z-Af40N5^pdma`!kZmBXf-hq8o>Uuvd(yeQRkT%))sH@L>r*PbY5Ki06v=*G%U z4xg93;L9YsEpiAcYCAPG0<%9-Dg*^osoXN??I%7i!`O=G!QS{-!3>eGgaW>z?&QG} z{(8pcipFtT5e*U}D!2TlVOCtmSgYPaN(D{+b{xmv*7NF39hr_c$D@?iw4C^>@{CfQ z>6^;bD6IyYk!m5_)l)KwK5}1vx$L6M=rfKZ&d8i(&5bB1u7=%a88GU^!cff~HM{S4 z!Y*iyFXe3cJ|E|gPH@I8@jTaBKC4W9J?MbnO~Fo-*{I&sMrnuzgsyDJ(s2Pex}AW? z<61<50DSlJv_4yX8ROmM3SD<#jSqEwe0~VGX&;+#G5saNHF<6D5ROKu%xwx4f&n#G zDroAfXT2XTZGR~rh^5vxJGB<tf}v5jb;o(<`I*mL>xC?b0aSJA#$nItd{Zi=Sej9q zutOho4}!5J#wLvWU)RqZy(;q`OO0UqZ0R@)UV6+DK>)Y^bPMp_Gtt{aER+m$QRAr8 zH}MJdX!FFq#wV23@up86@mpIIVi3S?66hDz_Q6>K?4nX+F?u(%Z-LAm8)=UMslBN3 zZtiu3y%^C_771rnMD5PJP+ija<11G3sgd)IkgTrQZMWoRRnI7c%c44ljdC@f0Rj9L z8g4pKNy<WHNvk2VenF1T(NS5-<{Ffh>@t5}cc0iK!O>5Gv6*lechnZ&A^CdoU34V2 z-~TN?ttR6{idjWQ@T;)XHIOFnrFXI}Eh?m)6_w%)H8G;|m1VvZ+=xthqUx+V|B5Uj zW`N7pGkd;SGs|%XAIAn7&#vJ5FFRGsLCA9nTgeXxgY;K-Z#HdvLe`sCvc+{c<`Ypz zza$F})e;$lL;-uYqpHLg^V=UZtJ<ke^%lSq5Dc{%#OlUT&_}~0Cs;GHRBJHSVIeI{ z!ZI_!Dt%~(LAx~=(~~qY4JZAliUY%BUZib;jd+Fib`)1GStDqTkc-h$s)Z)@o-|8W z$>nbj;^rf{eW1nAgx7j@VRb&ckx5fe0jVhKvaE8uMPSUxbaiwsG8$Q*6}jO8!&rfj zf`>0;h$>^xMGub0pE+{g?7umPNAO#(>|v#4fGx!Cs*vYaK<W&Qs_}E(K)+n@8#zfE zsfy*HXVQSZ8L^;gj?yCAg$M<MjhN*DE<+%MRj8MjAL{#<X*HEK<xwJVN2le@+5m$B z3@A_7v`=F7quIwvSNxNY`E+i?B=LbBz)WgIU@dPh%1(BeQptS+8CX-YbQ5Igz<h|C zjfd^>V#SvGn2ma^r`7p#;TUL6K&B9Bhv1pdq8N8hYHcd41C>AjT!hQzKo~#XNqlRl zv&y((XX7W{*qEH%H2d#T4u3u`<3en8in^$kX2Uux#F=CD5ft`jGxUYMUr(<&AC8TA zF<k~)hN;$B?A@(kE%#}gY0#a*l5__DSxLTqdrDVmUzS+dQR1uSQ<rvaJBa0DJC|5n zBRhU%D7CI9nSg$P#rp|Z<EF}FGRqZ}XN}P}{Sm&CfCFCv=1=OUT&%ISp;v<c$W-rz z7kXAl-an<?@lvbIA{4xAZC&6r^&8L2-5TO$_c;DkYX0u4@P1+H_La_tm8%b9H68QI z*cHo|_Bspeuvv0+_2#R?>l50dFz=jwyKLb@eg>D4CnjMde-m|RXsyHtfGKNXc9IeB zCAe&Gn+~NTWiLn4Drt0N6b<Cktm+O!m&T|v%9)f$j^&+w`J$w13LxmdX`Lq4yNv{0 zf8p8rm@t8{&9?rW>7FsJxv1wF(J;+^bj>*6er<V(HkXt!ZAqgxus?vS>jN_OSG}db z%R2lw(0&y-Ugn(<a<1%as$Y<Gj^8q(2||4k6ntx{$WR_-vM4AzeqS>NY^^B-XKCmg z6FHZ$>-14|3pgpE+J)Nt+4hZ)^t3i!KV$zU!HigpP6?HTl&lL@><H?D$m7BK*}-|D zpnx^jX;SMgn~i5F&BC$eM%kA?($JE@oAR#3pF@jjjRK&aZYgpKs})x8&nE8A7BIlr zY$KxYaecK#q;kKA2t(A;w^KuDNJ?zMFmfkg=YkxIT5!-RCkv&{R=);9U-4fVPg(xZ zmvTG3H;e0ic1_n;W@ZVwUqF=-p$U}W&hmLP3bf>8%?-vJ=c8C_2525E*h{QnuBa-M zC572&m?M}u!j5Az{y_l-ouY-+I;xA$XgyLUKHYL@s!i8_;XovmS0LiBDSo<^nHLb~ zP^JQAHMa+fZ;y@Rs14|#eKEu>%|jrw4%Mvig;ZGcI(OXi=}UllU~fpTx+kWi|19;R z*LmoqE)$;`P;kq0=*XynW9Wt#k4i{=CUlb$H|(KiC7sIDq>QU-2wVCeOLn5GyQD%3 zL7}eeJwLAZC`na_(FEzoj$R^4jfspXdL~RFD_+WEULM^8WoOuT<#d>bd11R7X|6o8 z8q-0Wj|>Nflw`X{LsCPg%2vCgQ$WAxo!}KeBoGweo%u1bocyia!*9#FxMHF`8zDOG z)w&v#C5NH+9u2S&r`IYP*o;`rr?Q=))7@eh%VFo3O=ef|ekIEV&9@JkhsF}=HFmYs zw#PB?J2`N`Ob7(IG+eJv4}CEYb+p;oXzyHBv=iGn6dRYTRn(=YW84Fm4w7zKprdzS zRmM!5l+iya?MIKK?ra1cGCb1!8fiCl>+paLMvf0*Kb2pCwpN#J_W{G`8j!=w>2Wc& zXM(HI(u!m{_Qc|#0$;_ga&V-k_;sM5%7zPL;;0b4s^P0EvMzqk%?Rz!8RXc;2sKl; z_k|q?U6VQRmjXmYy6rCo$WFks2M4x}?1$k{j#Z<+|JiVH)9?MUG)&#XI!y1DI@oTc zP!M|xY8lP}21&G9?1rr1KNmvR{q#<VeJv(<LbBL9V2e;!^z<n*83)IAl_W`w>ST*{ ze)R3Lh()5wfU=^WZ@jBN+B1I{Lf0eTxQ0P1iLBJhyGI726$I>;*S4Y5z~0dV)IVJR zPQE-+7r(rH0kd5g1oO~vI<kKi1vXv`KqNS??iJit-SbVG%a;9!-wE&D)5A9G`K%yd zC%(Z7hV%AssrNdO2F9H%VVRY%YndOUXtbKLtr1ciHnX;Qgt$N=p@?-Zn%DCFDNo%o zf93Jyw!m8EsQm2pVn5>(o}>Y3)4sh1(A9$3=6Kp-Q!4*IH-&ZQ++HojfL4z@!;%*V z49Iyd@XCj!%gqAZUuA7HVuGadl`KKA#LvnjE;f-8L|ZF`l5iJ3``HT*fB&DM<(l%N zcj8@Adsc|NBD8jz?+ia<Ax*t?*(ofCUYoHf`;BS1?zx<w2<~rib-)LN?BXTC^UIOR zlK6UoRx7@|S%-Q_)6Cny9hb?uiSEopmJ7&J+X|VV_f2kuN}-i3PLYCL%o<WYc1e7f zXt;d&;HdaPZ1hNq?PD>WWeL~VQ*X$pi4sYEm!hMumf0ZAN7J(~D@tZMPE`!o5WC&@ zULM6ls$^$|WSXt*-yrz^9U<m8;5G>UC|Tm9J1qhkaD6@qDvKnly0XS<I)^>H$*<s@ zx#p4c`s8x!J`40&KFfLjc5CHKWFM_ZpCq}aQ7z!eO8gN7^G=3wc)da8?GpbwDD=ql z@i*2o7Ft^d_Dj!jgydhyqlmn-mSu~>53H-Qdxg%txPo@5Qs;Yc5^(f~c;EbhpNMrF zv~ur07uxfI8|a!lJ+esheY;LP)3*e*?B;=Q+cGg}S+0cA=9{T2tm7kNcnFF22Xr2A zz&X92#OF=-ZqK@7$tAIFG&=xN1{30~LC<h7mpaM!$0!(azE~WhqEj0xV8wq5#X#iS zrPRnA?-w>;it!!kVWVIMjDpwaPyc{gNcfJBKd(t%@;Sqe3dASPX`*yH9v;<X#YspS z3?ydKMpEa>ywh(JK2*f|_)TybeqttE;hHYhYi$>2^<SRgq`PW)gve@JmU*iaoM&q? zzI}J{jf-9T^Btf!XHBXZ{#ZFo);FDs3Khuf1gdYIe!7i@%4mRQ4OAc@nBfwL!u9hP znq$3WDknUv=e>?RPAGhT%<KoGG7@(@^-NVq3LLg}1(4}VTd^L5YnF%Sha3{kr<O`k zqSGPrZjs{8B18w7&n2FSN6r{)C}dyY;qRNIXUXLg<8#7!zrT)82i&AA-DbCs+=!8D zuvjtnJkdM$3x8N<r5IrFCRqAZhVeP;l&tB-C4JHafZy;nOs00vCN070`|f4O{W<pG z%0=Z8%#dVGNzSX%t;=0)z-IhlR4KS}jm!RmYng(JsA~tR9ey`T!MZ^v0OnmPdX&5~ zb|XZq7T*=o|CO3uD!gX1BQxdi^P1%q2-)f5q_;#)$N&4yjNJdU@2B4QTq?AjcG*Q8 z%xh);LT~Irqf+dNb;wF<yW1@e%YJM)yczYhgyyd)+15MuyX0M)rDum+Fm=-p)c$%J z*Y_)E``zOwB3=OohHTs2+~;GeF8?kscx1!%rZ4t_n3mQbat3K+cr&9;#B<TKn2WD= zp4S^|v3ra#*9(-4>G#&?ZFcEtogWslT?~yvWByo;e1Mubk<mPCQ)aF9mq6Y4Xvo6j zQ@5JGeUI>82HBjS1Aa=$P!rLH8O4TUANl<v_0)&9z_%OO>wqMYf~A!C+9E6@7M0o6 zSE#+z8B`UQ&<v^(DDea0!cRx*R3B>T%V85A@X9Y<v>OP_5{_DgI+xC4MwbXq5+uNE zEvd$R!{uFjU5ann!FuHC;J&q&zqCaIPxLE<n|bv|sC<`6Fxy9e4i0uvF*{Y8%+<qL z-lQ7T89Yr0A+00)d+AQ{SqAo!y}f`Z1#U>>FGaA*eZfXu?5j_ZZffQV(uYrI`J#Q> zKx${cznWKvhsXlhMpB?|x)_Pza7{NS+2Hlew0kH7@1kmr&6>UoMAs*k+e+JN@>w0) zW^9R)ETGlr=QDG2mF#)7zn=@v-r3K-`cUdRZ|~Tt*R)iM7uuz<_akTQ$MN4@#vbJe z?{zOD_5zI0+PM>htE2=He1|pMYVO(T#cjFbXQ~$UZz!Grzu(b6c_-jo@rN6h_vZV{ z%vU)H!kJRY5@#@djNKX>iTn_oLbw)*tQN{_aLEx^QzHn*Zh0f#?Ock9-0#~PXv^2~ z{ddi0JNE1CS8~vS`RKSO>qMKr0hHdSSWgXyR4c^bbe^WwXvS1Amdor*wyZ(?j%!o` zZtCI>e73<Wi-aaXJPM{Sw|JDBYh^#WF60s(X#dAYCvWfA9%7@R^$X!L#0Dt^m6UV7 z#_0-UtYFzSmn^yY{eRAEx>hdc+p_mwD?Kt`pLI1}S~N$dJkAVtFW|%)LupYOJu|z) zPIZbVo{dD-_ZCs>1lwK06fQ|W6}0_+^krRttGT~EklU*%ySW=7a&Sbw%>=>N)<-D; zz?~xx%6i|xTZIL|aJ&VF&lBPUkRj%vyU7ocvtF?e(Rrzdj|Ut8SF}BmF=V<Ov9ga` z1K8xf(4i;)mb;w(RC+?lsX9%nFc6I@YphcR6YC!2^gw)mWC%jZ!{(od<1yY)xe$Wq zl`G)#Nhq%8aNCLho&_Lkto1@^^NA&-GrseeBvD5!9T1g;v;r505(2*zc?-gG-xpZ? z()7^ar`c1L=kJ#kkCf%3;<`~sdk0Dg2q^&g8Lsc1{f2kzm9>sQ{0gjN2C4310Ft)s z)27l-)|&pn3SM7>9`e#ST&8CRIjlDZy-428ddoN}Q+RKq5qNYXg4T7FN<0qh>~oZ8 zeQAN#;F}ytFp8}D5n`Nu?vCg4fzPhkV7>EeeB!Q=-09I5X$}FOob)Ut95=$vtE+hL z`-EGR`*~KS$%#ovT*2G1+!+^H57TY3-t5T!CEh%9Fj>Y<`Y5+_;_^tXWfTLxdRErq zS$DR&b>Z!_b*9m~t$(FvKZ-xvSz+{j<h0dllZ&akSv8I+Z6t7~_=#H(-#oaT>PMu3 zeTLuY`&ePytVwOd%HTeILi^X-J14Wxke%(_#v>cLyUhkZc-x0{>fsGqs%odaKPtoj znfU(TzpnhV?XM!S4~>!uWyOv_7U@zy!3{JpBoB@a1ssu=2K$0)&qDCfv!%t9IHTSj zKgx=LO0B^CtjcUppW}p?qdV2&+_g`Yzplvfz-F&qe6!=d*J4{FG{k!7#{V+W!vEG= z(T7^U$ieXOaFSWNg5imYGp|vi3*OYYk9hycO19UDa)RaVu3dChV3vJKOw);_#X1`@ z|GV!V<+Z(|bqBl>_bo#mSpy0IwCCh}-l-as<zI`(B#&o`{xN;`J{MfhSHaF=AZZGy zCTmB)OQvO>S-%2ArcRX+#^DFPL4dz?m$#?hphR4*D3_$XhG4M1@VF)sJNd~>c$cSa zm%14Fb$qfz6ruWw`<thhBN5p?;I`{es}Z>on#{&0=_qi|3?6;C77hKLnJ<AX=Ncqa zvPW7b-w^&gVd6~Y7DZprUmjzrH2=aBp$8?<9bBg*dH75kfilgpmmRBQVu;mt{mIb- z?PLf0@{t7<9}q$12gYK=9UK*YH8v@m>;E$(IUYarz9m&EG9BdI#9QzvAtoeDcL+Ej zuVI~;l`vnLJvDsUa+EWi%!>gwRW0!P{(wGR@0`d(o0S@g&Kxe2rlg8iQIklFnLtLt z{pA?D=p!#%x4ROGw7SCQc-J(hlYFnC{5Dmjnu@HJXTKMXzeI%>*C770tI{6IxXt=U z$x!@IN%FG6?9kh|>Yk|@^-|JYVB%a}5j<*Z$8CpmqL_cCmbm2p?tXY2t*89{z8~mV zSl3<=X1#4JhQ$BKTXK<Z&KM<Tpr1y$rQu>#c0qU5^$ryIoYrn%W?*4j#%iWJ4GRu- zXfx@y9-+Rp!i?#2b}@WMGG70Hn(*AC&%e6VPJ(!c%%O+xmk+t9;NjH$2@+DoLK}^r zGj4OWIy?tJx>d^5N5}Zw0G?JjZ7XaR<YIKSf@;LePJj245MSzcE}pCX2h#ep{Tln+ zpASqaH@*_V0;iGh5wHD@_HqxNKhIb^6u!OrvUlx{;g%DJ4>})d2$^*saJWRj-qhJW zuN+fsM%y?eh6=hAoh$HtLl^d=f)AC6USD2Pv@7I<7Omjp-vs;HX~?NKb9+7_a4yUb zA<`qg1f**-1c6Z{uGpC8?XFRT=_*$*lV{Uf3E=s0D}L=CFm!qU%85^L2c^V-EYqAZ z$L-C^W_d+Wf;RU?p@ngaWQPirf9G&>y1##xzonN-<?d)}V=G@}fp1eajsfm~oGbRt zK!JXPe7)rw;vdnwcNy~o0w!)jHe70(neI!Y(NgGUQRCgsGbGy;ojf;qqtyTn;IUwP zY{KWfR3x>qR46V$AFD}4J8MW-_Dx)X-7B$$6dEtyB3hF_KkLR&CL93P)u16_>G4g` zH;}YlCO!ZcSq}5=u^Dx)u%U-rdeUs=@K@lY*0uDTo&=c>OV5>$n3{Z(dmpJ^xKrT+ zm@*4f=1$SFbLl76O)T)5Zlwf=)<u4P+yV-<<;(B1lK@9(-gse^!K&Qkw^-&{+0lv> zTC$r82Aw!bItIANXYf@5diK}-@{gT6cxHX|AY<2trC=d42i)32ZhByg40w4bBJltp zyVJv`R-db1X>W3A$^NFlvO5s6-%6&9v)uoFvK-2%N;5^t?+k8w!9F#QFF0X-R8k&u z^1MAbvS2n4_0dHt7=63SPFRl-4v@MO)%iQJK04aEW=Zn^W?1*@VGl<fP*G_5y-y8! z6HSoE+#J_UQ_0o3c`A5Wg4)@R?mX-)a9&G4!?6<?=>Rau8p7sa-E;)R#6$1ZAKTJg z^6h9VXpWm5AO2mSz~5COI#Jj;=l6&c2BDmnP#rJq)TMF6)kIp>@_-skM0q*&=YryU zcfLCYB<lb3F(8`T{)m)Yd(b>J)&du)s{EFAb|`Ap>s|i?&qJE^;0Q_BHXn4g&$6?Z z#zi7uxuvo86ih99e*8XEK4x~Ad?6MDD>{aqUv(HHuErhO13y*Ucp4A#V&T_w?|bN; z*>kBKi>&YU>%%c)Y-O5lt3ej-Y3IXOBvSPhJAzW{SsoXl4L50$T@6X2Y>zOffb%L% z+m6bPy7XnU-O$?dxSY|TlwEhNgkvRAdaN2B>I(y-l(oZ_DyH&8eb_~36={a05ZpU@ z;*`94NREV!C2Y5;i=El9%+5SU3o}Z_CA4_PWBUZhrYCB<*viU2Q4QwvEK678TZ^Z& zzQJdj!}imd^`lAFC1@B>o;!I=YH2?tig{<U#=ZZ(AY3Y-?xlvkJ4@ve8W5vYtfQrs zU;ajbG<z0oxArpRya~+xHi)ps|5r@7^s&k!bZZF8L(kPr9*h7_`9(IcheGDPlzX;a z>{#F+`);95K+$oZ!`vxxfMyGj^i_VF6`p?Km}HJ@`B8DOK}MKF?Ct_2ZReey#y&E} zuiQ6#`@Zs`Qp)vtx0e&@sB2smD%MW1kro#kC1f-h)yFib!qCxQQ$nE6%cy<3plqS# z1^cns#Kuu)Is4}Sp*1mC<OD-XZQ}$idlIbK4=RV20`=I8bS5<kS&;xh;V2_MLUC)v zFhfLkzli*DsUy3`E)G^WDopGRF=cNV7~`(g?ndsiM4SiF`dr;u6JV?{db|nLwAU)s zIjn5=5?5Fs72=vF*#Jj`fZGJ1q<0cjRmHtKZQTrUMqBRV{5H{r?69eT>T<s#wU0uJ zJ(7is5*z47R(y?}vhhm&C?HXxBf+lTg1wfqC#jfyS(3%DttS_NyTqw8s^XpJ=y^WO z_0`TySeR5%uln^a$}MCouUHp`Xe$mTYKXM=VYOpC{B5N4E#KKOVM=6+X0hYMiA%M% z<LCHh!hq}rJ_+iIwP#YZ`?y%-jIB(pq^1trY5hf0m=MfLa~ZMDVh_#i3C9Z302t<} zLwZ@vkq)eZZK42eRwnE1nVl(MuUwi>0El&3eW{4bumxEz;-ISy&JM|J<^Hg9pV*md zP~4g7=?~lQB@)N-%5iMv`LnibEX%<Rb#tp2r+;RpP`d+58V^Ue+=AtdUIJ|%zi4j1 zU`gEmjVCzrN|S1Ir<?1=#-~c%iEObh^J&a()2@Na0C)V|+<x;L>U=!mPx_Aaw$2p& zHRG^hcE13hT?*<DzeI%Fx@Bzrq^x6G>Lz03<6O4efZFibZw<FCJeR#RW$?Ni!``yp zg2!zJ&-Do4C}}!ENjWkgk!Bm>x#OzV`NE8~Hy$74(lk^saD-Fk?KF8qw4{yrvI0gm zzytI<E}}2K<xgcu&$+aaZV^(Y@8de=%Ys_wrak?=!E_ChlGk2O@vOF(P9#Ce@1!S- zw`LAQ=i&k!GjNfsAX=qlwtrP-QK#K9IQ5(md-0Uxe5`F;G>)qy@~Wn&^Pk_|_8i*9 z6S4i|jm1bZ%PKo9FgG)=(@xz@2iF-E`bUF8*mHO94R-rbb7Cxb-IBSWjT6dTi;$)C zumOD<9+oK!^Ddcc)=qu8l5XuC7rC><N@toSRi_@Iv>eP9?V+=?8Zti3A+;fU`0KKP ziz=kMyD7<Qsh6nwZ1eDZn`l#`gaq+LdXYuAk(yPZ5G?a{f0?f#GAc*I3SFD*zsO9L z9@5Gs)3Np+_Ek@73MJT8c=*jv0C|G8ugK<(+Sk(0TZUo2xJeT?5jDtC4!S>c3tBiP zu)@yV?N5v7y0_O>5kt0^?CYEh?^<mhUn<@y`R0*d<=)Z!fS;VhG>KSOB*i6Jp(nng z$<VI)x@}j<{o5uIr!1eF>$n7-eSmbW8Ht4*$ngy538v`)=WJ1!&CbE|-M})z-lrGi zpDX`0pDg^E>#Tn<kA{+=g9X`qY<QXy1u&r0HiwvHPe{wI$4yh82)8{el*Xc^l8Uky z6X`iy_mwNF4A3%R7Per`$^kPI)nRo4#xKI)H|JVs|CK;XblKSNebS(G)~{CNiv>GX zZ0B->?Fw@0H4Kv{#yDJMKge605&Ww86dC<diFS{t=6;qtJRobxP%vQ;c~-sF6C~}~ zTw}75N%x|$E<#??X3_?LPPPJrc8gnAWJ;~$!>=S1xDIN&`e~lE9zbmN8dD<o2x5DS zD?!lBI3ob|vovEKofop39e8EWCL71n>ffE<e18l(O&(D<V}=s@8g6@FKew-sd4}3H zq0k0}*^F9fYfwZ%HoC28hCCR`D`Asj6Q>&B?jL3(_H>VMv#0SA+H%{+1Y&oFe!BTe zFiPe6KMV4u=KWiMdPR|&Tb7rSFX4T5>2q~u0<Dx{0wgL4*Xo#w;bDbLrd-ce&uTgT zG2gf0b;Yfg!PgRVr}F*E1pQ+Sa@9BUr$gjqzNU{R(K{n@H}$Q7qc%@lkRtXZDMHt) zHJy&bD+c-_)aa+i9UF%-rP^c5eGaF~4=6LNct+l6GKM<h9v60|T8{bzN$?jW2NdKn zuI&NdbD0p;Ou~gOn;R+nh16nW<qPwO%o-kgw9kKOQd|@C=KWCRVOsuCS)wi4QAsgL ze4|+(6GrXfSfS&2g&j|Xjg!Ed0cFQ7`PMd8>#F1cQ!*^IcEFAA*Rf`hiOL&59e%3D zh7up)Z;}+jg|Cv7zWt!$KE2UVNmyaEDx$G5#%;p0@x?o&hL~lY%zU7Z;NCh2v-&J7 zzFA!@jL*v$(Kv?7zI$rkRdb4M79|~ElYkT$;t-O^Dpj!9^@+dbFC!n7euvhlw*@yJ zHhovmbgTIWv0w^+(x_Hs8X8-4iHAyfKe0RSAB)N_%`OMI#)QCVfF`ows`v+h!Be|v zhcQwOAsKb&#@Ajk>Kbc~2l}>tqGQoI0j8!}+tsD0xYI7(&fVX%7O+m>f}cgIx@9=b zy#mflKF#^C5FV9?@LOaFWRu4*@C0{*8*n)82w=@);FHEkK&xjmu2PHRa{vdpS<o+! zBcaneJH=9g{8pNT34Pj-5c1L0lg{Hb5@5^coGC0W-E1rvZ0|g5*3KKWJHd^+F9gep z%3eFEyiVN{KWZV$(c)n(6`5m|9EvWDQU5AUY4~qxiXN|Xrj&TacCwlaJZq7PIoQ{U zo@XJm6a70>OUHZE(b#zCNSCui|GGopiccgr+&TBQ8uM44(>?uOZ{_BLsph0FRTP=f zC=H(CK$Qzz5(e6))UuF8*!=$#raZ7Rl|U8HHcw6`(W=Bpn7i;Ye}SjRE!d#}`nYOw z$NsLYN%$R2P+N3Kk^;Of*r8<5+^_skVM=+uP=NfI3W;i0XqZt<AVYP1c!AP<9O8+4 ztz(yvY`c4_av&$6JWrx=FSxeI1@;Yfx7~PJS7@INdtsXSSW8xsV!G_P0q{3B@CIX` zba}Z;M%S^*yVu}{;R@Qb#EJVmXA&IYZw{XB-MR9<N%Q!?b=QL549|S+8gvdWw0C+J z8O9go1nSzBdd9aE-jxj+{k-X6KH_KNlhv@X)JJJGX&mye*SQ)SoRg`bu=~dH|K&82 z^~V4idYW{7#p(Y=oRS83JjRi&gDX(XyinWIXf~tBk&@d|guAF?+`Ezp`KLN10O{V6 zc$K<tVDqjA_HHy5NAzqokzRF)uQ$oMt-7j$DG7SeTxJQZy~dtQPoWO%!5()nyhD5M zPMQQ$EHEB_YPN$ij^)6kLnfb0t_U4gi|e^UHKvqk*4fP1GHasv6t%U5hD8jcg^_6) z90|smTQ-=rcms!_>(i81!p8Awr{d{mElNRqxfPvX%FCD2(ingS+(DsiLLbi3u)xMl zIZ1>zFXneP2H4gus$iNM0Sjcbe*30o0-v*j-bDq!+UJU9K3}}$_57jm6h?b>>v1}$ zqF$)>#^AGcqUe|Xthn64QfBOWLzz7(ogwt??f=rH7-~vj7o;z-l+!ej@0k@{*(K69 z#lNZZ?e@!C8fAh+B}!~2Q-T4-zYaCF1DDE#Ye37tR-K<L^R|&bRhBcch}((Z^|&j( zP+bisC<(n;-YKXG-ae~nH-tbkL+P9zPIK`mbp)mMwl~_}pZ!V)JPQ45P>Cj@GVFHr zAbSnIw07z5gG#jjCQ~6k{12ImIwo|}0YG~UfwunnE@0=$s(PqzXB)$^vtb~olbIcs zy1FVzcf9eB-hM*y(V?*IpOqKj$o#f37H~TI|4{bcfo!&Y8}Qvd(MhXD)h?mKo^7?1 z)Tm92wq``AT_aQnZSAeL+9WX|31YNWBh)5{RbrG7H4-Bd-`(f=-ur&vr}y*e_s{j` zbzSFqo!4(3zvDQ=-f1qeVI)>!jQsAscHb#~tM5lOE?cy%dRxHBxJ!$#E@iAIm73d^ z2*}kOnJV@1+`sfd*!_GRT2^6wN(xUtV41}G<ZR7@@`*SMP6oo-2*vi;{-6Kw(elxg zDq0ft;PG)Y@&-8J9nzBWR*NF3eu*~`;&dcz_x=y%$=+(648|nz#?nro-3NLr2}zK( zW$F@V7@3Mz%$?D=jW5T){yMIY6VY2a-MwWCUbgShZ{V|<`*Cd8v#O&QLAk$QTqu$a zDsjm2{$@z<a7kv*5n+#oT;p*4dKHO_`9%}gf@J<<RQ*xV`R@U954YOVPuNm%iniO< zFf;YsAO~WH81fRIfrgT>PlvCbYM_NVrn0?%O;vL6LD8m3$CyR*<ga!2xLcV_W2+s@ zU_lq?bs&bFbSJ2v^L(Fknf6pC^K`d_dgJG`>V5S9GO7yRM6;up7om<qCd2<TPVgeB zT*+)8@iU$VN8FhID!)2#lm6H#|Cg!1V3lKwv;r0I4WouB{t08s?cS8wjsm+io2lWN zBmjYcM%^Q(w-Q}S;&Cxma-Gc{ztt8=`2!h$5`EAqFN|E&up?)QsCrU3Hyc)gsW(ww zlnwai>SBJWkKtVOh{GklI>vCX&gdV(42{d$f3$4%$SH#!^f7lA$Brdi8omF{!0NCR z<=zmEekE}JPV%Q$E_SDo2a#7SZrvtACPtn|AR@W}ar+EE3bCl$&l{_RHoH^}7O7_F z^4_|4>TdIeBUuU8gWnuGcI+abO<st>gx?@>c^tB=P@r$9pRKdwN>8f`@nNC+#0I|e zLv37q11!aON5K(7ui|o_x;>!6UW>gUNfQ>lkt!K`PtRq^9PB+<1~uu+bJO>1Ir~vY zO{oOI-pQUV9np3Ll|d;qqN8}Y&o5*HGCoDLja_%nS>$S7{gvzNm!Ob!zo7Q(=6O9} zJ$oFSz+>&1hk;xBlioZ_5Z3~_=~`e4qZ<b@u30xF3&;)5UF|W*g(?JLLe=J`JWl_{ z))RmB?_0pcXLJHmQ$JG#U<*7k@XYbXhmE6`9+6Fz6@`^uIMea57$UFV)J8WU{jSr4 zH@f2tV?Sg+mV3dOYmfK;GYb92{->|yJ_Ap5WJ$$LJEq8JA7{U0ozm0{O=zEYPQY10 z+$2gy?kk64HkES&z4XHdD|loipt>iBsU?mF_HHNW#qC$wX8}00aJB&1w@rmd84|pK z#S2CzeqSr120D2{I|w;BQ7mR3WO+_aaC2cn!#w<BHdG!KnHM+rzBy?BJom?xnGQj( zF|W<hLP+JG5&c!Sal^P0Vj9GQDj;>fCortsgLsi@2dyjc66=VG0K{9AQ3|RG?wm8) z``p+c(gNR+65TZ5LlqBHX|~T-ea-_pbGh=ZBv)A!H4G8bk)~k#uuj@A|5dYV5G?nQ zeCo@;c+{_*+7AE#D%@w<f|LEQ?+sufY`pa&7Hk|Z{_#^F*&WLcd4Rhun(jFgq`-Y~ z#;ChaL_0pDEEhY3TA%J8**oo8`MT0M#*bhU#SdQh_j0XIIoy1cc0u#NUrA)&A^WZj z0GrBYmh*V6Z$Vcb?m;2m+H2~+95LoGsm<xaOAv?D=G9y#9fo+4jyFq%T3GiL8RfsT z$6Q3^KMCu6yf$QJ(^fBim+ox>_jp~QeZKza(4f@SaF!MJ&wn)-E{FsZ2*&dCMbr@| zzuEuRA<msXTWfSVz)1>UCR89b39@^$jEyh;GiC=^jbJ&>)*qAGg?$`o8PaKdXWTdH zs?aPO!b4t$2K`2}AAR{${Q<d-@EU;dOch=tH(8u;0hqN=Ehj|Loh!TJiIJ}?k_$zi z+R$hWxE_hU>&8hs+-!q(UYX49HB;tR+Z)DF_%K+%#<e}XCd35*QkEad$s)ZfjzsI7 z7z_kf63s}9B9T~cMLHTW)g|Mh@*aXP^OO7Pyd+~tW+r$#yD~<5f8)33JkxsSW6ivP zW=dLb4H|?oiL0y=)Q8q)0Cd{ja1tgfW&2)tP7P%|*1Su}-Pp2^k<l2s-^&A&eEL|k zc<-*L_ObX6JC1>*L|L>)FGSNYNTba7xa7q0xMy-bd?df8Cc(12WwHfQB4%2>aXni$ z{idktSZ84N)J=GtR{*c;-cN`)5g(9fgvx!G-!E)MT7*nqp<*7BB|P(tI?xO46n4y} z<9l(Ll&)<u{M)vl3cJEdw7i$Bnf!!Fk^s!BMoX4X^w}5suy*fJYqXeN@0X&k81use zc3L^3kS4LdyG{caQiVCeYa<sL?E77ph_;RB4x;o$3oe^RwE!+|zt5(F<m2X@5p3xy z*8=ZWcHsB!kQLqwj-9;&xb4KDH?LzxF7ag594c(lcJ%n-vzo6tWcxf~&7q_UTzSEW z@dcxcI7h!4QI<T4Zb~h>7H0iMc5g$YerO%s$-I9yPr{?vXVHBBfPx3L>I2@2BexWO zYW4?|fOO!Vvr6QmX=|n?Qt!9Ca*C26M`0gjE00LkD5myh2reB!)Xj;cM*W7>1pZ`V zsd)^1DOBAPEu~$7NI6CL(6o6%-1Z5~`pjHhExRj}Ju{6uZB5AdLRKOa*!c%kifvP2 zmSS~W3Z0RgBf&X&qqUm4X%U#)ztJ@1Joh8&IROUh9k70B_jqjh-8|ZiT^e5@R1nSO z4NJ@#C;${x8=cS+KITSrUcn&8b4#H0W9fY}QbXLvY$s|CM^KfAQ=3dzP3T^dD;o?N z2J0-Owf8YxI-2YA2RRWCv(QE9SV-iiY4%n2usqc?0%Ep-k#x^m|E(_&36aW;H-puq zVi})XzNbbE%A-@hlIdP)l2zExk04l&G-zbpCz-V0*w*&_OvUHYu1?hkz(n&g>$F2( zBG{8HU@5f`M5yWUT-d<u(<N`&vdk;*TV{XY=WIVbd*?}c7m>n6@dhqTBe`^AU2@w# zdOq2k3E>v>=;pz)8RxJqv$}&2lvGhVRbo^sG{vGM3jGK7B{uIRl}{y5Z&Nq~H45i_ zLb6E1(2JXdY+%x0ltcvC_j_G^%E8VvU-^XIVm>J!>HSB4^nWh>@wZ-52<}<l5>~;2 z#-u>NpSe?IY>CF!fRuVmRaTXi1+YPJh!uEzB>j_&o|-43iqay$t)MY1`wHu99T?A> zEMXINcjd1fBRKe!X@%`uCEAcph40#IaB?6v8I_lJ@2BrVAP~4F>eJKz9CA7B%ltzp zF5ATm7_*=r8&Eu9a9y43mfA#r1Op1avk8y~|IjqsWmnH7n}2G`duz?1|Fv%${9(xR z=E~0Fg;D>S+^)ME?D%{7e}Oc;k<W#Kbmb-wzL#^G>P&won*yC_OIYnzW5b&{q@yoc zo=^HO4*RSKxZW`C1FbhNj;olxuklO)p}<S|-CR}2k#iHV`(&cDv%G+-+tE_D6f3+u z6*|W9@sG)<h*v*GrE?9cU#PGWyCx@m|C$x>PXD)Jj*lyKxDsrzeEYxfz}+$m4iRxp zISdA+NNIymcgjnNTqzjztCC1fQtTb#>;gCwBHme=PRwi;p0Ri&)jC@tgd3Jk7r>nx zwC#Dwe{XMlboeK?2?+*@mDUL}zakwOMlZoS@QXE>I04tnhr6Bq24_=A!R8WQ*o&37 zQOAA*<%f&96?O1w9x!YT(G&>8n1>HYcM_-E%Nv}Oc@~9!xV@IK{K#_&0dd}V!vTD; z#5%JSDY$38bLztM{=6OL_QoyS_I9FtMjvr%v;+;dus|9{%@rHcCXS??giD!>CI-4b zz436=1nffG+x?oK5fOM!l7j9^<RlwLIP_Og$!6px<};&+a+6UPyGzS+PhFXdhfO~W zQYh3V1rb2iho%wR-?4)nf8Mxp;I414)Z<Hj3sYRhuDu7L0pCr5#O5`}a110B4N9ZV z%d3dXL}CNAzY)xy%QVNCMJqzinBvyIdmn&1`><{-XUtvWUEVvge{|+2OXE9Y^HhzX z^^)`TfzB0EKuhTqmmAY~4pr`rB;+rF%SsIc`=(ve?fhW(?>}l;<Jd6t6*Av@DW4?u zdIgGvZj*8y^Pr(jZeUU~<jYMkjzGdZV@ueEN+?2V6T;R^{gZE&ysmoUS$kt|zOF3q zgIauyBF&!Y3mv^V!}q>G-Q>f*n-wP-53I<9rjvS_+?xD2OSrdBI?BGyEVz>;GYqu( z>__YPXv~I~ul)_K7tZtd8xF`#>r!35MW2f3`{3px?NaL9;TC|t04+UNum-_pEag#o z$^-eC9n_je!IyyMAlavm+DM^G%e*Jj*TDhDqbuF+?D3d=2c3*Aw*{GROIc{u(`XW1 zXRu8VSJK#X9H7{m$es#r86g)`{myWnw`Exr@I~Ks0_Dh1_+w9b?MrhGIeSZ(^`|_i zvp!N@r<ehgoL(5Vuhdm=_R&wPuk#ob$!10(&c(R)d3lD{^^V()B+Qb%UtUFz80CBD z{r!5kvS9d^tEhXRyxN)bzTd_RY%K>_ooh(azMBq`ZL?ac;#9(5s30^mA)nItBb}qd zE;wLi3O5t68mU`7|F#R?w1J3Azh;yv(^pFUKn9f7S<j}?p=P5Q;v7^e_yFUWlePG+ z+X`aUVno7X4N5_EA#tBeB>g2*7Lu71M6X5NQg#D*T}Bx8%L=b$?PpOLB;UyO7Aq5a zA$`4AW794@&w_-}!(;>md~esVMOT@$%V?C>5hahK#|Z5aMcs}b-_dprx$UK<CXX## ztp4Ja_;~qz;UyV09l1P^7WJj)OJ_1She!lH%OVJbm6E9=fgT_DM^kk_>yxl%Tw38S zyJgbpCGUu>T1OSIlRxTUNruPD`OmNq1BV69no9GG*hqk!73Yov^ZA`S%Q6rPHDg)N zmOTGB^gn0e(WzseNdJc!&z@vE!+EF9_~zIVb9GK@fA<oP)8HWrXk>UsSH@4ozSiwb zY630feS%4<gTFG}`~CCVpYE3KDA<jCm}oT!8oiu8!wQy+N_^?S%TJHE&ph_XH%y!{ zCTWXLf%cXo)KUr>Od`{(3r>n&h{x6n=_+rf!2vio%dr~)6B}(0=~1yE0>}lG6Kf}* z87-Uc>;T=@zrJ3LGnoJ+S*tWH`K0gA6bIX1%$c+<B#`Y!=Lg$HZ{{CrKF`(;mE9>2 zUv!Ms*T6oI_lgXlsnPGFJe)xRQKQcq>nZ|TkAg3%SdPn<Sk`FRn{=b?>qi6IEh`Ee zMJto+rrvVk?-e{)^X7I{x?<hHq^~~FKuN`u?TDdst@nhrV`}!9OO6;B5?3!(&%R4o zeP5a;aW*yzR6}UpakUhTYN))8aUovGiNcv8<<|7dRapZ)H;m18`dnL=8Z0D66fmvL zoyJ?=6O!6A<1RJ+OT4B|htjZae{rQLD4uHFph?*(&0GDFU?;z}8aBh=AC0!!$r+=G zFDN7_^DirSMkv)ieJeh8O-*I1dbna8=|96(3P_M`4tU^_=2P>)ZHJrThVbSd3^0oX z&sV1xXZq0fx9}a<)~-R;nC!d?sYO_^#Z!vgjq8(I4htP<qSe*+I`^3aEhAn_rWBgl zX27V$z*28|!E0KcPrK?wm7z}R#zpxjhIocs@v6_Q(m4;w)|h3pncZ=OdASu$js$e4 zYM3)7aGrO54Fvzp?m4AKKn0rCs$Ta)oAHJ?H4G>-XE72ksg=8(q2)UHsaK`9j%xR+ z^Gu5!*(gO764qjC2Y9Vv25|>L%&ZF?D^d^q<vc6*r<Y9oL`lRPTiz|>lGQ(3dTBaA zV>wRer@T$%dEIv27KW_+{LpC%UP8jH+CJf5@-|~PKWK1YZON4C6^69CGHz3L$H+I9 zHbqrV_o3YqJh`d+<maCzAr{831o^G+Gb`J%eXq=Cp1qT=w9$Iv#$qyC+hmT#DqgT6 zQE3I}YY#7p@)^deP;REU-3nU*a<r~`Ad^aAPL=T%SBha<s0!)_U-zX6*0>r(SG$R1 zHPA|F>&AN{bMcAy{@4e#I}rDka6bLP@;emVwpKNQDpS4w(PU<#e!c2zEe*7)YmlZ* zclUiX{<_!uZUr?`aP=i5P=GWyDl(_-adB%^!FMsF+Px(_b-EUoi1#UFW{0P)m99oG zLbTF>{mN@UGHne;WUBoy6BNsmk)@p@%<Z*aw@IbynE;1}R$@^B^ZHv!6M;rZ1^2tO zD1Mw`E{<yBPVF$TEu;t6+Tb_rI+t|Y>9ahd=T|=rKZ%H&=?6;28I@2H_-8Gzgv#KM z04<XyYdY4Wvh<l5r(}Z;QnBG7VSMA_7S2^X4pfTMQR%7Gob9T!pjf-V3vgQKWd=o# zn5iyNX4aUSpj`<z%C3AhHOF7G&Y#wudLlCpLEHEjfQ4j^mwLYj#TloxE1#)Zm<VnR zX~HETjo9$ogAJE=VU)Rm)j`ImLZ(j^db3(pY<G$|Ubn6)k?<b2IqGr3;FmF`V632? z`|yN-XmLaK(T2SHK_;i|to!bkK~C5$^_$4`UN?`pYFz1YhN7E5oC*YN2&$8uh3AnL zeE!K^$r`0n5RaP$pA`PC8eZExs4!S}rGzH;fYvu%%0uPP^J=d8iC_`YcjB3KIcg;? zCgZ)G`7EVHH~KWq@q3Lrm|`KWtF)Q5vs%8j8afcsTLlgC6jF5@h$4dWqqJR&;Fp9D zC|V**m@zO^o6>1XW^ap)K~4YhQ}IUDFuybH3WNi3-bb}!-77P2QQ{edNEg`Ze*7=R zn|=jQ<XDTK5_()olLqlMkg2ZS#5AcU9P-cPFZh?@jWGU*if_F5b`Pq;W#z!?XfSWm z*`LUmK3n<OS1{Ne!;+=2AaUIXDnOl{KNpl&?!G?3B`P_A)sw064U%3u>mDK$gf0z) z?=&3?5(Sj9e)Xey;cEJ6k@-a^J6iac4^ldj@^n+Pz=;zT(mbY4G1sAN_>Roo7hf5x zh}D-#A#G(5C3X;6-Bq`B@AiQmtYY^eDKw9mhVDRDfk311GJhYNqJ_D%nB}1O*#fq> z4(JT`HW$6(NW}co8iflT>dc_3t**b5Nn!%<-w)Wg<!VKZ@!UmvkJT}_pH|b?MH;ps zTSQgWE1`jt`o6mvle=u|_8)?T)-vg~@>zCu&Z9BQ;<`TnP%HC0dw==o;O_V|XwKy= z%f?d8V>jBs#8q+-Y-X;+BkD_^i;vb6>029cd$Uk16#&v2aTX$DYghp^ko5`|?fmTV zx7H&C(2pHomKs7n{ZCcqaM3N_5&NP`^5WXI#v}HO&BmEmW+!IY8en=E!{RsmCitgY zUpBwZm%zyaVl^@sVtq2#_YI?pKr)iP`c{-76wy$hbC!oZiWv}mgBn?{!PJXhGKNMA z^McNuNl~b&)ox=UF}hsFV51HL_k7$!8E0ENsbYD7#Efc<UYUpqjS!?I;L?NzfNIb( zvpog%hJ&t@sx~}u$=K*yToZMTj+{M^hxlBp;GIPvJ6I8{bx2i3H*6USU=LM2Helc% zk_{_ot7k`+RyVMnacZC%+X0(D{f7+q8EYnMLdPytcZw-k%#eK%iC&GYqIt2^!NysR zWC#ytQf;=zWg9O0z!wt1!pxTzPl?Q;0>t$Tmj0-bDdwYj<&QJkU2WW%4QheXJIga8 z{&w$|#vfc|ykFdyb9w%2Mv|qwpM_~6qDeCh3jT0U5d!c818ME-6SEafOr1xAc6eh% zXuac-b4B5GF`^&g4B><{86~<74;>&4b;s4wg^h8~uc-$OMBg2;N9p}lf%%wqUW5f4 zvl;@RAV0^L#g<RG0B?9s-FDCQ*Yrj0tdxh&yjRvq<Zm7X&Vj`8APbLg)N2OaD2_|4 zqb0gYHgC{ogvDKb4HQy0)+Yp=m8l&$cGEn4)5#m!i*6g`&7L&hOc~NQIoZhfB9>9` zSnv0-Rwncm)i%Nk%Jxg)N^i9@0(aK$oj=^QE643Y$peK=nEU)3TU_>Q3XNk9IG9u7 zvF6lz3t?i)gc>OlBoZ(WL#vjRIz!NPH2-<IZ4xC?yDqdwz`uS@Zg@FE+U&U)OTO*+ zpC5y&;76}LZ$AW&YCS{|Om}UStXDFjD1En{;bm=&&ErHV57txe%@NHsT)i7(LElGA z#1rRbnYhtwyI0?D?DAZZ-R<z)W#jjgc8jw5b%G(-NByJnej>oRVR7YHpI(nGGCzPy z4+i)YyZQCOXZ57D+9|uSE5!LJ*b_N{P}qy1C*luCW7(voZuzO2L<ABR7$Hz)s+-cc zsYTUV19AO59D419RCqd{Kb%=tTXDTQ6A8%?_xDQwsi(6X=@k?^DDy8p9nLF_p^3RA zT!HV3T`vO0N(MI-mC!iIn%{8ztL^QOyo&XX+)ps<a_@v>%xU`4<T4K-P<f$+B55G2 z#4m|N1&>ugJM?||w?6dMQ*M5hc{ZMEpLRt9P;EeAkT7LMoe8U9yQY`vLDQBuyqk~A zeB)r2DwQeuUht+LH~aBpY8_|kwb)ZSCh8;U0t~bQw1>RbZ9|dUd!<OW@_zH&?om`P zL`(tCGc6fy-ehWSt<ktC)1Fd3HV{9Oq|CRLB;fBo0aDt<Md7F8*kZGLxFY-)0b`Q& z0<MBVi$s%#D`F%`G=L@PA;>Cb@F%_{4>r8tHvs&^)Ff8FnjiM%85*|ul@=HjS!b#7 z_~n4=vcz!3=IQqh&Y(???rZu&;i8&26&vLn1M_}fOHfJ0zRGJRuHH13j~(=M30?)q zTCRZ31ouVP2Jwk)hJ6rXK>O<0F6fWEUuQfH2z}%E*=l22r{ds{XICqP+#6G9@wUL$ z?Odd{AVc9+n9E%`4G&XeV}Eg_ubd$*&?a{a?DdslT8^7J=9w7CvSnzyzDuyMZ|v1! zmdU>k(&2(zjR)m-hD2948#mh8S=4gDtry-aJht`27DH?5tF6YLt<J4lRNvOJr1X5X z85eAcbp0`w*K?%ZUs##1A>h&5le{X1AsDIqFvh7%SE-F-Hfh$r4|q)bgqB8#dA`dV zZRG|Q4Ksey6@lSjl_;lt7x46%f*ExmpE3w1x|EB_!w7EU{?mRQ<+;18eRF!Tx&RLy zw7xv&BduxqXOJdOy}Gq1p0r)8Xs7~fdg#s=)oq9U)Wd3>cmJAgfKs$erN!KwW9n8j z^1Iqzr#I#fj{$~<{63`Zf=!;TWyo)w+}ifyXxmCx%dNMN^w0EuZ_%&hdy61e8hDGj z70WT*w>x+IJ(_zw|Lu|cTTJqF#XYj!8YtCvdJ#C?#;;KmB=FQnMuTjPzZc~8@@w6? z+xu&e)56C*-kbz;rgx0iHUzBaF5`{nGQ@0XDVP1ZcdX=}>aRK!yS=FOZ%CTS51VbB zoU;OC%FA7nd6dTt{CQg3P)4fDeix^hi%S0OcJ3w`sD7+#eCPZw5UKF=O}vePPwF!p zS7hB!&7F)GTBdoErAx!O4bqCqdd>locGbaRWzd~EV;$4t>W2STUbn;j4Hp>Z*Z-ep zd&q9TSJDHh*H*W{Tgb3wd+~ydg&A*wbG3eucZWCO`O^Z|`*5e>*k-=AI-GNbZtH?Y zPafE8PLzi@o~|A1-C~2j&YijV=kcr_Vju8wiRjsI3+;?g<=OVFIsA93nsu;#tHZU; zcP?F4uWwmqZK`r4AimDJHF0jH6I3rLNyohj%T}|UXvpB7`|4b@IdP)NaUtdp<mtn| z)DxYozh&?;3%FL1X3U}vFACmjdwq7HG*;Xi)9=D_EXtYnV4`}5KFV9R?DXqbr9$55 zduJP%=K|&9?8DUD2ZhZ^I2UP5TXwlZ9>Q7iZ6mr=-#-uYjO+i@kS^Ta-^d!{Q7`9u z3hF33d>o0xAHm!GXU5bWv~MFo!N;^&x~R(EPc2cpqd4S+?&iW+Et1p6?8Q(NFkkG! zyhG$f?}}#50M)rv&T6hNsmaW`++}GCq6Hc|xOIBV{G7(#a@>X2e-etP5?c7kyX)O| zU9t9Fed0)5`=Em_$`jl_)AC&pcraAc^Fw!@=HOH8Q+-_>Lb_{52)Lon*{)>7R2gI) z$P*^A?$ELI)M<|r(7$?YQl|R{ln*NSh#F&s6+o6RuL^mPCR1V}78EdPqrMQ!hgjWj z&0Y;5^+xi}tV@{b(g;am8}auDqa{?;6F|pvVbX8Rl%uceT~#?#{frMUyR$tj{?`1B zRz)e%Ivg)-?cqD=c?LM1&vO2_TX+K1S@O~ouds63X!T&Hg}~l3_gVG_wfsU|yDFhG z43oB0W2ZhiT=3;mPjAzgvZiShHq?0=go{Tr4pm<T#mzYC8IDq}?cck`_euO)#&fvl z;5+cB?F7+8S(|g?)%!cZ<m+SrGE13|sBERcb7>=#+qBl@0Y6C|4p4!}D~~?9l$nl* zSAV$I?f*R6#+SE`k46V{SZg|xb@U6|YAW?TFI@UiGv>qGj`bG{bSUE`kNbT+E%{A| z+_Ov+|I)d|XjXjF{#XdMK^g^Ja5XUov;RgJns`Q}>8&9E^hC-+z0fRNrE|Eqf?z!F z-e{9)X&e8kW2%u+pK^}&_VH4oN3b7eQ%Vl-idk4pW-kVh<@a0w(EUaWxhaL+=M<i4 z?7b?zta!oO<PWbL?<3gH!q211s>5{j8(ey)Oc}^Yg-oip@q;H7Evmw2t1ke#d_Yfz z&|9DcufkLfUA%bp07Bma*TU)Y^n!JG<;CA%$VLmFQr@rNtfB)qm(SHi+XI?TplJe% zC1dB^OPH)rIGij~zN2L_*QwZpkPmV^r5@XbWqvoT)SQhhJ9%Zw(-C#gbm)z>O)d+2 z|0sat>-YaKsX3}$Da7VN!;eS>aULT7`K>&Q?Og#MJ0*0^*47uhu86&F+yF-h&HurX ze}aBTY8*YpU8m3->S!8Znseg5dt3cr>FJj0ir4HZMSBmqN()ERS-&~qqRt}RK1&H0 zS`r7PorbMelvIS~H*CgIRq0tjs^;K4QD0-RMBa(>&QT$R7A^8*i}1|!w7FW!&}?K2 z`9c^9g>m~kd=TyK?Y$yqg5+uybP9B#UQ`Kq)?s~w<DaYlih|wW;!5xfO%*br7yX@_ zXJd=aDrv7Vr+5cpI7m0nSNh>1n-5|6009@ms9kwp=sc;Senf~x<xAJ;{JtMx?(F~J z0?_>YfS6n<7`A0PSfU1H*mCj`3r;?}At?Np=g>I#zab|Y`NN17r&W{m|3XWW6||oP zTwi%jML<WbbKuD;pF}W(<>7N(w39|}VkhaiF(G);t><Ct_=i-1SAD)v=2eGGLxPHI zR;Q8FCy+0EoQ2D8-E!k0ro)gY3-$Npw4zZK8g106LSIZ*5RUtAmaY62el;_NZNS7e zR8SX{{L}#vanhs87V`RSC7$vzg5x+8DLenQX=rv-KBKqgdvxwYU3Mpb)bcS*jjBeR zX}O#Phwk3;UWI(Y`fjCeccgS;o%~gLobVIZ)T&wt>O=AZ_I>8&Z;ZX5^=1>XNkY-E z)R5}e9>?s+-7JEsRACsfnSAY6`mg`IeCyKAYBBld#43$1@e9+EH_~Q=T+pVQs~fMC z5^U-cThT|ZL6pPGd>g+{<DQ>|aW6UCFJL8kyqy$~@o|5-Uf%5&?-i2Em9Hs$VxOjU z;g7wsZvFMQ{Ej?LV;e98TVUHOWtOl>)OoYMD!vY<x$e}wFlnKFPl?p7w#S{<UQ*{@ znX@7utL*Z;Kt-4;9}}H_W2>iNA~pI>^No@G-sVACEL!M!*xT+Wby%^J<tfa8X=Fsd zhX^RF<1uwHO)#8f>&DKjU$spE%3QO&&F{rJm<`ixfMq@{YzBW5xE1R5|Gkud)%f4u zQnN<#>!gP~)6TL-@PRMI7AqT+XyWW`EPJ+>xMth!%e+&S``3zQ+Wax6AC_t-jzB9u z(7bS15g|^^-v|ffgGYV-039FbOej_Nr`o+Yz&T*&M93>^n?DwD&%-=I{hvcSooP=j z@-h~gkGYqv@WxXkspuA2x?lx8-oI1##9p7|vR>-`JUJ-YBZs1}m}VKPJ`D6<J8g{e zxWEw$PdUi?_FI6fTck77d0^^I*~@FGOU;C~^tfP7QkZ#bf?AuLs>Ykiy=SQlje^&O zhNliq$K|A`cTCiQ9&|2jic6QEuc;d#wpD@6A^nhNY&Pp-k*AWTAut<}764MdSp8nA zfbvKUSnV9VsjRUwX>YPDy}td`2g?M#)UL?lBoLs_{k^p_l_R}{-mKg*Nw2}mZ4KKM z11OI!jhiiNrq!M2;qWyF5-DY=Ki#q{O7qC@(TLw*2=HbLw%9KR3?p*aBp%23gQeFv zw|gy|rcNy=yiBO%vKMdWOvgBsUUQXsdG9r<BYSQNUR~ckf5fb38<tZtH1OIFIVijG z8$G%Yw?uV<oIdx*=BI3<<DK7VUWxky@jCI^RVm@?^2cyNL-vu1OXa=8W)4ShHoFbi zR}Pf+re}5;6L2q=-n_$Gsp$sh-un&2uM;RMUN<B};~HqnknZl&zMcCt;8UUi;j}XE z1eZQq2Bahrk8X+mI;>K$2?uCyHyc!yiQf<d->+w1*do6<+qQCbWq<tM4c|Yb5i?As zLxpS*A74?i&qDLt@uzbx*C&hT2eiNg0Tyq{WfaN9DewWm(ZmUDV^s39x+-{#d6Z9l z=7@dkZ0_E&A%AY!OBGFd?Ke)J9CT6VoQTskaIV;o=6x~|0~G^a$8i&c*<&zcAiJB* z=La$}m7(QkDZ{gD5Ic{m$@$afVjFq4!F;?)rFpmi>I4U;i$9%{Ol;ra@waTV3uL|l z11UhwP8Ao)t<9A<l6~7hzfCt=u)a$;L!uWJ<C6AyU>)K8+Qr0!!R~|yg&kWnE5$4T z*&ry7?<dezfUy3DiL3;IxTv#-(_OjG&RgCk=j$bg*veEcb^Q&DbPQfr)mp{ImJ5Ap zSZgIG)HwdLI#)1O^cw~HR3nxJEd`%->T~a1cCSy_pk{L-CBw=+?)N%r`%{mKf=XVW zc5^bjd$XHxM*X|L+?4dxdDND8FYS!C{^B6aL@B@@-T98+@h`~vHlW*R-a3!!j~Rnp z_PMugl__lUPeKttI*+|ld>(hwCGGftyM$Zub;^t`lZ$i5hg|arVRl6}Rd`es4&w_R zxp}9BF28e<(*zC)>$uR#XJvy@b6_RgLf!E8-7*0B&?12K7na$7_~yB{Xh*-xsW~M* zxoD)Qaa|<=f<1%_Bv+hsjeSC0Vo%gAIU91CZ(MzZyD{Y}`V}(aU256NFnm~ie!U)b z;UZLq*U`Z3H~td6EI#cf_SF*Ft2>!W5jRVa7D->sQ4KDLO`2zO?k7R_oP1ly)=&91 z4<vxRpzT4w&%^3-Ai#U)>noMj%0i8c#0m!cT+VN}$&8=6aU-}q6Y1N<Zw-JMPGj5R zTc8#Fu|NDRP-DXolHb?)D~+|BlUDe(d>rX@pXGOF%q7K8?s$gi`^M!P^Vrvoi}k|c zt=1r!QmXrJtj!>cPp5$B!)%87nVApTLRY%;r7(9ImctH*K7$_3SyYzocX$_93Fjpf zSc4y@u@RWgh9Y^lAL_cbWM@RI7tOWZ{taDGX`$$`eQ7hgVpey`L2-plmv3^Z#ZU>o zvzRS=ZiME@HQ+NJpFhZ2^;23ZjcMUp3N@Cg%r1%oE6FqZu&syP5;1ALN}W#o*3H?) z-S*g`m*>Ur<R!*g(`$uICyQ}hnd}3!%>;{l+Lk>TNDM1j>>Rrjb;)GTRo46FmVoPh z*3g6H<0E9Ew2<X!s9@?lf_L9GY+)V4p-i4sTnz5d7WHSl&G|%g9v*dOudn#ivkr5A zTwzLYEm(ow(RZvztskr}aN`mu(Akq#RwdOa;EvO(w7_FaWzA8c0)cCbAIJMlIV@;z zNuJ3Q&Q<)w1yQij&eFA+*$13EY4!YHGsIi>R#+=E3y$sjXp9fuUM!;tGE%;4uNDxd zB}cJF-^&EbSh0#wh9ML1{;OZCwCA04E#BR<_{v$U?Aa6b@Q2wgXX<3`eP0>tQ9&64 z%sM*xQhfGK!o3fD=Kh#?Xy9bA-9tpOEl`@b#Ak^8&gTRT8~1aXxXkgots-ZYbiA-H zO3~X3u5D*CwFQ@SIbnxus3P)bqF%Ww$pm1_tVLb&f9rS0Pvns?8Tq&S?)2v~h&)uI zTJw%>^Y8>{TFHoccDq+@T+Klwq>}HkOR5M+G<;A5_Bv1MYA&o1_A$E!6Vs8L`<_v? z-ob(#$~dg|8`-)>mhCZvAVQk+<7Ker0r9F+IWK#Wm3k-J7Ut8CqSMbUR|(SQDsm4_ zk4s}Zy}kpZ7I`L|`FKfm&t1OGBXoC_rb`<kTXzKZ23*}joOq>iOV}hE|4_T6S+jRq zv;*vJOkYemd7{8JOVCYPBtw{^<or_qb;^03CV0f;Q4fKA^&f(VPdg1SK2BMzyKr&A zEPzm&=d`pX^0(xUi{Lfe_<%{cvTf9;?o0f68Uf4wD)9g<!577Oq(#>h#NNswSq~Z) zadqf}eIH-{GB-U%C*XCGi`h!vu0!g+`?W)sljP?DLF`!E%m<nZV0<Er*0jpYF>$pE zEqHdZ*lVIWkUp)DOjC}|SKLyd+tOuJN|s(z7N{63@AiL&1{WUeXK`yD4C->d&Rgu2 z1Y*$~+#$e{yzkmvZ5kHId=UA>D~%WF+M_fnF_HU;t&LFVF+4?~C~zPdligh96F8mZ zc!X{jQdEAG1W)+iuv%Q)E%4}(neCC9ymGvy(HzCo&f=e9;E%L}oZ^bbn)*p59o&hh zB1d3EX?(}*XU0L7Dn;QjzI)`W3gg1yxM6@{i8)5u@!=6OXY9yx<?Z2(E$ojfNA6q( z#+WOq)AjvhRfKx8#+y}gOUGX!Q1ERbJ=G`iX$)1N)^NX#wFfU-iyf@vg6O3(!}&f7 zOs_B{s#9F8gL_;!@0bWA2y5!HW0~sNpJ2OeW-z_@GPE^%+wY>)gpg{z!`q!Fu=Se{ ziylVG1%_}*7u`-t1y)Sv4Nen;W%2o+sV0^aO)SG6Y}McTm2LGM3Y@_sS5G9?fZk!* zg@(=>)upbiN#c8Ma<u7M!LSx88#y<$2bau+8yKC`if>!zEBt2sF8XYvZ)}8vKlt`U z{x`G^{YWS@Y&qtVYn4eN+eJP=V?jIJ9u3@ReadGEnQdRfjtYh;jE44DCB7B565vR` zp&jzdW&RoI^wu_YB8fvWB`@1TvQI@xLqY-kuAimb4_~p>mpIWXZ32()3YhVHpQUUG zv1MYBu`Slb%OF{3OizoYxJjCCVYtZnzVSLE_TBYM?sUndc1$Foq8w$U;y07$-aFm= zRJgpOh*UF(XC#e_^CPz^xcVwB0^QfN-MfMS3BpM6_V-EF;>*0*WaEuNsFBh-s&?_B z?_f4$dj2)gc0T0dD!!{DG0$gAEa(}usP_7-jXSBf&+Z**FvmJG2l;Tx{OZn;I|E&{ zup%4<G(86iZSB@K<D{t=Nyu%;z5ia-n<Hz$QjAHGWahwkw{>oyy`~!YlXT~)Yekge zIO^_l>&Py>+=e{w_)AXC96iXnv+Q!*B%NvA%~<6Ja6G9@p@I3f?rCn*&kWkXwSax` zNVyx?F7uY<-E5CUX8!=jRuDlirU@dL&hMR|e+G92a~5ebxuIbmyAHsDj=#g!PXc-q z;=J-OU9$~T(oCl`C6ptn61FT#Z{4+;S%BP2X+D{h%_g2m=2?!V<WH{7-`t321U492 zeZQ(XMwFe-=XH*gk%d3rxm!)!j9D$=trG;rk|A8m7My|grp$Q`7kKJMavv>DcNwKu zUm?E#JCre?Hsh+x3y|Cil5FcBd&cm&?|_foUz>8=kr2m7T3&ANs<x`974=N5rEp8A z;&#l2{d$zDX|AD~V}!YxlB7{V$&7&aU#|iZm%rA5gshm-)z6ww6_HK(HY{OzqXfTH z3%_qAtFG357WP(jz*d2%MBHG#1y8b1b|v?uM83`2oo^|;_)U4)Hs3xA&gxnn9^7N( z=yj5i{PL}&{oYZF49b9NyqgEpsJ?tcugK$Aw*wC|&e>^1$cOEVA8Z{O#PFT3dYUon zUhg4NnxIkdS+vvc+Hlo`TmH)K+EbrUPi)`=WWDdZlU}MKKH^*TU#l5l--%KFygV$L zQ@Fh-$x5iicuY*=EAB2U)cX^K&D<zxX?e!cdZj|jDlpx`r=G6CvH??PQZBVm6UfLo zT`AYtEf2{gdQ#ez%#`d*ZB^A4D*~lwpxuGFf@NCrjP824lQlMC{WhNekmXPj28~(2 z9=(45ftPM|1HZ(I1$AwHX}RTb<6WZF_lb!ZSYjQcfmg92gPA`4YsE(|%eEo240X}* zNo6vZ_DC$NweF?37?&&Bn@+1HY{~^QxfI1kz+2!=9KppQ)jF<WUWj_V8{D+iC*%gH zb^~`b**@fpNTbc~AkS=!#Qud22>x`XTk3Hw7dkL+$Kt1Ck>WJA!4F7#Fa34Gjactp z_tkpor({vNw$(5}q*0n~Mv298wzN5@U`j2Rlg3*mnwAxL)jh&gDZ{8pFPFt)+dog& zpl+>b94jOyJA0&I1H)`RMw<ROXwur4vNMq5k-9Tm4N#fn;`Cnf?;97!hq3}=8}Pl_ z2-M6F%%azT+!1HnkSJ?skktDB2Yyp$NuT0vKO5H-Yw%OD2n^?9$ZE8;Zvf6Q7Dl{f zmrL_ucRIVLOKF2q2@P_Sl6f-&!DhNi-`jhnyf9xgV&vkR@z))A#oCwsv*$X9dF&Va zXwjoPTavA#k`q@|pMeWcj#QarXlw0JC0nkpUD}A2wjKj2N)-PCPj6jsWKA;exIZY} z{$;+=)&n%87o^&<gy7xSpuP8rB&uPU+kC!$_fmnoiMH$eZrbUuYVfDqL?<r<z6;VQ zhN;w5FQ{G~CUiCMU)o;Tu+bo(N^^8nPy7M`+<AXgfK4YXHlOmDnq;&MQQ8HT?7usj zu~RG==5YY79XhN;EYy5NM)|_VI7$0ty7!~be|8yN`cmERa%Oq?2JJ-C#Fext0FzQ2 zk35|}%l*GSJ3!5@H{O1$rLVdApn-e8^nIHad!Lra)Ep_N+OP8U0uv01*y<EU;bPD? zDc=U1e+4$jBhDYbUZ%eBY<dxB;}2>8JI48cb`7n%1cl6&&EY+3a{U;U%8Z;W=$bZZ zBPJVS(%vj<0%Y{NRjY)}n_}-;1qHqzRa!2Xl(1P6`4^goG1q7G*ox(1A=Q(@<cc8W zw?$LQ0TqF!>uXQ9A~IX0CtQ*m8oV;Nh`oX(Jh*#-nE7a?_(QkwEt5q!;d@|x6ed}0 zV-QW$Payi!zg}Wh(nYG0TUP5_18-AI2LOFKJ4dR&RWj_lQ;lo%2JJI-U6G*CU4G7O z<6UNCC6%<?5(!UY?tZ;G2>fO62Ul_{_7B#J{ZAwa66PZeoApuoyCEK<u6D|x@W?eg z7^(vDfcFRjs+nm$(y-M%n%co39D_2lC><ai+T!2bT(rtPpC0f|@D)~-WUqfUl@ z+kO7->S}Fci68@JCa>$dPx7qyZ2f^M;&t1_r(lc9J67ZQr^hO02dJwp4dD&Rm2<5j zlO4UaUZ_e9%Q}RrZQBL#g^};|iO*82Qk@_Rj$Ah%*6^6kAidrNA}UmggF6o~k(q-0 z7OS-$!{$jt8NK}Yak+dWA?_WO>h-nI8A?1R%$4`1W(|*Jda4Qiu#+-qV=3b=z>H#N zl(YZRMz7m?%gl3j#(cwHfEjSK;L*MipQ>(alQD1WQak_5tuiy-m=mKwg^6hE0AJ*& zZ+AnRDp&N_;acTBEGo&eX)Kj|Z9^j`(Dvt!H^}WmcNs%5RPO{1@_z<=*M<%TSPjPJ zZqqYAFFy|$BTnr&TOegRC5-8P&r-$b`@MI2vALzEV(;4fT1B9~lrLBA^VZRLB?p!8 zj@gNb7WsdZ+mBi29j(#ofj7Nl)095J3S2ANPsgd_KLLzOYN?SCP<`3zd+J-6G>iT2 zU-X7=wrg(Pj<C^aKTV4D9rO8v*X^sL*@|_lN7Nw-lmRUv;6Ky};e&YN7Moy4e&E=6 zi2OySzM;#`kiKw(=|VxDwz{D8i|$FaAkl`+s6!RI8smaC4gq?sfs?y!2ioKOQ%6i% zUxaedm%RtvG#b1MM(e5oTU!|MOYAD5T}ZYKPMHolvq&qy&`}$PC1kqjNJgx7-w}Id zQP%|7QPopJ<Ca59?HSQqz*uG6G9Y7jti^T}f8@1*x0D8n#~-*6CW!~(5phc;)-egR zJWSr?4X1Xo)tVrr3${`cbU8{=duN>l7t_QmYt`Old<y!eN@4~^R@6b>VyqZ9eWHx4 zciw!p#sGHA950BTZH~{i+_&viOkT$%`Fu3Q_NSK64?nut`=_~LY|+d4$@A!^zf_av zM7kd}WWHT3WhR9Ycy^t7+WaC(ES=j3E2S0>;$~&XVVnms5pF}B3NUB$cUzv^9UZz; zS>goDdsP}a^OyHKjJ`EzyfqnRj2|vo6doK%y4SE>>9J&9O-iB&rwLSpz`N-X6MO^U zy-*Tkxu;?q!RqUwHvDfnq2x#`=Kk2%Iy=f2^@}oaE1CLALl?_Y(J{9VRamN`3_g9M zUXUZ*Ejl18$3Vt)>}rD>z6|p@$|ixf5s8)Vh(^t22w^RQg3~4j1iY5UZp`$TOrt2c zgglDg*7|u3Jk>)Lupu24KgnOvemzu&<?T{FZ2D{Uu7OL#Jj(s?+%>Rw=4~7DTX$wb z99v_D|Lo|^Y4V_@$ea&r%(i>oB8+I~{%~!2pIK?`_P(t-pjEW)Zl;*6v1Fn4S+?j^ z#vtA<jL<%dmBF_TC$%PMM6Rm>=Vl!lV%6UzU81X#R3y%h`Y1*H8_U9N?=o(!;@7(| zUF^}7aNS=!x{fulluHhLALB$i=(`ap*{;pe5!2XJXRhM$lpy^tEXxQk@mZsh>e_$D zvY1Sy!zAk7FDTS4&7@x&P^QinGt}r?KDnwvs@}HB-0lBK^YJk=`_@<*fw07Ur*lBc ztXT2{M&_m%0WsFOvLV^@)+DuS7K0LWCJjAfO*gUW-L&OX&4gfm+wnFTYGY{Ji%y%h z<?9~#0b9XGVtdm5GLXS%pY3u4-FzCieE8<>6p`QiWy!ZQ7_qV$-|Dr*<@R=_&eW6j zQ^OmjbFK0>K|5VrO;!taN52tIuv-37i$H!<R^8E+pSDDe_Qi}1j@A52_eZQwt0G{y zcU`ROsufz$WXW062tgK8nW||Xz5v0ZBFY0xMurL9e%JF&2b1OMH?H$lTqw2qKdsJ3 z9LG*7-tF9)s<o^f%IvvO#k>d`viL>$zV5_19<B?$m5BmqluouX?Oj2*O{FC{u@H^I z7`;Q8ayw|$s^?v2FPM`vZudLavUwTm!;SCws3H-ubp7&D{+<=PpF^8``)V1^j(JC+ zs3gHB+Mi-830B|$u96wK=4Q}?0E{$A1|;m#SJA*iOea;t9-#Nt$Nk2%viCu)rdNf6 z7GpL!9-&R(W;sg5Ge}fig^ZAFOo?fD<UmC_pmVmeCIg|}<u@eXU-1Qrcu&R6S%YfD zOmUW(O(RObF)n9*UL+6SGksi~&pg1wJs_Cfpr~UOg=%&TaJ6yf2`l$d(%{Nj`g#A= zWtmWn`7lzHha+k2rrtl-*8fjg2$=Qb==ZkNK>_gnctRe&Un?fj5kRvep?DyDs7O>z z$3rCt{xv~vY@HhKE<9BEumZ<K(lPe~g?o1vUmAQAe%?MZk_wCsQ7X!_TRQ-k&ID>Z z&6~;!iMF^Y7?W4H2(HkYlmvwCNJXO`G}A2VJG23hXy8n^Cq!;$>ACjqH;PTiHV>BR z78`fML#E-gdj8cFQ{6uhIQ$!1cxkn47{Zfqfp@Uo+%3qMRg8EoePq@L%h;Y3ClHP< zfzw!Kf1_4c`0vvELT>>xNOQFx+0hFh(M_2ZT5E)c(;TZE?mA-SxD63-nBN!1N`Scz znby=0`05hra1-erS|I%F-ZfT_{bu{+h<>f~nsdcMx;f5ZEU?6UAoi1txOP>|VOZ`@ z%6UZ&dZm>!%Ilp?<ycG2i-<m%Fv-rGixU<g!=5MEgNdZySV`I~{KRR<uz?T34-4FJ za_?^#P4yxVnE8v?4PI*bG9&)MPm{Ei_pnBN<@<GqN=e=c{w%qdghnqj-OLcvYri3e z5`AKN`H#*D9BrUFke(Qg$hgL$yzSz1*yJ7B_ni<1PUUDZ_jj|9fTVe{w-A%Ntq_AB zeg`HardLtg$`S>Oq|`^CkSVfWk`sn}p~X=T3HD1-%jMc3c?#!4w(Fmy$*?C$5}>`F zopK))#M1lrX*!f!flvO;U#)Yh5X)QT{n-LHaxU+TYW$K*rs&{5cYuz*vPKKy4H#(9 zb_sTxBc7SdIDZCS-*tFMz9w>~?D)Qi&gCZLl~}hRBIS7E$H@Fuj+myF2~b+t>RN%v z46g7m=!K%?H#lkIOzcNxGwCh=PP*{MV%C4bPK;x2z2uFt1(IwF1KFNh#xkgLB7F-a z@y23J({zE0aJASEl8*AP@)3dfDNvM^Y+)y-*M6~rwb%LAe2}<nUN>TRmy!5%=v8h= z6kOuu-wf-Ep21PPs%Gm=zY<aX`*Je=7CtsRF@NA7vWs4Go<T~Je!LLdz&U3FeU2d` zW1nf~I}O($zRmUO@J4@y+Hu=x^x7L;S|($Ri5HJ!y6$*XzU@9cgM_Kov>ZqCc=Y^+ zU4C;*baagDp6}OE>Y{*;%-=EvR3!<9c;NdAr@|=O%VpZjquR4!BT}6cUgX(z8>#%y zG2*E-M@u$ElVUJPsbIpx<w2k)TK<mWZ`7rs$KrRqE%W>Jb5d@h746lo$gXdGDfaJ^ zWFaI<^(-8zl1aTx@tCO`KCUuemv^@6vhr~+UUonC<*jQbVI1Bum~hr!@{bj;O`xaC zlV3Eue|=uWiB|{9tX>Iej)?^<yXp^mC*7f1rYL$H0v0-@^7yfWjgszq<A=0FjiJD} zHgGMgcMkN5301=|>K!39J+4zq2v8MWDCwf3SYfu4-t{oy%3d3KSr4^eVqcolwtU?| z6D+(ay{|riZ(^xlSk5=R5>5AoPlc#Am8tuMxg?v=Ny$4-X5nmFH#$_R(+(~S$?Z!| zK$(TfJ8Ya>)N1ekjoyCREl~kI>0@bvchG5qx{cCa1!J1Gb@A=kq33r}$F?9hIPF(7 z9c$c^?<@=G5Grpsp%618YEABVe7EP_-c*9<-cIDtB=e=<1He`>N3k8GON;Nrl~-Lu z>ON;ch1yTN(oII-l(zchepr&dJNlcIUqy%MmEjPlB=yZ?+dJewOvQ3XVy`2@EPUB5 z*bVqwAP?=}MaAbQ=xjwsz*2Smn8@oC7JP4Uy>_S|cE!A>>s<cY&F@Du`@IhF=6I>f zU9CC{0fq=2vp(^l(*<EGKapiKMLpglQ|NvZ@f!!^_}ycVfary4Ed5C%DI1^woM1n6 z=PswiMGKC6yg6bUB{|))ttZ>vOeCfEiEz8#R=Ik2TPR&t`z+`uC-NQ01sljTf8lSS zSB0Ymo=Xd+=q84oE6dX$Eg!^So|caQb7mbPp7%!T{g}88Z<?MtTZ`n9-g?&zejy7l zaTv@x4+EE}-YFe_!j-b9oCbwQYK9K!?JXVib74Mzkk1ReH85#Alaq3Hz=ZHbFal!; zkEBe*j6va$FXYXw(I<&q1TShrMA<>t-pL~Zt{6>7pKokgm6!xbWN%-S#eT?Qf0aht zfMsajy(M^3VxBH~z>1iok*L5*{lOCzHG-<>C<b^BmSdWh6vEKpG@jvYWJ}`Pci?Er zD%SMN^1UA}nanQ$B7ci1Mq(cvYyx~6^1#WsiwJmFd^+0*B);Y(Z(2f@ze_wBq7Mh* zBD!l5!qy--Zp;zT@F3~AK-rw%`4_(<baad5L~hh`R&Y<oygm-oowK~%>j*pxx--y= zHfH08+pigxggS;DcL4GAzvD*_&}_ipPF);yjt?v-O8~Ulzajqya>e|-V|OL=er3oP zmqdXGg9<bGc({uL@Yp3af(xMO4Sb9u5(&Cv<{(NDRz)o-e;Gj!$ti;ZR=Ct{!OkUr zLvRjjJ;KKdt`6Bm;b%Kik2t+e$;AH6SRx$+u=wX?F2B0<a?EaoJI`Eto-?)xBN$fU zS2bb+l9mBhhDenNK9MGFqYRz9%FSYBzq;ayPyD}kG>n)(4o74n^09JBYifTV^yN4I zi>gGiA`l>6<36M1`#n2!8jk8Le!Wzo@sIm(IQ@Ch!Ac=>wF;xNg_8-A=MBnJ{vYbz zGpfmL-5=d{S*R>TK>@)f0wM$i1q=|dAc!;(DIpXkgq8#Z1f<3eNRt+%D;+|pDYO7e zClo13AV5%h3rHY@&UKytIBTD?U3=@ecZ@sk{gMy)@XmM6`Mgj4J-=sz5`3w&KglYK z@d2Y9{MinRF6fBve8?Z#)*0ydwS!t(<~8^PFj$B~Xsc7Pvw}C0m@Vi23EtZ$`QCdc zdW$)17NCTr_xb%!`ZqFU^4%R)<Q0l8{ce38=M&7~YU;W<&Qh8%q~PfhIfRsH=-~kL z2HvNBW67D{m3OJ4KVE1`B>?2|m=-G(vzqnliSNI`>HJSY(*JWz<=g@Q45>b@Pj}v{ zxH1)!{lRMUMpff0KLlVHqXQ0aX=?IlViLT%PPk2%+;@2=1u^yuh^C>xoz%T6sq@v& zom;2*JTv)cU*LC<;=l0fr8C+E8yiO94vWcd<nC-TSGjr~id>L6ieY|5Jv2yBOae9x z&VK;4j%gXKd(H7I4<H7Tm69|hKW-eJe&qP!PQj~RnAGL0SvRsLc}R7Rm@NLVEIP~M zX1a1ms#g3d`VAG6jCmCJ6V0C6!~D3};%}Xk+~04)Q7+p7nR)9~T)`xjoJ|%4w9XxB z-b4SLmhmeyG6nfAn2=GgagM7lPCfq7N|xBw#>giGJ6C^ithhT;E40MNGuzf(xm|<- zQ13%1&6Rlsdf9lmDk*7P4EqH$({HsuTJ@>odSa$_Oc=u3oiLs!@djI9r9+gSDSsqd zv<j(8IeM|LUim-}Z=;`g{gz;k++bt}pO*uEtH7cRcoV1zuaK3N@IIt{RIu*fxpe>h znU~lro(A+3h{<-b3dBu8W38Y>uLiR-JvcD*cEM~_me<Xfl+luhq@l-wJp3^WO@t{2 zJfk?f@g;bLR5;bt%Y?yU;wf_TDoF{y02;ykNvzdaoj2**TR)*&74Ve*#;ED#hOfu0 z^s}`-E_gwXQcMG0P2cTVE9hu)3>^j)WL?6rH>8GgFB!l;NNT>ahO^~o>JXazamTt8 zPZoh_I=_N7-h(>yNcL+ILfxh8aekH!+vR~SIU8uE-&;AQ<?YZFVQ^Z8DtMz!In&Rx znsftIV-Ihhy4%@PXTg)PG92BdlLY@wdcAPIL!#Z{!q080BH(S{p-28F6Sef0zk8HN zeJGjwi#r|niunb4O6W1??YB>H?Dx1BAltMofWO^V{vZX_6>1J)AedLKNHvIkx&waM zal#@xv}EB1CGi))z<7zb5>J`k9lm=SV+*LgYI&HoW{J50?MiRj18C1xnr+DFR`T$@ zJE>K|w)It=Z##}-<8eWK?$yMrbW>W~N()W#6#`J1h<XJJxbk!Iy1Iq4cUd7u9Q%;& zm2??sVlp@7?Olo%r&RT&XF+4ugk`$o{ZD@U32`z;LY=E3IWLfV^k-+)9wNNriwlJ! z-kzoI_~&1R)5;OdOK<)H;5;bi#>x5I4J0^XVu{t~c!oA(3+Cw0&UjZ#@a)dt8c5zu z03;L<Yt&_&HVdwJioRZ~ehc6p4;2^zxW;<>x9J=D8_3qUrp&+0+rT9RVg;;ReVE${ zQ$w!g(N(*O+#*AvX~Vmlw(F6hu5nXzudj)&9%%ty!zZl+2K>73Hy=Th*s$G(A9pKz z(lOXfmoHydIzPl{m#o4;qcfC5=T!W|(#{|0u`6zB*7i<;x9{yOd?Z$Eke;&969uN5 zE&f5R_r;x%ObSS|X`lRdQbVHp)q47C%aT(mbD4jUWgT&UR{8Mq_)FuVUX$5F>skX0 zRf)TToa+@k1Q#cSZ!@9p)8G2O=I{ULq)HgtA9Lz|>&FIybt^X>=fgQ}3kc>?Dpn3B zo(D-H?;XAtfWT=y79plH>LIK}@LpipF&#@(WRcLAN9#g|d)o&yhdYzpW%i3sPo?|c z7bxQzJ^wN!b!YjeEjj6GOAR*$%rzRsSz2VAPRhB&&vWJyk!m=d2(_8BPExhv+-b>j zp~ODj7n=z=SL{*1Sx_&meD_nN0hl<g%<2<WzU@$PlTOZ<_%hJk5-1k!x=+eADyw$$ zl?=E{Uxna#dwGS^R&tpW`^SMG7MeDmCz%$5hbb3gAg>oUt%1(FMz*`@#s5vr688UX zVwQQb&Hw+2S+r4>o+;$CIB<|m%z-}>>qjAWee>KCZ_4c3S}N837Xr4_df<PPU9GY_ zyHz9G+G|mGrGsW+pa|Ub;-Ftnc@)y8_kB`)S@G$b^xzqi`ln|5?S~5b2ZEIJsT=N* zGG!8|o1d;ySRSy*XPtzoxE^!qm--a|$vLp<|7h0cdR!Pi0;<%MsNSu2AG)ny?ef-4 zgk-2<WpG(t#Z(P|66TDIXF|2tQ1@wspYgElq5t3IVbQp^>Xz0Ww$B1#Q+W-Y=0Wmj z8fRpUAGc<HKQXL8M+|(|>s=o*z`Dk_)rvLR8sA#bW4qotR0SKIu!#wEI1*JEangN+ zV%CPl5?iwl)m+?N&1!~C;zy!UiK7U5JbB-;Y%D=68tW|+C2F}Wc3NXf3+S3iZi%P0 zLY3R&RPBe(Pch5%YW&zdu%TpBoa?;u{aMTOg@mBp^GS3<>+rr3#<Rx90iKLiT3UPr z_f#ujN;Q;a;WMrq-&VV|igBkziIt{>{VyICw~GIld04Kk{lLRgR$IuFwu#;VE{|s~ zC&g&&ON)b`wiVZN#D@8a%N3lN<#$Hy{>_JfjA$ObKkzBw9}Dp+jaPDq-(#2+>ezA{ z`<1l-tv^0*)T_0gMJe*<at;0-hu4gst72_?kxM$588L4pLOn%5pMU}<RW6bS-`@$q z{WFXxzBW~9W=9bTY7P7okP(=P>pT_D@Dvifb*H0#=;+5#SYwj`htD+SN@UtuvH9-L zp5Z-173Qf=zFl9RfG$t)V1%;V2Ki_70xk1J@kBk*r1OZ`*E(|rBv^eqrRQNxl?Scz zRjJ*$4Deb^t#9AaxV+0bE%aOP#^FerfZ-g`DsD#Ns=AK)<9E6{5^zO)CmPCe<1)l5 z8%A$iFk<y(<!X>ihOm!}sTQa2Z&=f$!+K^YA|4vJQcwWddaCCArFlYAe`mJ)3OEAz z&?fD7iu1q0e#9PiVc6(zzD)kmYQw~cN~7F9+1w#x_LZdu3>V7cNf}PFhy;*W$%XJ3 zXs5a<dW7>F5q=15VW&5E(|viW_N+&(KW6Jo)&~W|nDYR=OHQM3QdAC%9qRKf5C)lO zq(vV|tB%yun1AF%DR^vErkAX)r$mhNp7tmpxRj8HT~!`^BBg8^PiwC<-ExC?K7;3- zRLn(?m*3lRC4HYXVNi!SihXW7?b!fpBS5Z=sy<&Nm!{nv@#A#td5iC!UhysuideXF z>~mXXczFSP<#WWvbrbzHx|(mN%a@~N>mOQ^YQ@aQwk^L}TWT;SSNUFTzMk`cEBa2h zP!XjW=|wnP>t_=pS+=KppfW?^uS!GR1Kta+gEF3CL0KW~&YSt7sPg1X@DE#Gi9BtW zlWu7(`n?qP`Fypz55~#9#hNy@VlBj|pY>DnBu|PPwvo^HnI_%2Q$GYv86;Hhck}YI zr%{z*_4!9x<IvF3G+y#x=Fla^?mTU{Il$EFv4D4fjFSqjD0aiiZ$tG1lKV$wNVi9G zr8sM2nLIw}qtT(B#yU9TsD77zu^j_F=u8Tngn8=rTy@Dm0<JZn4|O%xM~fDdUAHs~ z*S)H?wz13OpV6{lc0YhsrXRGnma=5O<LW2N5#^pi?JNIi%HXBdEPVKWH(%?P$2ZCX zWkxn91;!&xh836%sJGk(gBom{;z102tlZQo5T1enuk%%`GW{1!)Oo6`e@tt9>pXmA zO&9~Ix+l^{pBIq!T}3W*948TwNW)F6(U?`nqyv+9*{GZ2S=CV3IU()aChi;X!p|d! z$K4_2EO5(Gg{tr3%?C;2(X*9iN{43r)h%<x`dQCgeyOU(>8;&?D!wPA{Mj$NbLt%X zW6!Rg<$8IE=eZ!}?2D6qZ_b(LY|yWNUHrC_a`L2bey&ky8J=K@wP+mJs9|T|6oS*w zouxcC;oZMC`uDSMf4?y~G_*P7jm2|R95klXITHK#`b3X(PbGs2NF3mZkZrqdS`Ogy z?0G0{5ZM|FjEo*z5o3C~&rQU)7ID<|Q?FudUN6{4)Ng7S*z4moPO@8Z0X(rJm(Ltl zgd2`l6#b!fbIqGe`}XcQ$gYWTs3j&<&7p4r8hV;OyBT)cJ8bS{f`{E&4yWaPJ0=zW zs1aNGkh*sO$pI_iR;-7)K!!GRsvGYvdDOInW?S7mRYfF?1&3cKTZ-3fKp65xuMkCS zL9)jC*-5|nmZsrI>Y`d<5VCq(xpckZ@<gx`A*fP(Q+W9VaDG#I_8$PG$8jPQ9hA*_ zU`bpBHf{P08tYko^Y?iXXgBS$zH~^SZ9Q@$wt6+V6IlmwAEx{HIQGqgM`=%GNOqwb z9N!b-KgO~~2S%|^h8GR_avMkXnaD?lVg+$u+``8T*zsc-gN5i*1V)Xs0;FA?Dq<$x zEKEleelr8`Iy0T*u2m$)8Cz*b1jOEKiby~7-%os^x&Pp*n&ztYju03pvA85`EvCC$ z-eXf`$@n}OM{H$cn6P$VoJ8x26yUT=j>ZAD;owazbkVmnsZ>z)f;u?qCaK0ZL<Sru zv{Drizhz%C@72$!@$27UPLC`<8bGm&CSJ$MKhjjfnxFHYl2aL`Z|apXuTF&oCCfI; zsoThwdm2~feSopX<g5Te8oTnPQ-5^5%_!W>w{+JIJiYqG%AE}(-XCE)Lk+99{nr@) zq2=0)el$hdTB^3H2*Ae!)HkqX!PWy;juyRz%T{PnMQ{PsnAL+7n-L~wikKq0K96Qj zx>H8|yEaITW&zvo1B*EA)>zvJE<e!=V#-_B7rJWa55~(y!zSYCglzJ{oIq>J&cY1u zX-i-HmcNeDJX{Aus_<=GGv_SbCAcnkxm8a&4t?p@SbPXZkqsyEvyys>UOYRk;AgLU zka=eARi3_b;oK7r>-VH%jGfEt1K7FVZT{MW_K2A&#-$HGvb3mXKds%Xay%2wjd!=i z-d!CK)2zXTm6bX~dpLxZJkfCX3k#oQIfpzDa!~aFNzOxp0O{tf61NkehQc|+pZKBL zQ~64evaHk4jHa%qko|v=oqap}+mUuO)G$#}qjr98h0lX%z2qy#t7)JNI#$q|s!?IH zP{RsxxAMDYQNQ6lnGhKjW4|uS&crtxxqljx9+!-lLC^H&w8T2?>lx9IdVOd2aX|QT zI(Z`cq!8>;?|VJ<Z~K8xsjJ$Bv~!ydZO}A#oTbM^BkRTL{^2tP`c<MAn?+)FUlQXu zU_fQY2?>#N4l@3Q{u}kKZ)ryiV{1P0CUE9GCIH;ov!ec@fFj?iCDzwhMbX@nU2kVD zAB&a*`R@AW%s0H4Xyo3F_x}oYjZ!|QAJ@8Zh|IN|CROAU$N!iiAm{(gfAXelEbWMX z^p01p@Y)cu4IIN6l%2!J+nihUTV}KJi>i(J5g)xqlf^OvmV(By%EOX#3pUc14Fb!m z=gLoS$Z`1>r9yXXTEHk4FZfAk7i@K&WY-lS(V7|J*LT@a-O~EWtn&DfS<OBB1y#r@ zXm&r)-DO8n@gYI&YjM&9)FB1XT*D%<HZo=(4q|awjpn7)44*RSPW2`%dWXI~EXlYy zGN1<DI7Dmtd>th|B?8o;XXUx@rCmz>E-O7(K=xYfU2-C^LXjP^DFWE1vGqQA+mJ(k ztvHu&vyX3+@Xcc+u{GpJf;?@@_lwv=BA*i^JBZ^I)X`Oz4bud`J}aHY2+rF)H`H4x zqL?pN%NmHT$&*WC_at}u$uMFXeenlt%^`(oB;8SZ@NJ*)#D<FZ$Gtuyw*;EQ-TxY- zKuD_luBw4PY>W+Qcya_R(d6W?uH*6*NZqyW+-*>vuphZK6qa&6XlG)8)zfT%+0nRu z`T54Fy%6{9WxfftYf+r?*7mZU(yr3{so*RBntCZ7JM6zZQVY=5uz%(n!R#fz9LT1Z zXqXc4!2jj~08~I{qH#Xwk7GNuLspZGnLF`vm149QBHAu|k576oojWlp2)|bC6=P9M zBxmIYv-_|-Wi(Yt$1%V6Ub0i2SE9^%gq@Zj(TxxvoUm%vW7V;)XYrFCE&mtR`77@` zUtIOd@DxZ5&b)&`w0dq+ST6ei@c1!*(JB4;&Eq-qNJp-Fp-cWwooKJ~`uO@epLGAF z8I@6$i)?3+q8xWi2Ummf$)*UWblVrCp=9v`u^}_3qO<2>0DJqCZ~nY5tN+7+9)WsA z7y0N+v;n|4zowTM99|9g!7t=ODiU>tFr}W;58b>p{qj8{43VBM7xz>1Q4Yn(GlYx< z1NMTxN!rO#5#*Ho|DKmptb14wWUc;<r>Y@__4WsEuXJzfKO(lA&fDpW9nXY8aNfNa z$82j{+^AG+t+1;+j1>6l@kPaEKZX8-Gu`vL*o-cz!c?Efzc94^nkyG>-U~2bAz?Yj zTZzAwW(5cllpj7`)a^i<Cc5L`-KuSYp`ra3XiFBXMd3n-|1pg$BhN^RaYyGW=#y2X zd}38oPw>yvuXW$Iu;7J?dWo;O(5yI09?FYL+J+5pkk{VT3yO6X!t`P>JC>)q;kW@c z&kET%u8~T-g`$A%D|=PXpI5>-`?bWM0>tS6fU{0tDM>Hi!Vj$cT7fzXQE6Md(46ds zUp%{dv&b|oAIks}F9@9!BS*6-&^h2e)nBNynH~84bTOD<NVh#{@P!i87GarDD=ZWM z#W$V`m4*ViEUCR~eaE4*Kyu3hiIDVe-_OP9^nMFwlksD65ZbBluq)vfX>jdSFIKJz ztT!Oaq}os9LM(-0{zOn6uUSN7X?S>rScLRX)6SpCd$GL3d*M1?Zf7g;VPPQK`Df%+ z7f*O-Mi^5mh#k+IC@*y_@M(KeRpzS)gzuPsQPXKR(P~h${CP#d`h+8UMm0|Cw4j;a zTY$J$(zX#1n2w;ica|dHS0YO`$UtZqUU96qawa)7KTwG~VsrK#v`@D<BmNiO9I_YC zeWq?Hjpg}y_;^9bOZc*p*hfJi#bpTwX&6+4RZ%j!3Rj(0wcE{^R9EeGWAr^k71}mT z`WM*5Ir}YA!5v^~?BPPubI}<URSTywPPF!)Qr3E>4AE<V+$72m)BPXuipndQwbQD7 z+i&BPsBgGzZ43WWE?&pqDIpVOAOwVJM~#ObT)j8Pa0DpwI_Ga!{KEVDsbEC_C_m|$ zA}@TGx7+)spIM4hcnh|6Lrsv;USa{7WP67Co)(fX8GRDK%eSlu1?<iR&>zaZj+jCe z@-9F6OVx`wKZ`L`2g{OH?tzIe!#6=}gUe~+sE&|-BV+{q_jmrG{i&}o>H_;lypNcZ za|y4_Yw$vUbgR1IKonV?kzXTElW5f*5J0+x*PK(U%!jWu($Vus?ceAsV($g7|HbF| z<jMZYt~5D^WVfdJvQwCUlO>mxdOxy9ZKJ|C^**PCKOo8<KkY~$I7VVP+D}c|GLF1i zl`Y}rryU-y#4r~Ck(Qyl@=iuFhwlEo<mG$sJ%w2)CZA{>lWfg}T<>)xVkjO4_{2|i z^1FPo-#YemGs>HW#$H9zXzvWR{#Xug+*X9<{=AStlKq^oKv>tw4=c960{|!12we4^ zBs_7PBSxO-$iz~XX@||^Ma)wLm*cD;7Y8e&_D8@4FIQ3rO0yDXe%`9=Yy2KI5;f?M zK$mSbH~g~U)KIHUv*E(Jt&&JlLx30zeaP*K%^$<_#3L@i8tAvHAYOsxMhbn~=iGZA zN*&IcgsC`v<L5QBX_Gy}--M*hHy4Jswkyy^`0)bIM*atwLF3sxxp-2ce$-PWHA9R( z=G@!QJ9ZDdj0hPz<hvH^_IhB07fQRJ@!2!@=ezOJe74o(pc_7`eYwh~-nA{l`E}nc z+r?&(s~{>BNV!p?#8+iPx;Q@WcJux8YU(=z?`mCsxDFXO=WgZuAcime=f<IY?>@8~ z{;^}GX2yc*(~Ry751;e3w1FD6e!h<|y`^Lk{s0vxqm>I7Wp{kzbf+y)sp&ok{8B4T zvGJ62JkxZM8cqL&`VmR`%gCPOo~%TLj)Z%<^QKk)+XJ(Y^W$U?{hb>&7#c}rJ}1B9 zIo>w@yH2x=oRu;0=<gpoiFCtHPLux#Tw*s(OOLhrw0ZqP6}pIPP5QkU*aEps$thl3 z*Kh4sxiuSNikaLa-&x2Tr+hf)_0YqBor_K+(`UCT1mQ^E`<|lxppQxCjBOgUAwGD> zDNoIeV+9M|_kTb7D`x!3-m6n!)tC=Jj7s`|^=9Om3_dK~#VYD9J2&<|UIK-DoY7^A zv3t}o1-DGR=`UjCzp?>?OkD^KH*6nd(~&)e&#wHu_g|H84RePv*-$X-VzU%zuZyvW zz!?;+I_;&Y^E)x4L=5CpzYBQ2{8hud;qbm*gy#+A(H_Bdk;jD_>Nx$mrIKJA;>~n$ zuTHg`pz(t#JGXtmV0lDNI^HtCwXrN%v|Tv3=lgcvwIpO0I0-7IV@*p>JW@4`l}izJ z%Fpk>_?FW2;<XDN(jsKBYnVi~MN=#kn<1DnVZV1^)3*4aS!0Aw?$1v1Pf7XwrXg=} z9B@1beF-1AcyRU3Wtg+hece4dne)N+j!eEFZ8)V+-O{jIh-R+Z)JIdf4k@%i2Xxvl z_#&)WYwmBoZc!GmOSA8=ul~Y(BDvpi^SV#Pq?~E7=9ID>+8{t@b`ji}!bm&^3Q4?y zIYUJ1?w<mV>G$wkEwoVb7pKGhOE?e+TPJ4YA~jdrqnd59uV82*n2kBq_pY3HDs6#4 zevtTc{DKJIsg`xhECD2+f7)2LTxqjS1~K3OO}7>|#ebP_o?P%0a!6C4wjqURS@j#| z+z@}L8yJ?<;QKr6(##C`=b$p>K5Jj>#s2cq9&8?#v930kt=)3}(_F2BA4tCQq~o02 zS*?=ft@UN^=Q&?_|MqR3tQ|OL+v-wr7rv}nVBLHtoxboT)?eQtsjH_*ta6)RqUTJq z#{MSd1nGpl9K13d>3cfubAIaY5g*qr0LHTKOY+)kMi$Edo4}%O^+fUbqEt@uIgiQq zfmHI!$`Bb1h!NeM)@DV=S7+v=y-507<@Y7(c(L*|Z;)EZ9LTeY5}lKh7Q3b2O6_#* z#V^$-CWLn@bw)(c6sDS{b$NmEmMgbV9)-b%2@@(Gg{uO|fk_!aLyF-)jp(WUh$*?& zk);nE4oo_J>`-^;-^&5?H^;r@1{e#efcft_YDQRoLQU!`M4R3pYtM9)j;@<<l!iR! zBpBPRlWHl+Gq3MmORYBx59tA{HNbK`wQnn4jg<Qp6qNPJ>Ha;!T)my7YExa1C(3u| zq7(!aaHk}D?NnBX8A{vZBu@X8`QSls-SJ6?u(wN6##k!ewy1dWXOI4FD-Q0_|A+S8 zE78Q18Iw7HSb=42e?`pMdo}DMOWSq66fJmUg{@tg2y=qcMDfT5CVKdw^w2NJ@*V5d z3p|%i?*pGJ{M1)09^=NHb5PkZC4%GyokrXZk~+NhHW#G&0roXXHG`VWxzBi4dp1et zB#SW$Q=F#zMmv51$s@v_YrQ9>rk0j^-ujEBhRJzru@HLHH2^EeC@iH;=_dYKyKs!p z@Hv&p^g-1E2BPd39J44nVstEQ^V|DTcCSfQc=#Pl<h`F$w!IHJ@Ma5<VvoOf`J;1} zx%LS|%PZ8z3j+}&D)n^gLnP8^YN0YGRh2H&pl&LsVZj!2sScAvzbU@hE97k_FW>ZB z<jtaFp+LsZnUvJr_hN5{WxsUJgd5K)ZsZRxx6kC7GF=F9eowJ->J+`5l)9)lcqi59 z(h6$=Ma<Y~<qe(Th_kAZ*RIsU24e|(mCfG&oa<%<eGQR`RmfTbkfJW);ju|vrha`V zY;IjiRSyt)l!@xKl%mpKZ?oI;L@sB(yP}U%l)&akEn-LWZyZ~CDomNj%*yL30uKEA z>?9AU?LkO=j^ZT;XB*luP7Z<;Eno)Q&!9!FVFax-Lm@<>X?sF%3%`JleI&LfgXY`Q zfBz25b?8$oP1<&}#@H{_OuEK}l0YBZ3H|yDK&aFc-}XN`Z%LLcR?EX{*Wl*M+;QK7 zhFeJ-=SKG`DtdL#-~~($O|LnT>N;{XnVvy8M||YyNOXjUuCh*kR!YJT`u@W7)y@l_ zOEYs}&%XQXJWe5lm4$f&m7`44a0%VqjZO<8^DHx@4OZNDO!bw=<0GZrCP4A0<nxch zSW;CfZ%Vq)=);~XBV`LAv(XW=WW4hs_x6U9Kl@mJpVohd&bkix2$9q_&QpUF_8l)+ zE%Dmav<jt|`+4H<H0=zu1bg9jXH&$NceGj08v{2~r*bD{C-doV98uw(@_lc-yw{o3 zifm*6n|3yS`JX<$*ZpT78{^w<DI?#mZrpNjJwR(|`+CSNC&@LQEL(Y<>bY4)c@h9A zu^VzA<`HezZVHs{IQwvtY9ze}Yu(n)M&iw?tr(BL-a)<Sc#-UkdF|Tk+qg_vB$;;x zP6$k(KUQ0I6HSzh0oPv;TjCijIu$Ns_2rZMs=KgW0avRDlZ>QnC421(<*IlWjsw#w z!l+iFs^RmGUks1IgSywv5hE+{9_WkVwb{C-?_;uPS9A6kQH&wO3u0S#NcItnc5Md> znjrbHn;=v^phgVXVY}RLCog&7!lZCO2l0K^i7eqU?pUPLWGQR~f%~VoRCsNq@8)=H zuXZM-c8nqBz1s2{Zq@g-|5~q@!oyK9Khc7SYlpwV70#FctLs&~z5lzQ_iCTJB5v#9 ztmFVOmc{GNQeKFK!!K*<wJZ5f28Y}ZEv96+IDs*ZoP(RkrCK1{22d#ydK;)G$6lK? z$iHz0mSvt(7AN>W@_I+G)z=HlN43Dc8ajMFel2@Ef;4455PkBtR<z+0<;J4oy>t#a z+{{{>Sg;tsCm=u<KKa#sOa4&nW7I(F+k)zuc=rx029`?#9~|^+F_P5KIW`EW<;o&i zqqjJbu%$Qpr9Qp(3I3nC+<Ty$D4nCvS2qSH5~Yh`{03EAo@i!^`aTy%tt}i!y%%0q z7g|Pe@|j`&&7$KC&5R4X>&=oagA66ZMenSwS-2<~gF?m2*m$MQv#WVpJ_!iFJ+)Y= zr@kHKN)AtwyaQhjZueUqV4*cM%q1{mO^_Nn(e0K4?#-FQcJ!4O<E`8WVRl;E`|G6( zqviZZRo#2-O->=m$quRF4k>|82az?KIjjU8l(9>{8u%c6+r7@C6J2JIA{j8~MA|5P z)3agIwmDLvXT8hmiWyiMP5OG$ol=`Dt+8A0JW%XKnqP`lZdJ9}atyIKrtWL^Vu<yk zt4$!#JqSUswx%BGh!?1t69#(LayhwQmYq5SmJ&!?b{k+07sYI<FUzm*?8-z*Gbm_* zTBbhBp=#!>+g51R87rJ8V*~Efo?+I4SC&PKV|b#>s<-XHtQ78XB2g}?%Aw}Ax-Vnd zE|ulV;HQ<Oj%|y^O6m&*s6uzD55>2j0=M{B^?s7Av8IrN$NUM^U*im;fC-pHCpB8h zLRQku{FZ9~B4cjfE<Vrj0f)0XH&G5<SVBcCRLrRlY#u;KE(UnjZhadIPg_@i0o~nj z+DR0KGp4#YDD~zmM7IfzDQ=q!hpv#MpZvf`FmLfalDp0x$4J};Y0t(TyfKh{-IU#b z%J`+WV+wx+KX*P^iQ$}=<wCrmI)6046Q#MC&k&V_OF@u&^ueU2oIdx{ykcUd5Sxbo zkpX%5?1SHUEs9`nzdPVDE_GREsnUXfd;Z4ho@9F;M9rK<g=djQoUtKYe<V9SgnW_{ zJgLwtpS~E(*zRWa89O{FB?RocPK@r>7$18wTOIoV>=AiHboVikZQhX@RuDfJ=oMla z(EQy;owt3pda+_5heqy`1l^1nwu&)KY_affG#sb-IR~KaM+hwS(9=Y?+oM*Bd$X>F z%<f7p=Pg>|&B4XB6vWjzwe`APWs?o1E$f}7j*%!K13!$6<M25f$QmeNnShE`KBJ(s zp)?{cP{Xle&8(-PJtDR;{C5@uWh1xiYFqp!^E$qqac}i;jr|^#5o>%({O7hu;=m55 z`_=(Z?Z*eDCs>g(v2vm;c^~#i-HExyZSR4(dBau*o}_aDiMg9>7_pTeo;2<^2qlRn z&1{tT99rBWAp*yISRu6BTbtJFGb1TtyWcRVSdYj->`w1Si~Z?@-E%&R%~P!>wxP?D zjU%yTwU4lBK40B>#N{mHlpbpMtO8x*{1z&%r9NRKO?1cL;iT^HuddsWs|Ob=!4lQX zo2(Bsy|;dH{-o-yGTn(7(T%s&2$n^K^Vh-g(Z(F|E(6s{*cB!g2U0+tU7PKjyC$-r zEhei~U_p9&W7p1f_(=*P7`2nng)0UW4(lx^502*-!2|1Rl|+>(X7iSd-YlMtu5Qs( z&(7(zik(mio^e{2`La3zm5gedoGZex(w2J?e()Tt%CC`o-n%t$#!QjxasV}xSr}-d zGq?mE3t&43rSuvw?sK#>z$!|<#_)W~#3`qTgysGXvbEgcb5CtjV7GnaeSqNdtW(Wn zSwHeWgZ{dRvzKu0QA1^%vGGf~JM?aio0FoYX81WJ#Wy$!L(0*Q#1<>~>y@r+0SZ1; z!~nqh=&<s237+9|W|qErTjMOuIFT&b@=|{ec47B=E{d~n;yq}YT2Ygyfcp5XbR&DB z6evNP`_?7|TM9ei{!$#poK8Boso|A6<kw3|-;9F67kiu4kK}|LO1+5MxvIZ2iI?cq z02`>7^QD@mshJ&1BHW=mTl@C{G~Qx({PWak(X~|NhlOg}C!5LoBiktj)f2}n7FsS( zB%rtO(9u9vrtvZM%UqK~uIoG%wzcssGvEKuz~>~dDL1!v2rw>SJQ+5^-xPeFiKDPZ zD8uy_V-dODo$>%`Xwe`(i||-)Xx9$7{ua?q*G+xgq~qTFibj6z{s5lXKC~vbzNWfk z${+YGhK1G8i^_we$*+-HA`>NBWbx*UhRLYt<nr2We+z|x+7}b=o6kru1EhzQ!IQ#Q zOsGhNMsC`e`JB>V^QI3EvxbORD-vzRdn5Z+Ty<Bkj+Q782jN8Tf6zW6*YJ5je+?B> z#AYjR??Q~?aLtRYJ?c~D%MlJPwUbG^$y0;l|2n+2PFC*H7x2AZNM7<KO6}oxlV&H# z@J?W(ka6U;)x-0lbD9MQ8W|9we0Id**A7&D?!EwYrG>aJ7NktRZM5_xNkNnmXNbPL zx>=%*6k-q8%I6A0aEep1l^6c9=aJ>t{CZVplH~Ds>>@mGZkI*G8S@WasNJSyvF1F_ z`3Y}m0vC+@Lb7DFsf_a)Rrcnok7j#eX(3{zE=zIl%aZ|3iFYiF+4xQ&Wyj~`j8tIt z!?=PP2fU@vx;{JY<X}=J=n{EXMyWK81Ds6f@zC}^+VVMooVoinz+dw5(5D9QA#$u= zJUP*XoQ2vYscf8UDoiqyMXRD}@2dwgcxKZK{qTrX|4hWZLQ(jD^&ApvO?A<cn8(-Z zRk~&&`ZVqvcA&1hjBKZ|cI1w=?e4ZNk9YUJo=7EY{2_n^(Z@vJ7_Vu3sTkeW9e=ju zuzqN)63@BB=<@s0Vnz<KVTrQBySB0Z>#4lJF9}6)%4(c%ZI`M2yq3zY^+g@*4Q?6c zo(M@DT1j98&nghgSZWt-FIw-+dH=5scy*nU?-%DVF@>u{@1^()QNe6Y*SLq+Ju<|( z0Hw3>b2I=vBT|Rvdkh2lL_Ik1yIh>)T<=GDhl_8JCI%TROkX9UD1YW|hkPC|+;9q~ zrKt^3q;gZ+{^}l>f43K_)0;{1B`sV`Hj+GD#c<ZmZuf~5&JlGgih;=0>IITGPOJv- zw!-6Gh0}~(HwAe5c14b1Hq-C@yywmN86gnZZ~Nlu#Og>?{G*jsL&i<}`GBWtGp!z4 zOm)J$57?TncW%w)2Je8{uTj2{N7|}qD-N0sT@<nhydCyR6ThjuNJ;s;yn?UEh~&CF zMIOpXm6@s@b5qFb20f`aQP?V*IJ0cgvT9LOvb8VYrN%o1F|_Tt-8tsl-!zC4OEOe5 z_I^SanMKcgv>T5XFBawQ!=2EnjA+u%{U_iBYWSZ4FPGZ+>^lR#Yu}tE(+#ZU6Wy+g zxZY_EIq2?X`w^Y?ADb<P4{V+Myt+Fzw&-_`=&S=V9HN&G%@o;1Jaw-*HJ>+(t5<Ha zpqby4kw6}I(V7;fBop3Bge#sGkHBZludMoCh5?luy?Ljc-E_Dg%NVcR`-`sDYyY!n zAf6~v{H_*1wsmv(HLaybqi}^L8_yy7Od#Dio&8RiiC}dU0`BO(UanQ7X&`w{gKIu{ zKe6C^tK76h9%FCJikI4%xO`q*wPGbTmJUAj+gx}!N6bKV)x&lvwP+#JraImMoNdTZ zO6~Mx_~PXb!dSATh<l}Q?V5kZ7pneD_G@%&WbI?T@Xl6qOKOnX&4|h!jC<>uby)uk z?^a6u@Vx*cCLFZ1x;)`WM6{zANb;;uQS8Vt4IL7cEFmeoUh1#0@!G6KG2T)P&O=w9 z)A4&T6wsU>LGy~tQY&Bit-{%@#$lT=im3^#nD?e<*xiwDeo5kqjS|{9%bBwAdO;Rw zEoJE<A-ymTJ9OLt#aRhHB1^IetT`{ViqFg%*&|eRN_0+Lq-_<s1B~DZhYJaBPJv|R zT-Wm~@sEu+JTG0kY2SrteZS{Kw$gBU;n*<wreh_bR;h})!~EhjG*aF*ApdBqt$%WU z_l!-1^}htcR#p${qN_H{_yS{F@50M`x5x~b-bHOqLAZl1f&T6ymD`sEFL|rn;7m<u z^UO;XiyIwz6-lZmSg6?Q$?%58Gua@Y`-(mEW`p0SF3JA&L5oRUx&(;;Ii+rGm2!_y zKGRWf>(LuPt%f-horf%T#{(-i+eF(unR}d$&S4T9)U^x}C*=I1s3O{}TpmSl(=1EP zvklYE8D}58joQsTb#c3wt=JhV8?S4Mi2bPlLSem*Z#>h7E?Qw7I-e#L8PL}4-VrB2 z=ArXF_AXXp2IdO;>1}u<BPIe&Ll-W*3JGdC&7CHlw)0JBT(O=n%k`1wBxuvphrCzc zhYhl@W_ONF)N|X23mByS(d!_5-q3ethixzra)=x%up_trshM%kRXFit44bEuZ&Jh9 zdif$?x?0Y9ZSQ(}5aUA8>BRHf%s}9`3fH(YiAACn6)sn+$>2=RO_<pD<jC|tXEp$} zZ*PwBv_f1f4XMMmruNBO_C7SX%PTg=*Q`O!TeWY?cE-g@za^)U=Lh^+Q#bXZb@({B z4ypd-)!+JDTPlkDv)YHe3G;q^T<+sTTX5%32%k?6mC4PWDv*eP3BL)pHl>~bae|;C z#z5N3_RU*99P;^X{Bo6HwMk8xPw5IzVbq5gJ9j!k?$J11<6#N)hibH?g)ArE_OPwp z_le3CC)vn#d_|U15{L5=u(dJJ<KL~3U9oeS%B%{43Y-0q5_Ef3Lp<~NTEa=@_=U3E z3dzL$x-IWOli}aaT({_!Tfr}`;H|1le2CaM^bY>jEBeFU*!uZf-TbatbS8U=KmLV3 zIPFq+nSCVfc_jXWuQ|ko_NH;b{*-I)TwtWl*~Oj6P&M>l923Q$1L~ZLu2ziA_AIla z!9ZTwK(#T_jm%TB!*Sn{tdUaQlpVESI}cou>q5t?dnNAfzO<KPyX}8;=1`FA50yN_ zFPpnNNZ^J%_m$@S)5ZbZW|bBdgE`{fGFIpIp??Q>l$(GA@_ko>_ZQ+JN{ZsPq-kD; zjo$PO1RLqdq8zVq(`+3Dxy_wHqX8MLEkVAe)K3&dapZE$u@!^bj4LDpXTr`EXA#`N z93!Pmc1ZYv!bkrXkp)kDU0=pT)}s32R|_N!e28W><<JrHujztIub+}gMPtF0;s#h@ zb_-ssc(DQh=AgxKN)I6l!9L|mTT;1B5s7hniiZS=zwUi_`NSTe{dvMMGb1PU!A7|B zq|=*QJ)pq?c@Gh~QBjj3HO##5U!%Lft8z7%ZADbN>VDQzQL?Tb;<ZazhsIwV5KJ&b z;=EM1^7(uViNCe)p^Lcj3)PFYZ>T9E#_%V$VF;O2YB$jRUWK02VEGj@i-xJCTU&O$ zzc8)=1i18>xd1Sl<?0y%iyPn>)JRx38J9<bR{EG9qfV7z_*Kr~I+`F5=f!DuUO^T^ zxFF9)^zFS$^cTFdVn}3*B=cK|1sjuUODv5nDHeVZ-?>ue>HhPTNm8FZ4?T*z(9spU zoMqBOoF}@2c@B1QL0FW7b6=$fW8K)L0v<MRZcho1diai-3#sW~PV#hxW)W~+L^cMf z?K#^rgqF2(Nf*@nac1TZ$+<Jn3c0>aGUI{wb>p>$3n5AB9W#Sh@D5(fYCg}abBGpn zTF5JR408(!*KUW&^9p?M!jg^d6h#o6@-=bc?22<uzQCX7y%{GR!FxU75w{5zh%l+a zHejL@B{zOdi<o7ts%?Y6n>u8zn4&;6c^R~J8|iG;LA7-ny^>?)o>!?~1ov0Woc-|A zgFC#EeGLQOi-V6%AHtn?eo0r1F7OI34S(a_fZp!5ck_y6E6B2&fE|t{JKgz_%l3fv zx@r8`MfRz=JBk3utUJfyaX*LDOv9c<m|gSR=}VOmm_IHGCp0)Um{+6>u8gXBU>foj zr+G{AOw*FwOkD|$<`C#gR60N+PV3F0AR(oWF38uU*?4~SOdU04`O__)ALf|-n27d1 zkZ*R4*4h_a9^PIod566&1GbpB=TVUlK`8|j+$~qYw<)P(Oj~H1TZtEMbf|nxK#uD+ z_G5=twUXHxaMwL-6!-V_ekC=0?n?!=<%L#HpGcw1X8q(@*U0_OA1+-~=YaE-CW#W# z&5}WD;`DP$lbAW`y&PZc2`J*ZeKmgl*u-@4Yc(*@joR_^2HBO;r;<+r+Rm*#Dg%ik zdF?3{p_HW7-cx+EQ+%F&${w*yL0D43#i<HtfoYYnR3#(~@7a#^gzKjH<`gSmu_x?T zJoK|Q&K6%jd|&k`_V*%9f}JxlGavNmyeZaFWcYY-x2O~~qD18^T}-yH+r^{Fs7sW@ zUJDLQEvI{Ld#M&wEWGI+KIimvLMLDC_mrq3XLMRWs{j*4&PNwTT|`m=`OsAPRE;Kx zH#p*3DHfQ<_9Vm=p%>=!Ci8x)tRJ|+63#m@HN<Q3{|NEZkdHkhryEi2l&MAbjV1eq z14jh|I(&gPv0~IhSQ7KL?3}3qJSSc$M?g16HKIH!N<nHU;gSI-dIMT`$^rgQP~#xv z%Xo|-T33#ApNfSLN%6A->wtB*!M~A~V&vX^N(GQ~C2`1{ju=>wcFKX~7z!VtC0B*X zZQ7FFi52p@2C)Y@Cz_2`X(I{<lBXdsC+kf{j-~SC*k8zJgzK~Q<tg%MhvX7c{KLS% zKjZ#a2ewq7ipdKegFU|zoeN8gL+XV|lX*uFWvkPn?qS6Bg3GhKW;uvC^~jE#U<_SL zF*DVXfEkHjI1z!Lt;)Cm6@`)cr!dM}Na!$i(gDY_x<w6V_Jx+0*2-x6TV`}k;@$nz zYpV(QRr!lui`s`8)p$iYr)iEwMeN`c84hw`pmY)4U%+xM9k77yB^X3y3%O?hiD!!h zrmIt-@yp?FD4j;gMolGxutxev80ZGm^K$@2Qz{*jjJ0PDZ`vyTf^A$pj61hy7HF)S zZ`#@$`xfuq&;Y%48#k!f#t+?Ik{ZMoK|oD|ijxtT@Q`{sV#+P;AbLAvvOuscw-Y}m z{@E>D@rSCw-x#HfUtGbf!#JQBJwZV~k|F?c4((I`&*^}V;t6a0EiLtEWH$p*mKQn$ zC=gtX^UrT``eU>z92pU*9b93HP!;@zML@EjXA@xnkv6_8v}ea@<B>lKV1~JL#b&Kw zikOa20RM5O5y5x8WR+D691Skd-J}RE8=b&si6qc_D_p{jW&}rILj!k?{#=KH_KfU7 z5JAzGGgD<L#^?36ox@E(N0I^ujz#vm`wO_9e~GPclRtker!3&>Biz(XzNgGNLn|u) zRXs&pGppvEob4>b1uB+r9eSn?&-G)g#=owIe1_X+UY4C&M}a3CUezpgFc-t-$0bK0 zAqDDw4QAj$g)2dWY7}p7NKzN?v(umHEXg<Owb&>PsZzP&=Sp6>j7jTA9qF+9OHS1( zV)-r~eqNJZseD?qXP~S^iY#adO)y3paP{3^E$-h*N|I5Fl#TxA^ZqC`vg?DSsIw=$ zxN<k=R2tM)J*mG<3T)ZzWUNwPqoFix9u&UlwQ@4!_5p9c^q(H9uhBKWx?8^~O5Vpd z9w(#<<L@9w*rk-^+?L{5%9}jr>+G*wmUA>iVE6$)JHgmy=OiVI0!3|q5M&nf94|I0 zH+W8c;d~)AH6C*ZW)n8{W2?judrYr;3cCv$$WJh<@=Z4_nxS+8L4v9%#X5^C@Z{ro zk;M!UIOz^GPZZ=Y3z%}YXr_~ttw3Ls=De0(x~xo<$h(GxuG_vFv0f1FrnET}n~SDN zE|s`J>G6zbXD++l`j5BzUwbyI^Zth!mkHqh1S_GyNW;nO(Hki~ynMF7WHzFJ=3z@n zE^ONmhYlc@*SxvmAE){{r;Dh)5su4#cZic*PNEs4)ap(*6GRC$_+X|v@&_93zX3lS ze}-O6WryWSScyTL2aKdQ@mozpL+BU`busUL=(0JfpCaws4J@F)@i8`zDxe$$`3GBz zwayt&XjQFg8&<TwUSqD~U>Tggqm88uzA*%jy{`2@&Sdz+PsI4oGWAJEpB}Ta4^r#- z2gqq!lYN-gJ23sd@Cqw6`_9v5V6c$Q!tbj<cUfvq7%&uAV4ejh2Ld2f%)apYDi6Kk zd{Sfi1-c^0FpP>hHhU^(AC__3RbbzRU(i6}4{W9&<98Lsod<f)87D^PvpM_xYL!g6 zs3-0+XW5y~F5JJ7$CL)e8Yc6+4mVc<YpTo2yAFp`kgTS17bQC^v3YycCHVV%BQE5; z|2c`@O7%5zX-29H1tYEn0_Nw~E+c6{D?70|*bP9pbDHC7CL&e&cqzZ|c3v{)3;h}> zU$Zc7xtZRq;tv9ua4@gb;&}3`;aI%;uy4%*)>GrBTH@M!<^2aMhwbBzhwC|0?rI7k zVLjB>4VP*s%P$W7#`_+oOY^l!ZKy<O7vr_>DIaeo_<{+~l$5eVF^vOXmnWO-(+)j> z(nJ;~e?dD$U&Gu%`PwToo3MlKpG?wPqVrPkhQm*u;OejGmd`l<_@Gd{WaxU&ee^f{ zy^SZ3W8ZYaF6~K8v~YfBuJK7Df+n!A!~7SfVHR=WEYNH0ao0+AY*V<q<uW`GPtQ4R z+||p^HE<ty-`S<FC-=MG++Sy#Ot>G^3{QLY1n64;X!8Y-yN8wzTbICCpg~_N>WTzt zqVV0DUjTWR?cMp!QTKWFFwx?h-6K0Ks3@|njn0|juNaLDrw~-6l1ArGb|Q7_oRw&! zB%7i@b8-5;l2aq^Mh^AY`5u4^4v#*|v!cz16>ick!u(1!FaMXz`LtzSqvmFf+j>fm z3unhQY{ONt^|axDS*QPO;FjaRhj{dh|CzTmxpyTRcjsX%#I-9WY7Or?k1sxqg_fpy zJxNMM>YW}uK`1`~;WSj|!Ky7p3izHVC`<I*3W!bJqMM($4}+5w{*<2wv=eKSU0xC6 zMcXSfA=~&gMg@H5tdH}*m#X`9N^{hZp8G5h_QmOo#)5z-r|@Sg)-i>EGbXPDk-YX4 z=QGlp_XxaDH&{%NDa3PbQF0-;`>gJj&4uym2*4yXbR7|fAK<0g52ynFZ0N3fSNDj$ zIp4YTMYY~wGG$Eiqw&AJ3$^2aUWLt7ug=M;Z<+bocgS{5nI@{oiv?|J9s`dTDHUJz z(@VTcN9<gEV|&F%;z>izqw-ljOw$vdzB@j0rmJdN-3wh&IVI;yjuu~)p3F!8n;D<~ zE7TNlY!owB!1;u^l=V5Oq{~^f!B-Tam{rSQ-!Oo~svTBIQ?K2`8Y{OkHoNWfDT3hs z9u3tWtoWOh^S}PgAK7cN_sM)v$^E>5WmgiM0BOSw*n0|r3EDj-NdY-7Y^o9S!e#*q z!ee7-NU8L(t&N?izUBuJuoeD!*z$twh<SP+D}6PjbQl_U4gZEpx4MUu$_~>zO?`(+ zmg~4D>Dw!vy{yuBVpYYdX!bns81b{4cb+&FJsGSBohlZOCyk6Ko{8(eoaM@I!2AWy zTWfwtpXk1{vvD%(iL4TIaJY39KbS6SC>*tl{Rp#jzzV<fMOcR6t%c?=P9KY?x!M78 zMusKOP8)_M{@Ot9WmBe;!7uQx$#I|Hdf*q<8J0_71zH-mTWs_lFPzaZBDi_=K{H~# zzEX=K3AtCa8**M2r1V<kY4|b)#R^6;@Ncy!9DAdZ?6|Sut3tm|ly4lyJ{A%ftM~<r zasG4ZOGkf|m=97W7O8*_NwaJ*`l-##lyY9A8M2!u7kSe4a{pW^wCT!?6_eg>TVBuS z)X7pYYi^{Nu`5W|c{##%xKwe$1j_QKC?5R<;@6deYtjp9S+;;y3rRifeVUAeMNM#p zOuUhNMmT=;dk7zVdqwMhdyn2pGv!H-X}$G;4*AIN#p*$GDSHE&`>xx#e?Wo3xObD^ zd)1FWWgEQK_1lwFPtD68&`<Tb1~<S3fa5qSecmuiN*o>lb62ttF*PL2BHYXoR+y;> z!aMS8H$Sure`{nK)7f`hq<M%Rg4T}A`Z?j#^qFVqm0QpIR@-J#Z;+)@OBOjc87Fj% ztF#701~#BMF8SKO4fM3gs}!a{k&oL2XetUFeDHq7W1%J1LY9nB4!n#rnCE8RGZ?W` z<6GqB{Ph=(GW!}v44$vkjRO-5XxYtgViEbb+WKNJQjN0?a{#^;DHX|w8KX26F^B}R z*FR&dS9bKVA<SQIrYdqyDg$VvSW@t!ZNWT;_x3L!)SRB}83e((`ucArrAmA^iD?CT zX>^0Z*w^~dTla313ma!U&3Pq>`}&iruT{S2<J)G_Jy`^7_=GS&bji(Io)DPr3kpRx zfgx(4asMY9MzDTBT=y6c?@AV5-qf};N4>B@(SBR+5%(sug$RMi&i#jP^UH^mr*3og zsp!CawWAe}XRn%0Zz)##u!D15CB$vS4nT+ysSfLcsG!Yix<>R!b23%eL$j1vlk~34 z9C8yHaYd=|zRs|}s@tw<hyIQl3}ip`U(R$f>{(4~6?rZdWL3CBU7V=iocHckAD9ZR zU{%*kwCdLmpT7x7eSY{q1+&NY?o-dPH^kubcR+y~m@S+|f;m35pA8q2>7=uE9(FZZ zq?fzs@Ol=!7T~@$O3TSJFnLPUWKl29SoaM3L=(#^`kXoApzs0QaP3^btGsxbXMtkl zTmfd!|M5Qw7d|JdfhQ5>;=5%R1JgvK{9LMy)kVeFn-m_)ONO0Soul<;7vpEPg(fs= zYRv=vclY~HZA8!B6p)G5rHz+t$4nG;4jJ;JHu={l>K5Fa%IwL1RAS6mP#+f7hncMP z-GK{9w$}eCw7yjMbm1S=73@MCwl_P<1Yi4(D3fPBy2w!tRd+l863OQpCS$XRxPHd? zzQ--x>eOhk>t*U2C3APBtmrw_GJaK7N*s|=q4nGHtKLqSu2D`#3axAXO9asN)PEH& zo-G}CO)H2FRT7q1d}69wvyF*kB~9E+sR~rwGvvKE%qnq3Mu%@~F4PqOS<iAh-`e<d z0xLF%V(y($d=sTM$moYw_MaGjt@0c|JoiCK^0G~NWI^?`JrMQkn6v&{J_8N&oedG} zh|}V$FaJsV1GtXht_)bzGQfOAQBoZ`UpuWT(aDtE*%312ld?Dh+j_jkw_i#DV?=3E z*`76$s<CK3NVoJd2yxWC4e?GayO4v%B_6tO#Nf-b^?SXMu$65~SZQ-amTnTSdwu<{ zWu83UTc0!@y*PAMSy)BaAfW97i$&60SgTi9?>ULFOCar5fMhs^{SfQjbf+Hrr3<0E z<=3f(sb`H>l!xO&O<QIKm{Ob8e(^)<L(wk;<|T;M9`Q#y7-kW*t_jKTRvT4%(u7%U zxlO9){QZQ-Qx;x(Bv1YaixejPrRb?a#a+-8B3IlH`wjzSCR(ouhfpqdVXlj$?bfJ= zcZ68lSnTUTfn<ZSlHRnsmkv;MXRNzAOciyhrgK?QjmN$Yeeq7ZSH}+#Re}%yE)Iuj z{9lZ{XIN9)(>|<-Vn;<lq)9)NfFK0vN|la;UX>0ZprN-Q#{yCXq=ur>O9(CW;*nlL zO`%7DfRqpjHPqL0{?}8k_xYW3__jXnwP(%DJ#){jJ=+|i`e!M~|0_-Uyft)mni6pI z<d<b`Wpi+ogK*_dR3%(@=d^RrxIUx@-`euTV+<ou6)XSf*qvfwYv<5*w|=ihhEm;} z(qn3(m+0JYEzEpW2RKKk8(+W4|I1|?O^*(|2(NU;n)LQL*U{qtpjB(oSB9@GtU#qu zt?zDX4{`;SO5WQN48ek<-nk0RAql?pmRhKZpp^=yrN-ZRCX4aE<+sSknHW|AcP`?= zABD%iXH0CPng*3o3bxB7!1f32>8@qovHm6IX@AwnzjNKVGb4hx4oMMFuz%OjVaC(9 zlOf9B(V*?IBSvPAXAEu9_Xs(B(==3m_~RE)&YmB2K&n+av|6quOnT#AfTz{XeY=FH z&f52sXlvVV|3kVJNdpLV>HD~#-=MlIxijZ<7oD1)>uNmIfXa;{zDHnUGn=>X1M=A0 zlXZ5+k3RPD0EaXd&YD!^&#v=U;~)yQ4?Kn^pyl*EBsD*&D8BeU-zc#a<9mPI01tb4 zo*zAJ%B1L=%=S?5+r9(2&8er!80`2KRzY5nV$Jhxb*&8Aw`EBypS(TpY}X#?ZsChO z^jKpH7=FnxU%UdO?$XiER4K#i7p-I<HL%bZ*QX(CYfwyeA$CsiAHw$|zp%3e0Q|&b zI^lCsD(kADJAK(^L-G@>q<g#q%7A{iBw2E7Sv<!&M2Ityp<?2LFS8{#5W%r~gCLe+ zQoL9p^JTE078GJ{47xp=Rk}u;&5E*n<Mmg$V(fC5Zr@rmQY=#d89-%A8}{gXVXLif zg7_HP@(fj4L9ik>Ybdtvoe5a6C3E$W2_hvXwT>^kTi70Qs<6&iswEO1Xow`5PGyHm z<7z@r))b(fOW{4?`;(PV38PBh<Yo#nd%e-8{2!_#&$MaIB{RmfTEsaNS(DZSjSNAV zgV;d5IXBD8l>s8mVC+rpwTV>unbtOGCW;fOToF?BrcAA1O}=EXh=lXp2&BBAuN;$9 zZ&ZF_lJZ}(0Gd|OuCh^OS{A=uw*+YfzKH&<LGZ6E&^_~OcezM|Z$;D5g!nhq$%5^a z5P7fT&e6WyF1x9fz+m&2s!$iS5S3DE>H{?VhvI%1g2~0aSW*$#+xt>A3p2Upuzeez z&{z{B?Ylk!&Q_SYRmzk?6CzYHIbf~75y+31MTn!9sw`Szt3hu=cJ9neab|Sp8XM|( zY-~)}g=Zdk#~4*nAzudC4p!ftg1Tfrxfd#DzsL}<CY3E84{roGTI7LBlofEdnq)#& zUb1t=-@~cvH!r)kC;lNj(^~_Owv)eyw&Y7dH6p6=Wk?xX6@hmX=-f<MhFQ`yI`6)W zd4HO^tB?WTD|mo`cGLdajQ@S~7oa^i+Kn`m!hi&}PePUPl%|)_QUwUpw^R$?-b;k3 zr=*9t@2Le^HxAMT?}rxz4S99#bEK^CPuowi{GZPJ|1ERWp1&Z!Qk*vAyD1|Q<;F4+ z>|ap|9^W|#OihL?dh*&pB2v6eq<h7iB1ey_H%;mM4W$82p3XaW6vl7YY~mModFW$h zic9<o8q3L?J1<CEw=47Nd4~8a%*dlrfYVHArKLeUdDmHGCW`@mkrBHa0MhSu;~UAt zd3Zv0@IVcNXf!?o>n1hO8}O;tr!0xTG8mBu<&m}|?Vx<w4F<rY)Xyr2X{Ys<9ST(D z8wG{2Uibi6?!td#LBBW&&j*{c3VQt2IVCv>i52M()EltY1wX~QT654AxMH8lR(EKB z&6ZT<faFYe#I-?d<6C3Ei)@N{8pL>;*m~5h2PUTA72mBSa`+n4Bi4T}hVam^6VAH# zV4f6OKyeHeGUrxE#=x2l?_rMDUbSQ#76{(4u2*d3iyrNgwJW^#{znVcMrop{wQ#J? z|GdxYogEg+8*Ed@9e7(@F$nA^<LC8%hLHS+O7JJGGhJv)MU2;%<XkM2*8_pTKFK$! z2SIipLJB7+Z%oMU+EUqah@oN6=9<dZopBXXE~nT^M-AgjK~t^oS`{BjQ9jK5to8LP zfNx!aa^5NNlK(y_R<7oe2F=4;If62l1pjIcisUkrDazc?#I}Gf0FTMq`I!s>mf$ye z*+V+~v&X7>nLcN;rKa!8_rQae72)!nJ5Gy~q#@%*CW_GvCdF2c{pd6U3mAVsIn$*w z#y?4Uf;7_uWXS^(O5)#avp1@_N%5J3JSVDId!B30EPrO1a7(-WEM^8cbKNGYV!kXy z_PV9kq<e9-pN#crh_`C~bZ>nTk%c$_bNe^7{`oDZKg~mEQM?FbK{bcKai7m@g%?a6 za<r-rx@@K|_?QimRk9r!Q`Exn(D}s*tp~epinpqcg>-%bGBNU{m||$ATUkOI`ZMMf z5;D7(dtfL<zLLlyl*evvv4Aaz1~0v)ZZK!T{|q6#Y@!Fsl|&}3C_<v(<zLG*W*%o8 zxVzVK4JWUOyVaOfY?^iL`(5_44p%<~IM7<eD<D9*)U(T_r2;O9P>cra7qogFd0Ka_ zZ|7$fP|kfhwS@(*kh#*<kYzXE_AR29o&Ay{WV71KW=af8EB@in5@9*`(w5($`uM@% zjN1ll5c%YG0L|YD2w^O2IajCCt8OPrO4gNgLI94nrVpY5QU0{^?<(D>Z|~qCqMWzR z1_WE941-5Pyw~QiYtV|PiFs+oABqhKAe)3g{~KK1cd2Q<=%9BXfwpFztbO9%YQ5&% zeeUnS7{5Vt?rHh$BFERDVo6k|--ZRkUB7vHQl!?c;$_Sj#bVyJ#EguTUB(&;$}aDC zd-_awTA~#ze0{L1UPr}?@j|BVN8(jXGJhp~hTr=O)&zEb{Bvon(D#f6Mf%p4%p&YC z{oR+iQPD=9XXDO9r{=41#}fSNV+uZCu`c|sYo2U9m}jLWP&HEP{VZmpUYT9<-&>tO z0bxRC-D|D$mHVJogUgOkR5bgr*0^&8@#(hl+uNMR@RAI%q#S9q5w6$_63yP{80tk5 zQuK=+V`l!pvv&Tke~10quN8D746lUS<gn@1YuM&wXvIs!z#4spEvq{w3hYzLecI0m zuiV5&0FXYOLLDANNr?e*6_(8X)fR*__pDp9ql}u@DTYFTJ~^@&5Kv$ieDKHjHrgN5 z6RLHt#?6Pc;Fx<R?r_@Ax{)e|fyqUSn2<(`ik)KJK6cAQ2#rGTvHu@l4fO2nnS#}G zY`c&c^mfU+*qcWGX86C9!*C~p)+Ol`x*qf7V<%4l%ve93tp*R!h!!y0d>9qC19fk@ zD@&<1j@G;5r5@aWvtpRTel;CeOFl%9+h*N$+Rd9MpC4I9E&*eK|LSPZG=8NzG}zcD zHR{l6oe%2uIv9)K;NA_BGX6eS6IRa6pwJXhy|#3N{WLVw$+lfpU3yu(vkb>X@)aO9 zS2qCIqF$V$KlbF4BhsLTtx({JmxLsrJ}6!CR>4b@=>toB3~BlO56SMyIiEqt3H&Vd zi4Qj4jYC*E4vH`nvkSIH8134<4OX?qM2W_bGkSJzoW?+2KiV&z&R}34*73-^t{W5o zCMFy(TEOmD^6^^0BL&<3Pxz^^;R1V-)G#~5I=>p$2Re|_PvhV=EmexNh_KXx80#}W zkQj+|IYsAP|B83h*?PS=oTia>oG<@V)Z=q~W(?(l?P>}WvbSnF%%bA%a9ZjOr4BAs zw<*sWV~qX93($CZLraUIyNR#Uw--*;Ke<>flH;anpr7EDU!xVll!n>ES&^&UJvi*? z(>fWw<^^iU+{&!hfeLCg(&78DHo{#A?4}4a1z+w-%1hOX45S6<b*X|~uQ-geKF7B8 zeA=nT1|5=mvS`rnr-j%poDBN}(BmdiQD!FtghH1fnQHJi;GnaLJn+J8FIC&%?DDtX z?F%w?g{Dy(jzQ)%59v$pMm-MD6a9DL{tRMuy>HzjvAs`gF)mth$%JcGyMFR7I3$IB zl#s9)@nAsN_FdQKaU>T^&`?8&QaL*=JIW@m5@qR(nOlBLo%bpzU!D@JrBC_e6d$E? zFu0g^ViNPvnaye!P=gZXj!veWBfl6Hn<jR-9>K*q><prMD?SmvnTULfdVX^e>50?A zKm^K@6j<EDI)0EWcE_eTAU<Z9?Rp_Mt;=jQK+6B_1G=Ax0R*QS$whSt9uXQTiOkbh zuzFBogVVaMKREML^U~z?j~Sj2u>FH=H=k?}5*RZL$MWEM#S7!(YO=iNw-taBhv~Ab z2hj+z{jQ7xdlANeckeFdb<;<2KJY9Ftd8qI(f-=xZ>EAqeYtKq0){JkoFKimOL#Wt z=S&3g&Slr)*vXzzJcKD%W2Su7K6njdHEm)9$ES+vS9R<y`2V|^evK6xqNtY6Sg+Eq zCF`JogqW2~<7G*OL}S!+*Ww@XV=-h>jMT^(g_Trja<P*1exP8f)-6-<3G<}U5k-U; zVr~=QZ|Ng+x5Nka%#p5;<`lmy`g3}QDfhwdp_>*ap(JY+>m1osgjHB_V;S8Wdtmu0 zq#B)0DyObSRG6%nUo4cZo|coJ(&zY6;Bjf@;(9JrJRF(1xU*nZ&=md!fXKhbRGQ-3 zLck2L{Ck+Q4%<q0(r?F^8~3FILV*H$%^r~B3?Ay;?foAicS+k16{HrsM*~_r%)Zph z2U~eWK(iSsT?@jCTSFJCwc3FT+YgoUVwW#T!up2-Z=9ktEI@0)ll2rEw5{VZknd(* zdm+j(oa7cl9jO50Ck`W?Pdpn{bH{SN^u=~oPKPgS++@<6QTLKUc6G=HB5>93y{7Gg zrK{-h_0Qp>-(&^)9$Wp}mVb^acp~=-PXEl@@W`LWgiybFX_ReF#)QyN!iRLxxOqd3 z(-I9|h_I>>aJN5}m+u_Ep)G5vkX%voP@W6HxDtnd+@)t{`Cx%11T{0z*h^nX`uAIi zkH}Z54fBmTc_}&ZJlj`Gq%>ahnWBatl*l}^Z4#_3A8#*Kl%S8ZZpJ}2aPFG{GF=M> zSC*PMNwriFV5|_X(~WQ07gbjn7dfb)Xe#rZ7J7;pW%LOfFNnT0ED_-5h+G6+uBd`h z_&N%_x|k2#Lht4~M*(7u&?Irm-NoX#3hS2S?~qB21JZKh0$2xZdSVtN={6jTNl8Et zJ3e2ENG|-V4&w_5L)XF{+q~!(hw4ye*3u{=^v92wJnzQqN*^|7<cEmu&2l<!syuq& z-<LAqFQBAmbCfyh_>(IYnKAph#dO@eIe1nQMU4{cfzWrfrAW(}P~*+KN`pTC?ZBo_ zi?kN5&Ita;N3GPmGEYmEySxxEQVBytdeXLa^L{teT6TBweq)-KrFXLA1kRa3IyN@h zszRIko@;nPd%=v{N386zTMo3Q?A0x%rv8;hmt5W=0q8hkb!@P1`84rhq}A^9ZZEvW zzsfx@LO~rkBP<LoO=8@IP(mvfxw5jB{voL3owrCniN?$0@gKJUj)oJG&e{mW`KP07 zuF-iBa?r;3X8<HtQdZM=phV3|#A91l1P$5#f>uUZ@Z~}VJVwo|HY3QlJ!(LI&QtM~ z3F~Tls<<2D*(-fQ3ZlG5W^s8je&5MHR!)|xS&E%-Y&=e(#3p*DtoDf|Bpt)a{N{(* z<P>Hlv@fHQwT<sg0TB?IPh<`;P9C#DzzQI{yM51QtPlIW6uCW5-~~Mu4WoN?&aG<4 zB%CZs-hY$XyK7w&y3i_`@W*WUt=)~%)}tVqUA}^zv_*mm$$-ORhk=SI(NAHZ1QRT( zEAEUZOW{K;XO3n;^Y3d`sJYDD=Go1LYa5GfANiP%Gc$hd9!tt>@+c)cvde`|R_?qb zcL&)}yg3irottzN{eRdE$BYEJ5Vi^NyIIs|d9rP{Wy_v${h*EQ=a5NfT{!&j<9L|G zCq^~xPo2++g(*a*P>nD6&b@nbj7#__COO#V!n2s}rG=(P+kwuAgBzJ&_C0I?L6&nZ zv#?pN;G>0+j?{=<aIEk*xrU-Yy|S_NQP69VlQ~0k@EL}J?)JTF{=$zhFo&oO*!YJ{ z)dkYaEVt*Vl^sS}!A|yGlaI!+BZ@mn$qiZkcPZAQ*~e2z#}E#Qx<jXWNLye%X@Qab z()ZMt)VveZG6LyN0OjTb-s9cx1LUJ9E5+b9Y(aY%NrH2k=3vh2cjWpfGuyp!eQMIz z`+f*0nsZ3ozqg_yoqJXkLvu>&w@aV{K`jE(rCD4W8S5@fCrD(E{#sO$WK7Ut2Xw7O zQHXh_rB(hQPb_7Tvs$&~APe8EbT}x>(r}<0uqdn~q*MpXVS|1H5!;VUx)}+LW@W9d z&C|H~(6;65Yk!N%VZ8T09NQ2EGDBn705~^C?V%mlj-2X0CRWQmaR9&TUGl@(PN)cs z-6AF*{x#UaZNo;v-1Z|#e>j<LqGL|}eo_uV3`77|WHGI@;YPwEgOGB6{RXG8@T(^Q zF!*q1x}!}$nc-yLVZ7jkRc$gk67IO<$lM2!cpMu-kS1p96Eya5R)9st#cgQMLzUf- zaSdV<o`atO&n6fJJ7%hP>j<fQ8fu?i+-j<?bR0q<AzO^*KWX%AiF)<JHkgT)o{C!h zu7rG6!>^^xFq4+;ovuC%Hl=4JYXe9nHVZrE9A_ytOY!>IP>k!{>|5oJrwJbi75!qX zafgPA>&(ccE60N=^Ity0i6%$31?S0!4Z+9f5427iY<q*UH!Y}P`f|K}hwH-7j(u0k zmi}>b(`Gvh_e$11)~sFG`tRV@k4m8#Xt{fFq4?Gw=WHd@{qSumJZpY;=@O*=2s~+z z1`|=C6o+v{)Fs`&4H%7OUtf_bQJGcAj}TSJ`ZC=KVz}+L1Ky=7)`<qYPyx#xq$yUh zggURX>4`5*$v86>=YS%|3wj=lhh~*oa7`e%(8W2Z;ntFee(KZ3?DTd%f6mo;X3A7f zKBMTKf7OM?dv<M;cxf=;ZPP4feB>mY?so}Z@R|+c+(K`*yqnWRyxjAK{?v!ZZ08v0 zMm&3t5*?S{sJnwBSA#H5V>%mTU26qhGaEGX2hx}1QV!f9eOFCSO78OtGb1tkFlfL1 z&aF_EZ4Zs!Y>wZcf1siqhdE7M3Gy;)FM|qN!tNl^U+g`rDpuw-JQdYo4!SR=U^yb` z&n@5XCfPIfYuO(ZfGKzyphtm}XMB=M`WcQ0`1ilRHu>r&VRI$^R#8PF9+XorbyH0O z>n0N?>$E1RUJ$>;27v(DS7cUX`V`u?3-2)aC9R1Icx{H5c`N8!$5!A>cY=aF%C+0g z<>>yZbzB+qJ9Dy9<uKUk8M|G(!T<T^OcU(>5r<rp`Gs&5q-{RgKFBbo$Md*cYl4mp z2!Z3fmnnTgJl<d=X}fZ3-%{<mqSk_L%n9T8#2@Iov*Vjz6;LlLth}bRSQPzh*3Ps% zEo;z)`^p(yS1|D0S`?no&s%Yv|31A9xdmY<&VoF08ptjRTOp3s1{>NOj1^%|VypA} z6W*KJENmVxOAF64(xu3~s>P>!Ie6^LI$Edv17PyrHwckN9!tTj%L3H-47^Nv4d6%H z-3<=nH<{;pZOC}g>eZT-C->Xy3WGEx7ao?VhYmZAdW&XQ{J+2I%3ln_c~q&{!bGBu z2Q}vB&c&smPmV%~6d`T-r#qp`qmCzH!RE&+3ZXn=2S0{K8kV%E(|6g+cWVF*JIik= z(w><4<xwR7Gi-0K3>h}FpGN0EaLy1EfUPw{u?O47u%<`+guu5}C9Fa8fz-Zv^8zb= z!tq3FuRei#A%I}ZA;565evZ1<EZaz)Xa8`N74R-&ox0m2rg#uXAu%5otx8v`9v|S3 zDEREaY<W_evl~H~+7S>cC`RqssNAKTB$VJYxKGx%{d!+cx}tMtLl0{>UOoBS6U(&v zB=v=?QKO&q8A~U6qB!2Wp~+NK8(mTH6lo7}_6+%`X#oZt*acUQV`oWK0F8PR^BrUR zct~2R_+JJoQBJO!zZRND=xY2?OPNO6{H9Is-ymP?e{G|^&4w%c;jXug`+f-JK)5Us zmuSl`K=yc%dD2*p`pDqSF0?72pL~vfT)SqSe+iLZ8Jg|f6L12p$p}=<o_awfLP<xP z^X)02TF2BRjc$+d79GWnETxn-x?|2DPa0=aW8wia2&^Tvd4~4ln@3j@Z(K-Adi<2d z!r{eF5BG2nDi}<^^-NknWMbc)WCDj3-V@^1I<UBTo>oo$?B_qim@H|zKHX4G?XgO_ zyViVy!p*E?cnK%jX-TTJ$YoUR+5{m`yHpcC%;K>d*(=3r1MAt#&Oo1hPDpH=G`8SR zZD&4teEjTq4vNMPCT@xyr(GQgecwM~Um{l{qo-JA-$lal?4IDaDYo>332infcgG=a z)<A5=;Bwf@-_OwAJ9GBpqcb!&Uj6@;VSva-q@ydo&`gwkME&6_McT34wAkQD&s#4O zzuu*j67Y2rreD&r?-7e?7{0_ZW;<dDt$n`9CP)kKpa8F&jQnB|alI=TE>-|Za6lcP ze~}=^R*pPGl7saX1pnHj{N=@~y@~Xt2}N>C72WCO)b`!^>8?<-wXwxHD3;lV=fR#@ zM$GFpk^l2@|Fc~GBJg6owv{Vr4b`m=E&D~iO%zPyOl(ey``WZq#^hf0>CYx!%y`I` zR?Vg@SF8NuT6STg0_|iW1T#-C3L;japcCC$^1U0FVs$?8x@uEP^KzWSThWa05O!F} z-eOOiyVUu=wgPg5byoHfqd|iojp>^8Y+68|wZ@%WRI*bXTi{5GL`<l+G>41C<Nt7$ z|GiY_8e&m)nUOA`L0C+ssw-#cN`UJ}@#-K=SkCT<s1^Pd77ZO|tk878wZwF&22AZE z(l51YD(kgX^ft9u8)P@!^?a8qU}72_{zpzPYF?D_uctRXqS<CS=<N|8^DJ8XRs@sy z<JS<o@rlP9-qb$4hp`O%?0G%qhkvW<zm_?-eo9_5_Q5IN_YorrWO~1`SbptPvM=C@ zi-GJ!#=U!!qNaiSC`d=7T`Q2DECiEyPxx8J_IsG9rOXgdrrOk;8?cb}1YmO#_qNLj z_wN_}da(Od8q|BazL%kXH8!j~tTO-j3OD>kX_wzhlsx4sc=yolz0MN|;Vsxi7{I9C z$6mjddZAdb%6VRo+V2v8$j$5+)<a#(4**#$!Mik!#5oqe*oNHT6uI_RpZ2NBKPlnA zmUk9um-#D99IT9O5_!QurF3)7`!R6;3Cf(@+`XT`=VrC5`RCva@gFR5uIs7UGMa(I zBjjuDS*kLAdpTbvtDd80pZ>Br*Gao`9c#*G3L1X*Z#(|Eyzg-dqjC|D_4QhhTbDrB zb?Zb;m31jJW+FfD-K)FYm1_BScJG^t2`c(kYt^G`MFeZ6P1vOe<BuZVhe4<2e`>w* z>HXu2D~;s&Q;7KLYgE{y0);o4D9sDk#3etD@UHMbmiC<}jyqoDm=W1Mvha@VpDoz| z3C}-=1Be?L3sc7lHn!pL>8c}>1^vzF)kZ&B4R*o)dNXwQA1}U~PD0qFpErk!a?fSt zFawiZjfJJ^C6jm;16!HCcyOR$WmSQ1##Lm?77D91B3czSF86uyKc9f+H@PzUa*m6s zt6!bR5`SR&3LYIOUp}KobN3Wto}uj&IEz(E{7qI_8e1S9W{TMNAo%MemA(jn6Iv~9 z)|E67uT{{9)DQG%yb7m$Y<#2g!N(RpBI*|zo%ex_i4zCkhMSmP5b+AKWtR*n{c>kC z70S4*5_T$iV}EJ%c8v2ymRbx*xDkf#xv(Wf$YjkD8VQt0e47Z+Y$y85XxwtQZ=Z_t z^%deHeEUvQru)35!lNVylI5y{w-Q$eNv%k7T-fE5sdD`M&)fZ%^@h@V)4jN*t@1(& zBKf{hlMm(Fpw6I$)(|@y)Ywk`GBS*YJe&f=n2-ehu(wE(*=lvUrPJ%WJdOnJ;@^?Z z7X`?<mc2>%bkfEYqjdV|4w)~^o3=VKuOdiVK}~ygx{g2g-J^z<tn_v(0%_%S1-Uj_ zSKNFH8yle7;tu$vMzH$=c`c~%W5FKC0mGH;r(~_v&i-6n=S&May7*71{=c@Q4{InY z;P3y12io*u)xpuclkfa3x5Wv(ot-X`db7pOqN7F@FU!4Gr>=?P-Z%>jIv-frSu=rZ zHiKmzkF|Z?w-PLw!AcW39Sfl8S#qb)=b5mV8eijH=}i<(>y}HsL?zE`z_CUp%7wc6 zslkZM!$ho_sSnU{3Sios9@3;`vOCPYnLpj>D&Jvpe#W6z>UPz;#PKEs74x|cV*_fu zMs0xfPXw9^W_4uzb}E@|cxjiv(6}QE^mJ2o-HPyKaZd3@!UVAup<?Qr3^(Nx>d&m1 z)pU><u^9aHKz?W7xmUEmzI$J{xyWxx<!S`()ks&v$X-!<c9&(xIo~`ML%WsmJeMMI z>fSx+e-r+%<y`tJ&a>9P<qJhLWGuV6Cg@mmOZ@>{DqMPwu-*_qJKi8@VyS2XeHkX> zZjSXi5s~lupqARxRhmg>C-1ho=?gTAo`jMzzaaD`cFJaoWejioooZjP>ol1>w#Q&) zSK-!&_-*r*#^Cfk5PMbff#Zb*GB<MD%iW*%rnG};jL<Jqc0#qW_nb8N=qBg>lv(iG zhk0wp=+TMGn-T9~YC7DUO9Ry3jJ`dM2bY^O46%O|`r0s3Vpw>&a_OQ=h!}FbnjrZU zt2RAfz%TX`{`=h)$EJqdbt|yIRr6fkWZvVz{g1e9dsgj^1m5f>3F*nHytoGc-<!Cv zynpEzx##xoW3z(xSRvQHo7>ro(fTyocH`!$+tW=G0~1B~{PUKAZ?Kr{M$)>^5;i!v z5xF~(I@6a0zZ@jkQWNAbZGJS8>ucv-t?<x~r+2wYo^!|1MR>Ibx%|UpiAj%<LHBf8 zPI@%`aisbj-nVzTG58lwTUWbEvqlL#2z%(~-c?TCzh-Sr%0J3)t_d7Gx_IsE_<ol1 zwVM{IN$)Otc}h<L;xtCR+yvlWGpYB+M*|`1wi&pjMV7opevi|+wqO{Pu3X{Om16#Z z<lf@i5Z1C9D~NIY!>B*FF2YNfB}z&fi}3wGZLnQsP@zNyC9mGSKa#j@&}Tcp{+W`$ zBe}|=737hIveK7f6NL2pNvEh(pTfO=<x7PZt1o@!Pi8V@vYY-?Tsm3xZJB%(NLY2B z1>XvPt*e%c{)VW}U*(#2dTNG92F4UjKpDT3U*AuiF%%}N)@+++$TE4sb2{?5nk_4A zgdD*t@78lq7aWf-Vnzq7to=<itmja^R{YhSpM()^-O4W%GQ6EVCDORT#}-zpsMy|` zEbX@zgTw|%q&MfTs7K5A*r8C1V(P)$9H2asl_DQ7WEH{!>zhTzxIW_Z*~$NhT>gKh z%d_`}SQ-OJFRkp2hpUT7rJ4B!7(HCDJ+EBur(AS?BcI^g@sAJMpZ9^^j~+ksF+$<b zyF9S;&+1Bd+LiLR^h_QDB!8W-kXMw7YP@a^llxs(tA6L>AFGNM4R3^{PKU1ApExYs z)Woi(VX=k`UMdmW1=X;cdf469<4%g7OY%1)Z`61%cu$D09=rtDh!LpZKNhl-n=&tK zzA}C)|9r;Uy(Z&pzb{|>_yt47k`m?eZNykmnBeK4^(yU%;6RdqxB^ZK<THE&WS`>k zTcd~H56P&4fIiRVyx$m1cv6T}HP$zs<l-!uQb4Ktw+FuuIQ3AgV@-afEc#?Oy{#Lw zX48{-?WdvV>}7B|gL`rjqx(UM9aD`NQfc-CHeQyh!ML>z-ZuAy$JO-C<tA!yu@yY` z(_{7VnX<18AN<T;n<tZ)1(s3pv51mV*^+9!;O~+<YIC*gqe(%1@P4(8biQRg(k|!H zDRzJKO#aq7`&a%Z6S1HV%1_WVrGf=z^~<T$2|Y_f$I5^&NE~+ostEu&wK)w7iuTpa zAmK7)F8rn>bN973Xy)RD-zJbn#qOc~a!yq;U#t~%D*cNoOlhYCH!#goQWO8X1>rZg zDOy*~OI;~ho@*#-m^8R5V98M-6xEW`Y&-U)KW}Nx_rVg*Zq>x72oB*|3oHc;9Y^&5 zx*2kX(h~2nQ7Pqe6aG@w<G8AemrrGA8=9Xy_6v%>@+UOhPsa}5(ABPxyj1H^3%9A) z()Wlh<7m{FV0RZnP|dAZX@R>n-IB-yV^C2<2~`APz3uJmP0{sG%p%UMCeaBQM|8Ow zyMEoha4=%Azlx35x_3&9jeayOIjQV`>Tp)TxDNwCaD()Ysfdz&3$w@vC70_gsQ#%C zD?suC{Um@JI@UO74;9>pBx>vF4$gjt1oRfXKkR7@xrSviyuNliRFyj$dL9Wb{`_H? zApqpb)ndXq(&_HJ)?MM&dI#0sB0ToHq0OcjJl1$-1g>huDM<(TC8L$?vs^8`c--dx z?;taAzvYD>=*8L^*NMZQr%Og#e^IH(hScKXLX-+`j7B63_slvKRiUhke%$iFbn^MG z?3Iol3wF&|re*SX^vku+kSfdf5g2Vyfy(E^j?QUmwq}N5M~*%R(I3C~q@LL0G7Fc} zk+^JHt21TG`EQ>TU#nscffT?FDhBdY5}dTDQXNd+Di$l<eGk2QEt<n^S65?pPuyPd zM@B%^7RcgGk(yB*CUL2v(OE)P&2z%8ocg|}JYvqXgfrk<E*FtI7iW+d(ewtrVuZX) zjj~S6nX22Jm{MwE5XdZYLlqdqoDzd|*fdr4=~tZ^xs^~xHNVg}!IRLDYj?m9zm&SP z{Ct$7aFg!@Gk5(|j(o`Q;_SmqRXIvJRd%r<b&QG9zlh9JW4U-S-tpp4!N&Z;ZkFF6 zOYqJd&X>Lz?;ot97R+<978~6=P(SEW3T{cmpo<rCIw{4&25zWoD5`K(?!VgBQDqMZ z-s~>K#AT3Vin$?facoE@?FY%pH+%rKU9LRuyIgrmH-Mp>1_j+&CiZ@fmmfDiRGF|l zUB=s~6h>kHx-Y_?*2x%W(p#YU;u@Dvu5DxJR>IG8=*JqjK8otVHEP<HyPYQ+13Rop zZ+I!|fu-T#-CaukgdQwbRVMoKsraxzzd_Tvy8RoUqtqexIH0wZ?~p~StViaJw>c&$ z+mYZZH<auw;(FtGGXkVRTbkN_bAX>Fyu;4$<G}(OPES-O=k8R#uW(0`6XqteRP%HM zao`fBgvRA!9#^Nj^>)P~KoxVizLt{76Mjw2YW{s)aU8Xy4u#lT>UT2MU<e@TPn^$? zCvl|E&2P9A1m^0SC8n}9e-sZqrQXEOD$vMke=<j0dt80nv(0cV7gbTNu5jydyD90p zc7jJxEL4Z5i6QypAF4m%4}2!4?Ib%GhXcZ1Zh09W1A>dAa<84r7Bg=BEIpX9unsZ) z4eLAM1HQF1CgB>r@S^J(q)LMw!m3ll+h#%nng9fmRH6tfnNta}6H#@ObEh}RX(M6g zE}NlOWq?&9e2-;J=G~v#`^u#G%;mimYzIHTSTg(JMCUU&NM>i6{NbFF`<qZfI?fN; z11&nTda$^R`$%v||Da?Gti3S#j{~uUL0D*H6Lq?)cj{?Ai_}FPT38qDg=~Mb<P56m zNbNj_s}w71M#zX>V_$5jU(HpF9Pv2&M0F<syTQ8U`1hhdy7BX>LiG(}><3j`bq;R+ z%!<aP)}PWoU=QnByh(_AKP6xOtvV~0qD9OdmX(m^@iN;!yATF%-QOd&C%VmqwZ-%F zpZtOK2b&%&=>BOd<sCQgSn%UBPaLT;(ajD>^GxF0?p9CV1>i_)f(m^P{lGz`H>dZ+ zPnz`yF)1Z?tEASy@6I<N-TA^#SZLN$KixTOzEyWZm=R`xt5kNq_e`>whBXL=x^2`P zpK<uM&f|BYymqiGFi+>Fc&~BQ>mJQIdAp=@{_oIJi8fMye~#yP@1n#`kU1eTrYn_| z0*E!aZYdQvUdmZBB2bwuqpcm=^H|&&6W_KRp;<<%GDB8}J4-c0d)AJ;{!=EtTR%S> z4b&O51gutXbI$lKW_i_nbNH3^*B#M8S4PrTz31Wcx#wyUW<$A|ux5bWnLX?J{hd6C zCTt6IN>HQko8U$$gO`gY!4sKsQg<Y3F8ff$Hx%0gJyfik@Jh9OnqIln!a6T!IwKm_ z%Qk*8mPqVApQxTOb)PrxXcbyN|1QXJ`%M64MDPe^p&I}D1zMmAO<!mbaus^W>iDz8 z_NQ&s^CDDlHfVLRIRE$z2ri+L&lV7Q*i~?%mQSuWhz;630JaG{*Zf=DSa|YCsZqa6 zB!yFf|2al6N=NPmNU2lT2r%g=_8x()$PhR<aE9-M<?l?JCgQh10}?9VK+y#rOfS83 z=8G{4OyWDAT`jy`zNoIQe5(IJ6lxyL2%p5yD*QjLbYJM~WadHM1LE>vhG60%S)kEp zMr<)-Q`h`(x`cQXr2B;Hb!$AbWz&ILU@6eeaez)-nDru-ULo+M*udV2EThfg;Q4*} z<GiVSnVpO})t2@8!Ct=;Vi4u6H2Hqy#i<WnNLdxVz+JwPiCu&7yq6Wh$NgeGoVG90 zg0~`A%xO739*FrjHm&g}CA$VS>nxP+r)O+FYwg}**9f^9ePhh(;?*U3PSg({?q*P) zRJn=6C!|^WiPeal?!NDow&>osMaR0~4@$>FX(QNC(B9BLz#-EwfSR~&s;69tRjZ&E zh>8VPg7#{RTv0jMC3(%xoX<_J2kz)gCe|LrM4)bZ6>)5`QRR(1%ZSBs<D|=J(uU#B zGG|Uou6I-w?f!Q8#k{ospZQ=I0RBiNdD=hTYR`em`<nXh4s>1<`H{U8(b`cpNwDH) zKIyQLaNV<!S&{1MAxbNVkSD>+8>S>*h;Vr8whDBu(MdZ50&?nqXrs6xu-NU#lr0*? zM9kQa+xynqqS|s~8sz{*=)(dQE>ZU5LbW^;c0>Zy!gURkalMxF*@JaPPEF*?R9uj6 z;(LT*{bp(6{QPb<z_VrTwOxbPW)YZp5=;@O{2nb#{Ne}rcnNJx84Xo<JhO$6pa)!Z zkEMOLMFt_96XYipEc5k##$SpG6{++<oLGUf<*jjOf@upSo4Kbqsbrqmh)!{}gjC5W zUI70s?E`{nGL3Iy&f^R~!dFCT$07l~<n$hBJF#Wr{oGZAZD!k{MpfE$WV4rlwH-K0 zo{79!XYZCIlX%Fg$ZuqsYs|z6Q{;%OSp0F}PqgpjFW+j+PN^zGu#L-84aR?%F}~8x zK<Fl)KOl1_u5ykHm`iv%g<maY7db(DEN=|rgVkq3h9%NuoGVL%z3U|%(pT%sD9DBd zGym_}4wd@D!a;{WEFE_TvxTJ<9{z?LtIrHMnH8Sb5Uxp@bDj}XIz09aF0aSJD!1+N zeb=;4p6*x-@vW>is;}Ld(l}oFcz*VlS4i=y?~r`jt20yA6K9+>o^>Bv^r!L=TE4Hq z?)FaV2Q=%{?V20`>hzYfPbBKU!<qX)`U-%83~1z*Sc`p?rP7tZKR-{JjulpGD=A~6 zD0aL%t5b6(IjOnH^%1#;k95yBUTV^=3b82C)TfU1fb`k>RHLhw?T_39kF<~tPMRyO zwna!$y1lxZ#I+LGgy;h!=TCoz)o0o~LtJ#nlk^&)bmdtF2Re=~Hr`S;qAtt>Y)^`U z=ZA_a*9NMH^Z0COC$nb1{H<PDa|MH&@4Zw@Jl}5hwL#GV+40#%zI6H)5A_@1J*_h3 z>KA15e_rp6bWvD{zN-9e^WObJB^T7Y@I$&!1z9i)(Yif}fJs3l=xm)z%Ra)haWAMl zOf0c^Q746LTjjrLCRy_Lxx}@wf#ovWgD2Cp!#6^;UrM5s3sD7LN(dEiT@B5YSuhJc zI5C@Az}^7l0QNDHil^WHl)p2FV{bO%(T?+1EP*6Q=qo;&SiSw%6a634zDp5{CtAz( z_3dUXXi#?tY<V~NV-M+S_+p%>$QOiJII$KX13kn|ub`)!kGRt;Pm<UI7V;=z%>wxw z3$IE!Rucrx*GV%@(&J7)<)D+E_#WZS#t8U+3kLdbd&KV5SEt8cXU<LqZ=IFdsI#9x zu`c}`8Tr-rXouJW1d}B~1p<i2L48BkwUJcAzt3*unQ0)C`K2JOx;(SH*$NF2Zi*ew z`@jU*=a+3Cz+ZvQ`<Z+PJ$Kk{pbG)q^h<iyF}-1L5zEg=+>Mv}K2sVLrtN0#8!u|s zbhB~%mA2KW(p)o#;Q`RO80lm@S}DbGMg3S<Ru-N`6-!ZYQ%b5DY*vT)oLEDT&M)>r z_C>$fj9BrQ9?uc_#!aWVYi+!;GG6XWJCeA_AMhTw<FoK{4ZgB!$FqgT&>7c)zD4AI z+SJCJFmW?9Ai9Y%D3;R2+EWy?m`KE=DDp2JVd;oqJV8j>Ixs)u_}J3n`#7K;;_7{G zy^;4B`3whaPjTF-;~Yh!AVY*9u)&%ZxZ$@Dy#(zQM<)NUJv6XTIVW^x)2o+E0k>KG zO_1~#zwt8~|Gl#-DksE)!#*E1;XjP5F$&(cl69HG>A~{+&Rns^AAL*RG+C6csGHC) z(=-rmOK^a|1j#PqH`8#ooy*tRY`w9{tbaz_WX)$Ai!;KWo<Uo0DaWiW0tIM~2eA`N zsa{_W51h$Kqe@$g6uL#ALvK^c6Aj|YO%BX2NNFwQG7bI?pez|PIL-*4m<*g?dMZi# z`^YC<Y%)JeqjJePC)xwSWL9EgjArHNkAhwe#eIu$p~J?7KDm~?^8w4`<J#cW!4^Q< zgWY6%dh2`Ewb2c#zXG89MM*aw*Q@keZK}_vQOCbdiZ|ut`(0ZCtNuvNCvv^6#Sz${ zE{I0%l{6fA_sZWegRgsB1_xiY7Y=3;itjXj-g(E-ceL%q?as!jFj9L1s=;sCmCSL; zZDH9!@zeNd`!EJ4p6!(Ud0IfA>~cNVg~`Y-5P)2Oq@73s>3){q*A@yrq2-$)=zpHi zFYuyc$@4>zFlTaeZ6+7{{uS?S$bx2<@0H-0g*k1bJ2tDWpM1M2iIr{>zLbWlmgXLO zJMG`+J(}MuJwsJ?roi#pZ>&bqe7@Y2cgP0$Chzy&CU5aKo>k>rT&(o1g!<suT;f`} ze$+0r&VnbZEZN1M`?hu99QlIX0X)0Z&WS|lh#nGd$A%I;byMSi7zU6pj7MqRynZ1k zl#8%OoRvqbSP-Uwj?FeH2;V7lo1;GlQR7R0Pe=UuX)+fKE|!c>?&rME3m7Z8p@;Ts zx8yMPG072#(J6x4ZE?)WX6*dT@8^<S%rZ5$jMV?pBhVr6cpT$FDv@PdYIAO$U=I#k zx%T{j9t%(SI*+JHN>uDCo6+q_o%);2#}Y1KR4&9!JbN?b2C15iwG_@Px9}R4w);kK z^IUn=MbzQ%=g;=mpDiyi3aaOPNLoc}azBNZymQcI;pB#vj%q-I;ktCeHSt$G`<~F9 ziox#j8q_+%IhMI0IOjGepN@}*7^mOCSPzn$(o%`JBlfJPF}ujdZ+sfLyB8PrF4j5v z`zKv0w(oF}?0sw-o@U=IVKnKeZgI*=M_3?yoz<-{GT&+U7Rpx$ZP$G$^n3=`YUk|9 zAql_Kg^MYP)~UCSDT{{pvw3y0tss@pT^0jtz@mPeLucU}5muNylQ@=dPfo`vgKu3# zV>^bG9Z>4SJ(S|*T&|>d57|6W?&W@GEl2m0)+O{T^J~?!c0$@Oed-9fULvI}rBC^7 z4#8R9ga~7TM@mU5*4%Igr-{n}HQ-!wpntrM@!vE^gLb*By!e8wvH*bN^FpNiux=!H z>~e+F`$Ddk^q<Qrfmh&;Pi!W-eL17pOu8HgEZk2#F4h2VlWu3z@HmU>18;|bc}=qk zP$qtqMw5Q`wNq*GA-}=unKDHc!K`GHQ3K1oWQ*&Czb|ta%cX)E3*GEtOK2-#-H)0V zrR@j7OpbYcJ`A4Cc?zJ?%@1!U*6gzjy?0-d(_be`;H<D_`A@D-ovs{fPqTEbt~fgV z;qo^mP)7_A`4#8ajJ<1NM~5I^2dZGRywd8+g9N7CIfS2@`f)TyfM3gGn<ndvO@cDe z9d-2<6;?ILcJk3CaleUsy4ny7V~0=Gdbkg}cw6oj#1HAYfhaEIFJ309$hy-&jLQK= zQ!mQLR>|BiKXVJ*lpe<j)aSkHY=9HX6TsTU$TI2DL@g8;EVv)9aV@_1PHhFZP2T*} z#@L;ROQ)<r|H_2(qth>>znPAFnEn=%UYyYAYV%*S0P=jTDx+!_(u}dZcTBSyxN`$V zL8kVWWpPvyj_=m&o)$JobIPUl;ZbrQ>lKX0eL}r1ok-X&88wBQ>0<2*LKJO3HD57% z5SLog|LDr;Jeb>negm5f`BJt$y>Ph%bp)wDHX4q-!~9I){!*bitKLR(7h6=uO=8hh zS3B{>Gf0DkK|9j|Rp|M!H-YUJ(4=sq_(rN_YGW8zwr-;QX~-{LpQ`!uh3mu2+0wW< zxj<4yWpBD~@4{j~kes%j-hp37+i031_B&tUL@~=|5$!pV<;KrVCTkutds=JOOn<At z9g{KE|CzENj`VIR^m2Hr7Fif|_LO%s1j8D@B@KHIuZ`0_1xwrCQ!>Lno8%Zp*<351 zn8ZFsS&BwQP2A<;fTMr6n`*{sCj<wJTxnujq`G&{qH1QT)io{FFIT;Wk<oc|w_PEp ztNt^e3)2gVxbfKf3PPwzF_q&%e_5GZfurTSO*t5(zidp+9U@#ID7`(Rut2GhP^*tv zb%%*EmFTyta#%WN$?7aSpuMe7(wk2zl1CoYGf6-lU-6%=zoqlZL)PUYN;Elry_o(s z4PvFq<9^OKSo0k4JTQ_jzwW+c66$Bo5@OkNSVknOHt%z)oJNomvd<ZzLlR9cOc-sH z35e*bhfg&pCK}OEf{jjh$~<8W!WCR)>HK$p|M?_D@?cEmT@-#;{3J4tYA${j7;At1 z#4RGKvB!9GIa}Vv_=j^nYQC4W!2GTJ+MXF-4O-^yVsN|^K3?*`;B=^oqz$HfVQ92{ zQ^yFcKT8AlfUDpA<}TQl|Cj-Scyne&&O`Xia<{x-afW~u2&V8&=IZ$H0Z>guWYE#W zH)%!4T3(GWe>sQCMyT!iDX$ilUBV>3nk*}ez5U!Cv&z*p0csp7R%Zsa^~lMl9@rRn zseiBJvQ{-OhE&D=w5+}1?c-sq;=AcwwAY9v4%w0B;rJDkDz$g+pH7EadY8P@&)l8; zxsTE;W~BGIpZ(hp&%171z01!U^(`;ZOZ8xb4R?6^^QEsGyx{6#q9%^pivW2ogE%Xg z5v!?7@pc~lqtSb-DU^JXc<#pkIoB{<jb|=tRww9{`JS1ck)+V*itLC$zreR_&18`! z|CR^z3cPsRM)m8mPJU@d^XQ(=yFo3R3ZSWoMR!!XA-p_h74|)>a%FXG>wz^P1iFn9 zCcc{6O-UQv{i7?erlPacB6QA`N-iPC*CQ2GYu1dq#3|J_Lk}b!JJ^}~)cice1de|^ zcP*>HG1?D454lNcTE4m2RPKxx9=k20p*R&t2)gF#?G89#^GR)T_;P$SIYdZ|59s{q zd7H_8-udExI<+PPnw^T|E5-bs4fiejz7<Y_<aqHnjCeZTu23G5b8Dm^wdL<ixO&y| zSCdO_WMfMbrYL-mO<A+-k7SCehH|%5_2As^2XU3d5k)v4^Z#6MJ1o11DIjraaPHEm z4id1+w%_G>vc3GVp2RM^t)P;^yqU}kR>rU(zj#wlLc;zgW2o)-eW3c@mB0&(D&&A? z4Xd?Bb5MNF>&oq^wU~-r-Q>CR3M&^(P=e42Bc9gX3!Fz4Rxjs}jsxI)k7s;?=%ymv z(UeJ;^nc9x?uQMG&8;Yd6$k3AJpiwDMXsfxCPWns`$8%!)8BkIj6hs2<7zjV<MEWz zh}3-0<zL}(1^1cP)>PHT&od<(0GtJg5Ow`l{#VjYj(J6rY~H_=)_7zQ@N+||($}YT zYi&bF#%<R%z<Iq~K7_14ze6ZZ__6TeDzKoBL*r*zr{H$=yi>Lab=-&YJ@K4`<b7U- z1y1g8ax-cx+W(UiK?QmM@aqNX#(=9GD8H-Be}6mL9xD7Im+Zy}@jT9xA7A}oq2jRo zO@%l#?ewGov7Ij97!Jw$7?k2EAQno@k^qR=t44mAl<{d{qZGsHDGhSOC5D~Ew3s}o z%4(;3*~cIcs#tw1Qbl$<<>tx*rrtlq;9`j@gX{gtA@+)XUP)6yeE`aehG}oYibdsa zAANGBZVF_ludQ`2KGb?2x7F7^y|q#q4zqqIH26%(5D462s~Osn*c!8@bgwoOQ>Qr- zI1k;6wme&_bgJ1_NDtRiI+W_v0&N1SSI4Mq_<|+i-Zsa|0mSG!eTuD^wX+x6lPI9H zpC>=O`Z2JCf7DM-=eo^(<5pAYbt!nY)9o4_sK?I(^iT}ShLtnNdoW9E@+yI^gq4T( zdxhBwK4fpHk+=XS$79(QMz9Lj3y?--j-QH#v1um`J$8F($1|}N_uu`;n9k4rDSLZ7 z)|}BL<Vx8<!dnm$QNp=C=KS<&DMZwy*!MwfU`D0f5?z3-S^wvX6{3MsE%A~_O8CAG z(1gS%uvwc-mc+#p<C+ruBnsB&Z6WaN1CvpHy8r1&e&1Do=D%$(Q9U<IDGq5c3JKKl zXr|}|Q24@ofcXP8Mq!ydhBC{kMWQ&M>2ciU@IHr`r(PYBy`9Tlc`w(8q5Ws?PA(_X zc{FKx1noVPv4i*KNSbzMN>A}Mhc~NVPtCXVv^=7GM=O2I9>g54-n>=5X3#wMuF;Y5 zysL-nflq0@#ai>REOldRj#zHq(3GU@h;2b8&+TLn?SL#CYqrz31?BoY6ij;(um|1! zGf@AZ@h8cI{=j-Ruf5wvEBY=gS;1EC4#QCu+2a!Kn8h;vq_^Sh{9xSj%^_qY&!=tk z$rjPLK8R`Ydi^?4q9B;o6S6L&zW2T~F`OJ|Q8Vo<oOa*-%c}f~D*1BXmQ_V63+#SK z*-A;=#&#BvQeRB)%<=k-L#0(3w$aw;F#EZyXT@oJSG`r9GRY`0mM+BL*k)TbJZ9qM zv3>xFh3SJ`Ph^eomJTd=!yi%f(}1|GfuxY^K99{GUBn%Da(9Ml<~@xGF>^_io)Br6 z?Yo6CrH)NY{C+_Be+>LFYL5tK-T9{NO(7E~c)Rh*D%yibG4AfLwf>=xf_bK)6Pz2> z3lp50xXf+qE4&YM;_E~}B#^sOX_qj-_lsyf%>$HmSI=ZgaNpWn!3E)~lK;!Vc!#V4 zQmjI$DoO0M>=GeyJj8V>cjl;XLZ%aMg|=)#?`j#0#bu!b)8O#?nq8B*-%L#)e@`^Y z=?VT(_SF@7dHyqgE~|%WGBr41InfDC7<E&?p^*EGbXJQ7M@GYwSg8%X7Uaun`L0#{ zfvJAa`YJ>SY*;~B3UXYk4k4N`gd#8n-J%ERBwNB~?rmXj#3*yOhgVkf9z4OjH&+u7 z;E<_kq;{rE|7X%?+i9`5)jh*;53K^7A(YPgEAcFuld0N@Y&k^L(af<=8h2F#Zt1%F zb`SU>`I?f3e{KWH_x%*gH;c_pOv&V_-{M<t{B*09ueGG^`SnE`V0BApq<G5=oqXHw z<efg3pSztZqdSTAx`!yk?B6EWB*amU(Ma>1JBYiR2ao|P^!_S-a>q|6bc~z|w7o88 z$Gn6PV}~q1g|z7t1me&(ya!#^4`Pcd=R~U<Hooq!kq$Kuo2?1#SN<d9&(l&0fE&~# z*zc)I-C9Z0iO~(8lTu&Zl?$DIup6>i&LXL1nY^ygP?`el-!LzbnU`F%tN~Q~0_aO4 z;zQ#L=Z5uA2yFXYd3sbcIF;tVH-MSat{&wg*+}ePRfIdOl)>m`=p5<V_(^Jx<H}lc zX~;U0xqS8Z1^eaZz|zeI7-K}@N4MCRW5&wm4P$7Z?rvvX@P6CSD@i%$+M{5H7PJpI z7Z_rw2%8WQlGrW&In`?7w`hWyl-v>_w~f@AI2h_T_K%AnoC(<e5;PwQ3ye9m>M9U> zXmEWZB-vZB%eh9aX=o9aOfOM9`7Vp6k0O&VSVBHQNiwnVf!I}a`O%ZQfn|p%`J<87 z4m*Wu+1VTQ!OhuyS7V;GNOK?8!?M+<#t5FXG%xlPLCrr}?FVn0$4b-Tv><Ne&0F(* zBLDGz-dFPfN6A~p#nCU@!hw(g34ss@1P|`+o)CgN!8JGxGdP12LI@54g1ZgwFfa`6 zFi3D2ENEbGci!jO=l<S(&%Jw}%l_8=sjI82R;_<ktq%Uu^0=W{x3!kujSs{4*ie;o zXc$zVde&Ls<>MMNPPV&`f$NW;%0IvhoDy!H?&dJ9L4CQ@IhK}Omlr3i*!WdGft2*; zBlss}uy@D!t|P$`NpTi4yKv?b8TK8yOINeEhg=p(^<}m2=$N`wS#aD=;xdAO_*HSe zyVIZxE!@Usq6|t2Q(<*pS^E=G7=RP@#OzR)JXSyK3ep3%Ic48o)WTzz^_NI3y<4DU z`sbCjh4r`1c`$81m+{l1<FcqYU(5_7FY=Y~9~a5+-Z!0=C!0c!?&~|hdz@jLdj%F+ zn{G!7-7&??w<T9=I??-#vKCJou3Uf~;?rJ(74<FmXO{_4*qV8D)wkZX&f?Si;~`|% z*X&IK%HpJ`#=UBXvh8Vy@uO@1@j(^sf5liU53wySd3}HALR715XI0B;JE1HuWksWH zX8M$fNIC#M4J&ZR&Lnf0;nz-D-lfHZniR@Xj=F=r+ON5-RQF%25W#hN?bH4lq5?YT z6mbwmR4AjR(cSyPDtA~Z35O0+w@x~twC|~J{eG;87?Y-PwH9)?KPvgTWw4fHB0Mvy zEdfUiCQXTo&MY7B*$@S<kE~B4Y8+f5Z#G&J2TH}Ewg^3$hy_yPQv=v;qqoJ>d+*S6 zA4B#Js*-Q<$_9=nye*Ep8u?C=60E(f5LH!~NI%okt?LBj$=0@6uZ_bW;bQ7e)p>S2 z6-f;h;dN=@!>$IE1i>aNOwW~JOCB{;4E6`r{_Tj|sv~Mo$NUx@!2uWDC6`Mt*{d8% z^Ngru&KL^qKj$(&RQ%T#v%ZL~mdKu)l*nY4RlnBPBi!2NI8*7o;Fwv}8>u~$^i~4W zlJ)HC%-HOzBkrgFa#}=yPP>SfCOv*c`;I`Z&iWpvpR&}93fBn)HM=bhaJ)ROeB%-= zHVF;VH<7$QJUrm`Cgl$Iw5hroodAKnSQiffAa%ROC_4#2V&X>~*>R4wfic<_|J<mY zvG^M*rj4P};L#pJ{;h?r*Ul%3xsqN+nJvNO)w@GSoh6h%`{Nh~y5!TxMn^S;z)Dl* zY5Q>baxaY~RZ%V`0(TK<+{}{I?9&wMUYyzMKJoQ41HZRR0QapuQ*ZDAy701Pw^^9a z7`Nt`u(Kd+cVi#1K7?CT^i<gGH@@>9a`9gmdWEKwf1N-+Nuy@<-9=AyXMIu5L)?13 z-*7$u;`HmoRs|DeUUa7s&1(m<bLG*ugLiUd*DzF^C0tLnpM9xS0lIWACv4MMVBdQb z?)70rU8wI1+x28F&vicL2ADjN)(E-7EINNh;OTh4U%mO&4|WD$iVxLfK>RG*7|_;a z3A=RBThcYz-;VBH=NXvNJ^rf_<m9?1X5KLQI!qY2CAT0yS4aAhMPB+|;Rp*}+-jHG ztwKetfk|$g0?uu}k%(wN4;b5C%G-s7af{%x0`UqHznO+`2C{$IT(&~5!(*S<lZ;i& ze3T!3w^QzW%PFm|Xx__az?~XDUlvl`Z`_=!>dtvn0zCk(ul)wNAM@4>>Fl&|nH$JI zC5t|VVU${tRY7ML6v?!aqW+zr5%K#kw`=>HElupK6#vHqwa{<R{Y*eRUh(9-{<kJ( zg;)PtR74inX1R3teFrv8GpXc804mD>0HWO|*MH|LhUqlI)BxV#vWBE$WdfyD9_p!b zrm0d_<eXNfjVzEmp+>(LW+p)veObK9%wbsx4{fcA;&IS*PVZhKG`KP_5oG&6cUpg9 zoES|g?%kA?Mvd18XC`!?3s}ID8y{z&|I18pLBGVZAyDu&vDYtmU&yI%EH3WGows18 zWd1lS{*m}GEhz&V5`<h!eyUu`A28juQ5pON;7c`9Cu_0!M)BIym+r+Tq`OQoVH115 zFa3%e5TWtkR{;(90<JKUC4S?>)-hWX^b0b)Bz{epm*XXVfE*%o4NlIV;Nkt>-3msG zlT{p6d7c;40->dl6v(K@Qn_bx5}99-Ne|;bjlH;}A~9962QL3l*ns=Mn_1^wWUS_1 zOf0aD>QZ5J&a9)D9bos)&8JJr^}lr;1K3mE1uGdj7LwPPhJSDC{1<DBTq@Xwlw>&| zEVw)yd-uXoe@ExZ#7m<xjwe%V0FtqI=lt_MhSckgi$3*XHK>L~3gb<Om2tQJzz=A` zWsl`!YBK}TBUrQ6kR8!OH(%chtQ9la`45<(18f0_ss=4&f)-15Kf84>CiO{6N{VWW zhX!98>@})x=`?7WX=bd&IVZCEos~I9RiEzU9)5dBccjwul^WWN^skpLz!>UMyWK0B zZ3Eu^HhDgNfM<kr*PkRjMpfix>WjN_6Vz+^U|q|^^)UB~ykw2<+ex#sNHlx*;}Rki z<NX*Zthm};SmA-)Q#!SsN4Qn|l$}qeN+CVE+YoqU@Pe7ypgU&$F8!2In*?OIpK-`^ ze<iYIJ=D<ZIowmmf6W6)zERliv%o1@ktqA(QmeyLBL0iwYoyD=TBlsb*cYN-fQR|I zDQDdb0sM0;rQgw0ePy3j5-o9*>ua-Hn!PrXrIV-BN-Pepr|sBopaIgm#dHF_o-c)* z7uA}NsMk$C!xrQG{;)MgA^NO}%}B{Zj4h!*`r1Ap*no8dkK<631b6bQ{1lT?QmS=A z^+gWFtamKGQq)jpW!>xUC$zFB?A6;2zTqUE$>IuKM0LUd>===Ajc$quJv02vJKtv7 z)YELA0uWO{_Xp^wK4r7RzJ*pRRcCwVZGGKWz}<|=X|_vkFhOwUWDI?G^2cz}p_WBw zAFhSs9MB-4TSI<4KoxV&Inp)ak=+C4J%8^<f3d3%;+un>6x$o%CY>M|GK(`vpV`eI z(mN&_CbS(=RVxluj`P^2aN(AxEsMnh2;OQ3XpCi^YAMh5!L$yc<^vJ}4XcR>>%tZR z3D9=?_0n@;1L?M_`-g6hp-4d7TZBO*w1c6vC#hbXLof9S%jx89Bh<Wpo9g&AXfEWG zu62!Sl{@-$oK*4N&d|=_yQ9+39~pbw{3j2ZXx+T}1%70JJ<In^uO>;k!l%V~>o=O$ zc%N7Th8{tPO9bpfH%!5W4h<%*`YK^T+_Dxz94_xPo25k$CsWp?+%kV`#kv`)MXzXF zeeJPhgUyEhFyW^V?GNK610z===`y=%nGYJub%^HKb~^2A%}DMFHW-mxGN<!w7iq!c z^`u!EsJ%f~-;FJwu+Azi9BI}DrUMx7rZR&+baH5nKBW2lcY?U4h@|q3<weZl4{`jM zBe0C0=w2)>PWh5TXap>*@GejjH1KK8DerL_8d}@>>rg?sVLz%p$XGA};5Mk95%018 zWmaawO04llydp9<4w|~1*2o;5?g<nP9s(s;Og??!do!wWVyJ1!$6WxNZDUP<gI-SO z5Qpp+o&xeEplE|<2gVWl6jl|-!h;Y3_(dvXHH-9T#h1s7trlDc+@`yBhd%3udnKzy zQLlfZS?Mk5M~y$MQ=Ead27YAyTPt3BNt~>>kfi`JnZlJ8_JS_g;b_QDU~i=gmj9ca zK&om^{H?RC=^%bx&+OiOEtyAG)vtu<uuJ_rSC_b1njjK;utS4Et4EuCWK~E%f=B0J zi0`DF<%3y?UBa@KVgaDBWoOOR3aBMio<yWobCJ7;v)yV!^pz=gk7C7)ETDSTvtr>5 zI{;SZFo81Sgii&gF7*jU?xi)vW$c;PdZMZ3gWI)F!$Y%*34jmF;^=n^((^ywDKoKu zTZrkf)z*yTvd3pGCN&Ui32%^}h@{N`P!pB#pmKoZ^t;E2ugYMT<R8rtrmvigQ>UgX zh)`M;x&{|{pO_iG{qB1y1-{UD*!F(~h6u34J|w%mTEF+>EL*DnI<BW|g>XJKmE4$p z_ooOw%IgZg3*6rpXK7HxG{%f}$rc=JPNB!DGCrqo_Rd_B+i7-XV4gd6`xJeCej{C! zVmILAL4XorfPOY-#0d$$iVsqcQ@gEZuYt4`FI=gQ4bRph1cNR7j}`qpKy^lxRCeWL zTJu`?)6TO=%JHPy`G0mcBt*9J<GYu1RgVVEwP(MOiVGw!aE&eX?54L9KFH&oPtn~7 zOnqs~inAHo8s$h8iq3W@U{iI7Ct7gJ_9?V)SpW)Rt4Y=LU4?2;*eP6jnST3cO|9*> zvJckPwlrh<p#IO=m$;^6zf_XT>{I2MvSU}`98#=5WXwElrb>mL-V!HRlBJytvWs<y zRYk6k7U$W0wV!)Z%DtU%GG%crmV&7Joi+hJA$m$+5;uqvKIZF=8D6XyhQKB^Du{;d zn=3f9Hyx=$-J4v5;L+RTL@%QrxZ=(nFf2u)#XU)<L#$R)NGi(<=SuBe6|x}?t$BnR zp&Tf2t6uo{82}GVVFiL~(9S2nPwhs1{6v(<PP40hW}aJ?8b~u?$4W$^V_;0BT>mmP z&e4b@>z`UG0sH_=Djzja;}(M++<liJC7|}@%ni0u3ZHzG&<fV9Q!j<!eRs9gzeECD zY}fCDc40->h4M=5;Pb}V?K2JI)1=Zg?WIZ7NCk*F_-ta-XH{-9BwQ&!_sYTq@p;Am zVvcAD;x1Jf+1#HXyo)}yv$sR^{Jb_sw8!V|(%4m)mUi$z1u+52GHqQ;I;~feJl4Z$ z$^w|7)Riy-kCRc^^*KOAe0|e8d+N1@9@W20nM923+_FYOy>T1zQ+qSJDShSq)2P#u zuOJbx*)vR}+|e1FwP9{dh}ffs2VjoxaGa9L&O$^az;7#`Q+Aoh54jOgy^3q<X-v(G zfBCcb$P(wDO&29}=rQpj*!&g!v<IE3Kju`a9xr9$aLT_5skVl<YJ&3o*u~V-8*Yqc zQ=-&0Q#Y2aw)19Eu0Su`c#B(#*7CzfZGcn4QdoG4gx+=moK!6OjPEn6@e!E-L3j;2 z#*$P+omzOmRJD7Jn4v`QH4z%Oc`QUT`e8C}V!Qw^rdmiGL;EMHVT>8OR*yxtnz^Lg zQ4!|8+4tAfL~ss(Z*wePs@YAs0B<kIaNpw@I7+;c<A6c2F*STWnl>lggN%z9d>jum zFYW&B%T>T!laK!}5s@(t#<skga);e%fD)Y>zTkc(kP3k*2Jc9DqH{c5!cyKN_bPE* zj(V<mbYk-W&-)c{viLr~XsA~wIU#FED0WT|(;MAI1vWVClDrT%>ok#|BD$zL$rK%b z<P!YA+2%!wyDzcBI+|1j|8MAey)&1q*0cstNin2ou_o2nv#&Rn4uCHoq0C;VpLIvf zQ`w8mx-P09qZ!!IuV%+?rYx6Hd{u&*xbx@zB~g_&%2KNd(6B8-_MkfLLAN|tVOy?8 zHZ=0%Y+k>2_YkybHbGiG!4NJ&zaU^~hsaO=179rR_$Wy#?C>dHIJB$C;e0}Y*BUUa z6Gf!xj3(T*P8io?PqE=3;O)=-(BENvarhER(Io$BGQD1_?o+077xmyJtftnkg}SgO zVZlPdPsHjnJRMrx^!*VESH4&It34&tbS|X?C@v2&VkcZf9aLhPZWs$+^p&i<&QEXG zq83usTRVCBKw*8_7gRL_$$&PQH%b>h_inbPK&e;ITQO*IEj~z>*ACkNt3#r=C+|6N zZcy%XgkD~qyAj21b6fZ9$Q-mVZx^!A7Bfz?L&D!fznHcdT?(yB5*PLm8Ht$&?*6PP zos@o<AgLUi4o#P;U3#uGJK+kjKB^SP-ZLc05njW3&fe9fQ`43C(olIhQj(eGGG$15 z{-DMNU;w0#^ri)QM*fcRnFkYEPIm#%2lt>YJYzWz)_AR0Y`hRxz{=MS{;_=p!VNi$ zIs9Bd2R<#vBAY9n^%29NB*&+|D`rYFHzb{M$7=7dIZ<^6DOiDz>%rIhP4RSc1@5OH zrxC0y(svJwGApI5af^xCYbfD|8qhWZ)EK582N6j*NX3|<TZYU`xK~Z#=u3H&fogzS z#%wz++r%CAiZ5c2E^~Bta@->IQK@RklUerGOJw<HR@=?Wx)ji_)Z4_(aQ-=upT$Gp z%pSapGJNuKJ*JO3iot18dYY~(#RkybHEqZ3&k7n&mqHEshKCq6?d^DbinF-!&-f@| zK+RxMZFO?2kx6YmC#uSf-0x?=PZ){o;f|$u(5KI<ekQOMKtI`*Emkk|KaeuuqH{b7 z7TW$=<gTR3pIu)AjvZWZ(@7TaX5C5?QWt^4^K(lS8@(9htX1pJyz@Hk7mPIatNlm? zGjUO1H-+Y!apdVRF0dqXiozJBE8br*WTlzX**W%xG}bDYTDgqO7_S(p`#reMK>+?V z*uul{9WqegzyuY5MxufIG1a+9^|Sp>Lho=b?&#M7xZlwvQ&KY_Fiy>WB&m!uij!Uy z?E%EYehcFWcRAvHw+ZqPAj<(hJsaS_B+ptwRhAmTWwvioc~k1D=%8jzJC-%~;syhh z+Gjx%3hk1itNsj(<;HF|x+UDm5<P?NB^6-mAA2(g1cnLRwMDyz`bEWGq!nOe88Z`P zcCOXlknR12jOAsC+&no*A-Cx3LFM|WP~G_--W{*y_s%1#erz9D(5LNr*!_H5L5$(4 zu)mi(W>&CqBs_}JZcl?P>g#V|<Z$2Xdzzka;~p9y;d^x0{ugk+!Fh75iqRXNcO1gk zJX>Px;zx}X@E#loD*J(yr9~DUlWR?w1FSFN2_^y%Ev)9gvmj?JAhz#TSHW}o-Ewwv zb3g~=txt-20Y)?tEYizL-nqd{16TKzo4zOXty}wRYEzvj9`!zFEKS6I{6B@n^6V=n zi3L3B2|I!>^|O`%dxet}4J^=<BxEuFZG)xi{Fu8U@M>%!#gB5oR|=5Ttq(6ci)!4f zIED61pZYelZ0lEf8}0JHAlLXjt#HK4trKK=daNIJIc$1b*TwKC)nxE95LGw}cro^U z*AnVEse}1l3kS5tv9?RZ_G4+@DcJQ7$$0;Vg{D8(LAmn(kVk|wR%(Op=VjM<i8&L6 zJA)DGRQhxy`eF8B?2@-v#OsZVn(OQ=kHBvb*}-d=oBmo1RPJ*%#9zo%`yw;NloyY? zP2}z)(k-Ti-8@>le=$x;La9#*g&dhC`YTa<4N-8U-$zM}M{i@5hSnd3-X_;$n)v zJ<_SR?-;H=@30*({fg7#lTOaFaglZJUnWqiR4#h|{HU+|o(lcosh-2^<FbH!=ON+D z1c!x%eMwnm(PfIG7D;hwD2rb#vikDi<llwwJNc|}j7dB0_Y;ftqPBCcdeimVlllwI zC1w@a1)koOHabB%uMM?k%97DbI_xx`m^I69t}*kt?cwrRB8A7qZL2A1#otE<Pvz#g zSywhEO}j5m?OL|7zYaQ$Zta{#@l}Mjv><iBr*q{Cckzh){ZK~B-Q4Jb#&v{|;h9tV zaFFq9KOlRG3c(DiPYT;JK}*L4k*!JVD(h;P(a%b2C;FL<f`3^01>c6f_2cmUopUnG zG)2s-UuXTSRa_G{we)eIEu%wk|9%X?#;nSs1Pmo9!6~?V!00@OZ=fi<st&sgH~E30 zB8$arz1}}6x)NPKk<?G>TGcObeZdivdVj1BbF)=;7deV_UO_WJ{J9RmTwmn8OTL*U z&P*VX@QwG`SqmBi+{6FCby^P3_kVI4I@Y9}Y?)gEu7jJZ^!J(%;m)VKik2QFzUvK| zQ3*ks#iHNHs;?HQ2IzHe4Jj-3nSz`4Foa!uL)Tj`M;gi@rOo?KFNfpn5xG3FXOd?Y z!p`k^>Rp>4y@M#1HG}<M{QOjj4(UE2H^&^AKkjepALr{R7m1B~T&RCA{eUsmFK%+% zU<hB8?AugXlK0XFtm~Ngw%#D}Mf+M?K9^^qIfRh8|2wEk#t<n%FAQyWSE}C6*K(@Q zHY@c_qg*M+F06y-yMil<Yejy=h9W`i<6tAExO$|@_LYh$L6C2Kx$huo|4|0l`^FvL zwzEAGQPMdKOM<9d^NZTtX?Gk0r4K=dq8*-c(GH;EN@U6m?SfHFK48i|x#fCKq#Pc8 z+T3~@%@J3ycUf1e2US|NXSbcMiU!~k#~gDkL#Es@>g>jipS2^&7^MEIefI9Pmgi36 z@!I#E&qw|K;`%K|J*oqjg7*%>CrKn4H54_QzIu&#BJ9|0Wqz>pSk8fIJQ0<}&*+XW zYT9B)g{5x@Nj$ug*?i56JR866{b~MF);n;%@wbfeR(n`@lgxSFQU`%~meC+_GFjiR zw|S$naXT4*6sk!Sc1P8%SO(6%8J!jEquTDrzf-+jc33Of7t_1jn!>K`^*hdkT^I_Z zI>7z;iJ8>lhHk(<+9h!#l?xPWUe$qRb-0hwu*5OqsKDeJ;<H>yBHu;fV)VlErkHmv z4{SnH=8G3^L`sa<9Jz_TIee1XFB{!=h^nA`jv+u1PzN3W?|Bs6%(j+X0Q|A-;w(l4 z(^+cnem}b$!ro5^T1W-i@%-CX#A@`rD%-AazZ#S@>&&xujT#xI=2VbYAHXBUkLF9a zs)mYRj?B5l3@-XhZvELC%gqU1JABRRmgo?Cvh5A__G-+B!wsJN=8(Lb<+-LBvNbEC zTH2v%Pn}dsS;8<#t$CxW{(<EWE)Gs#qnmqKjbk#O@ApB!ZdQw)Us<KMLywRCl-;lQ z${@Y{m0zmJ$^#^>&G)edQkBc7Qs#WLt0~0>K;?YHe|LY|h(4Nn6d5|*jpS_>9<LRC z<cyztPnFnuf5d+@Q?itIZIYSoy354qf6-aJmLT~9wRp!YjG6!<#)(d-7LD#VcwiTt zXR-2~=l#|u-Vugg<2;wa&0swT;)Aw8LBz=PaGW4Tt0MIs5pVDX;Cnf6{h;1YZrFF) zzNi8?5JA$5V7yx+zZ_l}w;avE9@BTqy~)J$GqJjxv~=#@@>X;J)ZMH|wld(2l<h22 zm>Z?DI>h)(tZF15wy^${rL)Qm(5toK8kN|%C4XqsWh35z@yM0oj@c>S+k>xIIO5L1 zVokef)gNxOzgeP;-g2fMxWT+XY7&8r7H;ppLTKLnJ67R=|MGw~%a=D)A|kx%GTZR2 z)?{rqx}7q3buKhjA2z)ch?|fcPE_<4Z!}rD1#Bh%qHQK%EP7;kp5An~XDm7}`*DG8 zZ^}SqgQfKJ^v$0p$-$5Mb;zWBa_F1LI-~Y(r(cUYsV%e(s?kAyH;27>4#3PE*k;C9 zN=@CM@Cufm*U%(s0sOl!X5}9GlpE3#W|mno^m?o!w0-Ku`<aZ0zh`Wwiu7C_OZ96V z@B)Mrm4qAwd@_LV@0E9wcJ>-}lO4BSTW0(ye$GO#@}7gI|88hEjaqc@&yV(&cIRM6 zdN&u-I-ChFOPPJ%5Itq_yUUc3J~*d71Mj9%LVPsG^pau<gJ}799CPgn=UvPERDHD1 z@<iel{+LE8O}L70#h?4S0iK@5D`FFBN&Tuaa>--A%irhztK36nXK`gzaAT0}Rdn_A z*HOGmj=1r!Z9VkAbm3C^nyjsDrdt4U9=DYrY^WNl;f&w=gFQyLv;USQ52dw*&}J#) z5AApJzt?`EL!eq$L^ZX^?ThAU1isvs9|l!ym6v|Mn)UWDx~N-d(z~G;TTPihMU@+g zPkB1p$ff8Des@bOXYM}}ZhqDWeLWrRB%tQ?sm3?N7A7hpG9G1=KJShx>zApxS)+@v zg@5&CR6d%ABB!OzTBUFV@MkF7!hpajiXo0`t2pF;5xN}glm2_d3uV1AZrP}tb?{n; z_o+#LOLBFcAuX{VpsHzCyp>F7!C;@kMPH{+b<c#=AzidisOa<BPGC6a&uA0Aw+@$A zs_V4DD)DaM40guWyQYq^$yS9aH>DU7g3L^&sci%5+oMWDmqqI}#_sUd)05Dk<2-}= zdzpZ?{gijTYg;s|)3x_2(k}0`&%phIivxmN`(B?1G5;+^PQbXqvKg0BCMwgCRwuAj zmUD}*?|dq99DK;WWzr&*;pH5plq&JjeaT!<JjYY*YWk%AXdRKS8vT{%wb!mu^HBSH z+fq~_E`jN3H5e<AzRu`oGE_O0|MQgLu2D;4;<QRif>$CXZJB6<=!tm8g1ETIrfYKZ zq&80>3=?x|OY|$;@}Q`|t?X*ilsKnGw^Yi-MF_hCVpQ<z7+zWi(H;vlPa^#XEXifn z9rYf??@KU`jsMtB_ts{}y5~Tt_aZnO)$TTdy<4sESK(rjH_=768Y(wtLo#cVRSToe z+jmrPcz4IdYpv(k-n0G+H>nFh*X#Wi%WYc}R3uEHIGiRl2)KJf;=b_Ex%k;XWTxLM z<j&`PEv|o8^hbtYuf<<qDh62EOpf#Lc|yd-H_W`#_I8Q;=dUW(`gl3nm$XXFklXDX z$vnR=LkGz435uZa(2ZQqVqnoXx|HNXYVISw@9M9J5USI=)D9WL=W9e4?CrGwrdF6L zp?Bl|+OtFl-l;9Q-v|T;+q0IZoOFJ?o^LIJyVN;Ip;Guu)?#ESr_y2U$^3u>`&?P> zeI9S(t%+T@6`8h^d!_%o3coFbI)y8pQjPZwCN6Whrpi{AN1Lb6&6y*ph}PQVLKDHs zwpvxa^$NyT(oAm02cz$<)0011j=>%_y4r=0njsEl`wSU8p4CdfPWdJlC(^s2h?yuq zXnF@Ua5m`oOO_)a?R+bNi%ysS^<xK{fjB`wy>g>#jmv`<i33P58<+rh(FM}9kyO#A zvnQlZG`JV{ob$rp*=SSI;xf`CHu}~_4nl7DTWkMkM)`NKOG%yn>8Id$f+hEm!9pC# z606>`zqp0JQn~jn$<g;!KlXy=<I|(+UAv<{BOEa<trs7*L{5D?C;epmPyQi|rTX!= zG<Kuqv$y9C=6^|JbvEQ1H`3Ym#gE7@Q_pY81}_gX`xYZJ`xEcBd~AIW?1b;TfCJ|Q z4yNixqUkjLP7^TaE87CZU~~pUu#&$N=yr~A{ibDn-Fvgy7|MYUeA{`<FKBUTRNoib z9OwMC@uWDZ`JO{lX!-n-#<!|Vc}`Jf_8j57_!_UTS7q@ZG_XAU?n46AWi(Igb@$N^ zG0cBEB(K7%r9h*Qzcqp}6gTRYz#ZK%D^aaiD~A3R6%?DLUrR$vOLQs{@)fCKw-l}V zPHe|5HU{;0%zN09`CvK_m1Gv9g#~%SskJI(eYU8JGFo{N7phkVFp{U6+Pyf0+P|Nq zXio5#3tDJ*3#@kECH34cVzj&rd(HBQGf|%9m1;82NAPo$$fq{~pJAVS)c{J0;G*OU zz@ht=a!o;O1|4>*gb9w?-+?>x3Y#yXKi;H8OF#H7m0YmiXm-c=;HhV?ab{e!KQP(w z>i78CRO@v^({VIoUsQ$Ad*do2qrJkT?KD=|)~$EK=c`mPBa}CI&V5wkcxbxEZbRNR zY2K5Duw~7AotCry)&$Pe(33sK%CwV_#Qy6$M~7sqREo_sru(~D@AVVBTi8uI>_sxq zK0V8}wqLevbhX6q`@4eDn_nc(Q{Ia-2vKOv<HaNH%ZaKHw!14@y&FAZ`6b!=#I(yr z!2w3HIE#W#)%a+ile%gx(Hxe5$T8y^*!cjGHQ6fjiUPJ}em&3?7P*limnG}&i^N>x z-@Hk^S%+WUY!=vZdc)J4#tg+XgZ|}O%Rer&(%<cN!uRaw%83CpDoD4+KyXDMUP3_v zdtA!ipWR;zu)0PgsHV=fIDy45HsgT#t#7pg_`F=dPQywm^LH<=YO07<kRBY;N9U_^ zAPr|w`aubA^v+X^cHOHjsnImKME=eJegN;{qCn=}1^d62zqC%*n=I`jD=w$cw(6`R zOQ!&n1M&Hf#5`l44<d&$*zrufLUFcdDxWp`;nY%S7MoRKcQ8B}nFD!Wc9-4LFEn<- zD0|gXFG@k86ipR33xb>@7={0AkU?l2_h6d?@TJ>5WkIxLYAzM51MufGpKRTKC3b2B zqbK@alT~jThu>(y`NjEXjbZTLB^-F1Ml^mHwPj7!-~pt2L^TB(aK%A$>3pVG@Kfbv znU1n}F>I7k)yTU}$)us=Wc%8~fML1#*S07KC|ho<jEqFll<d_^Ha6IERxu9&>B$CF z@1@hGg-v!g>Wumsm`0LCl)X-Lx4!RTQF>h2X4d4pK+;<UWaqNyE5VOT78H=RS8Y(p zwo5&GDDK1Nr7~H&Sbtv1l?ja2W{Wx-u(VCtQE2R!Dt^#f*A6}fjOoI)zf<|BZR1J2 zbrE$H+=n6+WcMw$CRS4n(oq)gy3MY~%VgiB{wTSJE!(k_hBncLM<YY7p@vF()52HN zrSaJ<enqD*`tsa9jOAXEMYF}vJ#LLhTj(%Y`ix0JIU!sJl&Zt-hHiYvo;kx|d4nup zuAZ5P+%X`oSeeCbAEv-k#R${s4SJbk*No&a_O2*@R+P?i1x;zp*Nyf+(+^s{n*`*8 zdvH$GowO=8V(EEqe!U`5b84_Ph~8B#Xkl~epxa7@?4$3c(=9X;oTjWvm9^r{bQz!4 znJ4cGZTzMdzw<mL)vJf99#<p;Xt923qZm68DNNawew_m6w+;^PvJF1`LHQbpss&@i z4^Svve4*K0J&mdYMQ=aEl*g5G)xTU){l6~B7?#lwuFMKU^BSM)1Zg36MN83(C*8zx z8!bh>Ppgxt7d#Dke{1!gJZYC7oIJ-6{FHTCQxH7a0(y6)Em3y2v1)tFu~bW-dwvk6 zFk~wim+}eKD_-KD8DtXgsr5)3Uw`w2TXaLOcUvEPaw3;WdA}q2#qGQzv~2?*>Zfc9 zrOgKJ(uT8lhL@%O`|SV!gXg}rnHTLxZt?MbeFdz-f+1O+2j<}Hxc2qiH!^&SX7#C$ zM#Q5=Zs*Y@92||54dsofoKh58d1=E+HOn&=nW&fO?=hsXoWK3JZi(x+;E^@CUpj9t z&e+Z<-p;Ui6?@?=57ufvK9{H{ZuDxo^;X4Z3K;+P1^)~46sfQ_hVI^Byh=ac0MC=! z!seB1R&@3tqp<R*M{L1zZs2eqz;g@B6dUai0W(57DPe=DMbWP~$6*p&$eiFxx!y6| zuCUG{j>+(It^)rAD1Bn`*et%=M>K(qR&{~Fx5)&jFKm`tly`RU4|N7azjBHP4E_A& zY%l%Ui`g5!AWJ}7?il2jVX>fvuJ8_<35`Ar<L8%GYX9?1S}ev6;V+tR1O5aNO)L(C z0O7i7e4B1~BD$k=mr)3DCB91>k9cjK%aHL#sI;_2JbQDX=Br-YbY+T_azxqTqXe*( zAnHZ|Fkih`x|V$akTwVv%qffGq|az(F8`exQ<O=7-=#~kZlFyEb=_SEto5K7M<oGX zSdW<zJh4asW0-16D^%sZNOMoQTrgi?d6?P%xKZ&%cVdk?3(J-vh!><iBW>5l9dsRt zAgmJj$UW1dQGHjA!cW6@o0O}G-MG3)DasDQ_x0gTtJgzs_EMH98pdkxdDKtcuZQn7 z9xF$khz`=9TPOV0Pl=yH;6(R^@sgHiF-#$%6st`Zm%MUa=(Gl_<>W5E5>PD%$ANNc zw2C{Y3IfNpUp(B~f5l3`yLpd|uw@0$1oWco91g%)nVsEuWMY|IElo8~b4d-sYfEg4 zKP2|w^i;5v`x7)-H7DW|e{u(GY2*^dgF|^o1=wkg+X#I~A}&~;aTK@`DHE?)vuTPI zNZTavL3-&b?3sxe;c;>Zz6q-VYpD5ss{0IdE3Rvl=xNW4_#RScP{j;5cB=eflhNoM zSqMU0SS)pL@+-HW<*f(+qW%CC9rQ0VsopTs*vmkyAjN=nqkdL1t^#v`oD!@GLg%8^ zfjoo;rg*?5h?UPkzF*GZ<SkUHT&^#ckv+_Dz~gv8ApTqJ*H3yx+{1jz?RsNlTY1SF zv-<2rzdV>zpYN5gS;xw|*Z0uQ&Lto!ME?^HYbL!*D`s-jSS3S+6v$M@Z^ds_0fLN> zAD$KBXxqHb)}BH}W<_udWY7!US1TPWanE9e!REQmN>6w44^Yo~=FNk6JZtd7ZND0g zB$8IVju>BgrsSkcXx&fdGWWw(FEEKcwOHA_*@0nEeyy>K!Q8?5T~QN`*Mr0MuN$F! ztPsq~x@oV~vpG<KG6Z9Ad7#u?F=lEf6q76Pwd-+^E`(PNZ#c9<MYu<kX*di}WzcFw zqpKji*CSwzVQQ6NW7ohCqMKG?ApLp6oE;=iSWu&(H!MTM6IREZ&I-r@{%m3WPg3bQ z`eBxFl5K*eot2J#e1GCc3uVN_aD>a69&MWfZd|CtRE>^>2|>4^6@x7(nZ=<eW|~g! z+qaOAnh3$KWjiime?m&J$+J5v%EpQ$w`-NTbs=#Zq-`r`O5VB@^rm6mrNLi0-7Hvd z23#l9s}{x~{rgkwvwZ&#vm)twIv+ifRQ~&40RP=yOmvw?kib%WxpYb=NtzsHU!ZbI zo~+VSe1GP&0k4)%M!X9PJhU~X!>pPT$Yq62chr<T^)z9e5=26<ej+9w>sdA7SCWYH z@*S&umGb9<5TW4OQ=)_>LVtSBW9vLK+P5`X7-22y_|cI-!Whe7XE#2ph2YsJ+wf$| z-nx`v(uaR+HS_`zG}=dG*$HN>lj@9WeEc2kL3;h~qD^VhUFNKWHwZ@!6B8F3wg~G9 z4UYp^8yaf_kvJN}s5P_&pM3Qgn;~jN&00%488PoIB*LGe{%1chf5nC-;FD}Hp=qhK z$ES@&qf{9@)4la4GKJ`A!P0pDK_u2;OB=-qw35-lH5~a@STvImcBMaUa`Ev$ZH2Nr zk>CgHx{eA+BG!y!rzc`cg7Yt<4N4X^j;hnT)OD@W;PFgx+&x10`O3bry!u*^Yrj7* zWF{x1px1tC+sYlnEps7tYK~CWf=F#fZvF2*bNq_+Nk_+gb2y!`kRK?6otB2-@nT|P zA}y__NbBDk`vR+rIYs2Ed{i;gjwR+~FW;K08T=8%zwM9^)ktWj_bv1UC*g=tSJ{fC zL&bM~O?XCuGOnxMa5<nUiNS4jI&l#mQO$bA)Bmia`~YE5g;Q84eV!dz%_zM7D^JmQ zuDd9!EIxL6#&()cV5k~>jyVAS-;B<|GIVTz;_)Xt_*c805+755q&hmGzbCuR|KMN= zj5Pi)!iPNf+%wFH%zskyT_RUl9CC_DcR#K0($w~JJx*F-F*%vycV>zI{8ZQ#WyTDt zZZfJ##MIuYgUvvJllrE>7~y>SvCz-AgkZfFCZ&?<-v@uY)83?P73u{uwKJrDgng;3 zl@DH4no}56LcI`+CCz{Fzn3K;d<>aL(jZhhd{3G$ANW6p#Q~$jTacxi?EI+|7pRVB zoo7{AjbEZxPY<OtwUN&TfP^IExw5dM4jVOj4V)6@*gqufHBkn{kM?xxu+*BBhcxE= zlKGgK|AYoV73_5kvGiRoY#_IO!wA$k%}+wOD~p#ZHvOb;&r`q2e`zn~mz?=AiDB1Z zD+#!UN$Kqqcua6A_n#D}Fnlh`w%XZe)lsL;Kk%y(b65*BAvUb{-a)zw#WbZdAGaby zu*f3&Q`%J2_hz=TNj{4^x{y{*$i^f_s(01BDkIFoQhJ=1{c}Oi04lS(Kt>R4E*vE< zY9Cjoo*5-$-UHGLnd#C@it3jXxsi#~XIrWG6vu5QfQ)N%PirHxX9Y!o;{Ovc;0W+g z!5iAujr_S-m$s4IURuIxK${enqrhqK7bxkB$Bw)PC|hj~h4rw#Z=cpy;hueAwP0El zV;OnReVio1%z<EOEj3Ijz#W1nS*_A(U@Rz!SR&({r;Zc#x@wY)2h8ei!@9d(qL|sP z$Ang4Zh@J*pp^g2##es<7QCaBHA2H7-$t>0va6r$oF;<c{dD@%6a%j%9=z!%R()1u zN5j4Yjq@4}@sSuM_XB8k#y!00>k+}_L(<V^J%=H}N+QwgAG4=7avrf=Cdsboa*F$H zZIR(0CQfqC%!@hFyy<<m_G@;=Jap_os-BbBjyV>rUk9RC<Hkr5uTO6HHN{0WSPJX} zP=^Yn&GyXg5Y4o|LZTSL5vSASEbhb*cx+{1(r@!kH<Wj=J9c*NGrd7QTR7LEe&@{M z52EbZ32KM(0v;ew479rGE-A&{GPZj*W}C?t@L-qy&82ZMRwg8k@Qieb_^%3;^2x(P zv$p@_&Z{-$>u@y#Be~eFt;$Tx(b&G0_M1OLrljRWg`ifPn?2~GnK|9K;X5^cpvcXt zWc?K2faH|z7;OlzQML6J+D;b<zFt#|Fh76bq0$B}f&?Gw_1xfbvgvWM)$>yG;-?R< z^FP~)<lfrlt5J<JLo~p35*;#%{Nr4yr*7SyiHAp$+vPCDs!311_c|8Zp(_ZF7w|2O z5KT$zp{DV9ji_CAL{XkC!AH}LY*&P9KlLe>GR7ZWa*{(acX7`Jet%egv;Dv)HZsj$ zSe;PGi0T;kk<p0Vfd7n$d`5T5jaR^IaC`hj7p2Tf*;4I*q1Cef?UPE~;5|(rWW1Wv zVXkxp@C}(}$hsBLr?s>527fw~_*9T4nQ0B8Y)pwjgpAB9NI*M;Mp#psWFfa%bh93F za^iERkE|APcH`JTXiMAm+n(*F7R?ApnRbW0&fxp|%(U$K_GL5z1JjwasI08JP(AmD z9Gyxq$d>9sroUA9!ppLmr!E^<*8%7uPp<RX%14+sd0GO*fWU~5(iJy=kGm!7<zMtX zs}jJcPfO$S#KdbK(!D7}6INz)J*{nz%uix<Q*6PRK8k0~i2TC}=k_}7DV<R?=RJJG zBO4_r;v#y6C}(}6DQWe(=Z)2mmdY1T0cGA6yP}(EF7`Qp``K~s<+3=Wq~tl=eYXQp z(fqwXjuBCNRy7XspTmF9SGd3rAv>Iuuc~JHs5eV+*rjy5lb5V3E67j49e$yZ9q$=e zZS3IL@r*U1nqT+*bV%<Y)BRtNMfjOg-McKyK7Ov0{EeznahnRor*B&?lth`%QtATo z&weVQQQ&{>RU%;DV(VZ~N*|N@>83~#k*g(RzcJNx0eXBsqc5}bHw?6G$!0Y*&3oK~ z<{R)u-FMyr0I02L`Q4a@6a#$%F8zYs?C)+rFW;>AxX`P!=8dT)#=K(9DM85rjx8b@ z27Cr-t4lov<6)5s!W(Yeg2GG_bLsOk&T>CIymooSSrmW@8$c^P!C}f7A*+H)gcr}r zO+5b>n1lWDl+$HopX<oUasGmm>Nw@}8yOFD<Vx*m^HzrRKO(4>`q%t?#0xTk!bd)H z5ryv3|L=Uv#0~hw5?Wn-ltZC{sBXrA@qh7r_x`8Dyhcy{@^*QN;?hD=NNM@E?Q%F` zHAHFJeqcbtI?5`|+unWcExTrg41rS~9d|6#2Wa(JNbO+e?lwlFH=X9QSqqIWBRw76 z6__(8G3M}J$Bk7+HvSJ{QS_Nu^(Q!xHh{iG^HKCzg`R5CDNm3YH@JcGFAS~VV42)T zv%mZUe<fsu?RdMS0NeZ@*v)@K7MZN(W{Swj?kCH`!?X~9({_PtDZd%>c{-)FbimNq zW8HZt66;kXdaZBTv`swi_@U_vG=~@~o!@CkXTEs=`OPNd`x10$G%~(84O<#$B#ghe z?g|%VHggEGtL?HB{#aX!9AAixP&!Qe>E;K=qmU}q#8~+N?BNM((Np)xrD4+i6*-X7 z;f`)CZ1&hJ_>j>3s)MgbG~t-3UR8ZIWIjmqoi(o6`iS2*NgOZHyKSDWaNEmMA4C># zlJnp=F~w<;e=~RX0ys{odV^$G?%rSc&M52qMzGm!;;>%0jv)G`prAP}Y8EAIoDbb4 zX>D?1uk(>>IWZP<8xi-gJb@o9KKYAzp8S~arQQ-c8>)k5ZW<b-HU~F!yOlib>>AK^ z*L=-o^UJi$%nH}SB(A825(GZ^1P7JV9%!Vwg{c|31$}<jE|x_&c;gd#WM>j9$%+oD zZ9#JjC(2o;*zdZiH;hyd-^lgcaK$0zC9R8$EG#aT((@#tiTX^!{NaT#wQ;+aR(xT3 zxs0+A`}Q`9%j3^WzDV-W1o^mMUc<9*ytle-U`H$y>|#_g5bCL+q}_pVP08br)Pi<9 zwNRd6xoK^f06G*Y=svnr!#Q7YvExgBzLK1|7}(7TU5ES_R#XL>A_f=_CayX!x85Hv zHbz^SbTwHn!CrtX26Ch@_S4uGFLuzH8eB=VL8w7xKso}<2P9&RW3j1tQ)71eT2a#2 zKD^FbY`l4OlVUo+rp6kR5`N9-;i&9=Cp?$gC~DGGw%_>1;eOjiXg<?<Q1plIbJA<S z440-o{s&d+<xjM~=EuGQ4eBw5?FLEG&-Z2nufDfK067WzcqTgJ`B22W!yhyb-@=c1 z)J)@VBU0OYQck@^Q&L7<yUDnY(p<O-^)U3Y<&y`5XU796L2=?doi5SjjH9dev@89o zOo|~)h8#4G$veF<S?85XlM3oWl$)&IJ=mg-q=mmjaeKRFYq;*V1*!E+q6t4TRCU*- zDwOLfCJBfNj2R^5RBnaOtho;TbUG*LXU=+V0x>=$=ZFyOO)oh#5nT9ouiK(J#eTMi z9d^DU9CkZVzJ4)@uuSru#QEfH&k})GcgZw&x(hGJ=s0^89Ui~0<JCF~ar8J9zqlad zXgh74NtRR*haX&kL0$Zb99<njiK}z|7ibx?iQ5z?b9q&;8EQ=QVC&o{@;R}>EpaQ! zwEu6)re7OHOP_Ux{BBo%lVILETk#FT_A~c{9Rjzd=u>1PdkQz~qyvvIy6|k4q<UH; zH`8F;Td5B#`P}H5!$|>8@xg+nCgFjYcyA~YuB;VYXU?F3Gt?`NZa{XK+9)1z-Z*T7 zBDp9R(fQ4_{*xc^Wqn;BeLku8Gx&)XNcM4|0?UDo+hCDVE@_CX%7Bv$#4VvaM6+5o zfG=GM@o7YSBZ;!j(sBixJbIwEHm4=b6yYvi!vCzyR@+@qmVq{gW`jW*D@xexAe+{x zTE$T?Dg@Ihe<n6-nf1PUkmYj0HtQp0f^9KHfUf<)(*#qI`zpO>7M|~;iu{j<LaaSQ zo!eY{U}mMMl!W^bs!4%JBZPnC<a*6P{+5<|ioK@lXEASD>b{L!JJGzC1z6`$od`WS zEqeOXK;YFcfX4|Vc=_z!_o;W@QRuMHth-m`Ub*TD)&5>vH`N`vgn$LX9(-5DXM02c z=77wh`{1G~9}i_1N_Ep~=E`yNeEuYHs1M|U1-@A}XkZp41uuz_@r(UdVj`E^=UWG5 zn9nF=`i_j=eIlU>0{dOMH^o_g^KaLBr7`~KoZV(8`dpZJ?1Qq#gMdDi=H2Erv$axh zWgu-O5J`0SbkROxQn_yj@!~}wm){EEM98C^r?ijA(6rWQ!U~5|ndvZdTEj5QJ}CrD zDKWF@B}Gy;-4MTiU+;~0YOf0=ymnXWIZ&rnN2<}HS7NmruIhZ7`=mOsR&YS}Hzm@* zg1jVqjh1*SE3IbHtyjLKc&c?qTYbm%7(p)Ph&3X4i#|8q5*Ems@jkyxy@h|BKGmSd z<3=Hw4MEziaAi4Rs2Tq=>$Ew52O_wTC#Mc=ItOQV!~L2uf&EN&y&P?If_~`JN)@j^ z&n7InUb{8yxWoN7i1#|nY96m_f<JEwwnm61R`eu1UWhHi`2aEeQt$t#;xLMrETSc2 zwiU<ZW|`e%eZFG(Ix{Iqe|qo)#O81MV!*nUYP@*&O_KJrRqs-DkpG~%9p2r6<Wkr9 zp6@F%yvKFsM9V;`JJBZV^3oA|<tG}~2Ro{uPOv|e9EIc!!Al7P`y4JgcGe0(Z*F)m zuJ<JaoB3c(Ppn(lX)jJp*xwO67gciEl@GM%{Xv3cwNl-{nwr0Vaf8H5GzF&OWYh}Z z=bH3xR*-&g*rj}y?C(1_fDV$kzaDD+E$P1$QSZOEf7t7PDT4dP#kT0%aH8W#Guf{T z>-yjO70DbD<$6jbhS7lgL&l5CIl-0OTw`JANq@~@5!^4rCi&9yaiu8(i^+|+#PyiV z%q%VCjwPRz)b9(=VfEDZ>kJ&K=lv<WixI)CVAeZSfY!_cf$aFV{tyJ;zSCAF43yt2 z+v@b(uhNGdO0o8(=a<kbOA|nyMEmXxUkq;S$F9Lm?y__%?{mdDEG_PzI9fw_e|m>H zgdevAQu*5R45W+f`8cyfQ;vmbrn@hjr-J~_nJuT^kV~*<_dY|By4M+S$6mO>5G;Al z9S_v7*PG;l62Ca1GjRGnvm{dS&1JYwzW!l{&2H?8@EL?om8t7HSp#0XXXi!Y8fyHg zKN=y*o6aH23j2B}J;eF95EwJQ0o>$@*1hRK3>r-ym{PU+vaD1pLQ_;HKDR|?>b$HX zJ}A^u!8&;(*<k8})9jx#nn#*ydG+k#AxK=x4r9H+29zVCS7Y~TeF0gpAW(XwQAeG_ zlJ(CEwhkw$Gu!8rTUfjK$vwQ2vtVgETHG3wo$#8WEucov^kdy4`X0ltWaZ)nk;z6E zxA!-Up!;3}?lW0IbCr279f8(UBA>m;AsXF}>XRC_+u7K@D{=73vstYf-m}LSgN%$h z#V(>5&HE}o=RN#FC%X=-kK+cq?VoMf=6&Q6H16g5B<0n+>R}3`-|#anPQRNa32Qkt zBN+d4Deo|3&uDzNc;8vzk89}KDfzo|^^04$LobD(FS*hEA%%~lUH;l`7wf$nt%RHE ztLKuA1QJ5|xZ>A%IZ%2I0ckbK<DrYb&5Dnj%0%$YTN9tv;QHky$b2LxJK<=`t_RYk ziSKdpr0eUt0_%l^iw>Zw=^t;&aEC#%uY-3$8!~EOm88n8?~FUKbNJ^j(bk|$W7<va z%^F?h5K6q|jP#M!^)qKBaR;0My$U)VW#bU+7)#yL6$x@?QRvB97tx`1B5P+A@s|6J z$Pa0=nKyjWvv{P0V&wvL2hDxD7P!BY{af+xj~w|qV0TuAA{+rmC4PZa<*(6npZ2Gz z_J7c=U!mV2J4f@`ThLS=J>%JXJ+kT0%J(YK<X-UNrs3I+?-Az3hQB`=IPFyO;^O3) z@f&B~!!g%k=7OkZbBQk_es-~Gy#`e`y-T~z9BC%(C*p$Pv-`E3hs%m{gF=)W_M(nE z6xZk@u=xt6XP(<t|DZ4yZ-2D6Z~A|~_jbZqJlcEmCgs|43T1ELC7I!UpjB(^zNkL) z^L_8ty6)8g{?BRL&cS0VGn*B+Jyq<Xb9*nWXxGeWRtBxPO^y0N?kY!Ck}p8#=Lupy zZ;s1<Sij%AJSend-x+x~>HVokC`jd}@{?VQ=+f>$y!y|>S~XlVdb^ON1tCheGi1mY z^u;RWC+U)pU7Lv<xrjWGoI=)^-<s=@)IiUg*GQ_D@K|KkNj;KlwOH8ZBts{{-}E`8 z)s`})>99LuK#|j_Ny_u5uB<U!0y7(UvF6{L)8zit7?Zlkb3n(<YmX#33&4`c(Mp#= z91b?!h?h90mN#%7p`9_%qV;#ETI!{FJ(MH@=3o%)x3}{=eIllMQuN_&>LpoN4Tt`h zP`3<%(S6e463GkGcjc+e+p0=oCimjz{z{o}MhNEPxdB^lNPsl@UO>=hTR+zwW1w=7 z0ERQg^0!Z9#@==$#xv=B{;Os7=|LY|WO7qfo)xHJ-S{~@JAJRL^}hysfnRQ5qnB52 z6{26u?Q(a2l1&`4<YuN}`k37I7J%Nnrp1anW#~fIvr&AUh7JkUe(ci6=kb>Ak{?6W zm!rMr;dIN(dFG^t5@Y~eX<$TkG5vJ%vrA^theQkykhb?*5PMndZBN|!hPb)qC`r%r z*ybvUeFt<$!XnTs$$KpU6U=keH29fMA{Z-XtDt0M%1U+4brvt-%r=KZUZO5f?Lv7K z7zomq$)}a|L!OVM)7>?;4MNyGj%e}Bw!U)=W|-Q&_gs~Wpb+iwV5_!(^1fX>94@2e zf4(_Xbvl&H3X1eU<-XY|x9(nbZ}Ctz`7*NP9RT?9S|_F>YCXKF+^!r8I!P(&yRsnB zmvAdj<?#%>SpT?e|5`%gaCj7gS7TM1<GuUhVu?y35bWbgy^YN1@n3?!rllWIo}Lqn zLWA6HI~_Z=VD;i?_Dp{6{6N)Jp<^#Qa(T+cX)|K^rfVl{YUS(``QrcAws}Xh{r-Pn zt1UIFsJ*JFU86>=s-mq;Yt(M+6~qW)7d6w`n~$xv_l_A`s+15F1hH2TGwz<x_xJtX z=RW7Y{=WWvo#*@Ud|!`Oyw9}No(Xm-?(GM0w<Il8iCbystM#&D3~#ubO!~@1*9nm} z$3nD9nJTFA3f#S`GG`?@OC;#q@Xt2ml);=GNMt@Wpyr%Vjk#puT~a{5;Gp!>o8t|H zBgB3O(<&p4pV(9cUk%-gYb6*$R+zDnY%x;jM@r!zBEuE<jHMAht@b$9?8x<9YD`AE zI%Y-M{ENv^0FkEF(p;2VFS(#kf&IM06Enrc*M=h1Ta)$fdoD9#<PurUm~yDRO?52O zW9G};`sGvX1Wz+teTwuwo%RSoo_E!ce2`mH?Vw@d{=Wm2ln`>IxAr@pQpUdDt)ru! zM8)*H!Q*?Bn~UXCv}0P=Ex?G*Nmto*sYK|T-(WMJ6iDfz1Lxp88l#7;ou{)PoU~f# z7;5wVFz*D&Jit7E;C=k@xU?b7H%LZlLt*h6I+GWwp|Ik<_4D49^)T>o%n#VVV26-U z8N$7`W>b*639(daViq>iQrRW?!tZC6ApM~7=JNxY&cXNlp?s@PUX-ZmBkNc6DpFw3 zuJbG9m7hPu%>{#^ibbC<#Y=1{1Ut)>s5R95x6&%{-+oNQ!trs+aU?C-r*)0FLv1~U z*#9>EKAl}ZF*G9`n%fHbJ>vU~JsLZW_~SS?64d6Zlt^;=SlBl4@tNoCd5TUllV-=) zk8Suwo)4>^9hO-ZAn+-~ofEbxfyio!zs}pvo`}=c2$zNz!gws&GsiRgYBsVs|n` z;<0v?kf%-7D80Dtrgb`l0}D6nzDkK2^I!oD8*(al%#Y81O3Tl&x+XgsUrudX_$=5? zc+dRgw$E{PtdkOT#x#|DEtvSbJv!uVO6OwXK`f%tRYB1JWn>L-dhjS)f$lHNY+9R@ zc%(*^wC7qxu>B#|?Yj1>(2=t0l7@<<0~L^6J0cJ)A9Q74JYbT(QmsIpw_34KeS&g+ z<@ERAvy;ujG!x(Zr<%EEJ{<vYPsj~se_$*2h63ofomJzYA5M=1?V3P;hS7|g<TP{p zc*>iJ>X)=GE-lLB^4Tq{UZ+o)&&-LqT>VZvh~9VU>&*fVJO^xk*frjj4)Tj+V5eh> z-4(TVwtMhM8`!Y;tEBMsVkD<95UyVJ+xp}sK8SULt{UgrD*oxjp`6&lY5N&~RZz$P zEVTQY1gc`N*Y-6Q-3(OS@jchLmZi2@WPO74@I*8&dSw~!yg0eC?x*`H{ck52R^e>j zw%u{aj20|$>shgHE&%n*yg%ZKuppt{>;L%=8?v^U()CZc$HY0{=jkt}9T#U6^)*Se zpyBt^vQWDWpY!ko+Ti}hxT_iw%4w}k=()ivHE&=C!;8cDm9?j^GyS-jns@~Vw#iW8 zcIv{yPTCLlW?`|s>NRfXo)wF8k>gMsG29hMYyyit?Q+%r-hHYhl)_=Ks|Fbs_nJ`R zFc|m0O@;Gfu`nk*nPL0JaX1Y6==Jl-x!9!f^cy8{^(L!<BZgX0ZW8fr&GFAT_q`&2 z+<BgC$1NQtg8I(z5Jd23yEBrX+<ou!i`QWn<LeYEc?7M>w7U;h3!QER!7I^5lk9@( z1r@gnqlQ7BmenK2s%qg;5kT}XYO|#Mew`ezQt~`(-Lb+rn6z9|KR1KL9e#Hue(j29 zv3bFv{P|S0>koEmjQ4B1q4Mm<81Kkk9Y&>D_Op|yK*bq<En==fGC69DVjOg)q(%(C zdnqM!0{(F6nWr1klwT`QJdqEQ9Gh7PIoUf#H7yqO1c;OWTra(_s1C(Sy9POks!8n+ zWD@sz5C*1pJh_5c7Xs9Nwx%r1k1EnaEQcf(pP}MY|8Ygu83hR~<h&k82i0zj*{xpB zd_I@Q2sp!z7xCH79s4K24_HP;`so4q(|J{(9xR{;L_J(z2_sPli3+h+&lT2U=D2fB zZpmMJ!Au$EKNv?X6!NJ{-wh5ri}$t8nef=~Gx!Wx0@IBRJ<Fd}9%8)XrKe~lk9Acp z@j^KX1+H+Gn2A$!3+xajds&K<l_IS>+=M3Di)dkitExLU^`K`+KPpm4?m>A?g`-fW zfvAdMP~C0!q35hJRg3<eW@Fw4D>x10^KpN&3D|r>h<(nEbw#Ru)<(go*s%BSan}A3 zbVc{lsA$iS*8whKQ|-+S^c*L))WrmLyOWdlD~gBu-onkQ7dabWpX`#~(;9{S)}Ula z-#q<6D22>ZWglCO%MQ}jWe~L_qC5!u@|!(PCeu8L-7~J$^DmpLtN0A>Wiu}Y^8<N{ zFs&vnKRf_D@xaB;LG}~FP^11DM0cq1sKZQ<k^!NHj|sCsu4k#e#^05a$=eSNl*U-B zC~(@l^k^frJ6a0w)}vSDP1Q$!%HxFIE7UMwBA%wJ_EqOi_>#{sJMc|iTwWIp$&R01 z1m()2MPrb|b=L#}!`UDH)ok)@6@DpZmH$dU+N!th96#U=MS*sLz2q<rFLv3my4SDd zL2IZ`9Hg7dbC!MH*QkH(TZ#)Odz;>SHQN(Cn&(V|k})uN?AOOxh2fLrX=|-(ZEe%O zo91KX{}d)JRVJN$(Ozv3CV9v>NXmUA4pO!<*P}_0D-tcB3>c}Soagp=o00ttn_9{_ zFrpAfSDx<k^kD6UF6W!OaD1iC$CQ%<R~AQ_k+uD%z*n9q0NCAtay=0IP++bqsZZMC z7bW$u?Q6-YTStw9O=VewG_I;e(#g0ZWcDznFGk|#3e>;&bellfrK6Z|>#4pu7X<g( z>LV@0?23^FQuly2BTzBmz^AK~8v?cEHS*8dd86gvY*m)a1yBft@-_bKM)p~CJ${;k z{s!%{BmbHUO=y)uHBz^~Sk*Yt&G__}7`RzWU7Ep!Aa?1+E?V-N!|k&T$YGGER1g;% zztki76F;}Msi>^);M!*`9S}HQ;*yTYi*Mpn38TYLgTbO{xM$q65bagG1&N}!&A8;= z#QBrJW4XU%uQQo58`Op(w1lKZToMyY<g`vZhoKk(o@88D7<J8-XIVD?hXW#CGBkB| zaP&<uhs7wTFwS1zk@ATfm}b6wmgJOXqWj1!W^}#Z-DVtkFls;VK46=+yaSeQlE2`z zkdtAmKTESbyzmR!6f84w=b2y;%5%){sW3SrCH!=!e<T^{EA_jJd{{4SC9!_hT9`+} z{OVM7C#Qud>5)+PGF8Uyi^LHA{Jwd4{B5r$g^2GOkF0Has8NY>xqTOE8FqepmGXMF zla0R8iC1yoloUH#j&0uyx3Ge?)>PgQUN&z=tJiwguu{MH`~lh(H*#*YvZZ!fO)DqG z`Wkvwv!9Y5)QpS_znG2t13s<Qa_Cw`xO06tKIW<j+__csksPeLeNjic-9A-Su6lGn zpHr#AlPAAjiYXA>s_6c68g@lwC8uUNEg-RZCpih)b4A#J8^GxGAivHXq9YHS>kzVV zUKrsCNxp?)F6CyDqx_O9r)wg*VeK!TlxATR0sMi8h?jehh400G2-#hH(N{HYWeR$Z z%qgs`%qK(lz2Q-#x2XPQST^oz>anpi>b_PHv$+30h&B5j?s7xcUg6%|MFx4lg+Is3 zonOXacYx{KSnpF(Da9s67}}p+#Ki-YT%)xMkFm{~?A^{&YICo;u~|M5{ji4GSIB$k z!1qMMDz9%ZLhCLjLKsQ&D-x)`oUU%$c0&@Tq@*8&*){U0#qloHmt-`T>JI`!s>8d* z4z?}7wP+6d3k5@@;TB#&+E<j<X1K+)*y-Ig)=IW0{xw+N`sv?lb~Pk$<@Xpyl|k?s z6-4U&j;a3xQ@CT^XN}pq?idCBZ9xz7EQ`#L&vSeU(ZYzkLF-0<<08^jw-<5u?GMgh zZ7CcuH_d4EG<=3ADn2}bEGMYw-W2Cv1%zPP4Y#l&+fO?ZURB}h+ivG3^%_&|lXd|a z{Mea0Bw7?4e?<=I9Z_Ctiu8(ZTu{XLYCT8FA`ZYh>t<PcjU)H{45;xMfEg#u;1 zt@9yV%b;DLiH8s$5!7|7yTAPTI!HdyovmqF8{SWhur^tiXyafoWS{Ys*ega88=G6d zY2JTn>MF?G5h&pN%6Y|aCzXjID|`Q)5Ei9_MOgjg!#<8DKetE;)_DpR`HHB|-)H#8 z$Db$}aznuq4nMFz%2!PGQaV6>Z~ve7LeB@r&2DU6zL&d!apylNrLC^c4qL%~Y9(Gz z5WKwa?idVS`s^#7FNtVy=DN>rH#*Y1Ep2v<j1f?9lZ}^Xo)~>vS%;AE%|oSYF0*3i zJH^etGBk<JMXJeY@&#;6`AymRo{XDwq}!5hKij?+uw|Ro3i*`e9PXfR=Y&m1vZpET z{Ar&ZYEDGSZ`6?c=w!3oB61d`fTKbW{V~}9u9Wznb~MA(-ptTRv)p_zP0IrItC@uf z1NgVb?w4k5_=9iDpu;g|i?=SpSJp07IkBUw3_m+Jl@FWZg$CsLIe@vLlZV7$>tapp z_RL&8v7m*63Zy~vM$i==l^gnPlGykpn-7}Q3>xLArKCMffPsnaw3uUSX?d-SG?T_8 zc<jlc*{7P>s?%9}UYV&WpP=R3`k^%S=rCx|2^HjIOW8Q!Mzlta{rGl9dmuTIIjNs& zcKz%tQ@TDX{<n_n%ToR%<;$%#<2=XSv2x0%N^q~L_ys~QTg&<BxD39eI{FOt#W>fM z3zL>sod&9{<wWUuoEPIbnhH>+Q4;LG{7^T&haMB}(zNy&Pn-T=JA^CxB;a!u!RVN| zy!e@y4Zb_3&9pgc(~Y~R+N5iOnUUWq_=1b#KW3r!quX-{<KR|+BroVt@0@tF<!yJS zca*2nam*|fUgl3&Q%UV9WBIHs%$=?D`HAk-*O!S(6G>m^VfRe85pcQ~7{%nrIHgkh zON&Pyv+z4zgWH2vW1QG(%g0}z^SqecCHxYqnVxKBO0j*JXgX`H9`H^v(55M^#BRum zqQDv!qvdV?NqoTa9u2?RM6zPV9ADD=ik?(|lSg4IqACp!`{2|nD=!a&NKQl>gN1#l zWi@7$R`a5H`nR4rK>!@o7Fp>x76SWTA%Ea~a)~cho!D~08(i{jJ8wH`_(EUfX^K_> z0yWv`ndrQalDz%o`f$OxyfZdBN@9KBo4gq2rKDvC*AY>p3t6@?1#ksqY$8^`rz+WL z`>;kBp^H$~%VOcRdKasHb&`C78s7)(%WjXecv&8-d*A`yh0jK=W8I6$3MW{@PiIf* zI%iw|Lcj^^$EK#HJGRTaD%gnRV12w9c8nV~jY0?M=0Q(Bo;nK(x#h##9Td3oo);$! zzO*D!20Va|iV9CP(gz#2-BMu?8OjpIoF&+@{{C&kx>v`69LVJpcNGN;R|iE~67(%# zEz}xP(}144nB^Bl7bmeE1Muf%X5|P`Ar2p{K?Qu4yXoVyWLRl3&={(6?=9J-1u7cO zKmH{`-ZHxkp$=3+VrxL$v<KOA@bC4XvEBIrCXTZ`lQ>Ez>9|{iJVRCa;3E%}v(}Y$ z0oN>GFu~rqR&n*Cj50#K^)#C;*pTLZeD>$F3(AScM0jYU+%xbya)DP9oxN?bC!I?8 zklr@G?A=W|XhE;{gl*ICYv!Eww8GBft4qhJz8(4beTH-FYXV3aiI06I7ZA{AfBmcL zCgMc+!(S}hQYn}6-~Ao<pFhjs>-)N^#Yj^Niv%t$t%B;*3_$gnhTyK{^eR+a4Vgk3 zQ|RHx6X0Ltfl;Gi5~ut9;X|ETs;2P9Cc_#XcTr}};+^V=-mAq`GbXs){e{)A_GhBp z3t?kVDfO~HJ;<273Qcy+lHuc!c0)bBWCRW+^sym3y?@9%mfF5^Ol|BL9|Xj}WuX>) z=8v=E5~M3xGd8Q31RXPwy4hj^2_%nhNb%Zj%$T|WcdG-x7O>~bt2?IXt~FoG-VC{z zx5J~Xw1tS9IVncqSysIscY(Fjjprfwn%N=;=Lgva@`yCjkFw82&bM+5eD<8T)>=6> z=sH|65N{zvUM}d%*E`CrH%{~hR5|tV?O)t>)4JjjVM-dfhzbhf0J0=B{{bgB(w=}0 z_C{Gea8Nfmtf;!r)*$P_J~BLk28&rp9cGNNTw3H1Rl8Qj=yA-2@2U%dFxF;B3k?~G z=||0__SmGeaZq=9t%@%H;v2!)X5tUw16lIv=Mlo9OO~Ar3(8V}0f|s4l!xS<Q9ewi z5wth4{f7QVY{%bhx`Cb=V$al8vKaD1ZB%mn5TL2E*UgO%CL-a3aWGKNLA{+%QK7M^ z*1FqoB-O&;2s>PWsG#^Gn@a{DbArwyjtL@$voPbCT2Arq2&=T~a6yBxErYQ$3Z)fk zl?_5P>jEI$vEA1v)GE^EF{|bbe+YqscEP+-6gUJ&WZu=WY0GXdtiPCc`|Dhn;fzyB z2#fqFgWT+giP6@d?6W~iWz41j&d?vyA?k>kN;Usp)d|UoI_--M{--yUnyymjB~pS7 zqw+5FYV#P)S?kx#-^ZbI3#_%@mEU;zeDST6r(=zJu(-a|{Rp51a-YknUWu@0?|qly zU1;5FHkLL2lnO@T;eh87vTWkTXGdx_L)fLc)~1xC9=H)N@vXN++P29(C{MzElrG>v z73{u1aBdQ{&%HlAV3u!s9B*P|7W0p-iI>aAgxN%uczWx#urbZ31Btv%<-4){_|nB1 zMS8~)%i-(VawU2a52e(gh&;h!%dEk^CQd10TafN`(4jIuqQ)6n$@h_GwBKu3Q)-S( z`uoPIan(&hibVKAwQQd<+F8eL^qU+jkVZL>s-5AqvigbhD+$VJFo%Z1f3rt-#1H#w z{B#FC5@q;FV@{|e17>&h8RK1Dr&Z+sT2bZ4=sCaPm0y@Mk>!qwIuc;F;da(Cf~~;I z`RZzMAw+{z!>Tq5nv$v0IKVeF&eWQNJ8cTa_04w;Y)V3oPnWQ<fYy=(TS(uC8gXvY z)r3ac2OWDP$m$HIJ3QM%grfv>dqk6XkjCJ%HB}MxI*Wig;Te+VJ%C?=`?gG`>k`tC zVsLdNs;0}8d7|o1)a)t6z^aK??_sbSUJn0mx4pJK4^NaDo&4dp`JeN=!j-pwQsSa% zwF&WjHF^3v={f57>&I7f!aF#jG3~zLec{jM#^_&MXo;@|;{T64|+n4e3ZY4drv zoLcDu&^KLpCY_~M2umX!`ddhT&b;C{Nm{m1NX6PwM1foie8LsABRQOCc$Pl~wTvm> zvrl@9&BB7_>azraBYr=T{wA>NPcGth3d0+O(1hJ|$V04DkIcPUacSz&pS*5>6{_s7 z#QsterGEBo+SZ^Q!zZ$u?(?76afxr5-KIXio*BQ+f-bF8LpYSKj;4;1=fBjW<(Ohi zhT6J<4lyS0cKDt9Bp%BX&^;6*krUm&^RAvQDjBdpS@6kLL)sx`ijC_!sc?!??DU$= zsnLXO4yZA?h(G!__$Uho#|JeM+25SdY5Lt59q6Q>;W;;#wnA$R1A3rCY~Bs&qO1u) z_tREI?-=#9prYxG`PBgd<v#l7@rofuUl=Sm`kcW$TqoFpqstrNd(cWEqt_$^HA01z zbAKN{UYP4Wt*U+|bx&MHRWHDQm7zlCYE^NeHZMrSLo!Z|n&WKxIim`-<C%mKY%YO@ z#dmOoaa8)qtEtn`BhC-YaF9_2TsoD5eO6DRXH>+0ge(J$J{iY(vjHx?RT{VQ$G$(( zhODchIs$?HS-?)V{aBK?JZa~iAc)JiT6bhnIf3d5e~pF<E3E<TY0FrA?mddDNc66o z6Yb%u^}}EqFz_|;x7sX5y6|c$z69CuiMf^2L9q+-ya9A0I+A1fq&9nfa6k|&uh8(x zljDHnQgy<6Z60`O@47CB`Hw!M{o?i}G591UP=+q}4j#7tG3}d)YQj?SAM8??B3VsV z>AsYqUigl(Ni&;wE4KLf8}S>%rlERhCkfSY&a;m3E~!)a&=IGwftZfPkeAhU9gnf> z>btS;4ln<FoiwhgDTXq*`6C|Lw2E|=23PEFxPG;-J#sRk!hexpI~Ct<6oXVx`vB-0 zyL{?T-=nmP)N><B#1%th&Xgb&%$DCQUEY!k+KZoc47@r!w-J^7u5=Q4GVJQkInk$^ zWn*4nNU6M_v1z26wTykYDVY%EI*3}&zqrO+?~{YFj_y8()n#y#eEZJmG(#t<N&R?i zTWORjJ7MKQ)TIw^Y{y?V&K^=BNepBVHz#p7whJg*N;7CR#p5kDP^qu)ok%=|Ne3-W zOs?dqEc$d_{!N)~OA^ArDKnqvgoZ|rqQgd;<-=@6sRmf=s79_C1&=M(4BeAWtAH2p zd<7>Y4AS>mYOv9-K)ncP?*cK1)k}+^nJ4rg1Lni*F;-8TRpy4q-22)!i3;}>Imn0U z<fI=eBHn^*KmO@msuTE;ybS~pK>GV2E9>%JOvrY=PJnuk^r}QFV|aeRlWHAUKq<aW z*uRQ(RBI}{8qDFcuAj$!Z%7ClaSMQYpJ1J|UE{PHr0HrNPTW_T;mq^(oKq)d!p#A# z0`CNB5yWcet;>MuFyiuWj81=2LUKEi0!pdbjwQbiQ^~jNHFL{JE-qEio<;=2NSmfm zS^D_Ci`0cC-h%)&@HMeB0BoB1{XcK$gRerg+suztHbzDkIr#MM5Pk_a4^@oX`hA${ zkrsGSefiBPLN93`rpV(h9n7@owM?;P{@B>Nx2j!rN7RM{OPTm|0mr==n`6JiN87*c zAWH9YD5OM9n|AA7NCyMiq*Asivdr|qG~sg4_2X^5LiQKkgDm$@qU#7h^-Qo|Y<zEk z8;p8?SxkYWwbJ}c^<wka0N!91<iJ@waAdS!26!xU9IN9dDJ7kaQ-<tD-XCHiYbIRa z4yb*vdkvpB54jm%F#60O`p^mV{EFD&^nN=u*t8<(^yF+FTGdQaA^n21zN*v2A|Y@O z?wT|>sWwKyWv#98zA&|ZzBj^hxPP=on|<WB`?loMm~MaW(c9T&L0^m6QdwULNJioB zKCO$LT-J)>D^18nDSqza=t7<mw1`*rTa!+~uqs3z$JBe^5ZO|=A8Cb8q!!kss{+Lz zy?#%}M*ezB4C9*DJ&QKfO^(`WN64DXUdEo;QbDuZYYjWL+wsfh%C?ZLjZTr?3&XJM zXquL@YM4NE*D1*CYOw1ws0!%KT=*|NnBOlt?FiGNWLVh+G72i8Hz|jAq03zi&4rh@ zFOz>|J?vm$k-uMAx4ySUtnv)-RsNSP72q0VIw^ClNfSby|G4$OI7ZxQmG5e^Nf<eu z8aXD##(qY@18a~*C@RXTpeQopp0@^b`@l`b>a=&_QVUDOW6Y2KVRKIA;iXcDFgmr2 zWU>?37HY%0_4I6gb6}UJ;ii6fbE<JO#yqHA6L_sm!A$!L$dT2lci4jwvq9jDQHt;7 zBR_k$v6)Kms5`Ytr`20_KknG?TmvZkKsgeQw(i;BcT|m<dNg}7_8wS2<#8T=M=B&; z*Sy!OFi$sBeL!t{_nN<AG+-gmAHWs(s!0Ayp7m*#C)%N-^I#{cfwsT1N(@|~IsT7# zWKN-+LS)1~d!y^}?~9ViJT#Y7l>33}5G~W+l4LWyTY{4M)E9a`UD4Rhq0aDZ{X>?n zoJZ!>s)w(LPAx8eHh3!cgYj$-Kd;>EO{(|hQu94`VDa66Il32ArMf1j%aGFJBG9`V zkGJx5uV$DOfpp)&a%ll$7xos)bE|^m&pD>CKLf1uoLh&y*Tnc8@MVMT`MrSh(&<CS zjcrZ`3bM9G{^<_M9H!Leue_%o#}WSM%gY_d9})9i3d5A}h@Wa?4-KNEmNt2+3p^HC z;vJIaO;-I@UMbylhQ0IK08vIkf9SBO(|q{#T=*pQlSYS!c%(w-Z3M?V>oEwH#G*Jz z@#0viLT*sJtH;(<tOZoR4|?c&|I-J4gYLVEB$3{)eqDgrj<bM6_MXp({q~Xq%)go| zA1=D3dRBpP*i-0~?1KwPKfEvZ+l8Y+m1rF;Twqe3DIU@JISnNz=4se@&PqPE4^Y`S zi->EVRs0;7klJW<QDc8Nwnf|mx!~-tS3sT&rfjeVhjJU@XXqT7ZSFTpY{)7cU#bp) zzBVviT|ah)1JV$_`HQ*7K+y`IN^kD4O6Gk4lfGus|LC6HoVo@Eu?hh`fax+Zze<J} zn5K)I*Mqf`l%qmNfqdD?v6zbNwwU0v*wN!5Jqh9Z@!m#TEvmUTRZYKAGC?Mdm}}A6 z1jd~PYqKPiDAxK8(<t9{dnqfFJDC^<!-+Sj-mSTV(a|&G_Cv%S#iI0gX52_JfXzn- zdkrq+9lNw(*=0mD`$0UZag!F!%2PPKGiNIkR2UU;;l}`QSv*GEIvm)VI!+3I`Lm^j z8gRL8UPq{eX8aA{sQ6ypbCvVAY+)BZ`Ye@j{(ryElA&%c!H#^HC5Um_U`N#gKV~%o z!O>+aTdz&8wnt{Wmmj<pO>*!fPUtrmt<SVp8xhX*OdYMJne{U|Y9D6#Ifi+f%5mUp zn4>@-OQQE&l=NQT5lK)KO}$8e2aRF&*czp?!Aux6S#1oXk8tn<QM;8dCAKkGWr>=y z=uZcnV;%0yhC-HcXq$(2Oo_(Vcg8Y=sU3gKWH4wAOhHiu)p|WiO_Pvyu=yKUxRCn_ zW<0&Vj2<f5%27Qqs%NN3%AK|CA560;ycng*2-NA}Y%kWBjFfO+tl>M@*q8dJq~u}B z?`(gBHS2qk`StP+E9pnQ)trK4mjL@*kuh87r5?~B&n7kdC(b?J#WQdBI)HnLe8L%s zCT_`-E8_=OAho}}Ag&%?8ZD|mQFk^)XT}V^F;%w(aYgk8sJ$5t#ox^nubuzrOO<)# zz-8Ol9qocoV}8cd0<%>12_7o7xN)-^?t`;JSg&(5*?EMQf*MsNb&k|x<@_HzxtWzo z^d5YtS@@Mko|2Ecp3?5aG4peoAm4q7q0HjQ0!B#>E|E-QVf2f&CLc-st7Z>h(~3N| zuA1G+1Yhf%L4BQaj9B-q@)9H6X=O6TL1DsJk`1bO7U0tMs^2Q+<hmu;Gk!5@AGIJ? zT=z^CA9K#g>l!fCB1AQ^7NvnhKOKF0C{g$s8_jK>`YXH(FK*FijrsVoQWccqrB$D* z?-Kpos&^>7#TTP#W`KbJMZ8%r0;mNWEtGDD+7^DX{aaF2=S04ykbVipyTVQtJVIwf z8)o^A(||~OPfp@RuHx!j_#tB>B97|X;%vditG%FQ*`+`=cO1A`^<v46GEnhTNlk!X zu&XCait7WFB-K>o3`rZ7J+z-xReAmFJ1fE~ma$H*)m90Y1%=ay-~_ms&5UaL*)*o* zW|19dzeHxTxYz4wSaJHEb`en{Ms}uo|2jx-XHNLwQuWSZ2xuOa7PK36Ec}t_NP)ZP zTQ`WaD2|u^KkDhWO1>?U)W!IcIg%QvD!+&&cbq6|5Q=WM$NES<Z{|E|<;Ube9o^!* z1WdOTMj79A(utZ+rb2DCZ{c_hsX&7Zc*>FxgXpB5%BZ)p%BhZt-3?{0+x!`E&k_dR zWamzj>!rjeD@Wf<mzb~HbVLuIL=9E|SFYy3Q)w{ABi3f=L!z!r0LNhBoMm5gwdeuS zsiS1;p7zx^Uz+tP48p*XxpSqbdvtf;^8G)0d|aXVhod_IjM9MzDC2EsknDQk-@APo z7D{61xN2t`U9^Q!AsI8e-k#cSJoCeYA5s60hRFB)R)(SHa9@<zeoT4UdRosdiX3P5 zZa}n#d&F2<(eepjKIZTO+H=2lNycJ|ub)6W_oeQ|w}zWL^CJa-lTY$A?L=uh$!ooY zJN^~s@Bh0b^MVH1=}a<HWfEU8R_41d3xcRx#lW^_t7z=QpJql%aUc1q6G=V(VPyWi zPUPCIl2Pd4ck8v7+Ri0^@>XhUsZxcyx*zmz=efZ<Gg~eSDec~C%(ibaZbGK0m;0$r zhcEzH(i~NNY@cwFOIvh`Oia(i;qpp^@iUS%^wE9^Q=q}$P(J3V0iqS@Lv+x~zjOKj z@8+RkXz0V2HrI#aqWkdta)34O>o>cD<gsbQ<kh`n7fFz&oGA|%Z+Y!OJ>g0nVsEXq znfdY@4U?RCjBlMuo?=K!Y+hf!hDc9(5^8YChP(9ie??AyQe7hLQVC>3kT8`mD;#-9 zJBdU-sW(jtcP6mQw{WyK0ad(Rg_)xyN140DSt1HEGA)BzFAc@lXn0K9i@%I01oYEM zr+qUDfM)azYl@lz^Pg^0E^-@GmwNinu7C42sIKIy&W>iVmQ5UW%&bXLM9Cx#&;)m$ zc;;Dj4+fGs0870s|9=9!P^iOQW&t0o^OfIUhFnaB_u@1KVWimdvw%;7J+4}VeLVk| z{yY92d|&75Z)@Z(gbnqRix~`{F%zaN|GWIuLHe`accK5S40wsiXMZ77i)AMCmqUe6 nXy%p^g(FksR%WId?uKLG%PtxEk=QGuzvr#0_Uo!wR$>1KeN!~{ diff --git a/docs/images/merge-pr-button.png b/docs/images/merge-pr-button.png new file mode 100644 index 0000000000000000000000000000000000000000..2f3793e45a17d6beddb14c1d22a7192f1b8f9d2c GIT binary patch literal 38792 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 diff --git a/docs/images/notifications.png b/docs/images/notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..66c1b501a7930557280fa818165506a31e39d5e1 GIT binary patch literal 122823 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 diff --git a/docs/images/open-pr.png b/docs/images/open-pr.png new file mode 100644 index 0000000000000000000000000000000000000000..0ece60d9fc331729e7c2d7347c0145ab241d8f6c GIT binary patch literal 170779 zc%1CIV}mHVvLM>FyI0$`ZQHhOo2zYGt8Lr1ZQHhH?{n^(IcMhL54?OzRSHR^Qb{Ta zmzNcTg~Ega004lM5EoVi006ZD0091h0Q(Em{E`y_0032DAtWR(AtZz^?`UUgVQm5c zAReBa0<NsIh8i-{brzk1a2B-f1%AeYa;Bmzh=iYn03^^C62|`9NI(Q+!XHkhPl19l zB8<FQpw0j<PJkZ+99mu81I<0?W!tl1+mp-c#QQ?;<NDIeaaxlP;4qXr0RLAC5Pozn z3Cx|Vk+8@Jy?qZbIyn%MJ-|A(YjH0N`6%9}jWiFy?4{?5dGpH7%GXNVu|3lo0KWjl zh!f+Q1w^hueIN~jDWJa~l6mDc(xf9sKQjR%e*cIWheHmR8HaDq&D2s*a4Qiv6hO|T zAtW*&z7M~%C@UA@nNTr-_4vu{D})#R<)Eyg0|G7oDm@L2Pl_C2CDsp}57JMSS!XL* zWHR~jn_D_`Cpeu_-1zt#U(11?m}a^89@}C(F&U(fU|e#{rG|}Udv4m>-2@O?+DLju z?g4SU+$&H6)0Pox+Q9v-mcD{y>jh9lP~^;geVPF@wKP29%ZaIHNW_Oz`u9GDVrn=? zz{!yI?q*@_DCqRD2({MkWRiT(5T;ulElO~hnJj{5_znY&lLITOl|x8nA${)9TK*uD zeJgH`VKyFZHJWi-xEGXS;Na7yvRz$HIu4~TD>R2bbk^iOtmY*$@iyKrSgSw$Z$MxI zKYcjr0E~M;jZKyYGtAZ!Xvd(=!9wZ~Do3kU7}8uD>rr|(mIfgGXSnH~p&PvEEt;?x zy~UtqfYl=c!>#;gp!7W$$5moBI!n$l(m>!p(6u7{mmaV@AHjga_>kuOxTOHFf1sn{ z&MM<Ou7S7%=paB0@G&bvtm8oD{Shj`E_zAjAtL%{YvGduiFV0LLCJb4W}&77B6p!$ z0c`_6b|KLL26kD}0F?AGf8%2d2b9Kf7eZMGfW>hbLvsk^#POj3i3mB!6Ap$7&vKeG zDZ?c5AIXy_gMR^K2h$3!{NX)CWQK?qxcNgz4@Ek_td6l9BBQUh`s+DxVE30jVHV&? zKj<x7D@^t8*a4bbkykKpJY0XhfkbkD!n{**mL$Y+)T0<E;h{fB@`8(C%82DCD#4b* zO$DCvZVJGq4vS{Ys4^l<v!dqUjqse<Q=(>n*#5K>Ow2W%qB^s^(|RKC1boNj=_k>H zp?kp~BL_<iRt}>WN-`{^nNFHa`b^TBLPZYE*Kw+2Rl>7kW=82mZpH8f+4Q>_e$)!B zN?^m0#WMAB>;pMaYok^pxB<9fy8*g^vqgObk?pD69lO(c!{o%yjHK>g+~K@(y&`@x z3q<@8sU-tJVh_UZm+fZ|<k~|uNTZiYB0WdI2{#xt-X}H0sEc<`e@%ML5hg54ycF*v z#-)f=7Uh&^m&7FYA)SbO8oNGJuMg`C)E2rX<|FJWktbhAL6d|biL4J)6l)XqkbNT- zNTyHGm$WBll~fjQ6yJ<@Cz6O;OmI%trbwsKp!CqZPdRKw5s=gx*NGr$5-1luuT<_? zEM!($m*$k`l=19v?s{Z7Q^3fIYK|&_5i90DE}bMvC!mZd7jP-5FUu?&DNQXKV5XJ{ z9WEqUh_E0t?`nk9z|fFdgIHs!|5blt0)9%~&YCSDS9DXDo6q;hPb0r`&;`<MteGTQ z>YDnEyoCIOa3q;3!78DH?nNYr;D#cXut%#~<vSfnQ$UYE-Jq%8Ab0}mAc9#0T%_4B zexG7!M6x!aTQO{2v#3ClEtxb~C8;YJbR0a1jv}^VRz+JmLFKvJxiqRwQ6*d1qufh{ zuC&{5lu;X_EQ(Q-%}7v2VoFS=P_=Big0-r;0Jl1)X1nlPI<VBBBK}XET7i_2ppps` zzf-np;IR?S@02Rlgk|3<+^X1h&h_|pttPD|F_%N<G|o0oSWY<?iuUPtjCPgwm&aPq zW={&w&_~;gfp^t+iT7XcEin4PR=_!Z1cAIlQF++}JGJArJ7Ly`mPs~?`po9iY|m`d zY_=@EM)?*<M)ezoBZnPj$rj~j3=3qYjHcbDZ>CqKH<M3OYsbHiU#Q7Zby2Zs)~UBO zG1VPu;I()g^EE-$ZJN&O-%V|dXc}!BaU13u!y7ov7wn`OVC%PRy_VpNPE1?ouCunx zysSQ`Ka`&RIM6u?*%!H@XqPm`bv&)l;tJY{ChF!Ldc*fnP975%{2MZuCfdf|f+Itq zM~c=>232NQ)}C4~u-KH?^0XQ@#N51Ip02ZT$>Hr{31fBTFlOv$9A{2+&vnCfVRezW zRky9WxP0h&eR(^4-qXjWSsP+F_N)#%wp%u0FVW7`u3!4~cJxknZ~?$y!7d@)+oi2A z{4}iaA&kMUA-z!xk&_S~t>{_V$y*6uO~N!r+v9TNEl<m5-)GC{TWYfn<oaC(MD}zL z6A<eVT@dkzcnGBk!Ski_m&LZiRKt!%T84HF2@T7QNK?INcUrvJmnoa+pZlP)e_5$& zYn9b9x*WZ!BvhzZ$c`B76CRu&bk_rEs8o)*n|}7aLN;@G@qMt21UIBI4Z9qs*oz@y zBTFKQBI6*x5XX>kkR_8wKWus&b+(N0j)^7k6@wHn7ETt57PA)ZE$q)v-<!Nrd|o>z z|FvR#fPe+^^zjFHjr4|tX64kgAx)}BttavcOizl%)fz>Z)2@<q;=e3h2G19)3RiAd zHYew1)>4=fE|NbUG#@pe*Q;GDFIcOvv~SwG9f2DOe1%p-qoYBwLLWLGEZGp*imcyh zc9?sJe+G_6r>;Q9K|Mf)v^rauQ6y2Ipg&qTt$FT&-@&)xyEdqsaaNzZ!jzo5RvTLz zUoTvrpD*|_zSN%&CS!tdy11&`aJPfEhIXFxTOO|0k<Jn}6Y_Wfy)>U0pHZ*AYVDS~ zt%_2L#Ga8~BA?-t-cp-zX1QxGdROiX?>~Oo{*nPthO^~*y+b&e%^si)#fl}zqu{+i zBHNaOr|P28DsQZij5Ulk#q;r?-dCTQY35r|p;AUu^Q+iffmsY$bX{3nTw0=9y0P}h z5{5MzF^b*c-E+vVnk%iV58qbyM#@6T_I{Guq=T1z%Rc9{@oK+|T22p~T0G82EhQ;2 z$!95Z`9srQbyIn>R_z-4e5@DkSH)4{TD{+S`Ie0{81p+O9l8yTlnXTb01cTA&ZX+y z(~;tQzUzATdV9h*wMO@@-LY(>>7-v}q~fG{O^?fK>)G=H_5zEBt;&}5$Mi|dsm8@_ zf+kbTrsc}E<%Q<zqV>T0WM3z?L+zU3W~;U5(sw8D799S==mQ+r5jTcc(&zEn;rZZ< z%tMYrE;2`ghsvk=vGd%mYbO(|5_}ro6K2~R@qK>`!Rz!1FWt`@ht^%fLxVG)Q<2S* z*VA^=>hihbs3t@YT30R>?VIB3q>ruLZu;}+eq}1WG<>h6zlG_hxhK_6@1gHrXvKK; z@S&`+>?~F!_mFSNxA|-Hf#iN-^zpo=wZ>%UvAfCd<>T9#)W%e_7peZZ5&%kqodD3^ zjRinHAMnpMm_IqgP5cQ^#><lv$al<%&!aYeci}LozeWY>EF}N0dP^c+5vVbIVR$FN z+TdXJAB=QJ)Z>RP@v1NuitKccSa+c;T!5W-Gt*)%Gt+Jrq5)p8KTek0nKNK{@c!Hu zg(W96qKvOIui)ADKot4m2S)$^fVmdR>dxvi(ws(iHnaxDc7`Uj?l$%Se;00d&cCWQ zCe8-<?l#u8PMq#Mg#V!6{Hy*qnvM|vA0*CJJcQ~p^7uk_jwbjlw9K^hguGDr`1st8 z#-^N#!lM7d{ujhUXzuK6&q+t;=H^E0#zbr9Xhz4t!NEaC&q&9}Nb?s3jgyD1vw=H} ztrO8dh5UbVgiV}`94+jfE$nRZ|Aq|=?OdFB2nqj#=AY%CicH)s{*NYGr~eq%UjwB3 zyM>N{mY(i^%l=#Z-&jt03wIN1bzut|6I-Xhbnr4Tv9od0{ijX;DXYf6u+lR!{VS`+ z|HH~n_kRuPpZ22r4}<YSant>8<MTq%cTxT|Bm4jo!UD?ffS1|O+Q};IKYq0a6Do)x zZQ;b?l9ajtBIt-BG7Hv?k<-jB!{^dZd`nq((uqn+N(Cj~E?G*?Z)Q%#6JuoxOf*xS zJLCw!G7QK<^85%OZR9VoSl=@Z+h6_L+MU6IZ`4~}J*iDOP0KGjHxt`EFCMujsoAL; z`}(#5kvh<mrd;fpljikIz52Gl*ZOcnicOh0R_Dy1Gp=v|m<vFk?dca1i1b%BVYs-s z{O<#vH!wy~ub7m0HHDe38VZoKr>D1b?iG0GOT9x-z1Af+C<=6-j~EhtfM-`XfkII! zO;&_2o|UnVtgQ31l14)Ub(q%hBWaZNq>$H&TxTOKi#c&hDW)`YP=PPYEL@+b%&iMK z+mZr!GpEcQ{<LRcT4eGp$)#k%niqSH!AvTT25d|(DWsEvi=E#zG3{q$XJ_x}%Sk=v zi#i#N@h*)-PR6p$O4S`6%VTU;&K+EJ<|;BZ#eK6O(|HYrF;Wc=M!r`$&b9N<SfFCS z;1N+y&{YRMm)}#uKjpF|ejS_Y<||sqUbfuc5vp#2Rpl8cH&<wDgPR<2UY0gZEz)_> z4xpY+<y<-7S}HN!HIg-dT8QP+c-K;sB*Qk9zhpyI088dR>Y;0}Lla?$IaZH7h0#WQ zs!3L_ISVB9Sgr3^V#40H<aSfrC)|iVK1El<-Qy%o!@j{$>@*y;gnjB3T=;($7uiAH zcjS%)m=ird`3q;jy~nS?C>ar*V_}}kk)8Q{x|F9{SRW@bV}J7f1e9lJKDpFzZEx!6 zAiOQ>&6yb{&3Abw!g;)WzMU?Vz>npC%`;=Y#Wns3XBI{!KYNMQRO`1!9<!%LstXhQ zP>-@Atee`M4HBK_ylO@GaVB<{%7H6SA5Wki2Nj300hG#fRZeMQ13s&sBHrwqj=x{v z|MN*h46#wCDJDpftZZlj4H*XpKE7fcOR8uKONu0gLlFxMnOzAq@5&V3v1utbJ|_sI z4;@}l&!)&E(Mi&mp4n@XIp)e#wa{7+qsT%{K98#!bR}MDB9OE(bJc7l5WgYgLJvM~ zYJqlC{F^TcQEKA&Tys@P>$Im`ot}tEWpKU(N5B*=gfyj<0+EQz6y!Q~I7~!$Jlxch zH?rfoFl7TVQncPo|86b*L(r8vO5CP}-q1nW$XHBlP&x``5u$mT?=2k>uK<<v7LItn zVuzDDp~9&DYERQ5x%+iJ9^G!nMFEGK+F8`QGQA_fQz(Po++ALGeTL=sPQi%3L1b#* zlu}@e|Hyr5dUB*EeHau6&tNcA7JZC8!AYiC%=s$Ws`*nVvFGdlOS~IzZEeC${4Iy3 zN96D&<Fhz<=PN&2TklJ}jrEx`dJ3Hf5E-6C5A7?=h4Q<qPd2klB-EHg&MThxb)zKb zwIO|wiA!-ML*kK`CU%ggNSU&(SJtDZHcH~VmiRKhhUSO}GB!vWIK23|@R}vjj55-V zdc97#6oj|DF93v(Qjlx3W1b&>RB0h+P%OC>=87p1p!7bmh5Ce{7E|JhO~E5LW=PR- zi6lA>OZ2Mns&iU&bs-f*HUZuO&qZ`BxHJ1`m6U|gN$paC{_yj1Ndk+7t8ucQf~_JL z(B9|KaBpq$FRrOYyyr!eH3f9Yf4KeH#FKdS+P$01_w#}qT(<+oPVC`FymzQE8Q?$c zU=B0-LiFZK{7*C=(w8`MGhU@oway0vHaQdkAC1W?pWNs33^rKr_CBB$sX!8*j$Iyf zH4aUp9+`@`-ta0{;&+)m*yUI`ZakTRl9GZ1B#BI-vuYs8r2l<?k#*q$<&5leJ28)H zc+urn8Lr(4XB)3$hYcZ1k`Mda-5V*A{}@@yxye|vmC0AipkQ?%GR=lkrbgkBJk+MC z>yfcR)(v>A8!6v!cv~{)M(Xx?)`%B=k1@EdJTp0cR~p+q(K?$Hr!}mV92Db-MgH($ z(`%-;Ka9`@#8JlBV{N1>L~W)MJ1p-Vlztyae~&TYChnd`%QtfLhUHC0swZ9oI__^j z2=gU=k2km8DiEsH>QJ>Pe=cm{{Ji<NxgSj+1_|;<KmZcthkyVi!2eGGwlsbf7Zz+R zY09k9t<^fCWV|z2+dyTq|DLb)4AR}xvwvtv#AC&=mqFscmj6#+78qoFVnRVnOKMMp z;?W9zkxm8bzoY*P;O7F`*VupytNb4bZBYV-MVW>wY=~zxfrTr(6c&qc|3}GBPfhfh z8kNcP5LdIK<^QdL1pk;ph)=HP?9n#;4?VGl2vfHT6jJ>kEY2guKluNP`+vl-uU3wY z!xHJ+*~O-$pgz@CFZT5Tet&<Xv)ki?!Q)2d3562k;{%vBV6?ThjgF5C8W`kxCMPBJ zPESv_v$xk<B})AFojG*@5w5(-6Pn-Lth97>bX5FJ9a%pR0z2?WAP@l^J*?a3qkn2@ zs@TQB!NIbty&d!D=!o6v7)CamGx(<GN4Lveqs2-|{(n&N1adhXgR?Pzq4kDr^{1eK zh>(bg!Jr=`3YQ17udk1_|8gi2O+iyL!s%o>pv!C~hX)$fMPu;k`8lMfhOV=-Q=b`A zYfM>LdG~NEk=^+eK~YgLE<Js%T@LlXQhcjKT+8=H#g2}1Hf98Td5Y&z2T0>;URQ$l zRdA9qCq16($(WvFe|(a7b(!fwHQ718KdPmyOUuVgd0!GH@xC|#sjQ+B@FeJKsLO3- zciV@_>&>1*t?_$y7UA*ipwN<zmR6O}%GK4?Dh(LboKCxSHqXU-77Pack06nKT9B4q zmx{-6NJt1FC#PnY?^A^y0Sn77sZ?4}uRTem|H4$ga`F5|O32t*QRa+n35%Ba4k^FX zkqoE&3+4oZa}P`6G;&ztiVbIIBZ-d_455L8Q>^o%qDhgH?GzKP<l^HW&qhT4axE<H z&g1Fq$PL>L*tfQlG2~~j%MV6Su^4QH?FJndkyxn-2HQ8Ff$io`PVd)R%KmY#Pz7`* zQyAaphFl6jxAjJg)ix(G*PHFCYg`A7|16H(E)dnaK4EUQ*!Rhm8}SYC>P!K)Ykc_8 zd~LVeP?^r8!<vz)VGV+5R#aCTrfRmfwZ|(%FS4Z@7)zuuCy+WpV`iSuEv}X>uW?N4 z&lC|u2IP?78(zU4&fJ*`Nhq@{Y~_5VbGTo%nb}yHDWvFKk>M@`t9IL~lj)v>k6@nl zJAS@8JiVXr{e-9LdP27B_;RgArVeTTmofL10*O8D{?}(Gc(0Q`nx&=X?!iG|dpl?0 z<p+`$t53{&MkG3eD|L=`Cwk!T5ONS2;zia>OmRQJj0_1af)Vx(Q!c1f{_EC+Abxmc zgt})iTmU$&-J6rx^K#3{ux$S&<l;T+bGY7Je%yv*I6|9`;-*|~X}z1jj)_^>*?+}& zXymr*lfy&uxs{zAz4Y0k?dNCXtrP&K`K~mZm(h&>+ljlvdz;*Mo{FEPwEkW|yg)m+ zl0p`~)e$dec<2CnetcP+>47zg2@Krs5Q1M|`=4XdmG6FbyVrW(iWc<2pd#jlwcsi! zobwY__?_VH1>N1au!UvfNI*O?e>;df$oumZw3{27^2%a<Pa@9u%t7ovUpE)n!B7JV ztw?a+bv+Ar-fF2r!EB8lpZCw#3pqJ?ZxV%4t;qyx6gG#V&B@r1dgao=V!i){M*Z{d z(#wmez{+}}I$H75vu>;$qGb)ZN*%@jnTLSP)Lx?rzQHU6HuaxJw&WB253R_%>%N>5 z#+#Q3hBYQUJ8BPLj;+P43xkHt3{$INc67IG<k0#<Sn;unhOHH;WgxQ6aQ0Yk>(vwk zrjYh758FUQJiKUvZ(K{o%;FHqtas915+hKJ<uEy65m+$^Lf~;~TN_<)*$mviP{VL{ zq0nVGGEK?kqntrJXC<@9H1JVf$aA#mtF;ftEqKinn9jJrxlV?Ai&(+2*l>D}MB5nX zQ6Gjg>H_XH^%`ik;7#b=;Y2pY(Xb`Q`Q;`vjH+uyx5pS?;cf*CglHn5W%sPNF``;Y z5csfopaMI26l8E4KH!QD)`sNz_{{0270e|91Brsg?1K{nfwM*-tHX1&tF20JW=)1j zhXJ{kN%A@ewrN?lS00ALO1X{+2ZQ%of^F#2CTh(FWKo*1E~kYI8MsK%RW!V6X}U@y z!6uHkg?pdd-nSR)bM3XTVV>Fblw!|>eCQ8$z5yD#kb`@VIiNaZsXM<ndcHC<)Gx=# za)qU(VN9p9!o$KKjE#-)d3bc%-Y!sSNx19jC-%ww&gr_czQ^|Iy)IqV47IEuERk9i z{B&g6o;|X&vUV>nDo9N`P|)Dv;e|y-DepF>rmDIyG|>Ltb=5?At9r<yKD!dIDObz- zh2xQU0tstxlVk7XM^)0>;nK+r-=iRc#6$$F#)Uh(tk8J9UEkqLE4rre^v^xfSkU*5 z_JQDyGG`sSDmpbkMB(XL;qMC+oW2q^;@r9G?K%6!ORIPjBM&s%h?_m|sZB|Jeaui+ zzedp6;R*)&8TxM=X&i<d_4s~sg*-3XQ2-MjZ^gFK`=Qfj<<SRdwCdmT-=3DKGt))* zI_<m~JHPx^vxo5fExx<zfPQ)n^b$aXxaah?jg`eiUbDgy-O}se00A8-YJc)=xPtRJ z8gCGW&Vn5X1{+kv#xcgR(8)`@2<G_|sAKahLN-_M?rg!{?Ht%HwwvDw__Omp5jh(X zP6oELqC4#Vp$LUG532Y*roOrF6wWP{9;P$mTj$NgiN+n~_BQ`O1T$ppKB(!LZP*_! zm01YiR2DWAT<7MK+tZL(SL&xQ%6)mem%)CoAN1(Sk{R>tI26$27usEDdOW-LyBoRQ zm!E;1S@9Yq*GsL5+<GFJ-0uliW@daUD(JPfwbv^<zY4>p?$7%PN%y1cT5!6^+ROeO z4JdecwSJNlgS!Ny?fR<udBx<dg$3lFkDi}MwjFO|F4s!{uU6d(vkKjm;3JVp)V=SI zn~}e^Yc8vlDONW(Hx>iTm*9^HpP8wtrZK0sUtQOOgTmYolT75aw8KWRJj?5H7x!6g z^z^kXru31`AJ10}(}WZM9;bIHA!}QcV~bvB`vs)NK<WIVLJPPNJM=lXb(#mpbs;$5 z0Knmo)omJdVCEQ|_dq9(J_`1C`($67*1muJVizY^Xl%r*;rW3p20s$A0+kxe;(WmB zXtbHa?P+OQYX&EX4<m-kcBKoteCcuCsiJn7$sc-{yf-jf;O}XJF-2P8+OSA`uv8Tn zCioQ$njBLW=~M3e@bmzoLMV&QQUWN(S|i}8ptT{od1p2F>P}JD%xwqHYWpOh63`S@ z)U+o3WicQuC23&ZQ1FtR{yQz<VE;+#kOoKKTR_GvvF<!lx+*70S$K;B9`_N#`=k7= z#pPrqFw)gQns&+aJ=(4?HCjfcOyfbh2n$5nh%L6F8uKtb%pTsAMl>-HIwTf$AixHd z^eW;MTRH`BCns_E_YFtW)!f8s@%?k<fGX01O-Pst*+~-)nP=Jc$06j(L}Y}5Yc)FX z7tk12%J82uMA>4~4ChJzj7S&z^9^{>`|2t>3ejIfO(KyzpJQbcOH(+}qGs%v*|VX8 zo4m5q?2hLPuF(hGZ1Q0s+ml8EDPkRymP?Cg9s@%b*y!fc>UY+9-w|o?-`hzYnVrpY zO?0*myr0h&vs=fLsVkQ@<KvPuh<|UB^?Y8>)YG|q@G&|QKxJdo{=P0~wflKowY9~N ztB-04mYL+lzj<b4%oiBJ9Vg7}W;#2$TW4_)QRzQkZerQC-GSlxKIy^WuuBKUX$Sin zIqKNgG~TD|d<%l)V{9e}NxX94(CPUh8-HF$`2MU6<#y(R>iE{RT4g&kB(-SJU3fe? zcFxSrAyz-S1JXIoztll&ZnHuc`MnO{(Hn=MzGgnCsjBWD#PSXAd_S}4s*JVEUYKl` zZJfwmgL{!`g$C=_Ws#X36t<L=l}RKYKo{Uj3YxTrwDh_0#-bs~xZjPb#ks*A)fA6z znr#nm0+QYB`&G7HyXeSt5ZC<Mt}fcU05zE5HZM_`ZO~*wsOx=WF$i{sE4L)B*M%ab zoD~$Vez)cXK{*pT#)guUkrDA3^`zeDZc-6FlF}3UhA2>VF@%wO@I7Q_ezD*e3-8AT z+?`TSe`NH*HF3Khf<5W0k8A3lBjEYhF~-Xz<oGM~7Rpt`csJb(jVj<xv6(2>6N_%@ zR@jvn0rxz7zpIAOCvNCC<12$7=M8<^%a(V&JvH`83eBKMv8Kf6Ewo2O*y^A>zRu?t zYEN@s6CIml9|t{@lUYniN74Lx!;awr8hGPKd$f@KOd!MPdMg+P$@)!L-`$IT#0-Xa zV+=0V$yZO5fQc%kcYolX;O{-~5%1dxce<=`EBqQEzbVTBj!WGZ$daV%vna#`Q$kYp zRK<+A%yw9=*sZjYq_6z^u~1az*l|;=yc8_Y%SaV{52dF?^srV72lfsp95|FT2IKy# zG|u^XJldZtTk8+7L9_B<+xx)Rr%}7Rxe#D_xOD$EC9&VR%g4$h(r(sV{*JJD&2=5y z5-_HfxWplKq(v$Qg73vFtSql0(gRm>eHqo#Jv~kfu7+l!0VFd;v5<HVufEBnOds)V zj(Eg=uWrW697OxiYhk#9%p59vqpF6Qy?}tNzj)IeM}T1NS435>I55>vEO$Lapy}ao z!FdJSB(UO<UEz!2B6{_ONSiWQH4|pSELsC`qgRCUB#n>mV<>HEFlQWyXBXVza6x>J zoA)*yh|Pc;5(kzzF{ceLGU(*_fk?gLWy5bmd8}CT0N&f=0cvjPC*BtQ4>~9gN6Ri2 zE;5{!%&YBwr<&=pzc>^^4os5MaKxI<1D9jc_Me^yA)k!L>1YN71z{9|E)Faj_J)O# zKfXK)R+Z%l;xiY7J7<_K^YGfzEi<O@qWgSsOFy+_)u@=&x(u)``OVryzk<H>R#1b( z`tIG{IDu90jW%-HK_oQb6;EY_=+hNTl$9ZsZLsd6?+{yb`8v}v9qhUfzH#BZ?Wm^Z zn-NM^Xl(m|fDps<!*Yw8O=tC$DU~R@1M>dhT>3+sdIhbi?LCQ^9_;JP<j;)(yV9WK z`_ob`Tg?6u*d2LPQc^mz{Se@O-3^rdG>%W{vK2bDWhO%v(Ks}YPq^4GjEuJ&s{ejk z(L2Zs#kG8L{kk21Pfn#B={Z_M)<|0tLZ~fW(=9d8THbD6p77++4w<;;MJ;(#YAM(_ z>3nC^J^ubYlk-#bc|FdwyFIU{DR1rEtnvF=@f&(PTj0o)Tz1i<dywt2{XXQ%d~a7x z_%_zunm?-lG`wpM+F!nn#Q2FjJl%q?-rhc+n1QczA~E3slh*+Zv=i4+o5vj^`q!I? zzErPfj{A8TxlKuUOUUj}te&Ev&GYt?`$g3gyY6*JX>bjHtY~ixh^;^#zbn*o%{TVi z;VUKz1Ky1WBenW>9g=0m1C#lWr}3fM0GlBkuhw^5`N>eIMk!4Rdt1%^l3Ozoo<LZ1 zcI7ihG)i$_10OfMZSRR!lX{{x83_^IucQOV=CzI}o1oBk0xlv@tmRAji}B)e13+Hy z;NW$~OPwFMZH*qZBU^#ApK-5UyQc?TZ*|BfjE$YXhni|p(K<xLy1JBFnDJg%FQ!-F zJzrEys~LSfNSlt>!~P*ZV$^LW0Z6|~nG?|jqd#gJPP1SISlFj*m<E4@w_OkW(4_@! zOqLO?WybSMD9#Wscy);vp9Riis#dd8q&#Q%qatsWNTLD{#7nP255~0We7{t&`OHM^ zC$G@gRfEUfy0$mD-{a33#Cev}*_xWfY7oCl?R2LXm1YnnOL^Rk*;M^nGuX3(e@5qS z8BPc+b`VLPRE~TjA14VDD0moxgEWaE6D!n=9<GV#5f*Bx+=+iO-mPi-(j_T5=rJR4 zJpkNfBS&ugcv)kgK7=>J*N7K&M<s`cpRnS+J7M~W4YwEsJBl3JjQVl=eZatoCJSJ8 z=8g9>Tr^KXQ7vb@Goz+5-H2M|aSBSJ8WtzcOQFG@DEhCfwBl2=AkpBY?APLuR)l*M z!`7K;(^9A$q6X)bM(WMia1e=@OK7JD3AeRTEvcMTIud%SMAYfM_RlS8V^4U|Q7%I# zx3ubRHX0Uh?4`4@e`g)yIB(9(sy~l}^{va0;$HZeS9UZ=ZhO)O?MdI;T5n~G(wqg} zIuKExAf23TA7boA?HUB!7KRVO6qY?+UBHWRvAue}_bcl}V%{6tFh2IpA{rqe;slO` zGa;~%#CO{8j7~J8Hn}{Nw#tV~dP21}S65FAd%UrgIeCa#qGE1>8yx?(s3M?^5{3Fg zm)--DtS6Vl48K!7fz`mq789g_{2J3@GyFO>&MMHmWoQ|px_PoP6b&6GV26X}zK6h7 zr~#*^p`0zh;%)WuM28I|TJ@+G_5e<d{8NYr33yl86#yQ=!^Y8lS*g(=E=?j3f9}e> znpc<y%I8$pw-JeSmzK&Wo%{2vnq;TJtCaN)9Wv%pVZs1JU76eQFbv5=BhF;bflBAm zMSzu>8fG8_7C2O!-S@NgT*r$bal&E$>e66b@Vs25!hXl+r3}55J0P9*&vZHy_}{4n zb#v32jsAW?m6RR!#=gZerDXa}uNPaA@^dZ?_3t4%-@N@E-=`%tOQx3OE^UrFw_7?3 zR8iE>HDLFt3>Hc4<92pzz?Fx7XgdF{_?2p%NVjbdF%RI8k&%j7nD6iJ)`J+Xq*TUG zFMY(!jXz|zSaQA3S1mh~btxCi7!J7GBMyFTIM_h@4Kut#pggFqO?jw~?~iiN8OKH{ zl5#5c_1@-G=UsSB7)d9;mzt^c7Oysv%nzG}V_fEpodeHqu8PjjOIW~GmN7F`M<f0% z%L@*4$RM(RDun{QOqy)ATeb2G96v*t!kmBq*m8TyIF;!<5CY}hd0{|I{mPSaC9c3% z8{dQT!uytCy1(Vz*>XVw67OaUF$TCmlmxihWFBtvBZ=hiM!-slid+Y8TUZm%47{^P zaM<*Yi8@ukI_FsNVhNRXdtJX2CKKk*;KZWq9*u)Wy1yp1?yI(D0_>HW8*H+OBipmW zo3x^TcvCWvy1cN{j+Sz5FvY=k>B$WR?aPNqp?NU7!v-RNu~GNx+q}kPal4ABe8*Aw zW1fi$k^cvR#Kq0fVA3AOf!9BgILe;UO`dCASZ29w`tk!|L)OwTwqbr4v-TzsmVHc! zpaz7%C~&MHhKD{<e|#f+Nh=gT4R-@~`vyoB_Z7^*sen2sCh3Ti?5JnH(4)XnMaa$% zAQ4=n^ILhVY4v4K%*N-$1}-CEGj#vVvo&>B`5o<1F+Cs=gFKTPb2!URocIv#qpX|# z(Lsz49_>(JI98KMYux!F6cT*d$Di;%1zYUEN1uKOy+{q4r~CT~?jC9ym~a@ba3CuL zRwBLpI3Y=f9>yDl0dc^9JH-)nBuK85={0URoO66Q4_zuI<z#-@NGpWY6RnD?NLa#V zRQ|hI+q;%P0y<dU83Hk~xL+vR$J7}o!3kYdKGV`^!8}QU@)fKNb`PTX%{Gh4wcHgR zcUrD4XXxF9i{_vUz^vS(ld4IDMe@n{MNIs}DBVmL#zQIfQY#dNrF(+j`>`Kxzrxqk z+=LHbPO~c3f&ej1){s6H_aalRJm1#c%Ca56E07Du=RLo+6iy5ducSSL;e8p=-pyRl z*Mj7Ip4g~GREFP&>5Sko*s9qHU#2ja6xFFPlQO2TYqqJia&x$DqS?Zm)^2{<<Q`9V zWjE@B4BUu)%Uhf-FDt0}Y?9Zzaf&fLOW~onNt-jS#R;|<4l+P*SH4weROmgRAq{6G z=VghJiHOby&#?j<fz=jh$gCI(-sR#Bbju%u^U4*5INke#lUIP|sWfrBS*?DV3o=aI zD=>CqZy;1bSGRgl71d6Io@GABh@==*+O=x9oJ;7g^n{9hs|6JpzD9_tZ9h>}3JvD@ z+qxsIq1Q6oS#B=(>(XreAZ2J`0foP#VbG9fWlDl>1gMP7<2UNBUlf3;1Jt#v<Na54 zMkDlI&(={mT&f-iswygf-GS6Mby{q*>+6iiklKx~Lss<svb*Im`xu-xn00%6c?5-o z7<@n7f3*i(9E=UKdjp4B>Bl?w2SFZ++@j*T?*g(QqC*e8y}e16ngk?c)alp~c_D&> zf|j|U(mp*t<o;+wPFtsn?CyMByIG<|)=y@F>Yx_4>HXZ({ro1&aTla3=QTQm`|kPc zjvx5pN<;A--m|+GE=1!dM|GFo&Z{NWl;?hb^utfRQ*~%uE<9eIT4%_1`#IjDZ$2gP zi51K+E3z=F_XRp(>T%FuhC5{Wt{DG1Nab#CSUc1W+4jNLhqt|1xMul-+m7JpV@e97 z{U%3Tlp*NdY{;OBca$t&e&YeMc-VKygTk9a9enmPc=Np;%tK2m@ozZ+Ovu@SFR!x^ zM{yKFa#VhoXV=ZAQqnY0(Rh2|F{X2e%k?LBu8$NtOUsI<d*4I()qp>Lz8{@+P~K=0 zdhJOEimgp$Il_Cp!=fkqv?`wWhrp2#;_3Cea!AXFkFty04Pc?`m&X*rJ;uwOH8%Jo zT<&C33cxIy^Ko}XfNVNo4wK)n_f;T%ZUG(9C3*)wJu`5^)DGs*wrx`1-Yd@up|oxW zG(}C~Wd^s;8>n4ii5ZqK$e`KL$SxGuQNMH&g{bqxy5mI>mSxrj6GiS^uy|pi4}MFi zPz|Ir`b}m}?8^f4r1=>keQ^`sEkR$Nj>nFm850w6jPOq<KW5s@nhyrGxmb%!aJu5X z2ztMoPr~3<J*yoT8y-v>5sP9rRwtyAeC_6`AwFMm#hf|prExQ<AK8>o4xuq?b&(_l ztuJ@kksijUvi0cOi|Vhc4=Q~Tm5dM_bV<9{0tx1{#Bw9qXxSuoyjPiY<{Qnkf<^Iu zOUBVs&ijp7m~J@EaxSg0f-sA+e%NT;2d)5}4FkJ1tRKb@piCt97YI@`;`SZRS@i}G zI_5LV$J7I5-q}{$EMRG3<>5(TQfuNp=9oLUSJg;YnLL7aQCD4bb?bhyvbN{97lVq) z9q)EzA>Aib1qewYQ;scoI8L%hXkEnMNPye-&HZXHlNC^cmZ4ncH^a1mjXnlTJ8cN* zw9+7(YeMS6vdLX^>-uP{qm32B)kpAN-S~zAd%U%PMnKyPm3?U-e}Ei54M4#zq-dGq zrqf|);Jnm+!j0CD;x?wta68Aob~onz1Yg)mrlwOt)2k7U6Ve7*JF2@uz!t(i(Oqp| z`f3k5ZqANx!V~nLF_2)31As2Q)Zwz2C;k<h9IS*&<}uujl*lvO#%efVZ1&kP(_`p2 z3i4Xy193p{PB`?|nvF7pib5J-`|d3MHJa$S-e@tt-R<*{G+MUNGCe71XKzn`Jd<0~ zDWkz{BBvY!IdQZ~l>)lb<@K`v^|GTT@^ZNr7|Z(((X#DHHJ!~Bs`vB0LRo!D8=2bc zw&N3eG?8j_FdQuz6de<zx=&?yGKlQ8<ut=XiF(=fvR%=SZ7&XtYS$Ly_x+IDdQsh> zIi$FSrT$~wm!_BX{lNF5<gr+Pa_jf=;%Bs2sz52+zvZ?Q-Pp){)HW&IVz*O0Xq>Yc z<>BNG42RffNE<4u511A^l>75(cGNVX+fR+_HY}~OIkd40I&<KFWU1hRq}5zJK*Eii zNCcFGU-9cKluV6Uq_PEahvW;n<FvzhzrO?V<5q80{T(17Mz7ZfnQXsLfvR?&JQY1k zZ!nQ(L835G9_wc?)7?0qO)`dTFHvU%F~^;aRPGb>J3{gEdTP<NN^&sMFI`F@-ZHNH z0=fNy4aLb!WUrdUF8_IstTw(|2wmq?@QNYn@@j<dC6&<dT6z;z<QaE-;AXpMSmNJa z+fGS=s7+9ep6X55#dFH->^#D;F%0iMMpt^LE5H|K03Qa%8lG`BJB*`I*P{fTj^rt5 z#@B?UxGF`G#9{Vt8<&2e3{zzfrf@)Dq8pBt_ym#1Gvi?>i%s{LwE7J&t|Nwfz)$u5 z4u)iITNC^fs9up-``V=wU_*Rr!ud1Ft|YtVBs8qm(`V?2ea!1{$^iGn53f`q7<se8 z9YHqj1p|#bDdv8O%^l=+w&NmRDXZy`GN)PboS*ake5(-4e39cf4ZOzE3<-KzR$}Jt zwx_7ccmcigdd9|{*0@I9`J#|O3djXNLi8dhFSx;y(OGWj@#+5g$6mUP=Qru$IKR#u zMTAlX2~odz<<*LW)+Bqf;C5qSFlIK-m=Zgj!yW_rMPfMcrB10LR{DJ+g}M;kcvNqn z5kv5Pwrn~=7z+ic=dtalbMeULSl`L2#MH%-cIfX(6k_m@cr`K{L8wG|iTA9LVCGLB zp%BMo1BS@ZAWY1~ggiA5X=xHOi=ZG45H6oXXQR~W^&}HR2Fepe)W9->X0SzJBj&e^ zc7xp`vF#G)%_nLY0j%)%6e-{4Y{=9}S0UGwWG<tZZ(w#M0XU^;+gdjlF(n}$+2mzH zzXM(O7dN4TK1d9)7(!lG>Ws{D`3X0X(T3%`Hb7Iy3Y%gTUnF(E@z#bACH2E)<6CG^ zJWZ+!<KNy@J<5&)`lyx-&HDw!HkVxRJ-{zo9?QDr&SoFpAt3qZD3D-PW91IVmMHR3 zx@MT!pUe)(H1W)nFTZ<r?{pV8Eh{doNR9JW5dQHb2&Dt^`S~z|h=x`Yq}Yu>E|4Is zF7|<%Wmg{vpM8fHT|VU35qjVUMiZ>#N(qMjjq>cVLz$P7xoH@0rP051<v0rT%xZF@ zgsR3-XR~dW{VIznM?S3EdTBFGM(5RIyU{EYUeX!8F_Z_-Ugu_|p^+Y8GErxwfqnG! z_3={SlSRgnZde@`h9wZI>h9@D$i{|7y;x6!YRpj?aIL~+I*G1bs7`;`Hjx-pw_>%^ z?bGMr@gy<V-p+qdY(S0f)Z==&3K(ORnVw!INcj5pHn(-!razYfdM1;}S{8?h%}78% zAh0yx;^em$nDRg$y1uS?{Ts<~Nw9+r?w9^us0c|gJAT&!sZ1nH(UV~3-D+-a?u&fa zhlKvufv_0O&Ta?dk&NNzce4B0m2#7f-#KV!+dG4__A7vDcRg|s{vAt1ii7hndJ6(u zCz42sT>MOK1HACU{-Te&K|R&-dWkX#d+oXqT$@bM`f5|TiZJ7CJ(2`@DP1@!+<vHu z>Szo(!>fewupTZHtTQdTmhq&H;7bLaB-U%$5j{Tj2>(&xN20oBpC4sX59EIh3azF< z>oc!k?vGC>m!6!cOgUNsU2Z%Q55(3Zcjq8MVm$u8X4(yxGGKzfeL1$X7$7$Moanay zV2+LWZ<?F!UZKgX#yi3(K%>sG3Evl!%=BTuKd1Y4VhZd*zPf|nPG>l;%MqZEKl@W~ z0dtA}(YafrViwTg48|#NZ%H3I2X8N7Twlhq`jOb#dl;J|1j3+F(;a37mptXHo5H~c zcN0Y*#Pvm-!BjKwVhxs1|7J7|LOH-V|1qNC9r*m?=q*byr&#YK-*+BRQfA~{Q(e(^ z&tpq;dlAe)&Xpq_>%wLr{Ao-gtg49;*=bZF-U>6o<2G!#kz;oX`CXTWdLpM=qcN(W z88wtRYsdZ>0kwO{1a#N;=#&APYb9;^Tzhp8NWkp0DUsn|Wj`oizewtAY3dR?Y*l%P zG$aj5v6_k%HP(l6@RS;Wq8ZbVE)S!cOF%@=n)NOlD^F!6MWr&0jvfnc_D*0kf@}Os zA!-IXW3ePOba(k9IGSHy2XQ<CCauGqb9~;Fh@}D`c?nJVMtVhpWZ%6ZkphltIA$<@ zQHZ=%|My57#65lCfiSY_%3RN6C1nH^b~G2+qTvaf2faItz~>c1>2?E{1hdkz3Ldf& z?kI8p!7%}@SDc1u&scu3exny0ueuQ76RhmCP-FNIWzSZW3wT7OC7WSC54>TaA4mu~ zlR}cv$LY&UCl{%{**pWf1yDT&_x6UD=Q(QSuzz=1gB;-&(V70V28y<IP<AHSxeTnm z8{>Rpn*cc#MQB9>av9l^y_-t_7YA+fujBqcapYK*crYOc51b4vjYoVtt$8`|j#{`} z^9>Ae>1;OG<E^q%NBF+Qv%ba;>TGbE6YG_)l1w1y_Kw$}-i2P=Dcdk~$)3$jDC>&W zd6onDO@`!Z1Ba8iluy_QX_Ol-PFWdBH`Z8Npp1z+r$kpGX(o%_Mm;(~eFe(pt3s>n zLS4B(7j=slncoLie`xvZN5=?>LVxMcDTbF3$ISad{k93kY?owT<=9`-%47)cuI#+T z2vyDyX|OW@d&k)T8+a+JEm#$#EOVqm=O=(!RZ6k3+3wWfd7t^%fNtuH2Az3)bpE`H z^*dBaRzEd?S9;bxngyq>uXm#%LlyPVX&LILloK2#08N^;9vjFfgD$$hzNY-9N?rPx zbUAljO-#K}hb<CgeB@H2zPv9qqaJjer;GDM2Z5{W?Wb%BoUqqo?+nn*F?w`N13@)y z+uCgAgo2s=$j-`A=4yp$iRD|P4VBz=y<^yIKKokOsKi8iNB=&dyR(enflAaJzS(Ym z;&nOfFfa1RkhdDsP_p3QZRAbsv`#Oa87!$y(On)B-e;q=?(a@?a#)#lCpP@``{r;Y zT(U0y;;aP$S9{fqaJf3iTqmhJ;Kk}!{1Z+=pu}oXJx19(>N|Hv0Ma|<70&q4ixpSv z_Ht76ftd^h#IqQ^O~aLr6{*I*e-D%d`eaU(S-%5Poq0uvChEUqmqBPYUxVXrd&TMO z`ZNe4qaLJs+&8A2=J$+okw6w4J4niMR4Jd{i6o&j=NnYxZA0n4;R#hovd;CT=&R=g zmBKSALpxlJlQXnO2}Tc7yufB)^!f0dU~GzAFMR{f8Avxo{_Rb4>ITZ8Z(KQ8Ke4(T zmBuWvW*86CyvF?shT3xwas*F?A7F@WUIlzFVNP127ZIBoj<KhZCiHQvK7LYSH<F>M zwbd#wmOtJG78E*S;M!{Xa@oQar&x$Xq$GgET8wEiUt~Y2Yd$8Q969A#sep9EIK4<1 z(hodYjMh<FXO<(BDO(UE?kZm=bG2eoLn61G2TTr49N_RBm^K;wT4!C~f1{aS4{O8V z@Km++=HYlER*K62yC8lTm43csnKAIodaDx|bkiH@{59~yG=J^dsiGf&$A>nbrmbSS zkRWi-l=oT03=82>jsWRXOulo2WpuJi(D_k0V^C@)E0QO@incW+dh4N&!Jq9qa)|kU z8;8e(vk@P*FjPUW*@pYiyL?<d+!(DBBAX-QHJ(LTDrxeDLUD9p1s^GCVdVxys)rjs zwJqt}swD;6QxX(N-e?n!e3O!y#n^fk9>D<cnC>q)A0fj^8AgHwd0J7~qOm!1#abn@ z7K4@_?)y%h@HS`+VdP+f%3waPZ*`=W29`M&!Neo27V?~C%<Aya3Q1OzCz>nvMveD9 zsWvmY{D6MZbrwZ^e^MwLc`dm-+)Mk3S$+1l)&z5{sP=bDsAzpb5eM8(a^I@JK&<l% z@hp;GOVaHT0lq{Hw6iYgAe=bS0cpH?9kLHoQH#+j=qo9-%#B<>8!;|8a3p2~_KxVs zbn~L&B#b6jCp8fmJi#5dEojH{Aii@-X3gunR+u9dS7|WJ4wyD1JR<Y4f&O7lJoZ_y zv74cIzNNTbW_R&)5Yz|>A>!e*NR9kj=KBm>!k%0PE_}$mV^)Jdt<ghcyLa~A8ock> z-<UDP>zLCye|o~7URT6$RqM1lCV@ucRZ@~<Oq8oG?6lFmMjZ_U5?0obU&=~y6k~Pk z?91&|CQb!OYjXMgbb}@J^BUSUKP*Rps6*w*X=qe{$f29Foc9uWG}>w|r^eCvd_T|L zPIA>eDtG>VC_XoZH$c_(_{|_2iAE=CY)m|Kzh1=c?tvHCU>(V0!tqT*m&@rQ>GACN zWov6|iRCA;{GlY_rp$5op8NesMk3qLI^i?-QU>#`^~`sdOQ!`QyRMqPqA+fK$TzSZ zm>eq9tUFywCx4k1C75;!tw-Xq%zI~=fD~l`#(vZ%xn3t(p@uU^jTC(Hedf`s2ojue zz!g8}MO#=f&zy?8v=;l3qn(#rl%SlIV!>uI*Ary_eB)T=w+9#o0h;hQ927!jw;_06 zZ7${fQp*BcOsBlKJFa-xY?}!Bum9Qt@FaJm#mp#f)UCK~XuDUQ5r48++#jo1!U}8E zMSUT58i7AF#u|y=%O%f`b%|-${m&LGB<n2iOSW<gZi;6D-3{h+Ai}f40<u<|W5!#q z^xBLORTDz59?x>lJ3crZvFBd8o6S)hPur|%!Ra>nq^v^g`!;B8ynd`A<5o@mp?jA} zHFO$a+~%wZpJKcJD80Cn=cPPc>$QQnRT0DMK*fqi7Zl%wsw{9wy^!29ORY6RfuDNy zFn!T7EGhV0EygDpaoxR0zuWXOoQp@4S1f>VS0S2WZ#*M1o*`P9K>=y1>68qXFM}nx z*Pq{zX{mYSU8AfuI2abNC*J&YvBb7<BV%pP6qYn^og(@mP1&3S%U)@NX6{#!bhzb( zy?33b1*{9yu~A@<d-Jn|t5=N`+kvjO9p9iV^+pd<g(BelEvZTmo<^#S5)N<Xa)L=G zQkuv^faJ(U`hjmS+EnFjph}V-_KT6h%j=c8D0jvCR;)b+uV=M60W-GANVe7=`O1t0 z^;2DHzwk2T`6|gx7Pl|gE$yMN*IqW;wqSBT4}GvNx0`m%`f}$;uKO#M4faLngmlTn zUI<MSyjc%7aKKxAZ?n2`KwQgKxM*!$jVm&7+Sl5w!|P^pvqssnCKHwH5>D$Ff5(&( z%3c4Ca55(qqv>v#4_&O;69}*`nkkQXD0MUEhYl8{ua_0bkY+jq;}+#YwyOFtD||@K z#ct(ascdc-eBM;Wu^g%WG)CIyOPB1lu+9i`yYLWd+c-M9Pc>5YIrq<~or#{-vTb>4 zReIX!oRb0Nw6p81X^|l^KB9yOQ}_B++fGFV9SjbK-J3$ArJSV-N71{X-nhgqIX0An z{q(l0%xtdP3=hL%sH)GyJJA)kbkb?xf5E#NoejRQ#y#oA6UxCv*1NbG)UyDZ*d@(T zH#Lm}UD_U2eq&ab+)^h->30rP-<`Yi2GpxtewjRx%iXuyanoH<f6M5#={UI>5dj6Y z`W=?R9`!LsNaM$0)Ipu)`1;!frN!#?c8@X$5Nnqn<}!Ukx9{P2N{F8yK-c?D<kz@= zm!(Urmgz8V+re<Ol7s77N6J;L`-I^Ire{#Z!Mvk5NKS2(h<5YHQ$7BK?o_)ETzYR# z%cgDfOH0p}4CI_=Zqp3(DE`c%RMF$4qIALY_gzm;A9zJ`ztO(-CJr7y+NO4u`ZjG= zWxA+?1z!I{Q_SmbVj{%%l94+-0{~a9H&6wK8Y_>fDy9%FqBmL(n3k%|{J0{1(AOHv zW9hVT=bJR_wt5$IHHzw9U+BI<+qay%g;EYlE)lsS5MwuYScV2**cb9psm>GJJQmR% z{gFu~1~zpn@sX$}8yK<S8FKV$f-`D7if=#&nj{=4#a*ha)W2msTKhoY=3f?R6BVtU zPQ9FEQ#Bmnn!{^xm~aZ~aavrPiyB<D*Imt2Ic*Pa_H>HA)Ye<8VYG)_nRt9k+A^IL z!bFCjX@gWXrikx#>pNApsdOqE*n71tzAqAEK~Je}(vdnk%)`of_>t&plnw)FHUEU4 zbuMVaH;hf%)UWAxII>VbCg8kR-JDM4PUbO*O>S=<%dWFV35HAe&;T9DOuPR?0<-71 zV0yHXGIL?h&14rYnfAKy|1WmlDZa9<dlRi#72B!UcEz@B+p5^9or-N%Z0^{$ZKq;e zU2k{)`}Egc^`6^vaqiasWz3ne2A?_BdX^t&Y$IL2WKIsWTd^INe2sPbui-UcsrvmN zcN)cPSQXhqXBw$LCgQEd#W<i^?o1fV(jD-%skD7h|9Pc7fTS3%z`paX;kwdPFg8RA zL*0YWZ)KW7mtUgVv>OOf@VhJFzidsfW;k5Xk)M9m4vU6MQ^Y{=KSULq%2$kHZJuXm zD@n2|Dyyuq7~Y|wXs5$l@Mn-|TzA90KU*yl!mjo&qriye>Y#;7rww~w^m|Lb?!#v? z3a;(etEy_hPeb|Y!9Uo!4>QPF4+7V^M&2-aW#h5=c(q$&)DIgr>#E@K6otp7RN;5k zkEzk(Qj*pd(JOKpjv796%9N3i5S%9-O>KutF4M&_$&+{QObLdeEuX=eOD^U0d{l%i z8trv;G89Wv+BufGd+gM%6J>mV9gga})b7P`O-X*X|5yU5W{-VAKY;PU!4z&L;^PhT z(ws&qW)Ba_NgN>M;cj^)MeDQwWi9EEQBQWRVF9g>M0a+6{yQQ&L6PL3Sg%SGA>l6^ z+Oy@y<jwAnf&x~{Wmej}WGS`~G~qGo_!717v&2T6kB%AKDn54PSpq#!x^M8~k1uhN zvJFfrBKt+;T4Vd<+sz2^iIy*Wy8po*DS}RkapoZ`4BN@F@}HympCo}&$sh{{XCeN{ zcL%o_mk5k3)(9aPz49iBvqs^m7(q19E6|A)>g}BqIPn<;D=PM`kTfyQW_W+FBf@fB z*6HB$xL^T!)M^r@h;>e~JEVZ6C5^V{<1(po)9#pd^+b(T>a|*x(PWI4si}AJw2JEJ zZi4eDQs1~OtDkT&xFH}z{9aMypzigklT%Un#)gR}T;7k><8l~cT=}28CTb~Y2P@}$ zkuF8U8?Q|CL`6kQ@w|Em1_#UT|9Kcp-DwxoZt0=Ka33~4l#`-u!otn1<x_h(^5g8v z#1v2aekxa(nlyku;r?P%AEu%uCNnd$LPTqw58xR3<A-7{VH3|{x5sVYPZl^JZAa}l zhVb4D_f!hj-QlsN^dw=jYIBys<MGK!b)RWlox8&=1(C;AC1^0K@I+{9TXRMxWxndj zgh455;Kb}c^XfN~k7X$nodyT~Yqf>B9i^R_g$#vP{WO`ek5i0St6?#b2v{*$TlyO7 z(P`7STH*iWt@!{wNrSUvwkG@SK)vM#Yuh>b8hQ2J9ka6!;O)y|>=$SRtk4mRZ?Bzq z`ac8B2kMF(D7JpAoo!h-_~*s*ib1yYEG`9a<r)?{TjX+9&hKG~d91Z>?H!9<*`-ej zJ#lzHKh5J&57U6RgnR-ZnpT8ol8Kg|VdO8GiC~fwdS43iT=k(!vF_R8gKMK$Q8|FL zTldg~H=21mlL{tW;9Nc1Q*F?OSG9~=TgN6mAE83`>#H+}3K*iCzaYXQ{pW+E|3$8d zPU)%|SPPsY@=N1vh5T6Z0GCAzZwLXRqu9W^l^0CK_v}fw8XUOSCuHYR{CLTo$RZ!J zwj??vOVb<gMn~AoQBzkh%h<d3Nqr_M{382NgHnxQP4-y`kwBDpuN#WcJIAQfiB>hL zdql5<cF9R;hlYXjK`YLBxHU;sn?f9_py8{cL{MkjZ5)b~rq5z8u0w1k%IaP|Kw#=d z)Ba*i?Zq}@vqi?sD?`6Z{G!Y?i-ykLR@k1#@A&@fYSrq&a|#U0zR5UX^yI8|qmudE zWE02n+MPb6mh&n8EZ0TmPdqRJ&<{>;oGnbUJg9a`YTFl)nNMo=%PYQh<#4}!EWl&! z^;rGOC^wcI-u-DmnaOg7lx(SXsn~1D3DrXvliNdyR`22RvJ2O~ElRcQ-LS3`&`LTF z_iwZ%hY;{`UTe0+K^j`h<(BME;guOO<f!kjhx{aDWDs~&i6NTzkn{aIy2bmpr^q8h zXWI7dWJ0zNgeWzX|H6gx4F2a364-ttr77xn-h5c?_u=dA=}Dcd=BJV^U9B*x2lRQl z?;lB|xjJvXpcZb4S#4Hbrv8^5e+NW>fA{3%#U%gt?;EtXCWxz59nY{}PzZg+ig^n9 z`c*=B)fTHo@`O!IO<Q-1`cQ+-iT_F+?21nRbP{lyKP<l$uCWRiZE9>x@=vemTfW*I z%quB@sjRHDu(0T=H66V?D#|VmT7*ldm;D<V=zqQ${Xfu`C$qJdR$7`3Ej2Z4e}Dhu zF5yS95UGYd`$GI#d`rl`v9BHt!OQ!#0EA{zQu^|sv?G=Joq8S%2Zx8dtM;9$@!@P7 z9Qu=1{SE(4Srh28J6)=w<5j3qq53x){C66pimGb&^t2+EWtjPyEI%Ij|0S+2-DSKm zQbtGo)S4==pETIA{4?dhCbCmE;HO?4Ff*Y4%8mQyM~&LR-~ZlT-%kBs-vam_O$YP$ ziUv$PaLd4d=QaxTX<>u?J9#rePoS%^t*xy9vtBsu|3%HFBj^Z1euAi|sOrW>fcwIR z3qYTn_TSbB*pm_&+1m3^&yfGC4eYo<iT~M7=l>hqImDw-((wAl-@gugdnxLBE}Bcm z<wyCny~sNkV*KFHhOD-yu?{_=GzdgNs=3!1mgM?(4-0VomTSN@45RvYxh^1zL(@W_ zlHC94q;paQz-g88m98(<aXN?>#kWU@XaN}!q|fV`<ML~2vV!Ctd}$#wrJnQ3;@|Wm zenfTCfko8Y^=zN5DxzWlnzWxEgiz)>bXOgj40v_`FSkASOg*5d%f47_Je1?MvNnZG zxQz73vA%ahoGD;c$i_&&tOTaFbvfOcKC$cof}#cNWs(V4+H3mT^JQJh9=Y#`uBFQa z0EBYq8_<Qj1jsIlhe^#nW@9?47ZyC{E6@0WsHn(NyJs^cQ4>|VLsfYvG`gzr)UDWN zID_Nkkl=%)#63k6VkIy~W%`5nEaV*`nsLaz#^%OyLXYT~9ECe*ZO?K{1ip5B-m*{b zCr@mlZ)f(%+p8V?nTzOxuH#KTEw>mOr`d<{gaf&G%f);AO9?tWph$v#)`8FZc6fS$ zYlvK!^oD9~Z;#NS=4a6tDU#v;QCxhTz{iHxI$!`!(uU_J;W04=w`}UUmm<`B%UOmM zKi>8{H!|@@K0M*ri}1*D7d~(LBY{J?ck8G|)URjnoV?<cjzpx5XrX1%pG;V_PGbP8 z$}##yF<Yn2IMSIpe%3Z%03#u>A_o?d^YU2MG9wt#eE_J<Ttn2;Dn$d~=*4vOg2o&i zd97o*zGE)xvixjc$(DeY3{H~8XD7H3F$VhFi&Bonu22o;2|B9gtI^oXg3Jq*vY^>D z$+D~jG{-ct`uXb_%`U!Rr}&W$dydu?BC4wBrN{6Ng|6aCVrjB!-w5e#i&q~oE|vm( zj^;0KZ&esn@{RXvDXvBvXR6BSm6`6(w1b>nS7M309H64q8>u_l*}2P3BFjof2Ua5W znfCpn`n(qMo(I&|wT#`a#ZKi$iE|fVK)x74=XSCI6GJ4{uVCWj^{0pCZDOlC49~bt zX5qo*&L$yj%i1<0!29a%&3KMy%>N^lH$=NsLdT@8@2?2}9?C+%2GJ-%NDoal2!LL@ zIbCyDYH>o%d^cd>=v!-zZIJB8c>SzEU`UpGCi6F~s^PfC`Fg!#0ROlsRBW1dKN6GW zIohLU3rhz*AudNj+$Sv%aE}^k{8Ks~)i+iJ{;x-$FIZ+f=wlS^Q%f{|Bxbs1a@C|P zn=+^W!g4jrUR}%;)YA2i;I=F+-Ko8EU5+VR6NERAq%n{o-U;MB(f?d1M;%m_U1z4j zmLgK?Hm_q9QBy{8Vx}9p=vG+iaW^s$VV&+XUs)N=WzIV5SP)-w#_8&sL8rzr9xxD^ zDtc8J<*7ZZl}xX!Z{0!Iq>!8q(XqeHYsX#~Y!yLFB3*5MBM2U%m#N;wRK1>JxgerE zD7Uh--BzE&gacel?%=~lM&<`Ywpo-RUZyCy{Bdf9=bVMhf^cVt;JM|<!$&bx`^;(9 z=8BkPqY-op$U|CLE-A!R$<F8=AAoyM66LNsp~Lfg^a*aHv3PPeP}V*fA^X;F(6ZM< zR;6pQDYD4BN<Pgcmh8N0t0G$D!Jv7^cE*bC6Db_x;@m~{sqU~(uv17x%{w~sYg7&+ z9gL`8-PYoJ{n_bSJ`c~zowP5&ITsj`{DIq*)bgC3pULr>nd6hEMH3UECnnIhqUR=% z&-I_*BlrRmM3PawsyZIIg2)l#9~{!hRlz6&p>J%g#fx&#Z|uLK1*qcRj9~8M91FY6 zE1K;bIH;F;jFD5)kQiYgtBP@iX4)gBlfEH!y(Rd*tW5k%+zubXZaEA^oe*mTR&m%a z`d$wU6E)(sUYJtVE+z^qiLv#rW-IO@KGr+GdR};j*MJpe*G`o`1#T#ht)i3x^i+Ci zwh}ovXg$_v0Y>>ywx&MubTM<_Fdd->K+uR!Xn}m)6uTZb#_7fhpj|e;EoaYFOLar& z8T;C9=yJf#_E2z8OMAK;Cq>YtwXbJbBY}rntadEbF_<hVu290e4D0pqsgGhHAUkRy zN{}oN6fag<Z;G1B^NX1oaUiX(k(^|oB+a>;-i+Md-C<a&^MJ4^6Z#hqb!OPIdOREc zsMC|3TC@7Ic1jW${VYnm^(|T3Oe0Gg`!*Y&e+Gnt@w41Dl5bxVyrKCVS(pmr<x-`X zYiN!rBV8-Xy}BrI#63fUaqu?k;4}+blJntujCL3gtO(04@-^`}bdOTD<6MU%Rzgtw zffy`vl}l7usKvvqR<Fs;J);WWja-?zh)KCozGnmtQO|mZwFAfuq`<>dY!9<yCwNEg z9ud-mAEEij`9d%y-s1*BYemyf*O|EakQ++{Q=;i`5%VtS^e9KEM0nS?nxpM6b@rQT zUG`S^X~A-uV<)M?bxbe26PoK1#&1%+s$Vo%$j7DUL}*~utM_NoZX;7=iTMwUieTJq zMUrN*#v<Kp@LBY@R%5k_9p7Efw7~n;B%d-B)kSs>M)NFqK|6XG$@qlk$F7w%-KZP# zF@(Ps{O}w5EK=&J;>_I<i!`ds7;kO|wOm#CNwW19q<n>G47UdfyCZDK-7kwm?Z)a$ z%S2)`{!cbbIm9F>*AF`!_6f#M*H4!!9x_X<w;U4DKG^aUk6MW>J^l2@Ry4Lk1BX?{ zSGZs6WrGThpGMUT(TCz6Zq$>vB7Mx~-j5K+dz<08G%gQDLw`=eJ$dQ(<My*ud*{Xt zSb87q&g*yh7jt}k2bZ?^z7sK7V{(N%Mf<r&c~pNO16o?Y^rpu1$f(ULMnzNVjfAk* z3HHiAp+Mtyg%4<}wuAHf-X6`^Th}z(CTK^k&C!{9wZ5%Wdla~&X)9Dwn*UKDfu|lZ z4hV}))dlI)ei80uf5aM9u;5zO^*%}yH#CgNj*u-0DYaNBvUa2;f^`0QracMq_Uuv8 z36lJlt`Z;3%bKLkP$Jh6nu_+&E5ufeF}iw3KJ^ZHcvmTZ`hT9Arn3CI;e5~QYfdTo zG+RMh<2uFMx}O>@L+VFmgzTJ+nW*WarE7nPg(a%1=D}#Ub=K6x1#5|m$cKrhG@}0C z0>mW2M}%hv8+OQ9(2grz;WXR$@bW_H=s*v~SoDbjx=NZq1C$VQxh(L=`#+OhH6d%J zt{_U@3mNA&F#PCLE|M2_3B@dhjV8LQ7k#zKZ;^B#skjzc`lS(p0G~6Exby2_1<|&$ zYKsz%4)W1mQ$==T$#z%-ZzyGva&6^D&QBO%(ul@#34?InqJ>NvTF|E*y(CvOQ7Lcc zX~cb!rX_yx_(His(jB8>Y7wPlOI3}pkcp&o>_)6ik=Xrjw7oT`E5@6yw~zOFJK!h= z#^ka+O^g(KdkHg+GvHshc<#NQ$zZLYjn?u@_5!#O-mGD-_6H^ipZKzCq+x*cq%yKn zImTF9fivZ3HeB8Xcbd;@<Af2HM(^K--rv2v?LAD*%zowseqrA+a^~ett9)p#aB>zU z=UeweWAh1O`Y|w_@A##diYF{ml2w9A)jL~CsNx6sN=cKm8|ZhBSuCEUG7%s<%{tJf zz<40yGpu5dP{l>H1u3ZrNml`eCRMuQ63TII>L7o}Dy3V#qwwI|Y7H`%Wyz2jk`aYy zZ*m5ow7f|J-$GTk*8veu5KIm9eYN=24~AG15AT*OBp4tjkcpYs5bu{wZ)`s6Xayt- z&JX)9Fu?O}R{DWWA%RLe9akv9!yF{{nB3aD)*8273{t<$fWRBuXg@^gpUy#*RGN51 zNlN`kv}E}hW(Q@iQ?uZ-CSO}_U{=}9+JwZ2A_llJMWAunaJtXMQYOs}P~m{2tdZ#n z{wdQSXj;4A2$&W-h1><w;oEH7-z#<Vigo+=Np5fk;Q`+yzWfF)y+0{RtaGJ(sFc|4 z8+AzP5A;7Ctn%&kMCaYLcqGak$&KN|DsI<~Ggu@TE}{%Rot=O(Z#<L108`!F`T>up zb%<9sD&!cOAGoj;UA!EIFL5uD#Sp%oue{!m8&03On?SJ9v4<9g8C1-Pch_yo6d=e= z)G`E{P5nFuw41VnSBlNmw{|D_2ExqqE(dmAYPf|@<OfPc-8m>gE`08>`CcA*X)Sbq zuwnOKMrinBW~a&6rbJ;T^8>cC#9R`SnRNjsLhy*r4_#4Nb@j_^x9r^dM{Sh!%C0Ai z--S9brr5k)s-Ys+^On+FaKx&RB4B6xj{K_?v5?2~L02Xq*d3aGXZB0_tq(OE&_&qs z*=8&Y2Tb3YDQe%!RvA8_QBV4x8Om91?01;|J-OF-z$36&P7W_8c)~7fZxq#1%JcwR z5(M6Rxl6}CMrL=G$h9xvP^|p;AR1#Zi<dK`d(@GC9+H>3y2JPWkQHBrjjuG5&*D+G z0A=wk#&2e&QpuHPMIq6A1+g3D4iJ{=%10MQI*|L;cZ71CF<z33<&(FSUYFd56n>Z* zm+0eoxaL0Yh2{(G%oR|cx0!psz`3Fpc;O_eLe9{oT?tSt)AA0nU$fuD8pE1=gY=dN zeJ3q|W}^+{#6{-##(gcHoRhLs*#ZS_obYhOj!+8Dl9kI;kiGvj$R}zDF_>~EXlaM+ z<7u39?zn#l#h<LZ<ShbbIl>>HG{Qvf2q`p=Cj%CfvJ?vZ8nwgtL(5SsUWM*7z$1|N zC$E?xf|sG<^-U^Rk*>8PDGi*fF};3vze1zmC004z*iZ2QTiF+G2%sln17T4{-DRus z?RiKr_AXoW$$P8>tGdx(Y#ygAY>0J5p~$?7O71{7`AI6XyqC#(LmF<Y7(syMUhz4T z6}Rkjp=`!J%OF_m!npzm%fRF1lh9cMV%KEiBDcb>)W%WbZK#V;J~!d>W|FY6f9)^2 z#tbhOVj$Q#hcWx{qOFjl8T(kH2oa+lJNf=$UOp!#8|iB_&TeFT1qDgws>vY7vs|CH zT;XVR*@?pp_ABG=p>nK8ipa~W5!ykP0t06p=CRDZ5WJ8-2`@@kJmQ)YjZ>|~-YROq z2rZfcXWMn1qP&P5oUy&}nHh96wtA;FW7xznEsl00{36f8O?<6IG-l!KohUvCKOrno z0PQi>PG~Z3faBm0%N}ObaAHzK$`F3p{_d%ufJT~J+8v-cdnoXA%{OItKN#rpNz?tl zRSuJpq<J(;^NA8geWk&9qi$3c8vNY&g%N561GrndVRL*eFG5qFZgr#Qtqj*_Ffwq0 zOU-Ei^dbShxTcIspdU2`|F8pWe{$!~1+6mugjnH@$};y(L`ypDCcZ<w>UL{S*defK zD>QO~D}cV`m^K#?Z{D-3k<|<mu3lv9D*`H0zO1IQtHacP1rOWvy5Fk8=Nle5RS8f; zeocUOI7ji&hI73M^wF<E@Cyf0Kll9j?%{l*$L-{8n`0dSySlXtW&FmSkFJb`yoim( zSBgAXD~05+>TqTsCh0{j*6OSGZtt&VuI?A#rcebL1%sZ5xs8q#{OG~%XVQ`ymU1Eo zO1$7kAzMTCpCg0HRDa}vUXppZ18%g;cLYm-#m~Y7*3YdB8%97Dn6VZi6h@8VTobDW zzB|{bJju>4wy3<Y<z#2Go}IDgYt!ErO_XUng!gWC!7n}`qMdW*2FHBD4PUTj*=h*= zWHL>XwV6rbSbL52Nb##$F%8LPHPlY0tV~I^!A|mU;Vug3I5VO`<gtr@7N=YcsA3qI zam$N9BYdu~O)R#tcC-}?XR;QO#1?$GoF#-+H^s{wu9%4%k<yrhh&tDRqgmFmWl4YX z*Te^L#-?7%sA^oP>hzcvVW*@Krs5s&ZhpRHUVkg;W1^{<8t5pbUbdN0=X|GTBWOLk za$DUS+7{eqA%`?XA0Fb46^lP{MDPNSh!S6`p#7y=<dVu{OiiQMNb24GqQ#cOA9z%q z5X<3#PiveOmB>dMQRy<qHZGc2(})9BA*MCSyRj2N#D85`a7jkXh(Tsg{v~6A9ns!h z0iR+8UZ{eAfI+L}wQ0uL?WV}_)A#7;BFww?O3<Rtuff85l38hPI1hcBfz{e;iYbZV zaX2J$%CCWn%Dam7UJSKz+2Wr7$d0fJJ%D;#mS>>!VadUp)5AirRy*98vAtFZi$#MD zMEL}H`<yBNsFX(2ZD3>JsP&U>y9FHng^<+^onSK1kq%pCUnPw2&d*;+OCw|E1raBT z=o-&fI{%lOu#&5+FDwlP_!skWrE%f=cDfWp<W|{za}|p~mhcNu$x?Ppq`{Dig8>8~ zkz&=105?N)8(3G3Tt*Oci`~?IiBko^W|Yl50zX{D)Fi{<ya($7uFt;#XRiRy3OuF` zwLPG;)l>pBcwgup-W;OcNHd+Yb`2Vz6i)7;y6hsn~?-S-MZmmHC2IuW0AYH5I9Q zZ~ti%XHSIvHom_$=S`N`KtzUhBo1*$WF>iuz64E)EI_FAb2WjwXUO$(I&`SUYI@Z7 zdeQ%w7n74I0A@Eadmk3G6DSBiPh7%9_BHLy?tK~1<8FyqgbwpIkW5Y{y~|j<UVdJU zhFwf_DA%HpX|bn&8gnWYoLL#a&1(iSS(V+TGg*B0mMkC76>qWr#bneJY|!U_GH+%c zT+NseACy04AcM`<RZ3;HXC5PNjs!!v02-khwIF(JMNOPb>OQlMWuJ;q?lq}}XH|tz zk5R41`1@RFK1oH+pnHwy0z9=UH{KUTwc+))u$DvrF58KVJcscfV5h);%;ig7m#cr_ z`Ev?uZLNn{?QP{*S+y^^`ne~Zf}vH$r={fNX8Eq>qLeQP1%-$4t^*rOAoGx^@VQFB zq2wKl#S~#+N=a7~xg)P8-g%Em$}UsXcXU0o(qYW~DaIrtyjChs5$cyX5VCx=dsY3b z{#VxV=hLI=+1l=B9md@1Q1_O2b%Mw&Aq=Y^3d3{vGn=x}jUZXIEZ`ZPp05s&VH*CV z5XCziam^}KW^8MXFgF&4a^eZxWmsvLf)@N<Q=C%lMzBTck=WfIQHN^7*-9%cEo01B zC3GM8L%LBslUUW1IwIH?oL+Zl<-zmuw!k?7oP!%3>KDSWYvPKDm3Q7AccEa7Vkk6X ziwHdS3hF0}%rn4{ZO{-68xJe=wmgIQNQbEVSp^ztTU<^QVA>f;vPNL;I{M08gaXu& z3vR_cCe@x8*V8y6Nuxz=ym7|KGKr_`tpiIA{WMf7N;g_u1HD?y1+Ks6aHA+0X1;$} z1Gpzi>q`OBniVy}tf@cBki0l@im2}*<`4tt5o`X1?dxa9q~SZ4*3BXU6%L)A9-H&a z<<ORb5WIl_d>`!0eI>(+v*QMb<xY?au2vn!+fE4O1B;Chbh0PT1Q%%W8D__ma{8uk zmXdC37NCnxbw^^2ipQw`Ind>|1T6#&qw^w#PiMCgA2<R{$Y2n>-zG(|as>g1(2a6D zpuomEyn7=v$3Fyq)0XCIh^Z7|tfiaYPb<yO>H)iqc8RlstEH?Kd}&z?BrcXARo`F_ z>x&!_LW`e3M{-;xTPaO^{Bq$Ndj*}NxgtgN{a`>>f7eA3CJeSVw#|n`NnXKQ+H>w! z3gsIxf<VyR(=06`1pm`n>vtRDnHLO<MX4Iomqp5)7~~?BxTC9YDC%^O89u@mS~y#M z8>AV0`tn9}OuTJyCk=QDeswfnE*ey^DOf_y(ujtO-Lu6dW!*<Xt(PCmt(Z;4=PZ7& zgo)jPsVX8BIY=U4is7W08ul*pwwOlxF;)pSOdlFR_;Va%tvk%BiWMuAIwLLP*NXbG zl6NrMskJRtlJv^7z=dBnZ7QEdV*NpSMP<y#J_TJpWH=v;$O_DLKV>YWIzQ=cn)j&_ zblhY_oA5k`Zd)-vn!S~byWB|^@u{tt8%rdhgtmks@;_qD*Xmq*3e)i=0c5zGF4Z!I z2C{2!=GKbZpEsa_^a3vSJ2sl6&1WkoBR-HmE8F*iWW?NJEm$XVUUh>|Mtg@_pu|`{ zY?)~3>+^kY>ya*QSEKVwMlAMA4g!c5*Qvf&F3u+i$%1&l;qXy8`h3?q&TG#uOFDMD zUn_{dc9?NNvd15ae_cr|u51gAM*Pr(pTjwi?+hIwFG1=tRUfXX@HR_aI*g$tb5Nn^ z)|R|N*?uMqR$6N=$*z%-{OSOMKCkA5|Kvp`xEXeA^|a7E=&r72o?UFQXs?(t-e5jx z=)rslCi&t7zgWt!6ZA%2vI0f&eeFQOF}+L~nDfhH_{nR3#B@0C)$3I}HEw#r*}5?_ zkKx0iT=E6R!H7hUuh_fPG~U^{aHwuP$*!;aCV4;E3BE}wEgJo%Ay1`w!;kb`H?ZL2 zVN-A5YKEqI$Q{8hC0bcZb-$(d$xnHw`H7Q^ikV)YzCYm1dj8}-9IMRL|Lo~-n#j0D zhbwxlK-y73cBG7lhYlOJR$ekn+p^TpFPI7yzP_<irj}iNg}&dEYRXKrqL<zWpPOE8 zT==b-3d(OHUS}K~{kW42P)8;@Zu%rT8gsF=EjThsZ>l`-+Ps&`AaV!P(&0{~K%9!# z-;(Um0){?oe&AqE>WYYlc*FM_w?1`(5cH?xvu*`PP<_3~xb?yJNz{j=>W#BscDV5c zsVu*H_v%Ad@&`rB`2;~J00O(V3;Hg+d)a=GA@DAaxpxxww6ch9I>Ae(zrT0EUk=IT z1@D6tbcgczDw3sC>7A{(DGq1kK|AdD3ib2#A!UMq(K1<=;aB?WLwXq*4DR=6!M;s0 z{WJ0AYjMjd0xq`>X-nOkoE87ryy=TuK+}pdqu40wy8Xq1`t|sPfZ+y!^T`8-@432f zd3_7&118=$QJ{2nMD<YBbdXOQMu`VcF*w>J&I|aXl*OgdA<4DMz7q;$+cCxSj1eJ= zUhuseg=!iK%=FHBp8quD4X^{X$+FWW2s80PHn`lg1x4rr!L?VuOH=<Pnsh6-1<~QU zM|`L`2mOL&@5^xGR~6nSOTP(%7Kftb3FC4)V7dF9)2o|c4bYGMRd`_AODug)pRPxL zgQiw}p5$0ibDUDU^9#w;VUOkBM}G~w@&Zz{$C9mXO}kWbJMfT&WK-^=TV?L;DTjwu z=6&gf;Cf0W!ucRBiHrMPYREOSgV*oDGk3>?Z;#98c)>grS$Y5HYJ~kc7FxwyC2*~s z?6@ZGc;4scHj(D+Rj0YpvFt@kZ~Y?U5s7d(XhLS>+V90IX7ccXa6t{ctkWR|iaOET z30+Zf#k^rL2m155X7H#Fz%X<*8vKC^;ue=ScWv}>ulSV~?-l>`WKVq0S(zd`9q#dx z;r=TTKW=XjkWfoXcXIs3*ImyUpRI~wQDqe1u*E=eH7z)}In9T~!Ul3r3sMQ$;=rI_ zlx}PLzHNMU5iQ~GvhV$>U$8}@JU3r85~jL%FUyHhM_nW97j0dsB>MszA=@1ueQ2~l z@X@tfyW*MvE?QLSfeQaFT{9i~U7(czIv&&1r@j`#=%BKqiP4@(ZGt~P3nm;s{(;#% zEby|1${k#K|M{axFFKPrDETCc2|lX@QXBW#_-e(^xj-w173u4lC7~Gkc()tO2H%x7 zu!XiIJFxzPMTz&4kVnW#Gg)%=2Kn~l<A?exrFGSMzrA4G3mb9~!UrN>tT)}0)&$0p z@JvI*58*Y5!9)F{`<9h&y8V)ze&u)AffuroYLg^g{({`YVMHbRrF__dgJz$n-`g8M zUfX`RL@g3J@3?ut_*W(of_o1^g7YU#kC?oMVe_Z$?R%dNk2-;98uiMx%L5Q6oBzr( zh2IHxi63xM>r^GED{37dqp|6K@PTZWD6Z(Yu1vAG_CfMC0nIjaEVsJIJKb2NolsCw zS#fx^;6?t6Fe8kxui+y6ludOWnt(H>Le1Xytc9nh^}OY^sE+4AbQAM^9DCI+uRF|| zUGrs8{kTE5c35?oO-B(BgGBeMP>08LOa5{1*nm`O!|=h?L#+%vsx#>dm=}G*Ou%Me zR2~X@nIiM@V$G~@S1nzxZS`1qh_mNRFZfy05pSyJP~$0r1~Kn=pK$8j>)WWa<)C?? z;CU*F=h0A8nzBYL1tMx0bgKVe)0b-#505c5`F2j$w-{>q%*NcJ%Bt(NRyTY6C!J=F z6-$1Aw!9|dIfJn+H~fPfcP+!2*1qrsA=1{PYS>(ov)Ua({bTcy#0>`n4S#sW3b*Pc zQ@w88Y?Lj>N!yA+jRexXK1QnBmhg7@`W3$EeAzv8qrhZSb$bb<2Z}}zxINgLbd3rD zBl{KqX17eEP6GyZRj1#m>pXdaD$pvlv4CrsO*#l?%N5*1mnG(|gPC>lsbQqWs`<io zxIHd={8(J+?XlHQ4VWc$Q|nMq49*g_yO)kr@wV!N4?kjF5t;q1;sbY!FK^-gj9+@s z+)A8pv;sJA(<pDS*5o*K<Z^8<B=2B)cIIq0`oBB=SB^h;)oH-g!n-n$K%mz*>l;K1 z`^y>XvM4^0;r+6>lLo?_j`<D&+vIWSz_i9b(vRu2Mj-Cg08yd~2H^;GZ`L(qzQeG* zbrO2VNL}tT@2?TVlVSoQ!Qy*6DTnHU8T_NFcAxcBClnXEU1M)`zTLCOG0K3b%B2MJ zVV?@fZqMPvdN$~NmbEKHLvcQJT_((Zn)wR3Z8dHMU#97Z)&l3o8A)x|M14|LTmfzL z^C7km0T}O%*sOZFdIO6S-qHY#f@1G1>3vyE{*w-f5%<-#gf8bYmN@IEIjC`*D|-|k zyE2=)5#4V;6SK#o5ayu7eSLI&%ydrt7QIRYRm3xsHnd+jatdn4Ctc6YC2!o^59DAO zHM}T*%b5SmOusGWEhLb%I6TsH;uC0?!KgYqeh7B6Fr%5#bM$jkQJG3n>&@V4<OnOG z?I?bn8{k~@a<WFLIjWq4`Ta8?X!~CDo>+jFSXU=M#`}x&FMD}ohsm)M3<@JGW*w)J zhdO?vYYbdt*K8C69PsRx^$gno{a?3f=SX*?9j`0jrcJL)FFefXoDV<+`|9S&4OTj~ zp;lb#t;3k!Pa}goutI-ca1)6#rTTvsQ~u|rORm3Hb;GbTS!*>WyXfDfeqWwp7*sc` ztI$gPRc7lR<`TrXaWaWc`TrK!>IIduQ?c8iLE>@ne?W*LxzYTm!!K)3{`iCR|G3;B z?J}s~Sci`a`HKMBr6vfZwa@*6^Uhxca{M`99^a1S{jLkI9BBU{)RYJM@m%%cDgI(? z-tlEBwaGdfxAqAV(OmM+_Zn~j3Iqbj<*z?O*eMcGQWopdiHM2{7R~0GPi7h51iQu7 zApKF9|Gs#Yrpw^$?9TM$Zz_L+SRv~&ux(Az2>siA=X9N+8&u!lKi9hci^ouYdrVh` zR^(qi_D^Jc`7Cq)U0pXAMvYZ^a*UsUQ<l=f3*yzz{>CQrFM2$D7igx!wZGuV9aDnh z_d)t;L_uOX;12FOe`_^K{B<&dN^;lmS1J3lTqDZX$cmk7E2qYvb!q*gkeVD-q4`89 zOi3=A6``2Rj)vz2m9Cbb*QN_ryL0ABQ~grDthu6=5rS^byv3>fDu{7?vnd!muNnN6 zkGv}p$miC}rTgdIqhK{+{fe=sqPvgT>dwmaiVUST<V;i};xBDy$02cDuK6Fv5hEi< zYBpSF%)s_Cc4bVim1yx6LoYw6BOhiZ0FTldEIU^g*a|{tqUZJx-atPucz*EiK>s=W z&TIW~ED|wIr^`r01ufRRc@FvLwW(@nzV)c66=lr>u$lPTu(v7u>=!SDLQu-rZ{W(q zW%^LTWS4x(h3Fo_(IK!n?AcIU0o7mgV4agD#hWI=P8Vksm?$v<_6HrbDn5(IW&xgN ze**Pv_h<B5>N**BO~BF9kr;ib%tWBNbW#9kUQP;SkUs)q6n~_!P*k4Guv_G9S!2R7 z!V6&<)l&W0OkRpapW-_RsmcuCs!jWG+8S8kJc`0HkKpRD)r}sW&lpuhh)uUqXf;y; zFR4)*>=Rg_S}aJ5NQp&Yzhj}sveKg&4qT8-7iYi-@7!XC;-mSCY2(u-DVaL}YZd~H zl=)~CS*jhjd9Zq46<i*{yjCD!4(yhx1GEg*Zap+o(uf0AdO7J_%dJeBF*IA93=+F8 z<L1k1-1Uf$VK)Ys@Aqw*Fzt;RQ&80x+`?D;1eN|6`)jfRQ%x$ggpVAj{NA4-M6Y9* zp5o)FXmnAPnfU2Z8hUyuEpB^n3ra#&vpLzJZ?fx*`U}5Z`fh(FjZSib@kQamXF(XS zpd%C1*`?Y`Azk9$C@z$#R<mMp0Y6PhDf1oU$zM^Q`7R$GLiI*lYT{vEtj{C^oaxM$ zOEH{Vc%INBh-yJkPZ)!()trA2vqmqqst65>>b*|hsYiG`27*R;T>!!My8e=LTkxQQ z)4NRC@08lMM^q-}W<QC{IpnYxhfCGSW>!MKu~&3`wSrj;m(@L@E-_A2j+6=mr_-=j zl`pomPTy;Eou99?8jQM@5|~s|jNpDWRLLiy3Q`h74APm)lE(<!D<U`kwqSU=>?>m{ zK*){&mz^3Qc#N#yrs&_TW#2}Fhx+GYs}7Tp&6dkF^UM2DUBR99K!%|wOxJwg5g{UB zzaB6e)AUN#S3+Z*j-U^hD+F3jpdBw9ZEcJ9ONf|^H9h*L63YM-7idGA@?uuDS_uxT zCr(y8f3>Ef7U`421D@D{FG*H9#)jBvn+pd-O5MHPah?62W7LjFA%fSdw%X?nvMuu) z?0#Y*C0`<7^E?(05-T+46A_V9TUtE(A#j~j+w%LknV8{*T)CHRXTwi5De4o;a9Q$% zq$H~{{lqRSV`Q0-e##0LaOd^KnUT8%c3n~<uz<iZR+IEFMLkap&Cc~;P^zkazwj&V z;i~kzMxhikUSWkPBH)KVk&iXqbsHwM3$xn=1j!-N-|DA0IB|{1u<}wJ4eB7NVnvdQ z0QUmG@VQ5&_(X-w{dp}8t*wC<)vJN>i?ZoWZ%QB4JsK29XasC<2@%vP+^xIS8FvIi zq!^JLiMcxW>i|#4yjX$Ur(0XGQ#?#CM&l<VjYfNMU$vI<nnXadXrz!qNZtif1Pemn z*NfA@;jH9thQ83E2${efO0ScJ-S0LV+?-M2e<|jT+BpqsS#$Ff<7RAm)06VDyw;3E zaVr??WvXh!QdwI3LAjdrTIo90w{QafNeyaNs|JZ{5Fj9Qjq^e`6UqxCN-04-OheOZ zrUYs>!`;P2YQ_^5URL0e0R~B|&A!YBpVW&c*qfYRzykxd#sJghy~V|pzg)O)PnYW~ z<08yVJp%vM6szHWfu4eBi2K(=q&9$7al?#ws?EDHhg$W%)Rx|BWD?{JU?b0IgcuhR zW6Pp-TtLrJ8_z;?Z7mzZksMIjBX5mp**Bx&LH)Vm>LULd8d+&&?pojmsuD9C`eaaZ zl#vDYM5ZLM5}avIE^FoSY^s80YHE%e*s34Z;r}Hvsitg$fa^-D-yqjh4Q%B%x3^{f zj?UbxJ_P|cyzDud|JK600N_~Vce&}~C4a7S|G=o<fTQAJ12-z-uQ2M%KQQW-nRDr1 zVbsHKq;S&y@SP;@Z#ckP;&*KzY+25r{u@x(YX7GrUbJry{S9q^5dOw23jjOzBB}r1 zB>&4Kmp8f1PJh#*i44T~YV-2`y_b@@OqApm35y+;B`%)HGv+*L<?dhv81ho{^@fr9 z_?D5JL8R7E0SaI(toQ7uBAXV3ofpKdvDg^qY+7NzZa<OqM`Pr~gN7_u85%!-rKGGg zoNF3RF^Lc{UbZ}4t|eFwIgo2OKARsK+8_&92@oTdBY<z$HxHbNET*jRA67X&i*G;K z-Tj?6zHpqM{(OH`n3U_$x=*J5zGxVgSwRk7W6V@FNa+g~LV}9uaX;Y+W~-NNrjAx% z?N;*JUR-hWzYk(RK(5-zKi5j?pI0<5+B)hV4}H>Z+vC=ZGU8&ClNQs-KPfk^(v_tQ zA%i_S98}2ftpI+51(NsP{IzuKnI4X25e!S~258+W39u%W>%!>@__ybydte_8ap~sb zzl0DuzI(&CSOu&ZX=bJ?;si_RGRa|T=gSb0^Cy1pt)bmRqZ;fg?(0uM#e`jgy;>Rg zhJ=RuW5<}hSUvGxNf{Zl^3I%&!%*H6BkW|ZbP5nDY<2uOn3_q$>ut(Wk&@f{^MNAO z5+emh!*%BuT{Y<B<&$9SA`&(a?;C-txsNjjH$f^hDgA(v;SzVVG!dJM{vnCY$XRqP zFkituM!#)53*~y^mqyECXbvI2dq!AV<Lc)E?3JxGy~&QuDBeLUCZA!ahzkofh(@<_ zpl+dH)8aYhq3|EWZmJ(tO+`iW`${n>7BA*x>01*hFlMbBcV6HurLU;k{Yse;p<E~` zW0Xc+ZCdKJegZT+UygE0zPl%c3Jcw$dz-iQ5+p)G_YrLX92DY$Ffd6a7dfd#D}&Ds zb|688Rz_AVUmwD$p=din)fWEZVob>6(S$Z3=dh=UytnEUYo>0Z)JL%PnEEbSGKbwn ziCD?J4;1Lv`&@C6L+yfsL7&V`6|ZRO35Cldw|vsnek8<X>XhI~JjRKwJm+1vztqg9 z3knpJ@V5GbF(KX8wE~)NF9RSM7R*~F?lzUoMB;)OE}7jTQg(W!UM-1`MJc8mC_a*B zQYZ^+(!(lu)pUsdOJ%5lWo_{6_w9DWAVlLJc6xRii^7eZnwpmIwWCUKID7$woraK( zlyVrIWpD-q28q=)Rgca4uAgR+u=#K#XY03$cTX;*WZcHufGOl<*1aTTIjuaR3lCZj zV=DCOE-5u;TuOTZ`UQoZxeEp&GnBkI>yV|vp@Td?4ClCf{vT-=zLy=r4tb=P>A{yd zM8Sh{z0Sjm#a}Zc>$G?@tvK1ijEZFAfSm$UDHp~r?lH6r;{fLPqtR^PwO<aw;)C1G z^TR0L>BKfP*#gV&s|at<k|vY3-11KXj65?T3d?1OcywvH5BF18^wbcYZ;%|;zD39L z{Pn1s2Ax8ao^i=juZmVi1t!)EK}j|SvrEa3hK|`CHmwB#Q%HTKLZ%$RCn1y@MONZ; zidno!Z$$=N6eC;r=WVnRKogUWRqj_6(D_u$ZWB1X0~lh;+e&Um7X?O2(JnPxI%=!m zHcS)-gN6S-ZNQpi+fpdNU9Yq{>eaKA8i)9NM(>x3;e;hnW)1$LG=YIRBtq)HI&(mw ziA!5ZYeIzyHfZQsP7}JS<e|?yXi!nL;W3f^=Q5WG3WCK!|GBUiQ1fChripx<Y64_r zkPl4QMZ!m+D$~1B)G-uWBN|Np80XZ^&sPWyCMl~hFRBzMJ@jZK;r}tg&8|%aOXh}) z!lmFuov>R@TANw#02X)3G^5<QNF=SjbzHoCbzbyckECX=K*fEcCr_gc3M|nV5i>{T z8EY>k1}NkMtvOe`pgzJ*UFP=I!}v5U$eH2%Ih~of#;hUVbnD<t7b`RY-ru|-;2dyi z>C7mH5rolJ2a)b3HR3<xlz@@lvwDPEO+x{7v6nc!vq%{M7t5U5+5cX*U!68u<9BH9 zsI^nGyHkG)Ij(K@5>Y#IeVgTy5=Nt_tr<~%=0yq<NEnd^>?(F@zfIs3uV_XhCu3Y2 zxE?F!G+nl3n)!B+J7X0zuJxlWGyQVKw{gGyT-XXl8X*)f8VTmn%y#8R-M(20&7_gJ zR$&HAcN3+!f6LR30hw4i;hm36xb(nIpM-{-IWe!iX2IyVZce23p<cwx-`cV%2$&h| z2V2kPMo?q)zOlSw2YxT2F$$(sl$NdKN&O*4-g)Edey*XmqXylVfcd?Ci7*#h;Y5cF zZ4r8+>JXPtc8l}mx4<E(&7IT9lv=Fad8<4oV<po2y^C&GS5DvB+QmE%AWf$Btr})l zFd0?kQdVjZ-HG$5?MQD=VLc<le(4^Ag4nr@Fy@cLB+^}Ah2~P7Yo6LB1NbZ^gGjwL zEQF81tR$r<aLC?5hgwOBgNVhP<{t2YGuyLHZAJHd`rn63r>9(we{P4_n8g(pXE_1z zW_9HTiCcNu-CINCC)3}@tyG2MeSZUKy$8y*l>nY<n{|eJ1DE5fSiI%p`x5&S{&e&M z?qSu{8Q{XocUiS}sY?~mW)P4}xFjvps1Xbz=e-3TA_;=6g)BO1YFO?}1YWOum+0Nb zBI?n<0jWg@7e=fV1czfgGKrI|M2*r~jCm_n0!FhKK77oywi8f?_-)pb9K2(ssVgah zGe(J%?rAb8x(f00xbMpn+MxP7LksN^H02j6#OC6o?Ev_}XH%HR@4F(&ZHsvw9UPty z=Wzo|(0>kQa|lpKqZup`NO%{oE)DZlqjtN0!vEVYyYAP>RQY!Zar@>Ay&)fCrjGfC zB;3H}%TIb5iQm`aaJ-C>B{WmRQej}Q7FO(S?b@{){yc$c5g42$TD$w={Apbvhs6@f z(=Etj-Aj1xPDmqpOiCKZr%X06dntmdPQ4kzDiK3E=4pp|EG;gK<v{x^;O=j*Js=&1 zQNxQR*Xyn23H*S5$R*trJYoR4(HQlh!=dY}iKKPW;d+P*k5hd<R!Vk6uXn#zN+T`f zOb(#V#~bY<PX9CaD}0)9!JpyY?r*@j;plX6e7TdmxGmvrAhR4nQs^TgzX=e=KG6Xi z=M8dNRD5|TPh6_rj8K1XypeXE?0kU9l40mx<6vm$)UTqp?Cyx5S$f|zgS2ix?r>oI zqw`<>LD3yvPU7M!iW(*t_MmF?>9B*&{hy~Lhcs{uJCnk%C;GJauUrFWgmNkY?U_-X z5D32t)L;=$J0^SJRGj=@uBx;KFZitg7+#wwzdDesy-xXLv1XtiUun*AjaxPz4L3d8 zyyn@42@zTm!5rZ`JKfh^uah2*74=N?)vaX&EaLBfnxA(?g%YzqLXi|o6EM5MW0Zm0 zgROjs)OVv2_UMzdW2f9GSYANBf`M*d@GP!Gsj(}JY`l;A=y1TOtmfMozZ^^%)D0c4 z5um)<Enk=|YG*cbe~(&ER$GmOTj6{)&9GfZ|CZOFwafNL#Qyak#NOY29wf^^vGqo= zsTKs}e|sR@I{MzZwf^x6h^R!|(0H<)!&J+$n|jm8_JOqKzep2YOdmCL+Y?~S6p*|_ z1Lv3%j`U`i_^#^bCo<SqoS9l?YFW|kzY$f?h>s;iWHaP-LApSY%zmc5^R4qo_Tc6P zXW!FWyv7w%^}&x9hsz49J)N_FdR1el<7=*bGw%?>Ne?9D-cvy-XKdeOM{K_~mtIZ3 zM`$qLyWLnU8~#}b#pAPgSV<Ph?exR4ntS8)Hz~wd3o-Dl_j>{J^~%*6qKgXo^=D9& zqPw8Z>&EgLNd~plUb{)IKE6lzat~&lw{$eRw_mir%^x@;c(%X1498EmQ@G2swPuvu z2yjW~dmPP;HVNFlSBQ96ruSF#CC{eRqBhT7*Lodo#yBotQJEoE%^&ZQq!Qqv`;xLF zRMaI}S11Q*EVFmlw(Jd7<8wJ5^$%mH$QE9e8D8JV%Q*Fl5<latVXkIjpS4jOYg%(L zv+xaGNb5Y%vlkNj-ifHh^XarZ{t>4=hW&F$bSff~(6S^PZ3Ns3EfbI_z_rzW0cn3| zkE9@rSuW7_`C=xY8i`__$CZ*9v&&;;NnxZ2c|RU*ccfHym;g+~oY3jl@*w1!BP6+7 zjCIy~f4zgtsP&FqBqS_cu&ve+uXxpLsng;`z`^_U#E*khl~;bw4NJ=|qgp9}#B{gM z;2`MMo8Mj|$m@8lgHNBqu{&Jv?Eb9;Lqp|6a{Wvb-O9^Y{4viS2oI>-=px*t@6S&O zz$#E?VDsXNZ^y<CL6*q04nDebN$49Js0F99STC=>>0`rNQuI$|u%sB^D;D1@yBk`z z*C(jxR|SS27^MmWxuG<D!}<()9nN*Y<b1Bl;yAJfaLWcc!7?Z|nGKHySFDbgpm}>p zFEf>$@NwNRwxy0O#y*#Kt=-ZTCngQ@Es68^zeacVXuqKA<In7-S0=lCZi209bAaJO z`GkO5Dn7%AKjCL3c#e%Nyv+4#YKbNG=o27JW`;-E`aLyDpjoB!Rj~kk)}F{hK%T8q zU&{x~6oUmL;S;whABoB5L)+qZZ+Mywn%<M>5X;P#No~-HABevc?k(}<h7WfEGl#y- z-)t-T=W(`a{#gFLLHw>t-@U$)f`h$m0L1;6@ixVf3dJ4<r>#f2&Vw9>*ld(Rfh~MX zd=%h-_Y=^K)1OQLiLYe%7Bo%YpkP<SORX*6TqLxyLI99fG{$~<js(t)`hv@Ys+^DO zUsAZI(0{_kqt|Migp?b*mN?fG=UK0R8uNIRHt2Ea3*npr(dnnb4JY-t==PATyNm(% zz}KEq&|Gis0=76G6Gj<VfQQQ`YA_xLBq<Y%_(%uVpClQo+3{fXr^hy1(M#blSJRc; z3AhStmS7YoHg`O~_F|b5_D(Wj7)?(wkZqk}DS{!GSp=*s0iX;<cVqA2)NAa;ksI_& zdl@!gJ|9I7moAkGdF3=<&Ls71<r0k_9n})Qo>RsUfvAi&SJexg)kC+jI>xLlj1g*F zD%x@NXv5D*F_mFIjYzHMZg!o(o!*2&`M!3BG~pG3Prb$7g7NxhD*`t6)eH{gNkPl( zm?u6K)Fk+Cf*iPJ4fK&$!T4pP1V*rI`>!XhCyf^{ng_Gr!A5vLCpghft_B9#V~oCi zHqKE4JNT2o_-MO|2t4}7FCw2Oqm7fmjWFLAu~p{Px?B{om)N{5Pa>yBD$i($tZ1`B zl@VGNF)(H~v5Qs337A1UpDP>6fjL441$O$Q)`+h*4KxbYol|=i3_I_ppE@41<zv&_ z@SHhPFI%InnC=6ToO{V%or9edOJ}B_HOEVA)N$~+Am)UllQ((`iNC%;fG_SDX)A(b z6ks{JtlO0H<ZPft*G2{13<5p+<l(+SS|wTs^nNGq<|Vgz!Al)E*5>!)x%fOsP4;4V zaQco?s;)-tR|3g7NjNVwe<g`LAyA>j%t#B%-&h0>eOfer`1p=e?!HTVJ(0K_Hcz<u zBid=AwfngHdiuY<1)vi$ik{e{v+tff-vQ!TyuB!`PwYBqiTC)6n0`@<@o{z9sj5E5 zVQUDfZ?wwUh78DQ>DQ&x+dp}ggyK$Ma|vB5ya~l}7NBJs0o{UFGvc)lzpsi@;xOSA zIoJlqboYZPZl?!dvaCn_kA2JfpT5<N|B(xhrdUE>kT^Ybt*XsS>RfKK7<;>8Df77B zyOhO>XNYpi{qpTjsL`{Al{!FU()JSUe!gB-8M&T7cpgVV%|@y+;4GVUD@+d{iFhmI z>xRCNr5G4E&OZSk8Knc%x_bvpcl*UfKd5*y1#V&^2QHIJ873zfrZc3=2Is|K^=&}0 z^5~@)$tPa<-k@N&oQKD*30&X{jRSre06*CP%fH0R)s_I>t?|H?+xpWNk{aVQJ@{*a zk3F0PGZmtzkoc6ll}*J`x%I%!c5h^PJBIFfZTyP@l+OtLX-{vAYR|1iWghw%y%ddT zTV5x!Lo~C2eKF!IZ;$$DRk%yOmn^{9pyrjsTk)&=Imn6JwHRRCxi(>hLv-h{3v}J& z>RY`R{P`arN$X=O^iZsw*LJmfy+?e@G=7A7r(#?52oBHw@~)o!-`M-AsJgml%izH! zXmEEAdayung1bv_cb5af-5~^bcXtm?a1QQraCbWS@9lfL|1TN+)(<`UZ8OFi>(r`U zdseNgS;a=Mh{x876{V8p?GohkH#mh#Wj9!bB|xcvr%$oZv2U2y@hi?v<+I>(6M3M} zWtQEv3qHl!LPhxlv?}8W1Q`ap3Jtwgew_UQ%IJHl?knsDSTpa;%0zefKGw9dyF{TU z7)p|3R~=*<kjR{7xT?EEN{xleX-e=W)xAgQVa#?CyDI&W2O+CH(v2)ML%j-3yBo|S z$_rF5lW!oUtzO?Mb&&q<ldWOgRq+iag#N3~N6kZj0|htpdJ49xx%G>DO@g~K=_iGY zjfxc=e^)hMX-0N8D_^AKr$(Hp`5Y(z&sv0~^F}80v=rL87B!}|=BN^u=BuB>E@J-Z zf=h%hX}(oTx!t#|J+~cWrLXcm)yQ?$RbJFZPkEp-pU%%21dTuy^VVDwPf9Zq;Vul8 zYYHNvT3}#0w}LiwF7X(o)Ze_L(vM}RSV>9^4@ppq6?lwQO?!`?OIbWN#MEzmt5~nM z-ei<r;-Jg*Rx)6xy#l3@fYz0M(XXx1LY~UBhlr&JIHh1z&$D~-x;$NZLv};>Q?;c> zH43V^-(sDMMS|!Xl{u16wNs2%+X8Vw@Je(rQInp-)o^BPFALcxchDlokR|=SIc38U zF<QhKoY?w7X5YH_;jnI_!NJL34{m=0#ASmNisoV(8%N%KiGCv;<H?~gi(`?txxp%R z^!MH&%?amb#)j_rKbGH#aMp)Go=>oA#|OowJdDmMx20PlzT9ZJSDa59X6Y@ws_soH zTJ&OC?>*OrcF33fzBeMG>&_Eblk(f2^jbXazBBH(nuoTMJMzX7Hx@mP8k6L%v%-p? zWnP~(u5qf5WIO|AW9&2Z5L4pb=jCCzJsI#njUnG{QQu(ojdz-R$6noWoq=wc?af{( zwYk+IzXIFsUZyR%DT==Ub=BF8Qs$Hv?8-v9Ly;-J>1{3u4YAYv)I2q)N@>Hx56nah z4vrA7b&b?qTo)>J0%IS*+;;LrW>oXRaJ+z7kfWz{lN&nyE1kQ`s|P`-(P?j9h;Gwa zby=B;>dg&!=e(*i_=WOq3%gpLsWCV(ArvIiHzVS1A1w+P=kUE9oFT?Nb7;{>zb$5; zy|a%%*%NFa*{fM@4ahWnJ^V@Z%xN27`o~gDJL9CshrQJdE>l-Hm>#h!QQ<AMyXQfZ zZO|h!zCl+5u{c0{qf!mq9nkS|%7^SLXiZrzSQl-v4y7QGChwOoj$fs7QC5;xHXcdr zMcAC2kNijt(wL~+iFWh#9@$I0Axcd~ndU1$5WnFOD<f=t0intX5<}$q1_|nRL^VcP zHtQG>A3?pwRoX4L8%lgw)p8^1T&6Wgr9gXp#5m5W$RyHI9Mu2nSX~Xx?aPMH(kRdm zinjj2W8*uVjOoi~PLn}IwWt>?YWUd*p7VQi)Y@t1=8^GTz*<)lvD>zhovxD06D3Sf zlzFCp{|m4At@M4aj_P2QU7qRW2O5HrVBPK@>6*jajTcbB(D(9dAzw=P^87@hX5Cg_ zDf`!|*oD)S#_gf!$R`EP6@C6GrC%<W^-lN?B@Q{nt0vMkImG42A+GQJ6B$4H(;Amu zZN2UWge4g2wtj`siqzvtl@E=+>`Y@Z%5N&(SUy@>P$qsa!KQRA=|FwJ=Vdo*B(lcV zZnh8&;48AUi@B)xIbCGfeXo8<!FBX`Z;`~^gz^o&{T8fymA0=4e)Ov1F1_1JTrc*= zZq0FxTiT_H;cGC)a#FlcoET{rIevxb5Y^+nov6d+gY-kd+@Kv+r8Ps3mNWm^=B3d& zp-4Oxuf17u`On=InoAT5qt$e?G?jl^2_aTdxk^Xxa3rJ-JsKwFOa*LiPEJ;QaP95U z;&e4iwa&GAQ7N?5{A^|MnulZL<Q$bt0j2LJQRrM)SZFx7wL0LpIE+s)ja+XQ92})& zXPFR34j_N}>L=IFUHAdqIVVZFXIx-DJfqV9=UuFay_Oyx%fa(E*Q$U6`lxc4amFU? z8!V<w+GL^f4<zRFEoAbgNck(5HqOg!e@<2K1LryseNM+_Jxyk~5Yk@Cp-*vi;;$3Z zS1PtT403rJOH>bPZdn*CZ`Gav0I@mnI3zNTU~fF2-U&sj0#wJNu;R{30Qe^cCBY1T zUUc*9gg3tMBKmK3PF;P+VG_VPA42QEM-qK8glB?cCGkZI4_j_6=hxk;@$EwMp+|(< z6)S^BonyU5IHap^m+!t%*{h9Q!cYmQS}EA*Q&;+aqW3?~(x#Nf#!RT?7`6k>iB0*y zgS5-`PL|jc4rWl+=v=z^ZF_I8P2F5hPT8A$RrtA!&c)NJmt$~LH)zRpB#Cyi9mXjD z4M(uZa{`!K_zzHZ3iZRf52lbWB@URiG?7-6G)@bmbqB<%uvP>Ll_PWRZ~HRZa;9k~ z666yuew$Y~1ZOwGS)}QmN`M)_jK4#qk@R)$Kj*sJRI?O_zM;5R52tM@aAezGo_~J~ zvCjV?wFV!5!J)EvWgs>x_gSoopGnKc10PTu)oob$&O}DcqDBGv5ENEhO`D4_puTSB zgD#d|Ht<~?O6oN!F#R;;XoB&gH>K}Bg%HQww%h-yY-PcS&X0|6KbOV!!0QtL){MEo z@q~P`_7UlN72o_m6lpXfdN5}UPTxg#A_6K6hg86aiY+PuFyRpVXP%c0JhcAQEu|1h z-H(xeZoNKT;|D<H2zx?dKqYhq+}Nv(6_yYvUG>EPp{G=4p@X$ow?ZCyCP-GcJ8oy> zd}f;_A+;vPSrz_OYPvy8ok0|%sJthy?+b-wR)eDIiA}PQbyvzK2JJT7>A}EtCt2(; zYbj)FWRuup6m~@%!__PM$$6}e=QhP1vPK)aF8yPjR{I?{=a274(b2iTH6ttrYBn`= zu;7=nMUzQo>?GVAp*X$TS@VyYsL?!B*w-5Ukv4${nQdRJE?~<$@CoIUXe>NW>cK*j zA&kqeqzCk(Rba5f<bLqML_Qg(7aDBfpy7+-G_Ymbty3QUhnUgWMIZ|bTkln4ElY$i zrV+&|sHi+N5j+f1=U1F#5?B1LK=j_Ee*-nlujmUyCSmZ|q<lo?Ig+l2IS<)vVvE$h z5Z^Ue8JD~lonHXG+9RtZ$sQMY(11TpvRtoaDx}O3qotG^)wO<F8QDidZCq+b6FU!I zm8l|IUo&fDd-$o%%))~QvXXc)IA!(o#M*XK2O2xIK)AEG13<S?a{77)E;gYK=@4m4 z&+nlBD;4E3Dx;gVH^lplke&(g8^_McX744@(FYZ*xv~coqLu*32F5+vtzf*a)=naF zL8jB|G5^aw3l_KSX91RZ&u3i+pMO;Nh=5u9=P8W73FQq}m^JL|3Nf|#g%MyhWo=qh z{PXbwEH`n+4UcMC9?a3gDg&j0JfXKeG)A~=(+=|Vg^@Q{HBnO)`Z_Sflxf0WlvB18 z5l^T5Fly`JY!h|Vp0UF&6Xp@mURLV0zI3(CbCD~-o4`tg0t_^j>s|LT84}&BztQ3{ ze-R9aIL6ETBod&+xplqx(<UGJ?Xg+boW|1na%*Dx1^JTvyG}fD-R~hmE-#9MYZDoL zJF2{@hldHGTl_Zli74}^32XZI<Enu$anjVs$+uhCOfA+OMuVyUUiueueMci`DQuL7 zzHuXJ@Uh0hW&Db)Y{6MIeYoofi6p01P~Q$SsjN$y&0MYNtkAKr1|EKewv4RsKv-mr zk1Bk1LtP+=GMQ^(7`-32z?(M8Y|nFofO^-<iXZ`hO!!fo(#0S(RN3yD;$C?l3Mg}s zqB1T3&6-1kH&9*!Wo^oYiO(-_qM}D3e<j4tYPAhPDcBrhF&vJQyqynrAnwB#vCc4W z_Ov>AZ%BI6O5wBNd1J4!C1$=V#EFWytTND*qLnTOzSJ}hYFU37jx<Hs6PZb+c31>e zsRce$hRC57=O}?mukHB3*~y{A-ALj2-5}06xUr*$bf}JSMlM<}KdPI?x~R$Fgg~{; zd;n(0G^GP4!`F}-gUGI|r=H|=Os@JSBCakU4rB1fg$kVXu12RH$i=k2BUe!>Ud{S^ zMz7HiR)6-`nRZ-=F&Ln|R+De9G8wmHRRq~|4K2%6ZB{y8V2a~S>*Gy-hclMB;h30n z7*e|AS#9wW@o~=Yl{4y4U7M9nz_~Paqio0EQQK*W0H2!&oR9V;`I5T`+*0T=fkQW( zuYV-o^pGLlE%s$BWSmnnNgOW(KW^m@iZ7^XHL@~k;rX=ZV>}b@2L=#xWvM<qA4EXx z`<{ex`gZE7XFiZ@3O~@1f8CiDeo}m}8~674P!MF!w)e_lRB|C=m5ybrqqs|RQrq9I z$D!D$s{m$xp0$5+8kflXG^5`?qQ<g!AIvI+ysFy^B+OhN78EDnfgte|CzXXgkoT;R zJ+>TPc#(L2hNXI>X63mq&VDjDy|ybTKu4$dkNo)vbXc{iT+$QQjZcKMOixo0+KdV& zDPV+R3rQpf+760rP=sxmY_ERhtyDUY27UpXctm)&7_H35<eT@9C8KP5x#-<KNlLif z$2bC#k|7zL?4>smX_%1H8!|`Bs1)x-<W;T&ZnjgZ&+<)KswDY|R`DT6H9XZ$b0H*| z85G51nys)S#K_|^Rtks;+jv{OOD*!9Y~k;c@=kk0d)T?{H@`m1Wq)gH>3DimAW>ES zaSH8dY&9H*3e#Y*jFwy7CbOyeZS#^U>HHakZVHBhAUq?9nE-I+E6k7dDvXH+v?4~q zDvVl6dHmNN@Q>A2sCQvgESAG291|ygDH`hUna4!)B&xVzKjYkUe$W+PoaKGmRf3NY z5Ku?{1}jx{)00}sVtB|^O|C&!H+<chRBU8H0|@>CU%)Bx#&NI*?a69?-p$<=9Yy&= z(Y#!Tvn=wAfPgiL%NTqQ4zXpoinXxRWR(PDBLBJJAxj%;CozL*h2aUlrYv6l@rsFd zb>p*F-#kXsvvyCNkogH7L!!{}%qdD&#r-p@>cG{}2uxEMrx#Y|l7}Q@JwK%%p1)e* z{T3>*G|R%o`Fx4Cf3hBl_!=A_2`L%eem?ht(B|+^!dXUDiHwcUl<?ygpXlvCsie1E zb6-S0-m8%C1y?L*H*ujrg(xt|@ri27q7P=o`7Qk1=qr`ahdWrGR~IbZVsL<(F^ZBM zA^yuAV)<>D@RQwbvLCennmQYjr5Ggs)Wk-fH>HzEdc?t#8Vw?R4~pkXvf~byhfh1} zUaQBo7Ix?wa?i|L%BDvSS*d&2y-qqVyO$|vZPkuL(xsh4Ft<|yk&@|G{pa3xyZt*X zhUe4Db9%h3o@}nO!K0DSkVh6A9e;>xgh()?llUkh7I+CphWh3hwPG?-0}wh{Wc0q5 zlqbxJZZ=cWzKsu#IbN(m@4V|5I~t}HQ?{ymSet<OIn6>V6aB=WRweAPVzYb?L4iP$ z_NY1hW`6~xw~#+L!QOx-&hHrez)?;XqGy2iqru>=>VkdPnvb)D)5tCMiCN=!@kYWc zKk?m-E-+M;#R)G>XZXi6=(d;!6nNHSDZlk^uAix}N5`EAMMgBjq0HkRZea45rR6J; zwW#Ds_~>|SP_Yb4;yAOjVI>wx=ZSwF&e7X;J3Jt%QZf3`p2HAm2-a&<sU$^gPL^n! z^Wu+S)L}J_u(8=WZCVk~X_MS*8M2U432T1y7dNZ}Yr;jTX#nX+H_CQUvpYS8A;X`( zhRG2HCa{7^#yLy{dcriX&x2_0<a2_bk=&jKF+L|)_eBTTxf?;~-h=lf+%^R?K6*e^ zuSLeFl!AswlQWnHa+!ZDCyYJ7=r%(?S#6kkQGe1v2cRwOJ`qm4%x86BhX$Eg2Y;My z2|Mc49Xx{<spiv7>%G`x-fY_LS#dp~%fQo&^sa%tGetCt$!b76;*b~zaV0hnh0RXS za!2VdT#uR^2j6^x@6i>AGOZOHoHlykQM)b)OvIrq;4$>O!lDJtvpBwLXs5DbuwzBD z)|A{9#XX8G+OSoiPc<e;X<fv8t8`U<O1|5&!CR6OEAf69BoOaVkw&+_@THKauh1fj zm#RVb5e~l0#NOa~ea6%Eee&5$(e;qQdv|t;M{Q3t0xK<#ySdpZwysBc_g)Y(ATivb z6w)}bY;bqah2k<?jwqDESs?Q5gSrEPU}fYvfNkIyurlnB{Leh4F=WffTvp$E*o88a z4-fa*3Y)mFB7S=`aQ&O9&ec_##`TE|x)<!Ybxt)F#UvE`wJ6b2&%Ewv8q+NhKZh>P zSSEH8a@F07)U9%`RGk@>-#{Me9DYkg6}o6ij#+Ml&o~f+JjqV5`EcZESp;PmcXqhy zA@lv3O!Y)U#Gl{S+S62nnRO^6A8%nVwpO*+T1?CYnM`p7XXZA@-UK=e);N**UfPUv zAq&&RrW=DZBkhA4|LT*KFd|U1Sy|8D`yvVVP_@zZ>$kb?4jLtE{A(%Ha;q9h75H>s z&iuSi+2^6$jEi~6^@#%L*9x-NHfVaI2kx+8PZBErNvOvJ^@?k0f|$nC-sOtNYdcsG zMoPV6S|p#^X9}OKIsdq%tnBLihU368H9L71YGh|iH7+!G9~BFh83#%8Mz|i>rZM4r zeB;cXdpXQ){FK}9=p$s%+7(w8e~8TEb1GX@or=+HI4@pf!;1X#cOp*4H)Xo5LrrxL zQ7(0!R<_FCwcMeVn|G8v#;jYOp9gSfimnTn-_56NlVlZwf*v+;<7+^TL!F;1ge&-? zA4><;b&Q-Mhg32=|9S7Q#hip$fU2@C(?_=Zq^y<VSL=f~ugRYuPhyS#T(238(~|z{ zCaLQ<;;|MKi;ITEOp7rt@xgVD#q?2BTxwe(z#3X1KabUzmP&$X$rwH@)><=2-qiY0 z_7qJfX63!-q#8ggKxAt6^Ea3JZKU@tvdyQ>VhgC%BEZIyI+X^^R9J1Ac!H7(EMI7e zb?n(DD^=Ls^5Iz`mV!j21isoXHFa)ZOcRu22<a{4JGi?gsQ#C#50+Y`aQ7PkRZ#tm zxw}n$?Q54k-mQc&mU+mOO?nI2!nq||V-;f$`F7!cDtO_11UJIWD&|ckbj)mKnc}bu zmMw$JXdyMMbk${E`%+rR$`@^}@>7OMRPscaWgpnKRwwSKa%3}k|7G5t!p=vT?^v3v z<_}7J?#m+9{m#T%72~ykX1;v$TVmshTjqz5q&<58Tih}i7?(Di0C=$nE#?ZYbKYS? z@E}%!e~4<xXhny^aT(1j=%4h36o{q|a>TW*FPfSf>4J3o$lpm?qVi&I@{S0x9a1rb z3GMplb36Quc<^9HvGKtcH|Xo5X`F4a;jl5j&9274ZFhpHB%qDQD#XSlpzX4yxVD^X zOr$^vVBvt|zH)&VC}|3VwZy7<1tUs6Sg-l}pEW_FHFj!5O!1~e%XqGP*+6g-7ONt< zHFzWMMSt(pcE?SMV<O$?CgM)ei3q^4oYXJv1`2vHp*|i0i-!ZoU||iy5;R*MPig9P z1M&~aIE{Z;XtdwVm%RQEf~LJUSYrwlg&YR@IRAL*)gYj0r5aIrG&t)5-UxOda)VwS z;_d4@NsAmiEe41MN|N5VkUTLay6x1<$%8UDXY?PDXLOSi2Qc<$RWaAPy0>-|m;B>> zUod?W*a+V~HWaEQW&cU_w`G2g$jkhI-V+v9N!pkUCI19b+8@hFp*;^8Zh26M)`>aj zK}jNpK`HJF^vznP`~bwIBW&8VTPax$#;lSVwhv%>VZ^Fyq9Er*W)d#*R6Z{Td~h1y z7Y376uv@kXQ$`|Ol6e|>+HC<TXjONFyaq>Q^_$m2-9<(Guzi+ysPB3TtK0RIBp*HM z{&1||Ft#8g^h88LR<V`6V-T7B2xZx_ZXOXF@(JZ>)C@$on@Q+)-^v5bZu^mXCkRR~ zEf-nY`mx4zDRjE-&7p{#*rw^LN(3^1x#*aV7BM69)$bdkD*P^!T)C*mgUYDqMwy3q z6B~iJ3smphHi10??Bfo9VyPD$=jliC@=R|<5Z+$tqgUcD*(^&Hmk5%Lx+`jp7wxM( zpykpXCz9auhlq_4<KW8q%TLUW?3SS(Y0ae(#mKX`#C{ARAK;*0opDv)o&()@bKWzb zc2e9*Z2k;*-f>SEE^uDGdMQa>)>|If_xbim3RssKw8wJHm>Lzh{gPo&(+I<127=1) zH1>L59|TI1EAJrM4T8OsHUyhgFQ(1g)PAigX~^!@!!UAn9$|E{R3iFBHNt_+$d@G@ zrZuWY$yrpEal9mK4DX}K7+0w3-v#U00v)Y5)u6$2n14)lJ_B1?wvf2J#yB5e-?3Y% zSysrwJfE0YXz~7Q(%=qj1PVbNe+9}13e*p^>O11V%+66A#L|Y!232Nx)g4|=XPG#h zoO;i7nnBlp=2jcu&dl+4W`Y?-Hn~qAfF$<~uAU9Qn;j?^jVChryY;O-`%XTkK3Hfo zu=b*{B0-%9jb6&ig#IC;Mk53~A?eb$c5RYgv5iQFpSuVjTy@CwMD40F+cB40{wud! z53`Co^Qyntar|#A_g~SWxL>#CX)_K1{9j4zy^u(A4`*Y0Gk@)5I7Qd5n)5t?5&uJ$ z`9JGLRll5pfY&9@UppGRJbyEiGCaFu|FYm;^=AEY)HN^Jzx5(wo)JO7TDI@$+EM(K z*N=+Gq7Lrm%2fJicJcqVO8hcWC({2WhfpiD)TImgv@&A5_yO+>OhotQjQQI$?zN79 zsb|2s&kA?mIPOXZ0)z7eqMh+Ezi&9t$3GL+w6LmF6LK1I5PTpY-rBvu_jLiY(-CIq zwyNina_$yrQ*52>%6uo@{@%rro(KKUyDU*pzP;-w<KVz+Npmu+UCf$ZDNFc}gLys; zglI|gdzdu#!S?!lM@6Gt)(2*&1D--s1D(Yu7CL)@-9FJ0@rF$+tKlMlR&4I?dS4Z2 zOIc;xAwAu@yg2dAJulFCyy15vh`)3WbLsu=97#Um-1~Fq$fP6$d@hITX3EgElqU(j znKeW<E-`-8a9jF9hSJv<*3cAIN`m}*TXJe@!b$_yj8H_;+;Vhm=~!rs02W$SJo{=` zWo&a1g^TsMZ#7l4Bhb%92NDKZ4e_@{k7`C$4UcOg<A1iw^#(*59>n38c$MA7_|=ew z1t9km@RKfi;a2nF)+~5qXo9q>4OZiHulId2!(PI5gGXMOPL%rN^bfkkI1fQg=`5Gz zUqVFCs%J1r+cw{q{r*lo!GGb80&fu2DQkh~mRuCAs&l;bIJs@IhV{9132;%<2E+CW ztWwrOP0xAaEaP%H4M|2AMJi0NhP+VqD7=~8rw6s{dwqW~*hxxA(zl5;R_6AB;+85H zMS*&_!djkl>balnDI1Sd`i9;Hz_fCH$)3xFA-enaOU4eDK_0z7%gBWNwyQ~!)QsUr z-}tksLBltDmsi;%TC-1+P3J64*9H7uqxQm4PlmAsT*wm)vR^a%zt&yx4T^R=X8k_A z+cb~ypEr(z-@m%~R9mi$nAw0fG{AyMxEc@%<}#cxa9>Da#gmSs!18xQlvkW-v34MN zRfB5Ewpahg2OHVX<7Vw!tc7>-5GVATo;&rG=Z_?cUyn_QGjlEm7Z7P!s+13O_hwL< z(!T4fJh!JBz^tq+m$CmQ*D4#{{uOzFOz4xW5=)d(0-(3kBzOCfdv$*Yir<#qdIBf@ z=T?p1KvDEtEgoAu)_=v$*5BA!@!0+I@7PKA3p=A%-DLmFkN=IGOuw-c>|^)guh<#= zyC*7_D`UFguh=R58#`Nw36TGaow>iU^Z%fdv&)K&zsk{63(27}>)If4v-=M6<HwJL z8PsZXE-7V~SclRz=Re4!Nk~aQu9|KNNqS!nj8gG|8EO#%88OXuiyt%XK|hu=SJZMo z7j;0FDu;`o{it0$Lk~OgW#@tV^Q)Bo-62ogFs^DLPd_&^^W)J}ogXavA##2$8E3Od zdv<t6sPyOJON$bJYa~*0_9}W(c`#YNL*ir9r^1tO&<*oL%n&ByGD1BiP)Js;2(gKO zENZX(ZuqZw*wdeTpaRyfw)2Z^pW1JG!gUC|-mIN_C`%|m)=pT+E18-5awO&b`Tf0z z*ez>cY9w>z(EUz8UP>mi#Dl>uHIA8`H&B+u_32YL?uKgPYJ|fhhpz|=EUtF9o})9* z=rE*;FO)DG?)T@}v{Hp!Z8L{e4WX4{ap&fSDK*PRh`<8&qN@4uFjlge*}NIML|agW zr*AhK%KTe?&!frMr8ea5Y?dp|k-M--z;MXhTl>@z`+}lRY0OXP=vV=7CxC!fjuE;& zc2TUuLlcn@Zt>tAgQDwfEa!1?l$D8Ad|dwkW0}vU9`T+B1n}}Y4zQw>D6eREu3z0O zk5fxa6>JseNC2GdblcilKTzyiC!$Kd{_HW&WPjW5ddGHIMld|<DJf~4Im?8j-K;5! zes|k!oKW_Vi!Z{en>TF^C5?t&4Qe!h^JjXySE=pOv|<<$N}Q82ahxJ^7(e)hv{yQ^ znUm24&TEA)pfv4PE@DX#%!KS=c-4BfdqqdUPK~FRJPMArH>x8w2x{<TCm?x!9k^)M zCnH^hvp&QKVn}L>jb8j|J+b6S!bnWZV@vGm5PrG&%qF1mCF~KW9q8?tJ9}wbGtFY# zZd5Ry(<Eq2uB-QLoq$+>AiK_3J;~ewD~><3(SjB)q1LA1<Wi#!OtL$$U<&FZ(L*9& zx1MNM1|(m>n%A0=)-HaAi(osc4=-4sjE^=9ADwOXZuops?*;p<2~g?y=aOL;JxmJh zhRrfI<>W#2tp2splKhGN_+^(D6;yNsW|2ymcTy;IVTI!5+D#No&wkN^Mg=>y&2_4X zP4#Rpx8j#MsniLQc?F`-8mW17S*MJ;)4N`xpxLOEfPfo}C2YYUD^m>J#*3)}Pu_sl z_7yD)GmyewR9cy)3S|AsQtCWT9d41zuvb#^d!?0&wu~V&qF;X&H#;U0KJMZ+KYBf_ zP}9}AjL(eKx8Eur>`p!;LDdg)#78VCD@3mXhtawI{H>lab?G0kGzCbJu=>DrGNrE1 zc~b4>r%tY~DQ=HN96490<PL`o-(Jd*ysqn(MRcyMiZM+&NRg~P4sMN`d}b;Bxaa|Y z<X%DZEMgO@S@|%kV2Z}YO}UDt?S!u(-P-*Q+h7piR)25+GkOF(jmqKMq*5;)3vkqz z=^L)MJTFrq+o~yXTj7kaT}z0xC3)?GC-Aa`+uW&Xk>m{{pqyl&*O+c>8m23a;W}}H zYHg@U<ewNLX9Bwy-^Wg8LES3$+!ko7DOuhU^}*x0zC7CM$102$S|zGX-jWJf!*N!~ z0FCJ0Mh$`@@pr!eB$qg`2>nB5=J(?&&2LS#&~w1bq&`Dp^N?HBIIufHs9JlL-iHi- zz6-dtJnNQ7#R~`u!x+K=N5iw5@{SOXag*t-pGKynhK@Tv$_#s~V6-{UxJ#`R4~?p- zU10CD<N#@v4EYf2U7TLYj=Y^Kw(TN=SPf`bmyQnQl01fSPfoBIK90Tv%o&&{Vifct z2{j+Y(0fBEvP_!^iAsh>T>6YYRsZB!h#;pds$}UFbrx*sc%{RL_!*L#@>LD>B<6i% zlk>jrd$gmujRzRVYPw@*0y+z!ClmN(rt~6|0g}?<ciWC=JGh#C(0$YtBnDD-UhkU} z{^<0aaDL;VmTO7NM-NW@6MU`M`+Y-e=TZt${%_!p5+!`?_U3`+2NmHKbxv@#s#tm8 zu5hGe%`lsI`K3k!ys6>)torv6cYQS5yEGd=2vWu=viHp*+ZoBJyhbLaT0hH<h?Fj? zB?if+(3i?O){&TwDJaiO^!rh%oNOC>`l<!3&C5BD+3cK2d#}yD5~b66n8L5hN&V5V zz2b94;BYLv%}LADNqf|aG?ZZ+Maq#nmi8r{1AF5TaXBDbyY;$;ZlSt3lW`DY?GKJ} zUkYexOdb0;A8l8?N!%2ryZ??2@;q9$7wWm4V{|U$-RTp&?`sKq%&TP@vA^;8e4Vcc z+A*GUE`z}1t02uF>Mn(Wyb)fFi+2c|&t0XPnfx?}@s>m4;lcDk`gA|zv>d_C*t+zC z>wb@4=mnOiCmparQb7yfAKH2L)xB-xGA{?Jo}`2nLC~e_$CDM}E@Mpa=VC2BY(|~! zC*Icwcf^>3kXc!`<(IDNIbLgU8y>Pv@(NV*q4}*}p+k-aMB}hdH5j|ms+z}MDFYk3 ztc^bI5P*ik&~0-Y>Nen&U#8tTv>Th=C`q(}T}roA72SP((vm#T45)GiOUc+R%QcE6 zXty#G(YOM(K+c&#V20a2g$h`}aJaRu8!o}F`!F#+mR$f#6iV-Pm~dMySmkM=-?DMa z3G9r|yjfqTW?xZpO=hiU{%I#4L0M%^WKFB`rMq6r%YhG0>ot$@)Uvgs&ka1HpyEu# zF^u~jEPo!2p#3B+4Uv-c$V=~SZELE>g+FrKv8vuc{Cb{dwOr8ZKE1((?7LP6iRjcW zwBMJ%@I58mm?!E-u_<x82>DFqnk7ANK=pkjRLUmyn{uvX>53(J-0#(&ps2<({1};u zuB~Y7A%&5D#&8i>dq^tMbC-I~S@?Y6B`-BK<qc>pum&H|yXNmd$D@~g*nYXK|0Kz? z{?=J_E2O2S(Y>}2EMt}+v%u4X+2*QWEN-Lg=+5yZ0#|fd$;|A8oNIz#GcnqCglpYj z-Mk&46$Y)wdfSc>z9jQm{9EGbetTK+nl{!=hM(GPI+_yuFujyMs1X^=UQb-W!6D^4 z*0@B7YP(84@dq}OJ@5jx`qr18qKg$$?q$j8D=63Em2Zd4rL6%qGfBH!5EbnC?yH!_ z^5Oi0#hh64$^3T9m7|Vk;xwa;V*ae<36_W89rNAK+}`hnvQGzC1Z_@8nR9sOU7wTN z=+c)4jfutSdli;!n=8pN>^Kd-#CL!QeA95!mCPLr6+mZ}P?f2TQ-yww0NFW{Q^L-L zB+Ef9qexjq8I4B7P@ZT>HXt@<ZzIe6+cLE+$2i!HpQ-9K_E?77fcqU&6ocy|nQH^3 zD1rhhMACN&d^O_y@1-Tf6ryLpH;Auz#$CM?GcQ}wLNWQw8*rBpddAG-|2?;&?@jl+ z-0VQk73|`<FPlGMOx$rbp<jqSU7@gdocAJM=~<A%0)F_#X6K1Sgn*^10&G5T^s6c~ z#(fA+gUvjt;GD1kiMzJWp47L@+Z>%>9oy6&SG+W`K68Oi1e%<yi-D@5N@f_8r8TUI zYNGJ*@?ww|Wbd|}ukO>?nUS{MY#|0EpL!>zdY(9*IA&h*aD97u8fy-3IK2t{EYh*e zulhl<%0<A%^TW+nF#)wMD2`E@gWJCNi(m&eaAMiloe&>KUB7NLPQ@AmeRk<~jzRbU z!QD;G6b2!HK_Q#Y`7VF!M6VHP{5s9Rnx@A_PH1)|Ztps3cPcahe{RFG=aFBFsiWBi z#)R^lKHKeA!%F9y?a7B50XLYnq~KXms$D}c-R<|=Lny&NaeW3MO{J9e2SRo%Js|5_ zVv8{OUVZ1t$)rR{m(IbN9bqkfsVurYf%IGj8({oe^p)eTN)&>=`_hvmPNPkvGB1~A z=Jh4rTdk+fE_CJAa03}HqzV33Xx7=mvr0i<IXFw-^9eu<3jnS(xya8F;N!VXf|A); z(n><DKUCYDL}`ZuR>S&wwKTPtFIjaHri+)|`Y?Yt-=q3eSy`OVF<UTjPR?D%b2l9C ziot%NofU2AF6I3Ae52>S6ROsZPhlU1HGk}U_pD+WODfImMT0jEGf&+6dOs!O8XxEV zblQp-`*bva#v_N>e$w817rnJdX_L!IZo)9$P0Y88CvAzPJMsuqQCGymjYh<dJi(WS z{QUv`Vqz9-w6^9B6aBm~ACriIrZblxaNDDQyuOICP=io`=UvaR@bn-}<8^53B|Z}c zcw_qMM%q)p$ts<C@*bk&mJ94L+xsFY{&5`si`EJwEG!`eehr`HR0)T*AfthSUdZ*d zFM`~K*(qm$w_;~Ca*0rR=AmV`(sYouC1pt&XD)o`3IDC725Cd7;Pi<B_}Cc^8Lx1o zpC3%A-?rpE1s8ai=KRua0YCn7@3Q@UfpW12`>B{gy83nE_K`_mbD{PWu-|CJcKe<d z!PWMb{&>;(R`9BMR5%o6rUd)_@Qrk)?djm*sPY6%1V2t3JRL}nB6CcgzFRX~58m|; zUatus=rY4Gj8H#EnSw{*K1W#O+_<#j0X4fPOKJi#t$Jd`&)In`>}&v_s*%N2lew}| zWfOJ2xRbt|j;!20c))K<HC>Gbh*NX{P+u*78VPNAx*bo_J`JMNzj*yb@)A&jETmM6 zNoszpMBRT7{&cgBYQI1Pv4o@6O=S>Ti_ye?V=MUeJP<jBD9^Vsx(UlvPA8#PEIn~) zWd#_8uO?4DLXg5=J>;UXn^m#n!vH(^s9D1NeA`JVDmdJGk1xj8@BxmUx^A-*A$q-} zPo=UXABRF6d}!7eIZUTfqF-=VT#g@Efg;mHx)TSne5Nbl<FFjHJyF&bH$jng(r$=J zG$A5>m${Le`pzlqQK}S+{`J;D#$k42UJwxSPR)mSVpQEvv?88HfEXwmPTZT<1czUw zLcZ~>UTOnq&5svb<u;dm-P-W82J@b|I70o@<i@y|Y&D3V`l8xBkQ(=}JZE+6k`nj6 zg;^fVR72v}uD4Pq_^E^|gW3{QaY6sB)8pfW^V1S?LnT!GWo#Ot)AgWGO@AWR7dW=f zZ`D2Ulzer8yh?t!lJtn7JAB;SG_-HJS!{NqF_FDDL!!$c*naDuPHd|cx%uSV9Y$i= z`E75{a00yKHNx9BQiEA}dS9@o7uRN;7W?>lsOsA1%Cqr{O#&+nCxc_nmMDCzC+F)+ zFn6+;Wy6W1O%;r#@wgtyGtYE9Qq^iT7To@APiGE8)mO~^4?|nlJKi>3vOL<BXn6<v zfTq<OH!o9C`5;zQ;taqDgK>f{Yz11|p&Usco_-QDCsiKm_SlxpkX51ocmQRRdWsPc zbb6!C4@&yEgrW2DaDe=smSo!Bbk7V<v8sSXZjGNnC;raond_J4*fJ^l-FqEv2&zM* z{5Ps9ljEXaOGgNMTwPDjo}T1uEOaC?(jtpHl*j#caGWOmIp<Hib>|<tZ+AR0ERB7J zyvu<PzRzT<tq^<<{gqOi1_%s8?B}EN4o?_F{K=@%F@vozOQ3T-+eK0#Hyefbqwhvj zUbdweUNP<RulUm?mn$|YF_x{1I#K%aNFFWI&ajp!K4}$@iR^wvA$zV)byII5zS>QT zg7e<^>Bf)c1#qNlUCY)=w&};ahi{P-Vlo92ZCkl)Y6dK;(2djLm7RC{rzz$U$vT@j zS0%~(SagKt=?)X-F;POL8yR@0KY<H(mQdT=@>bB)L!<&L67a=`TF!sx6<sikt2_gD zF!fJGc35}}(wJYHjzeEbuo=3h$JT3#Ecj;-+hq*3ywNf~o*$E?{yt@1@9#In;EixW z!V+$c6(!~C<;^uH%?~)L+5TiM)H)Rwu}8u-uN&a08Nm`792RMM%dti}o_}~bpmRa~ z>@3yke5CS#&zuBIQ}G`#l`RWY%0DYv>YWbm@_3T@L)JwHp^kI)Jk)vikN_v@`4wQt zux^zs9q3!Rr6%|k`z0=j+#Qtr_H{?jAh~i6-_(uHGYNCj7Gnrp(OR+vb+aYd;~ITy zGl^UE<kzSS6GJ(RGlDaWfuJZ}o`z5TaVvQ1NhF|KBy*Kh*n56nDg}sz7^mQTk-}j7 zMnhJ=-IfOkd{`@wjFhN-$bWmwTCwh3BA$zowGb_x#f`S#(lBzjIb9^+1l=EeAz${M zmCEqGgxRRTt<F<5T;BGDw*(ZhAP{OP5Mm#BWLfm4eCI}gB>>;4P&cES0zw2U1_^`f z3LFNFz12?J?h`E7t%LPJRS?P+!dp$@z=t!JR+ngfPA*ViG<!TB+Dt{>y=yn0pAeO} z%CKtu4EGOr%5IpP7y$tKo?K>+<>^=#dvvO&N+}(Eyz=B=3<kwJb|xNJZf~scms_eY z(6nl)HEI;`Gf9uhcWtJOy@;K60w|?<TAgE$5oIBgp}a)w=I8JEa3)bZ4;zo)Q;Im7 ze1o=pT(-%YP3HCTOtQ`_grQ}TmFm3`S7OnDteAcELOUfC45fZOx|9z`Kw5Ymz%HHz z(sx=WbMlR#{aCj}q?A^k##uO0$?)Tb7uET!9%1Xv!!L2VJ^8iRZC9>fSeC0|UgzUa zpfG{J1(AtIXPD1Yzdsi{u6Q$2kA6|qB&SMG!Rpa79Ao>e*k<d5(97ihB5^4BPRgHh zO*mD2_mq58_Ve_Ew}unldRsNQC{c&uG!KiNWSx1qqOabwYAf;Iiv`6g3&}s;gzW%T zlkv4EtLw2;jPLJ~+qkaPE>tM7@SU_<%3L7a?`Ca{Q=x3_=5&goI=xTX2%=y^<qOtX z&8r^nCeG66ofVfOgG$(r7N6O@_H9V-ECm;f(KEtT^vZ-qa-mG4CH+)-1c9v5ul6vV zA$vu)np5+Y4BnV#_qI=iX(+B6LeJ5jnC1=};lVyZ?6b&COwae%a;U<aiybdtgQY(- z<i0m8J(S-oisPY~**QTh>S}rOe8T-wdsOpf*d@3AoK5#}qjPf}g~Q+GX}54~u!G$6 z=Oid{KZW~KDKN-WtQ2yN3E-opf-G(%)VJ&n{OElRlLdE8XXOR`HYFx8EnFE-(!yl7 z3onCQzpoKBd+<%DYCA&zv9sIPKcsPDY0)Cf1Rr4;27Q1zj<1n=3$IJ;qjv6h^K@U9 z7%mnGm)YMx3)@`iSI=6iuCHApoQJooJ&oUcyPBBwDSz>%!t1=V)lgF9!mD66^#)EA zapy(EuNx1MYQtv&k=N9tCZ31hJ8kc5%w%V7CKUFk(1ves7<V_k{e*m$zZbGSLBhDp z-#qZ~K9<uE!-?2~Y@kGkJcqB>VUW|CUpX-2_{LIn;t2ygeJyZvy0Z&rX?_R73?1sq z7qX@w{IDvFNxV>+Ov@6b1hpU2PqDnz+W-^7Lp_4~^i=rJ)dU@yBkkTqy>8)tAy=KV zWlDott3!F>IKzgfcf;_=a$Wr)flx3?ZGzYpC+Jsvnv?1wNJk2@WhV)G!Rs+T-mtBZ z$7@2h!FQByfOF;14gE_#UqpIcDv-LAW7|fuq2P;gkn|l38E?xT_zvp(+A34Gwnic6 zKF`Xr*>Oz0#iLoJRysb`ELihUy%E7c?9(G;F_csG+UCuiY7>Pe2M9m$xbdbP2W95< z#^nGtCtq;(?$zZ5303f!<BK4uHp#m5ifegcVj;0u_Y>Db$_zmZRGY#k$P+Bq%Ao7{ zc)nT>`*3AuVFp~CnNh|?g8dp8c>Qe+2r}jQTbY1_wBBq8t$n(DZC&pZ=7S~MW`kc& zpBa>Yqbn%0>p=m7#wTX!msy8hT#5TnStyKm8RO=_9olvlJdb66c`KOZ=bUw$zNP|X zJY)acZwLXqF=Fybtfo!6$}$Kzd$?dN#qXdU-TqQ{z+Htj@v`Z^*x>()=1Gig$gld> z(Qv=E{)nkx<$`9v_~GwM<Y92jkX6F2|60IDK>FQ{6A&^|@b@8tU+KE^t&0@P#Q(NH zULWn(?+|{{=KTEEB_zrau$Cf;hWvk9;0GB%gT@+SU2Fa~N!@|sN`)x*0yP1-B7Uj$ zxked0Qh${w1d&A@&_^Az@>dOt1^+tv|KH^Q?M;OG_Hn7iB_R+ZIDy~3y(i#tfY#B` z$+g}mVEzxIQh*5P_A?$yBBiA@54nk1`CrCV-{t+X>gPODzxl#9FtDORFcz6U59WP? zgQ!xERtf)^SSW;?uh8ku770Fkx|~=$C@z!xZ$Vh3pqr3-Xj08k;vsWC3mMO_$pb(p z>07@i^RU#x%&bX24Gd0Zkl#f8m*8GgkVtbrQ|w*fe{Ui03K1l0!~UPM0C0+i^$^p> z=D^f@{kcupJwE_UJ45d7`|{2JCep#AK!<12ukpe9iIytK>vkwEgS>VQgPLVy0QLnO z!+#N@PD+32_ck#;@}H^g2Q-#FvdUi%7xA5@^xp%usw`~Xi4&hu#2=2qI!fz6gR5pJ zQF=Af3D&!xyAqakietTt7Pz13Tcscnmbrd?=co9T`2U>ueMLD*0;8(Vh^@X&O-YXL z*#MfXdPGu=GoSs5Q{9|3?CKD_MKfnBa5!FYO?d2En0rVwSFskJd!J@7GBkZGtQ&qi zY$~UEy4x1t4sue(GIC4;Y;o=N^I=M?;6%4Pvg&7kS6OHk7@T%NxsbiNdIeD)bQbDp z&3O>C=Q)HB{?N*dOs{G5o%Pq<x{f-E8n8P?nlot+k$$n)o2V{9A!jg|wUEneEpcP6 z;X~m`yOiJIk&9-3jcY_KqH{wBUwZiOm++a2S1*-kvZ@iT0LMI|$zJ;zwzrFKDmM0` zt_2>i0Tl6|&dLt@e>KtxMgP(<KlbuJ?URoL0#52S5kf<?XnA5hNHIa@v1tz^OUtYX zu?krHPD8&E$tY@a1WKYkcFDTym$3p7hVsLRQ--u6j;G^$)VQacR(b4DVJ>o#cajjN znd<b+t%%-PixhU4y?Q&W_m3tnSZhW;#bIop4tI|u(^ofY2WAj1G+H25xu8nPCh4z< zu{Rts#IL5XSYC^Lk&L{@Z#0-4)klTu2w?5gidm2k@uoys(YsdEt%5O533SW-T3m^3 z(AjH!NaKS}&viTy#D7o2^DUZSPqs|EN)4{=Gu6AW1{}Afyr!T4EkuPDc0I9dPHL$J zOfu)W54bxLYeuRn^zwC{h+#7LRgBYNmej5WBR(PC@KOjj-I{eU`KTnh>aJ<bzYM(! z>z7|!kR=4j{`)uGD^7xLwh#qVvuc$z&Yg&))QSh-WH>|m7-&WA8T5|!=Kx?;Ifes= zveK%@-yB<GtpRcg5oiswCKg0VbWV#{rBq{c-0FHzrZ_khP-O&z&`|j)j1mTqzBAIh z*@WABG1L2YNW%v+5W|IWAtMqK-lc#+J@9Ev^=MU-?BgPexf<kTx-2(<oYnH6QQ>A- z5#B|rij({u=a5_d*hF6$=B&@U3$;;|{`K5F4ah+mPRDuo<OFv6P^jKw9=et@(GOf8 zJi4apcNBq{vZ+*MVVbecb2@+*`eR@zY52tlK52wDifu9AyV~1ynj?l}O`&l}#0TP9 z<->$^j}xM{8e05m1~Dhzomwl|!gsMr8VkzGK}QL#scI`odcWMg0vQ^s)WDFzKj+p8 ze1yRII@;5qvxp(AtVK~)%cc*HT{*MkdT-cpC)`1JBQ3wt!??(4bujxKxr8en8LNg( zqyn1Cv*El%q(k3&;=GGr+`X6}ZaufW$Te0a{kuP-C#T_c%jX}f#bM<OZKgP?ChAT) z&eoyZ!_vgS5ddy)-RSJpt26h3dcbH9AEtr81v@003*d+*wlvXtD9Aee=+0VA<qIe- zY?d=CYZN#$9>8Kd+DmjPTSnjh6{c96(xDZ7`fL6x>qtzVPVL(J=A==^g_QdDX{yFx zdd*r+qxreS7;dJ2RcgHvSk#xOkrDst2X3XaK9ad>{Lrq-szl50V|r$@JiV!Lz&kam zQ@=iGc#2oIIPcSs6kEG4mBA>e2RO%6Puv+0d)MR@NG+LcXD%~kYa~k3uOv6Lr%@VV zg$=8AyO$$SBf1!lv{+ZAFGptdP5BIXz!~|mip(v;H0(*bSoiv*%%8@;KwAxbDq0n@ z85y(z?#riR!E~PVB(*|nHQM%$2eFlnWl}Bn@R+H$ylX8pPU$qLN2x;nu<KVkOv#{L z-~P6=fmcDr9s{6e+dT)v*%s%mg=z~(g!}cHf6{juqluj^J8u8GUpy0n;dR!ptCZ$E zq6dnQg%ZvWS6i;gN=h74XDzCczYKn!CK>5B9JvXwb7~2QM{$2U7iAb+k;o>fw(2^< z25;)rq{5GBwIU0U;b&F5nx&qulNm~8?70cJ@cTgc<|HB5ygkIQovIWHFxNpNjl_K& z2ZhK+Va=g$X=eB1;tj9GdwGmAdq3795aOJTXzvSSOcPCm$pnI#kaxu3)U|4Y%_6P$ z;mpS!S$DssaDWF<gGnr0N2>A4x}pZQAuud|VCl=pP&Uj(V|eH^KojUSW!BllcG$x) z<096W%!IKEG8NJ0_fcUn^i7V1gc<(H)L5?d`*c`FwT1x$9MjmV40PVZ{=zIzpQjm{ zMh`Kr*r^Et>=5W}YClY^I?UpuvAmZ0Vk&i}W~*v7qPMpisrU7Xu=!%W+?fVcf-<Hy z0T2lUC6=!Vq_R~p`{Hv}Xa{E$IL0>0ih6vm%Gd30Ig*);SXGr!E#)fZwC~UmjIio- zW|t+>J{Y;Wo;$8*3aFbs#oeYblA@X$X>whn@SL}Wfi~Vo=9|#0MO}K&d2^^#aV2@J zYKwuXYYC&9nu#naoWw}9h;K}}<W2vjUC&$SJ=k{i1S`0GUdc2?(c0|nmNi_i0B{C2 zkG1`MXq$Jqziw(vQ5XLT`3;!PE=HKQ0&#S4cXRb`{}tBj=fR(y7RGYs5}?AIGztZO zNpm4nBwE-(BwH<%b}Bl3ah1}a7W}qvtu?$|!y>7n;)62B)0k~G_CfBT%X`XN+WOTP z?P{oHWqs@C-hPC(Ej6sqsVfpx=1E01Tk`BGp)R26USN<wT|vP02h;#BIXR`BSEnh* zkAAn1U$>eh$l{v1h;Dr$b#>en4FE%7O!~jmyMVFO`ZEyI-MGmpc{f<}2_!jOK}!d9 zx!E7d8au4l1y->0t}{xPkbQm%Oq^%nZ?~_pLKhQXP4dH<w_C4DzD5S1dEMRwoc?kj zKi>UvAKPQJ;{W`=B~A1YBU60a?%0q`rLb-o|6wliZ-`l3<h=M&e+OC5Xl5cR##ox# zx4Gp%SA!5gJAXFI-7)J#=l1!p;-g~Mm((D0>}j2hvFZQF`|AD*6x-E4X8el%BG7=? z1cG*NL~*_ezmEnV;<dS~bF^u>o+@-VguUa|aY3&*>ylp6$b_6AI?SXG*XsptVcE@M zZgl~-%-}&A02Z^-o((8C`?76Z1QhI?!-|4}+iT4V)tnr<JN}<~8k5;q?p3!Ok7d}3 z-OpC^d5DnKI5EtffIWXX{g6ncXA3oYrmT{K3Y(H_LGGLXeY6fP+pp*nCAC;z{FlbF zNzkx~upGE@a&pj&-!^+>Vlk_7_OS3Ezq2hh=(0XvS~^6UhjK0|I`uaeV;j#b4en+m zWc?V7(E=P%fTtcXuyH|2`XT^KXzjZcEN^H-GG(5FJ=X9w{wRmLzMj79>CJ`JqPAwe zY#^D3fq(GI^E2qubi}@T&iA<k;AHskG;Pwic4Hv481=wkViH1bVAwkN+@T;$%xwiB z@i5RqG>nQ$#L^gQ?WA!#R1m^fAKQJ1=#4WicvIo=Nvv2X5izka%zk_|gh><&8wUJ6 zFonxFXRl4Q@0)g!?Myitr#ni`?#R7Isc`)}iJJT-!F1jzHuJp#udp!bNzy6_SJ7q} z!c`^@I26-X0Sv6Ph(L`??~ki3VU6eG8gP91RiHf7IhP5Z7E_iK1~<OTS_uNM^~~i- zi-%`>AT5ocDnf4rv%W$JSAupx&iqU@1E01h<ep}(z5_?@d631L-}aTv=)AK|k=rBk zcgGLl>aU{x2ID=VXc%o;SG-JIt&dw?;AFcZCT_X)vn9vsr&`*g!-+SaX&5~aXU8%W z1~g)u-H5Vw3(FKxcdwXH$)CgNw-;!?yUj=8BPda9l{r?qWi&OaWSu2rNhI<XgR+tH z1H~sZN(PEerrXnLJ&;eiN}nCJJ9VSW3Nx-?5&{xM=XJX9smF7hrFB?jcHJ9BYd_#N z)vIit#a@QUvSh1zO(l6l9Ijd>d7hr#dvFI*jiQAwrfS&Lw%UDU7|E{yCG1#L%cK{b z@GmDO16Wq)2?9sT=hoCU?RM|d+}1n=srwFj=F%0IKV#9*@$5OCH9yk1xoV!dY~b68 zrB2Q+6rE}*^(d?79xCXT54;chT6|e;CL1S^ebTeUt#ESo97Q>yyWcTix5tBPm^-O` zn$Ur}-S*+rtX{(7rxjBLx9w2M9}*60S6KO?+@(vdTH{0igT1$ks(V@XMuR&92(C%6 z;32`?g1b8j?yeIjKyY^t?mBUIclQL>iBFsh*?XUJ*2>B^?!$e!<Bad6$DIGsT3ucJ z>#nLU&5(D9T^|_aD%P`!z@W+pqT7y6D!@JT`LdF>*R0v($<+GJEwOlM{5485udB7& z-`sW9&~bMQ7*mX&KV%|_9uzfKK#YfHce2pn{W!c}yZ==2;OY@S=vP{5$d-gsK9Ud? zn0knzX!l*I+lTB5TneqKx7jr0$3i9q?9_I|caY!U84bL-G#*Ma6SOUc-YguwZTY^c zEccGT5IS25Ql0+QdUZ7>J-_PWl6}I)&Cziwz5v0>gFzs)saE+=WqTY8Uh42Po3gVw z9L{3l%BSb=7$HFJ*R$^(Iv$SH++>w0wqGcu_X%xbVzk+ESdWkA;vWFDP?SMg2;Z2O zgzm4;T3#4VvSWon4@K*(*#ff$)xs~0cgrlO$u|7=f{z-MtR69p$m?(|5`*gPCSOj@ ze{&jD-ZPU<yk(2(?YBHooGYe|X2-7aOLP{1oPolN!6uG=p^2M2qV>&>g+?>f@fB98 zpuHwj)ViVutYi&O$Xp+G3SCv!;2k`+A$`}>SE`Q-gU6-X<89;+O9aL$c6qh*)#Bx9 z!?BMnHnvRm(HMk4^=R}%6=#h^=o=3;`7lF-?cCwi;OhQyrqQQKF6;r(f-Lhi8@1p} zF^f&g3;8ma09v6J-^Akp48w0ol5AR*4s&RgGG_F}IyG&=um`JpgJj<>H)}9VNAqkO zdsS#sc?iOpt`}D^vMvWnBbXOL?2y^1U?GO53ftAGJ!HPc+?`Q9)V8O;lE=_uLKx{W z?8=!x{x%d@^-%dl@B~wd-VGaDkX8%n510De>3ceFb^bAMEqMdxv{87b;%hz^M}7~7 zNa}5JA%}jK&3wni$WqXtW0U7Y<rI{uIFdsK%jZHV50y#ueN&<N$T#<mdzN`b7f~mv zDVBojl?aEYoQ^9tn9)&m7^ks~G$WAvou?ACt?2Hnf|+2Ei$H?E0US>V!<id1>+~l% zxeSTX^dZOK^SC({x3B({!;iIHjyVH5X#}JJbWEmnHPpZ&@$-D)(+94{6=p|{O6*VV z+KZ&Tn2|Tukb4X)88c4Wv~eY>8zTcD76KRVIa5j|{55-;p*u9S97nVn#Ju{Q#VZYz zMmAz%`l&dqyHbI3ws@#w6scTJcs$A9nV|DX+pP&j26(%!vHNM8X}xKEVPxnYi*J{* z-z89LJsfwL$*cH`(Up7?PYvB19hpgo(plh+9Bgy7z!0s8XV3UzVMozm-6GFKEEUd& zu9Ux)`woQ$yM8gmtfadl_z+{sQXt2EhH*aiT~TRl6q6wIa$?4NOmZqpxt$G{s&O?( zHGlKY7@-pC`TlzX#X*-i$~ZmgC{r5rLCq4X2vTc<sSgS9@_~Cj)<eSyDC8ea<^>ez z%;e}SD7ejgHg5=w^JBeLl}5JO9+lY*9ARaR;zI@kBHu5jUegZm(UlkPYDPjYXXyf{ zkrWhX<>g;GaFG}t;*2pd^mBvL?52|&l8Mz$k(ul}Dwn8kRy4Ni!Sds3fESyGdlU#? zOacWw_}S?dKYpIja#gA(U+?7E%73iDm8EMRq8h}E%1O!g_lfC`WV6l|Flu5ElRfum z8*&$Cno#<Y-OX3TrkEl;Xg&(^;y79+Lr}XPaaUfJrN4&r_uUlLs?l84p?CY{Yrqi} zI#|2Bia<5O>$8W1mGJm=@dMqUyLR%vU_GVfmw8(!3j3>oSgL*b%nb_72!cM{M4I`A zqifBkp&U9I@*U21Ba>m<H+$gb+y-dYq@MLEJeH453~J42i;RGvB`ph-`xQY`54fXn z9B<IyjvKDfxW$JRYs4^Ai~}%=UgS#|+RGYO8~ssqs=*CO*s2aG;~7=^O`9#?Ts!CW zl3<KtrZ#=sw$k`_jCCJS9LQVSbQP<062?3czEVty!J4c3%wta2*Om%MV)P11gbqx` z7LWH+Bk!(!ktg}2T7T0}mqKIp86ny=m4Mz|Iudz#Krc^D>*zsFf^$fx5}uCoRBk1I z7B1p!y_}Yl$cBH9Tq@Cft`cKz(2UW@l8A63v48i2JzTY7-ALY4dM7v1m4B_Ggnz+6 z3-kW^QM~nXZIYeQ@n^d%dbDV`qUnJIt-6qb235(#DIPEHZ0Uh5Hk+4lOQEjXDAr=F z>J9;9Q0ie}v6}r~)aWy{VW6Za+>GOq`g8N-Kz^6sRj8Wh?PRXfH+7UXC?RGUKVaO^ zN6_LW7!ll$9<QSLYVS?kiE3reHser$homYlRC~I5E>pNz5De9l_-*AuD@6q$_B|(B zI-u(j21TOljUMCG(e45VmhMr9iObsDZW=x{M;MsgS?h=AC^x4JT#5VoOa^x=&C#`D zD0E}1Uc@Vc-0fNS#I&=iyM3evq_N#po(e@L{`mE3uCY=T&=~b&!s}Mp<`IQK%6xNm zqV3rC^;QhPyHBH_434)~*aDtD>3vy$y@RB}dBWB)t1k$7V5nY_u048HTw)VlDd=2_ zxbtzhhBI#;$}?a~qzzB(_tt32;+0Wr&OgrltcCUwuL_OKfxvfQ$pJT|@fk}NpYz*t zB`a0;W762VtM04O*nck$q{%74U_@T($<;kkh!UQoz)OlBU0)K0lWtZBG^n9OUpxx@ z;wSRf&|GrNb(A*A2d`g_P0k%P2b9mJL}<7>w9<xj?H(o;K@LSP{z7tE<^E`1T_age zi-rYO?PF$*@)Ghl6e|(mV#@ahq)=6eFK6^BE%4H+amU{1xU&k0yp<0tY^&}<cTX<L z6@WX<r3YZ!DdMQplRk>pbFOU_kiY)~N<;nWDmc56<#cKp7OET#C(}{Q15_6NPR=<= zK+_a`>9*}mtCf26GP^MpmWVO*2!HmGd$KHEKLq?<<O$I9(7uh5JXCJ2zX;|?Hds~_ zb*!Sh4K8;C1_eNjkGuMh&C3S_+=1#N_<fdF=@AqMLxgE?R)sECzpH-gPuPU*_#mS` zHt_}=&VNL*t6kUNy<lp|xyp*xg3)T+)KCeUID%_j9^~F=gm(Jt@k)+vEc)hsAs(Ca z^GE6`xtVBg6(7X@D08y{ffEf7QZPbv^XSYTRR7B-uv|Hlqpqn?qki4cT%8NP1r!vU z$K*g3r&$}aMNvxN4!Pj<jw)tK#i`XDZxL{ODt^q6PASBEJfIBAsw_aEb2xpO#}p_n z&XT9(6R8kIMt9tEOU0oS$f80(ErGTU?2uP%amOtq;q}e!3rt|*RDxSjOz)9S`P$Vb z1Rl-CRcrm|%&o*~(xZqFz<x2iDm8=G0+&=!xu)?Z>SsqbC#7{^rSwdVMMptr*$-<I zEcxxxXg@5kuP%wA%mM8Y5n;u}v}zrE!isQ=3FqZ3`P@#3N{5l(0wc>d20On8NxM61 zuy&wOQ_62C&;dv_qM`lWy+0Cxo8Ha$C{5I2rvR$5d(~!9oo&Qm&9oGbGm7$txC|=E z!Z}W)$KOo>ftjV>Ul{-~kR?SC+iBKZn|XqA^dmU9<18#3sJJzAeV6)Yt{y;%9?dst zSz=GKj&Q2^v0iGmy^&e!6!4u`(n;BT*=(j^)S|Z@6ZD;2{Q;t5Ee5WGsHXsJ(Xw&d z6~)dA?TKtvb55SMeB5M`1}?qilxWtuo)wFgMVEvlion5pOeiCVcc?hA{Xt`y7W8Ua z_0k4%tGnE<)X$3l7KQc2Q1PbJFP97*zDlmqIKp-{cS&Lj7FGr2PqAH+j~pJi)RLU< z=uj#yCr`)npwiA1Vfw4j43?LP>zM2GQ<cP;Bt4pp=%%_tBvlE*+a4ZFUgfh@fc7`{ z?r>?<nUI97VzLfYy&Jq@k|Q2qMmaL7aNag=mKR5=`$JyKX_(tm|I~k{sxp7e<|xaY z&w^=~BVz-)Y3`xuxzu7X<cR8t?eutySWp$?4^U{9U!4Ip*Y|P&PH@I-RpVr+6nG2$ zA^Hmp)u5D_v~$pqqEpxaKPjTHd6xFiA5bX1oJ83ZdaTn*lW^`_C%NO&?nX`H*GY-{ zG1uTby1-9Efc5wAIeeKY5X5rND&r1K2&)HwP(@R+PA)q=&gN6azB3gO6GJgH;Pu`0 zSoK1qy%lJ{v`UF>fGLz?=I-y){HO(j1Dq@q%kOwfDXF+$E{u%0%G0hMSeOiU*<-C9 zfzx(Zi$>X#5_}$dq9WOGLPez4PXqNTz5LE6tM2>`AThW5>Pt?`Ia>krl1KHbv08vz zY__9Cv$}A}lvKZSL(u&pk6{!r3`Zv3Q_LjVv-%i1*f$l_;@_z67<b#^_IUojuPkvz zGS1$rvcc_=i)vVFgOwrbHEkkj+V(@dTY{GXjm6U@?S1H+G->s4f5JQB{;$*iHKYpl z)N0BvCqiWRU)s}q>9958uzK=Ecw&-(PY{S9^4{?}9(W8*#~sU|+Lh|b8~Y1#n3Oj# zHn5h3CBk&cx)CAVt>3iM^MDz-xkS;?u4NyJ3el#dC87sTk$bxWsnv1H#d3`mf@3~O z#pIwg8PHdM1h$b&a7iAp@6eqCKt<ZgTtfvfF2)s34o=xUF5p%i0>y&4z8!dIn7+LZ zbFIcb$GNlZ*DSO;=!LE@H8Yt&gV|s0`ap8(aGg+5t0M-^Qc)vFN?O=7yNFW4w*%aJ zci)s|-tHsL>LHlBWB_t`%UZUdaMjLj`6xjAh#ZJ&-q(ue9^R-Dxb5_T>(dd4@2fV} z?PCTAsXvTa^wKKA<ZxXdoNzaaa6!D6#ZOF}0|`C{Pf{_jm;aX%yiF8GR7xt=jn0Mm zoBknVm1FiOORoq7;!?d=@hZnS&JObZdBrJkZ%if{j*J`zp=Mwc)|B#-PoKLb23b?H zD$Lald++Sr;e|T&N{qQ2u*MvhxMEo?Lz$U?o+49oeimkQgbx-f7O;pEUw=Tu!>tVI zkvXK|Ior@|UVIfWQCJ(0*$SRrUA!G{Tz(k1P0M=dop|IX2S*LvyRROdI(;Z7xnIWd zb^!3K^5i~jWp8sG{Y{exujSRgFjk@({XCo<%x_`B<~~Rj$^=_|QHcNKSBlF80c!>~ zTB9=P*hmzNO}FPTbo=>m0eH2=+8U^$<BpY>Sc&@MeD`W6E8PA>5RE%~wbp92bd}X= z<$yc%7dC{|BBd~4!6rw!F>wATeXP(^kKpVHBxA}*TTcgQZcL3vQpRsrMo&&ojIFGC zGX(<}0hi`lA~2TIJ!{2=Ye;|6>o&dc1)>=TQA#FwkxRr~mF7YMAJUcDdqN2ePzK2e zIUSKzN;StFrag4Il`@zdRy}Sl*ixmr9<J6CKI9qEi8+i+6)1cLsyh(;{SM&2fBLuZ z&5eP6?(Al&qy9ME9F$G0WoBl+5jljj#G%(5lb}xFbV3~-9_F~c<XpWDE6t6Qkv+WI zQ)xxy3QhlGY?s%xZ9@yM+1MW>NUlJD#+zl32hQrvOzrVSnWq-X!0_;N`y#X13}1=O z?Fc7`l!awRBlYjN`@iuR<I5*JhASE6iBqQ28us(&mk_)Uuq)>3R`mnbN)i;#B;s4# zBfq~L@gEKP&a(#nd^=wSZF-^B6mUK+^0{i>&A=2z6DUph&mM5k#hekXhZkP+SW!o_ zSSy%K6v9OeC$q{JO^l>*Yp9&?$R2bBV#=D$+Wt{5@BgeA6|^r^ge@6}lai4U(QUgd z(z&O$TyDr2l$V!3zFH684~Qzr%qKlmX*tCr<Z`zD78bJn#~9K+2-bLCb*X*bBn`R> z9gLt@9n61r1>PK=jq-+HpKZUTrbeW;E`qFHktz|p-76~Vu&m9>&Hcm>xTck--28aA z&D;Anoa<-F|AAJx@QkXr2$E5VEv~a^7p+ZBcu)>Q#vi|oq_DSqv0|KY;&W7Vf3#~d zc-VFcKl$VP5x5JGny{aZN6`S!(j>>LUAGNrHhXkxp7!bAchrxNdm!=)Fy>$Ae@_0y zHZA(jDNi-bKn}*yJ)0biO;0ly_qLDxG8Jg+Lzned|GgaJCt^j1qA~&EKfXrsY^8+x zB<-eG+YphEpyK&)xr}Q5!I<?wmOT2;mOQy%g#QngJd|zEJ_MEj>}CJ2>t3W|2))+| z6>om0^cDQakIWq(SH2#Fp;iN{+g=g9Gkfj$`pr)Y%g|kcfP?V&xZ@6!UPp{?Enh<} zYq9=laKT(hj)Zqw76JeWhHTJK()p|Me(_oT6Q6auLC(AX))78N2;bL`L_~+yV&#tJ zG3b#!qSX>(H6u1y7ok976AOqp$aQ!us3(ESWEAfBKlC~>(gatQ=L?dN(a_LlK8F7i zwr!*cPYX!2-2C^*m&am=OI=d-HMJ6P#SnU(Z)FwKyzTN<goXo@cJ?d<_j~E`txWyj zjribRi{02GG7&%0_Q<4oeG~OPYA9MHs=g=dZ8v+KSX?Pc<e9MC`7PDI%M{%yc>6{U zGMh{6p72n<L6HmR+H<-lKqd5Yl-#ZCosi@=c#!~Fz)OcLD3vm8zKd>}gqO_3laoeo zU2P#XD;WiPrC`lOhEY1b<-H&U1)gN{>-Q)J(7#Q{+5;l)xPSgP_@##N5dS@zx^Y>g zeL+K^CBpCujQr4K+<=h8-MX16?^XAykeTGR=|XU1!c|1E15F|@@|3sK$J&$9ujH9v zxO`8IKzOPC&Rlh?kQNpe#!WM%W&@6Exm;s3w6w^dve0c#3`2-GFIzO}zn7rWyNIgh z>5uq3d|Z32@RduR7Ez0}fsus?Bk<$|mqhQAzEG{E6>UQ&N`kSNkg5?u>FhmfE%LH4 zXs_*ST>&_U*Zg0$ps?8R1a*l26jsW*6&jxaUsmCsGvBKOajH<NxoC8+j=GgZL*qWc z+CyJNaM-~9<7@{P4`KB1Iy!+xm$M-5mtK+2@@|A23kxUX)9O>&4r_w_#VCTTA)hfe z99a6I5N3}=ROVoxYLACJyu>K>IO43ETM>a8HaeLdb%!Dcx-0Fha}g6)LJk!ZRVs9b z{oN#|O%!ts4~P<ak6I)*&>KeJG>TWVOn0$!<k&vF5R^<r@|Ljjp;&)hT0Eq4E<rUU z8ZK~o$5>eE5M+I!UQ+C$`?cy8cEXa&N2AnwY41jLW%1^4|M=a3*CaxMWY3RDgG>7t z-jTd{hd7?zy?MO8V4<IsyhYu9H6)~T1K~OMw8}CmzUh6Lo_F(VuXMP5hWa0{?)Ge* z=HQ=z(VQd}=WkD@bZYU@xxXC1Hf?@bK#Yb9!LxMu()1pAJqzWuu3TF4u?}LLGEuib z0U@hc=Qfkp$+~lz+I!LFTe^8qR=5ZLA!|zArCex}j>uxK)V<c5jAAHCr{eB~rVkLk zzMf4n@qWe4oBT+e^qcL5gT7rVpusJ+2J}RBn4O(zb-1un;A<L?d|8&e`%YP_d+LXe zVNRqvJtkEb5B&=%a3WR_w=>ItioM4r)D46Aa&QzTkrG^FVm(UO?aY4Wtn6Vo22s8P z_#pkg`vI#flR0^o<AthI#*EejL6cpD%MOYUcZ1%ul~Y0p<?lRnB+XYMNARzqo9;IS z9wqBpf1nlc*zo=g>oS)h1Ys#02GOBeDQ(G$fiWzaK!_%&kGrs7m64?|Qya@sS}JYt z)NczP=@gfPV<IJ7I6tLRdpD4sX4AB4)T-rDhc^_thi3%-Y^OULC%<8-5!BYCuC@!2 zd8s^mP}B;}jQ3sm8Zw#E2n7QJb3^Gls+?g=$?{4OWy0V#aS@^{-!L1L2#&*5sEh~} zIG}b!p8IKCqI*Aqc6{`}d$HewIQIaAHjp?*k@-|odn^OiY11*1zVz6*WyF4l8ZyL< zzgy)<v^9P@<ZDI+YI`2KxtY->al9RKr9nLWT-n8sb6gNpz$lgUbz}zHWlR<64cRF( z#ggAvuItpD^wWUB^lH3dWoNPmOW}-3a{iSF*0;2VO7jHLP$}_YUz+s=_KHVRhN(*T z`eQ@C;-PHj^hKL%YNY{*MeYa2W&M4clezIS+50#rIjNj>ceM3gDuwOHB&Hq}AL(^C z69eApe^%;g`#cZWwTjg=Dq#gE^|($fW`<E8s5atV!*FjVgRwhl<Q(kbW<Y%+E5Y2T z57HxrU(7G@4aFKgcFSk)++$aBT4r%s)Jn=#X>Xnl*9eN4ct^tB74Ji}E^N+LvidyV zBe7Fsx_G@uVXGaHc(y=etpx<%qT+LQG54-Fu$RGaVmLcmou~pWc!F3qGeL5IebiO( z`S#_H<>m*7MbECg-QeR<4?%hF1^3aMYoZ@V*3Z;t8zsK|o!a80k~t;*<$mgAtGVAX zy>`Ul(;4x!&?!Cwmjw<s^o1ySLi*sHdd$IeI2;We)@RDB9UbIZ%4ts6c+9AnLuj7` zQef64qi>ppbTiLP(JwidAlguS<@8Gzd`5~bF!G0bYp${8s+llbgha6>V-H3oCTHI8 zdXmf}i&q$Ii;c>|G`uXE!`ZQOvXJZ=ahUG|L-P@du<A|6E%z<dput=N7+b$kDjOcb z-^4oSHNQ$oN087pg5p_K@Z_ZbJn5g>w-6m3m32MGQ3X$+yaj-)OwFgF>A2KFEgl~2 zZ6T_sT4*ky+}SJU+kH5!i^(Ls6s<9S$I@&&vCJv*o=L?LlI5U%JSuArxDbdkUnE=l zwi)#RQ>S>@H!7NZu6CT(!vI2pyDs^?_{-&%R%j#o*mX%4c4_Q`Hf7FoSLN@ejB9f_ z;lhoz8GY3di%cc9BQNy!tSrgL8rkiz9Gyzrc>2$mDIsQ;la+sVN24y|JjRDfT=!wm zc3p6uyO*y`(D&!Wel?dN54MOsi2Z45jIjS8g;sQbK8;bn{D{MUdxwKO1?zw}0(b3I z@q-I+@LSLXWEzO9arldf3U3xAkalf_P5(D|5??Ao+*0P{hzpZcT+e#^g43~za*bMR zg*R2H%jme6@3F@#5WXFt3Z6TE=;`hfD`!F1qE|y~C*Q4es!k-+Q5N3w3d-Un7i~Z( zGgmL<%@c*quCj-yiP!A-t~5!uLisML{`UCrK&^qx!;Ids%u+U-KN@>#-}RLnrv}`X zyz*gBO*G2^t&Ofh5Dd9SQ1&jQxw`52w&lQ};I5AnRed#TQEuY-d$0r?we-SgE!_)F zY&Wp>joC+O!Ig1H#W^CX+T_m~^>|cEXn<b){Bh=Q11&yM2|2mU2C2~c;LdSUz3M*i z7Xc2OIf{fSi{x#tirQV)07w5L`@6!!IX6bk#xUg{v9a>>BAlG5){dXP%uHBinHQ8| z-*vYT>?>d6B)&IOZsK{lFbD3_Y`D#Q)8WKK@mPOYOf{Z3a$Q!;AJoubfO$$FUSVs7 zQ1j|ykCYlw8=}%t7n~&Akp6C!z75y`!wq2)ji)Rpixxh~8dS>6q%#rkj*uShwy=7R zzoN6|$M8O@2B#nX>IuKXCkUZ>|8{Z-;L~ivW1em$D6cA9X}0uFfL^k7Sl2^9<xJwR zJ{nNcEUwn8WQVoEloU;1Lm$_p%xHJP941+f8d`uyn2`SDtRF(_rz<p@z-Z4uVF5C= z`|jomRcxkkKf=-xrx#l`)`;dXkgPV7b72{|PUl*?{cT($dsQKRVXVB2kf?~mMmDUt z{0hb(RCxn2F=!sfa-_&x#K*m*_km-u;`6R)Oyc%i*1@kRx4|24SXyCT-`!A)loXbw zd0!r`b>&RJW|#-l;*{s8<dvlE6`Rae8ogC6Tl{*ES~wRp3~>Bx;Gd(Sb&)BURAD*P z$&W=gyU6UaGbdlXq8?Iti1&IV_7PX{?L)dCQ8aYIAX3hUB7gyh#@6-=SLCCWdL0Al zpeb(s3tsrZ(aR*G>u(Y&sj4qQtLfT#$d72lptbtIU`R-yscNPF;d->(#fVO)tI?nY znrAdR7vvKZJ>IZ2{yQRLtcLChBMN4-BYXm8w+9K-Di=o%`%TQSL`2K^4PSZ_t8nDB z07Q|WwXUu{v2xHWcg`<;rP8aWb=PgX*e6Q3pEF`~cZ8L!cyC;9BS<Xji1fpM1!8jS zR$st04snQ?PyVxeUIDGjoMOhwNUgtwL6kuQ_9wkJTZ6kOX&GgWIj}K(IX=uKaW8i4 z>|CKd!81C*Qqx3z$oN+!<FAKMqUf4*r`vfL2$H-IPMcW7KCJjhH^z&1O>^r$7Mn@* zP``>T@i|kErL`!>)R?jGJ>0O&hEA>#m9bX^Qxn&i6HKYYj~oUc4Ql$aP>5wq#m-mh zM0pi)nyEYFW&X@=q941SY5?2__mmYb7<^e~uj3Z>02EIB#5o7k;NvxN$a0eKo)HY| zr2~*b_gmcHNHELWO&dnt{p}A+PJ$Y=Ms?v)_rD+gkkP%_s_?}6(<dO*KnvA-S}?}b zHcB46HKw<4S7j6OgdB=q6HX(2ot>5$yRMW;iWG;T@ADg6iSh=@GMc{QZ^rYsT@RpH z3o3K(poV|_yu{Y*NM{ZH>}w)1J1GBRzZ|R|OE&44QRoa;6Enb3@S0X^%|mov`XCBU zrofKK=(NJJwKyqbH1ydh@Ia?lj<>5Qt26K?5rO`uJOOrg668)uLZXS^@()yU?E#J8 z6e1BDsTNkx-5q-Kc+pkUWZ`r>hI{5+_M!;K<#?yLL4)m;Z8>m(Jre3b=d^u9&16_} zGT3!y%c0MAP`e8+05kXM6>VQROi1%~7NY86@PO=QzJQVv7JX_YIay5{!VWEwW=nhp zSd+Y(``PFbVkMjoAk*;<!ua9^5XDw+j%CqxbFXklzRK=3W(f)X>}v-GqFD0R`Xg=? z#%hoq^d)M;EpIa&z9dYUmMP%@o1uVvpT8JMj9hx`B%scDz+GN`W@2=#(t$9Xxg6{i zcsjn-Ax=$At@TB|-PwzJT-f;ZKbYPW8W|QUj!wfrJ3IR|x1p7;BO|BFL0_45&QC=8 zI~kY;4$Chgng?-Qvc(nkT5((v#f$It#^1p;l2tjTuw$QyDOWdGzP{O_Lzu!x$KHx! zHfsds2S3y&=c<`Sw3a~7uoib&%Fxtvp1PY26gK3x;cAp!<>Fl~(^Tk2-|8>kXw8+A zYI`OC4M}R4i{k>E4H}ThWgFjmQs%<c<cS;HYaPVAILuXJ936<er&DcMbzis(1w?!p z&gNZ`@RX`j{@hHbL2RqMVX4|W0@i?SZ;UEyoI9L4b8Yl(9Gazcsauei8Jt<NP%Qxe z$Ba@YkQSwat~I<^y+FQ!h{oV*WthwJEh3BlPI$}yQop7c<HE9pQ!sayO~8T`N%ZzW zF7m<Ps{b?%E2&-WZ33MWoMUN9E^oeL({_)Md0Xj)qxo^zDvORlm8qT1p}LFrLEamt zxu$*B&f9M7Q(tX7Ahm2Gh#ia%yvfvKYGOC@_(_}%ZSE<1O6XBO#L)ydyrMTmH^1|5 z1IoLrUf!Nb8Q#z<XRzl`X!VH=*Z+`J?J%WUjTDL5zuZ9J${2&fcrFyNlkk%b>U~+% z8d;D_DyzNsx1{W=Yx@NY7SM^&Q3byiOVJoi=H3&h-JZr*=<njZG{N;9DJ6gpu0wD^ z#v@K;daDooz-d1BWhLM{bCv6e+<bIpk7;)QR5bd$0>_$mfPTB<rzAHBu18EoWs5v6 z&B2Y(qiY;jFy}yIl`gaLcDhiFHVNO&dd!1pGJpEIBig;ve7fnGPGQ?(C;$+D_hq^I z<dSDq(9>#v^4@&ErUwcQnGwxn+PBd$gVYG(a`URJd*5l|+nhyjWUB|^;NuDR6`bjP zfa4{vvYzyj%yB&kXT6V=sXfQ+-oby=!_<^|ikGF(O6}=fcr`=-c=iYJ_8Q1H$hbsp zQ;q#E=@ar2;$qe7&M_9iq~p2FJ7~v9sp@06Uu83u5;P%jZFo=IuYa*h_Qn(uAM2uQ z3fxkWPFglTC(<_E%Dzr(J_0ji!N7k>BatI?GpS<@CcXhY`c|)aLnBPw1RV{}E{1rt z22_AeDYMa_hJ1Ah+BG=|g)28o@c@;}c=aCBB4d`X;@r216r0D8iyUmnY;t&O(NsuQ zgH(%Ry%#bBIzgnqz)q`?x!>akwY|h(d}FuHBJ^-cZChEZE7vo2>!{J=?{+{%lDQg7 zBH+~Fdk{2k-kIip8}UQC`zOEl4TKI&;V558?b~Q_*+Gj9ct%xD+pVa#zh6ANy@AY) zL8g_u7NRFw5DtBZA%t2&ZH9sgkp+Y2QDlJ}tzDJ;3RiaRh-9Blce3~omwCT_W+F1G z5){7L|L2FReqBTgJzw{u$4mWVtjd3B5R|;y7i4o(|1m`JzsN!Q)DGvjI`gDIX5q_+ zM4s`d?solCh8Hlfa!>8>cNt9nIg0?6ZaItMyO}@xLo$AQwrzbwpZv#{BdJ~%zVHQR zidPW-`6BdxpHJlzk|q6F`6s8!|Fx`Aa4TzddwD1-CU$b~w#~WPUZK}JHa>1cqK?)a z7|wG8zqc@3rbBW}HeHLxbJaH6%gOH4)}!_t;Q!ChV}$32Nu3!vgR$v4Xv&(tds;3x z_yNske}W#4KyK}0aO1%}J)aKdtKbd~523V=_NI&ahK9bnsw}3aaO$rAd9_|azi|UB zxsXCC<Vkl&kxQHdr*2hRZ<Ky%tJv)*9<IV4RY_Fv%DTI|>zq&CVAE@U3kgBS4eePR zFlQmy8cq&Cz@%7Gj*E-)-yDqJKU;AJYiX5gA2@RIJYJ9P>)I$P#_*I@0@l~p9bikq zNitj~UrTQ<7p?X=R-A&nC-ya!@)ta}Q=N2~5*hV+kcSdKh@@wgI$WO`xa}#V3y6sY z(yQos>|_Sm*Ef`&maCWCeE2O~(SKH9(zDOxS0f!5`o{;*qqfm(p>7G{)YjJ4m(z`Y zj)?1Zl1E&I=5q{fz#%h{^Zj7!oy4*pR@-u`XX}H@#k5Lh9HnZNA&TWnQ{brkk)8AP zX1s&!#S=ZS!U);FgY%@4{T=paG7AdCjLr+a$`Q{C543^z<0SWy9*+YmEk2%C0iI*t zvv%7fyLwNk_RDnc9$@so*7KHi*$Gtdd0Xol3~~nnoVOB<>@$?7m1dRPIqY{{o}Qj& z++^Pr4YXX8SpC@7d2FzZXZX9;v5-$nD)iyeP)keet;07$oTuSJ{tuvr&Y1Lr9U9gw zpslH(t$0E4MOA*jD4eP1RVT^bTCw_v%iX;6p2QDE$2(c!d!z;GpW2gCiz-#7b4L`s z)v;bGsnxCCZLyy4KA!P5NH*th;xt*fj-Fr*gt4|2h85H(kt!Js7V_<RK5TpLImJTk zdzK>77LgO)-Dd6On-v{sfwm4O<6F+j@7hW3ye$Q%6%KoQdR&YCu8V5>h9xWZaqn@l zz>4{oijGn78NB4`NsRJ7-pL;R{074D1q$j0@jhJXEhAyoDdH6YfxxQ=a4TqEO;r_l z#qCTgKL<gPq7X5=@UZM*uk1MBiR`XAsd<$u&4c9mP9R(8LLYU@HjP{vcxOCbk0#K! z!lIg*8kW@xT~1KzV++qgNf}SR?txS5tyXIDK6fu*`DuN+qU}Bvg>ObZh5DP!MW@PO zGR4a$^2Qu|EvNexA)hzz3dKvtQ68`OUjP2Wx7*`9i)5D^UQu?E;7W0S+?5pwx|h&0 zXxQ4=;G>hsh~uZCq8gJRa~?fQJ0o3bHe0#TG0S*S=Bf41p_-q6azlRRZd?Mqgd83o zzTwv<aXa?*V2np>(XO*@ueB^v4^}qlFI+294_oV}OcydUqwxTNJ!Ie<r{!U(MGFTM z<4QPGfCVE8gXnYIgKzTJpVtHNX~e+5fc>rMykBPk+Wr{^CMF=YEROqlmDptiy_xvw zq&}j+`y{s}dj(vK=K?V)&nM6xENs*N(8sK2u?xp_28T+>XK0xFASZ#l)Zie&YduJ? zq}Z+o9P(DzV<9JpF)=Z5zQ33qUs);jluqXfJwLbC%8etGh0p+|cyY*ZZwvy`s1+;% z8e(H&cFYR)?<aZhF+Cp6()SH8n<Q}Z9hG?RSYr{I+;1JVo~GGj1psQ+mSDS@1+S{? zpB2I-5^*_?Ju-s-u;DS9!t{vpF`R!}$v0@=g;IeKe>8xkkWTsbB)Fh0G^d+wH-kKG z(pV$*OY$p?rlW<Xqpy8pnVFf}zf|mymU4&yb67z571U6dPf}Gjv5I=F(5Hi%M#bQ) z(9vilWxhyfr6qrzx@h)MbGme(&Vh~46o-0ortwn=N9oPaL%lVJ)n}R5$^f-Ys`IRd zVQ9T$(susg*T|Ke_doVMWFzm)t5qMt3Ykuquz9DaP52o4YI}NZ{&L#(3EMs`^(nie zIztN`abN2t0$P+D6Q$a+8|tfF6ff8stYX@7A}mQ1M~`wlrCV=z1TGaA4PO{dsBk## z*+&Rt@AWmKKWqUZED-d*j0=Wbea_RBNGos&Fz>cr|7piwgMeqOx`ZG_yO1znX>!ST zioE{=Dr)<NqicBhE&U7XKStR8wY8%@qox40FC>4oSU_iZf)M{duf)HKPiprwA)ED! zvQ{<rHb!-8%{?qFV?_0`%?=xrZ8mkExRqP}+363?hizugwIdFo&<dDe3rO*40m*Tk z5VHIR;^4eFH1lot!fIxf*GyZrSV)`FPj~t}5J3uZii)qkBZCXxvpm13uKNm6D5T@P zUEl8={``7O*@ZZi)w^GTF2C`h&80s{Duri!7F?*%D`#l+Rgqs&6H@V090SFoyx%&x zfw8$t&U!?|ng=-bVA-Uo>&M$|^i*Aek}N!v!L;^+1d15!X1~2HM=hEu*{-Djyahl# z5;W9(_L6SCs;pIs#z9%vHKY+DR<0;)Sd|INdipKX049@VA)j17`$wmOegD@Z9B{$g zQv93Aer%v5pFC`-Sro-rMWblziQQEfMoJHsMR+=zJS2x$InMj$%v{Z04we*KIr&Jn zYlj`I)^B@4Mi$hChShz#J?I-={|X0(>;J5}^pEbL|LxU+otJDnatt;j&_k(bYLamw z(>=l4KeY5SHU-{GOJuNcvEbFz?=k{s*Zs@u9>YB_gI3w-ycev=Mk`<6M;cGfO7wl8 zRXwtxTxeWy$Y5ztf;E#Q5Jw6Z%V0rP*rx9iNX9Dt#2FMc@|x>CI&A&Grkzp?0-MeQ zPs7X5ulbH_jVZ>5QE&d^?SWS_B$=(DH*U-zI9^W?60K_qXkLyccf*RkU>%#jdR=(l zwkN9wfQrlwKvz=;(!<CX?ogy1(u6llLAsn2j-WW7nV$ADM40lYRDI7~K<Rb3kNeBe z7FqBKAqV`(t{D7H^dUm4(`TqF^D#;#dRH(l&70Wp#S6}SbqHU!jOVjdWJ()I3V-*m zK(+b{-j^KF&5G~+VXg>C>S@l1XL&OGraf<HlgV>fn=`eY2v$@a&Lhc3b;p}_znRpB zm<Hacr>TaqzY7#iVL}_6z_hNa$H1}>OGwk@Yg}itXC<RDvx?*4iGszVM>+Ek8r6x5 zuza<}1B6$gkP_Hy>K2uO7qshE6UrkOqobsrPC{jlt<0+-C|}IMnXocJjhiA%;brhv z_l42X{0J8qjq%>fh61C*^82Z|ACKUhE=H;0u2bQ&h>iYJ2b|;Q(|y}9)*2Ihr_<4# z-EYgg9g=yQT8Rr|%bK!~TEqL8ihE)246838#)~7+)}K59P@+&27p$~hJ;l;j1hK`| zD!Fj{a0={rxm&OxpEUwQNQwH>Yvrs3cP*+%VX}mZ(-9BHj7)jSS}u-?QMV^WC_}+d zZCS%2^<2f(R-M?{aRDIPTtwd`={IkUei5sbe-Pzmw?vyQqTMxLh&c7J;H7m6v~#kx zGV6~vev?j5B)fX3kv--Vq>Y=&U(PiU&vqAHVjC}iJDFu8O#Nu0h0CZ}2sX&SAkbEE zCpTq;dB3i&_SF$<{M?dT<}xTusUSDhSSh%<uv&B8ReU-9);08fa&|s(w8h|YcDEO{ znq}KdqLSGTlv#-7dC{<_gGD>5?~-xceCGJMSKVKg8n;vtXj%O`<L-r38`a0DRl;Xv z*pO!1H>dj7t-s&Uj)?KGw#Nlc*`To9&Irda4+1fACE|{R60#9?VdA*YppofHc9=v7 zA}imN9SKS3EN}k`_|d7J(dwy8FaxEx{kxp)RN~`SEmoWPAes;xXp}z8FCBK{f<0&+ zZ6GSG$u{e=(T}0%pxtxwLCM(6tlf`wHDWE7(}kJqJs$PO&4WgFzNv}e;4~5y`y!Pe zgxs_)Uo>&t(#&J;N^_ftQd%I1=SCDf1_82<ke)9o6)rS?W7mS8vbTID))y6Pm2u0= zk}(UvWyD8yRR?~$bJ!XmEj}lNQlXNJm^E^@Y*?&(QEFTv3<TIn(#ZBUXyb>`vyqg3 zu>?(c2#S8ty;~G}Jh&+y#2&p6V6-w$dJ<QgvnHC7;_0FBPQCThOj9$BW+U*t{-?m< zEoOy*wZi00%9!}}5snGQA^QAj52x*M)7j=-4a9v%CGX&3BWhy<&c4fF6L+DG+sx#f zX0673=kOqRoCRTS1+CO0oc&4^5#GpJ)}yGpv(fk(ZvmH!92El<s*0KEA2^Wkq+?6a zeZ>}*PBGV{UN4^h|5x(S#T(39odb`t5k$k;SpStt-2uk?$i(&sCq5aSn@&R*K5apI zNnA%Nf&Qj+Np50ZW(X}(pJQzMZ0^7wieKgD3-MY1v>Ap6+hjRUCBqfRI0CCZN>2}m zDs$)S`C}&760-VLm&pAQ(7Xr+Ygz1s9Ya)gsS;FMX=>R0Cc%Bn*ozZsmuoeGlsILC zsJQ&Z3S|zb*$X45ftEA+xZq{)(i@mBC1jwgvz*)R%u9|-BI<k82Q`-cyR>N%ni7mC z^7l(xJ2|GSr5LR*`CfQa&{|9T#Zhp1_=i1>P6*5S?xc4Uj`xax%8pRz1qAd{o~Oik z1+wA^TjkkF2A~m7rA*Z%K@ezzG6oL0>7UT+6i|y(d}>l@FRgBUVde$Mg=n;_lI19n z*^I+h6Lk**wgz7C{AAib6?A1YjQk*gGiU)w8}VK%mhqQ@mJV*)y#qL?!!9A?AI?|h zJphs)d^L)c1q>}d)MZLS{HF{5N-{PPt0&1Jzx$a8zA4Gk>kUKcDQG^t`M9X=TV3OE z^e$%R5TAI5+t0H8)l+sh0?1-D0L#=a=3i_1uOy#>ue=5yz7hU!v;6O*ZT=;x>i;eO z|9SZgVT5XnMP+euarLQ`MB1lS#SL-GY2aB#Wh9d^JinimhW@vPjPW3!&Rp?0+Rpr8 z#M}!^6hpM=d>LYhsu?p6+HxalFWMKXjATat)&)ADwV%NZanE-Kbow=tzj~382}$ca zCd*zb_z&ZGPVnWtbS>U~nRxXN1A0!zWFdTjD6#7t|4b6T40IUy8J0H`Qm_A!CNCgS zut-%G|8EEW7k0oq0V9FU=8I%#K>NS)Syw_ro5?7L-2APE_msNc3ouC7T}ySiFaPz4 z@-1KarG9mO@LyYcX$J{ys&^E}NcyV*Sj3mb7Nmsne;ZheI|L-q=#iKa@>i}N%%|Zw z$5ns*YhBi`FokfY7U@2}zVInvKjn%65$lQkW$fzteARq(W-~Qo0p2EWp9&6(J`v+X zL!u<iUza4pQ_nOyv<$<ZD;s?ER2dV9v+7gEJkq}xchWsqBI$pT3<IXnXzT`j*a~sj z3iIyYyQ#1@i<He+2;Q?Sk<h(5{&CuY#LzdMC9+>Q;PT&eH6+vZR=>64NBmc9QgUl4 zh;&jmYrhKq6AKvcL2?5w?b8uWrVC@skp&c5lS4@UId78RlkhOKAxMP&=gI!)@HE#_ z_oz%Be`pH(X^xY-E%Y(|z$;VF%y_}sclCFn_HSlYgMXS+?Al1Ne-@&A3OG-sodS`r zi~J+EdK<oe62fXrpD4Wlnc1bZp5{-X)%X7r;Qs{yu3!cni{pApJT+^esl%~bPpXME z=(}SB^at(2_bcMFhn$8Mmu^Q8UEIbcDp}ohL1Aw5SZrIVJe_3*r%@wD!Yx(;d2Bw> z$ujF;o!evI(=EGT{c#Bm)3U8px<#7n>u!t&PD+=O*&aL(x<w6APDdATmE-E(=uZ<8 zQ%0S%vF$@{fZkQD44^kJ&o>${BQuI?jP=(|x9q9AH{x<=PdyLeyWMzYQj#^i`om8> zT#Wy70r5NoXHc`(zV`e{f$07e@dVG_&`+}W@7sY{=rr?J;$h~rJjB4QM2@)z2hFz* z4wYvnM2^PUNBiTFx0eV}b384?%)((<t>o<N1l^6Cly(-)9Be4DL8}9CDl9jTyL{>0 z_@J^!H7*q2z=iB)-=?3dmtoAYv(fG|$pcNelz-tI6>pYdhc81&Pg13v@76L3qgEQx z$(XU&6DM>FOYAdSV1?)hM)GTU^kMTU)spN>@#$5A)0@e`oa(_G`M7ij1VPJqf@qA5 zE7ZuZdflfJ6Ik;4DeS=pCheiNx5vb9yooA*))T(tF@N1L6Ey+)bUnjsU!_hN!`GgC zIzf}1GbM~^Rsb+BYijudG`~MDH_Ou6USYb^(21tUuQD$=scgPxue`eunAa)2J&ZEw z+mV}i`+7=C>|y^@eni<urA9iU`gPXE&2hg^%4QV74w;z2wft0OIvHry?WbE|sOxMp zgV^QP8=MzXqGAs1>YlQIUILnp*e2QX3I~CpCFjA~>|~{U1JpO<r#(UD{WPe{Azx!W znD#UtNfFv1)mlEPa9oH+-Ia9Pb`m*Bd=W5X_uv`{rB*#|pmldIBXgpS7jP=ULsbAt z7=Sn#`p>NVdMd6?@-}-oEsJbRm}RS^c3R@e93xM^3pjZWUG!*(_-*}k1wV37T$hza z5fWu#C4(d6I?suB9%KBsBO+3$y8VQ|*NS39P3lkO?~}U)FEL;4r((&78~3rFc1?V# zzrQS-a`nV)Hj*pjRz6KDb~Z`<N`k(-1o-B*Z`Pdcs@ll%fk2RdWHO3?5Z5)%fwyko z!NqmirvBpcHS^uNpOz938p-y&1v*<K-pia$JZ7==k&bm1KOLo+OZM2mxNig#0I5!y zD=K~~|4vFYe$n4vLBN7RWrM{Ex!1A(G|x8Y@vv45Em@ZiRG&}3i*PDl4Yr&%DG&I| zy6%d3kqCV6z=@0e#Aac9fZgemREmis>p@&Xnt|Ch*~)CN#Dw#x@^JKY+jf}1eJW|Q zyujzu%F0gpV(*2zDUS(WVJKjL1bKO@qHnBC)Ix17k^oR*m+sz`+_cL)o~!vB>z!rv zn@%RCjUJDF`D%6z<)&@-;$_}oCYQH>Drkk4H?{gpZ*~h1N=rQhVaqO8LfP^2vBXGX zU*lz2MqH*_#ySOARI7hf1*k#=A>3QVd}ckLN&VuYr{~RS;9WzDGDSSQcEpH6d?`&G z-J}vXK=6b1=X$#rbkJE28@*DC;{`e8NH0+Sx`@^jSUkaJkpfE)5Lzb}1&QB>jMA=D zNls2Ho1DZW$z)kC7sZU5c0YxP(p_j4Y6m~CFH!YTmLO(@6*(GRa3Z_dxT>k5lgCVl z-uu)GX)5=!aRo*kE#8CrRzeU-k&suLVlx0N@tIM~ADMu{<eiOaow)LT<;xOGg`C<I zhQ|2j)+mZV{M8E`jrh=Iuncou5}WlmJByOidIG0<7v)Fb{>7u6_rgfCRRntH1oM?v zc6-}4c^6@l;OEbY=dCsgOA#|_!)Mf>^s<VsBX{zT8?W%@${Kk-tDDxh#*Y4cKYTpH zSCT!Dzi1UNC+OOrr?DFI{rK(AeF3Ot=47?zQzrM8K^lf?9#pvRbnri|fP0rG>-^0O z-Ic())bm?)PcU)8;e13Jw#xz}5TU?!{o7|I#`kMJAa5oli(o>A+4r}-)?68njB?cc zw<2Nct9H!wLN1_&v@5^AGF7QpE|lE!ma;_|F(FZ<c~&d#{psc4DKi7hJFS~by7;AG zkg@e)!U50#9b<y5`<5pE<a_oxGTw4+bSKs1S|W`FhgkZ9PUQF68gZAhGSPI)6AWi7 zKUfA#{jS4KVLN+a4tI&{a|9Q1Fv`3A4^8TZUjTR>y>yjXx@E5ps3Ii*Ip2&|g_B+{ z)T&IU46gl<J*LfoD7sv}?JMEk!Nm71DJ)vwck3i#Y6{OOyNoDvuT!$^@Gc=rt_`Z* zr*jH<NSd>62yM|CNOKlHUAdMml{w0hV+?iNy#o<1vrcIb_$h5+9+92OA8Th;)oWD= zXaV9W27`Lj5g9(bjBq*?2R5QJHI*edyY1JkpLYEu?4Qjy5SOx}0?5>u(l*Y1Tii5@ zSNCd4c5A&=5n3=t<FE+sb>F;f%<=r%W$EQ)cVJ$*WMkG>qf-0oo#$z|W$MC@tQ*mW zSEhz}+N-VMgN)0dQ!l~U8OtniNBs)1;~}|si3WM?NA)poQWp+y$L3FcJ7s=b?z==M zmMb8){Kr=j_(`28PD|988Zo5TE^6|we4L^+*UE90?l=1%%H^t(0b-9lGs=hHS*czv z4^2%sC6E#6%b25P|30+y%TEl<$zlwReIT>O6)2Ks;EqU1_(+ru*chSN%+!-*z;R>O zU3!Y|%(^*Qo&J!*ropnB;@p1#LC`oW3z-Oc!_3e%6jcA3xls`S@(29<D+d0i1_63R z=skFWhx-h4UV5|ibAP0*Rth>@jh^_v9(9g|5(GpuHQuE|IW@^G=~>6Py~xKv4GAy9 zS1dXJJ5$NJXhK=xqten>6HeHw<>+)M=A^tdudE`kRIg${VkV89Vi!AQ0XfAB6}g(+ zycBz<P42>enRW7EnD0*6AGXF`6?@clvM1P7&0I=@&C;`jj#Cb-5dGF}JWxD*W2RJQ ze@IKoz*1>j&w)C)CU3sEM4|C&0W<#Iq$<8ri(aGNZJ*jjQ?Khm9-k_H-z-7!i(IC1 zX!I+M$#xp-{Lq*g3>=hhC!WfJw-SdKl-GVR_*+wLdI>r5y+vxg1g&PbmuW?_pRSa) zONJ(L?0N?<Pj23OEZfl^<$FRNYK^rl@pcc;2+pd$<kmDF<P96R-JdR>b-o^ux<P}Z zu@7Cr68;|kjVw2JkgoH#ffU$kXuQaqW@<>OY`GSBHQ<?&zdpaC|5!K1A-ozNOU|>> zL<2TkD7@!ZNtUn}b(LziA^gjHumK>M?^gS&SV>(!Js;ylNYz{&Ea|K^OD4;(f}_tZ zGs6coUVd;|<~aNgbjt}SH3G<!zq%6_pQ#BNFqqSNBzuS7MmJmYQ!~3lD)vPlvwN{~ z5mHj_>Iu}YnOH@G<pHM5rck&{w+{7c!#!M*3H})ElGDb8gNA{FwD%JCU6+k=Pb~%+ zyI6n%Il+0tt9awku$B0N>5pQbjH5-9(or9ilofNmfubkVW~==$i;&I!{i%XcImHKc zuwm<(UknLw+)6&9Lea%nii&>}J(?j2t=4)(S*6mqD)1NO%&X(e^vqV$;B-kApDm;d z9MMQ5-;vj7K3~PasVfbv@2M$dCbFo_HCvCq9X#aSDGUGR!N0<3)!$H3AEhuR;cwRC zR4pH!ShPQwdode4Bi$S}ePaIVl`+GOM}diDCQp;5`tlh{;RskWlzyepJ=7(@S@<tl z`HQR<vzgv;E+g3!@F(;pZtmb8nd$%e1-M{ddxZUQ>U*#2SDr?qg|c4Ins>9jynL?C z*J+7$QHXvQav9WK6Ig?NuZ_~a35L)@O{gieQYlTUauvb{`4T=G{?PV9tuluA9ERq% z5cfXimhP?ryy{0l#WS<;6^^`#TK(>17z{3Dic1(74Yc6wb3}K|)?AwAYenwWPYo9n z<r{hRrxTowWVp1^cZ9>pGvb-nDmc425TMQ*KSR&~b^PVwqC^IjN~N;7y&1$TTYxmT zCidPI7LC10PzE8=tG*!NV0*1)%;CbY-pk_cH)<z0sP8zjW3+B^z9c(f1!r6SAlUit z$v>|l|9!hids#NQuw+i#c;$9g{k7HJ0)BgjhuVVO{EeTbO#@FQP80V@p?Wwp+RoXl z2vfn*&8Uo~lk@1KmTKv-lXK~d-Va4uDglYp^b6FD13vOKDy`KAv2P4emw%X|q;^>z zj(!sN9QK*H+rTQSt-CeWNdN~KHj6YkfGb4PX_(*9#HDQO%!0+uz-UkFW_!;u@S!-p zYbrnJuNMQaA(+fYUw&LB^=eDR5#7nvS*e!hZAzOMcE64cCC$_*B%W+j6c6uv&q<7^ zF#W37lrAvNqEP2eTx>kGlbdJVlA~S$t>-44+D&imfvp8!>s_H<%s%Hult;gYewD|M z+4Zuog$;X=@JgE%Vek4ehAx2x^(lg-vp}bd&WGt<qg!oE1ouz<q3QJTD)w%{tN{!A zDJ+sLSlXDgI;{4WUDv7;WhxElB;@x&X>r3=B~jfh&2^4SH=qxDEc1^`wk~GV@>+^- z6r)^McX)zy&IpC7{H<cP(>#PLtFQy;gCydry9PpJA0J6m*$lOgUq52GP&b_mG;Wmj z<v(QVy6rn+(@rz64-Q045rD?9-1p5C8qNM6_TDqB>8*JiwE-$3ZVL!Vk*d-(2uKG} zdQp0S01Ban(0d0Jl-`jJA{`P)NFb1a=%$8V5+F3CcPXKScHlYZyw9_rckk=HuJh%5 z`F~!lthHw5H*4;DW)`+_$&Ck5buV{>gUrNiY*ar=X!VDUKf+z>Y0gv(dAT03wA(4= z2w%PF-btZ?0D&gpHc*ZJ25PHs&I!-Ky)2$MyBP3E+Vc}`hQf@nugFU8)bU-GduChd zIi%|;Y^<)65ZIMQ{q3kZNbZnyEICvI@e})sCj$haaI5**4&9*6A$5{!sMa7p$}wlu zBxjFvq`W72AC0{2wC?bH(s;rRYVUF-`}YJ{Zh5G+NA|Bg4w|aFq}LTqqi}Ktk5_2# z4a6QUhtj00vao+L{SX7JEDJd3$hEA-+#9$y<a#s{c<{dN`O8u3smgoA0;-!!wp;H5 zt7GLcbDZ|S5dl_Fe1linKZ@m)dc3Q<9SRmBJQWw`>k2Eke+wOy4F`Z8507dV4{$!s zMjWQjlw=ZIiS%K3mwGgcdcRcr)x4P}cCM;JbwtmjxPeiCRt2*&q}6K9=SGeUIOsN9 zcRT2y>F`3QXm$x*zelin%{pr6b=llN80jqK!u$+&v{(Ta5X~&zAL*qX!&L@*_&qc} zdT*5)q#5|Q1L0WlKAW{KYI`9zXaN&V$u8?FShJBC6mR?sl@NmD>P6aU+mX-})%HV6 zNykBRBTO<l&QodGyv)^1`esyZ*+)a<HM{6Xj`(Pok>W8D_a%UPu#6spU8`zczDa|+ zBVJT|$3Evrdrwcl0jXAaR;{>QY2IwvR=b0D=_@DAG)Y{`87VZW5<Vopt)N!Cr9}Ku zZnmnojtx8zm1FV6t(zq+%L%nTIeC5qB`1ZFtr6`mTC>3gBEK;FRe2ODEuM!9+p#fh z|2N%+l{ej#X98$k>=QKma(qs+SpYM6gNgH}$Jb>!8GFvZFd1D2!QdO|s}<n4e^0gC zSiW!!zG2)<v0!5VC+hO%rOO2L`})p%f6vBn%u!t?v>Xb)4gR0`|1<yp_xW8fIqqIo zkq-(L)qHSQ(tO&^tD&U~QWrJ--yGkIU<>Fi%<F5n&R^0po0@8Rhw$HbWqNE8e1KU+ zlg0uc8@W~Dy9Ld#MzVWT?<A$9)9O6LJQ*J8u{ZjxPT&p%qQ2&VsCnEL&H*#oo#|$5 zt|#Y3ZjE`iw=@IXpBE-QtzKk?L2T=renkTmThnE|E3Xl9+yi*$tr+)wuc+)~UIB2( zxCed<zLKE(YCn@Y(hZyrTJJ7e-jdcsh-DwHgzl&LLJQyj=|7JA^j}}?tqYeRmcPUv zUp|eg9M03e(E9vX0f9iwG|{jpVch0B7W(pMe}=QCD6{#zSn;oZ+iD0m6QsF*@1tj3 zM^$2p$?W&LBPFuOjmKp8=BiVWl#-HR<C{PAOHy+ECgLwK4T`A#D$8_=$_lGyNkSoc zJ17bwJp6tY<)C_<IZY;Re4%#InDbyY2P8tn+~5H+r98=0Ms92Fd0P6Dm(MpwbIa2t zfP`zGd4Z>)d{0`^BP5?z>fu7HOV=&Y?60*Sb-M0Iy!)?IgV?E-v*|o2FV2Mw2>t#} zD_pxWyuUS%|M&-&so3;c>FEAI&M~*=+K{2ShvkDukNT%ZjH?Xs#WE*{TeIPEhk5R+ zqoRNoELPg98{sZEO;|EvuqW4fj&;M0QEGt)q{$AFQzNTgJ|zsbcw`j7&mfJ0tQbpK z2Y5FxjY^#Ol&uRNyNse6Ur5cfH)aLxj(d&sOdLA2nmSBaTLv5)Y|la9aO`HpaM=kq zdNO8}RMUeqHsMRjwd(oI?FJA5%@u<cV$)KXuIt#ZT7-1o70GusXS~tYN8$egESlvL zTZrN2=2OLlaZfvFlRk?yUC2rU+|LBdKwY%Jo+a5mnPR+2Au{gi<(*~%iPl!ipwe%X zj+GoHyc+3T{315*VXTjp80PnoU|dr(zH&dqsw*fa$ua9D_x=08{#K17?h)Y+&7SnM zRzFuX0q)&5nNm^&HhcqTf`sBTz&HU@lk)j#@XU8jgq>%YyZUvIoYj~WE--Nhvy2P$ zhlgAMN<Wn5V>PsfIhh`K2*f|3Pi}6wHYu+F^QDjOEZVI59bk;n=?Mo6wQ3lz)C)^S zj%hGW?_0x?ng@7Q(ZW)-9LmV7AM<5nmR&*J*&+|e=Fg=)<ug$$l^t#PRP|RIe(H2S z6xDTb43N5HT>cH&Bg^kK<`Qn|{quwVwNnsaHCX(5b5K_sGtC~jm#2{ic-gR(wf-VB zAMMmyVN~gIxVM3T5QQEJ2{D+cHFXCa@6WGc8(~n=J{^mgik)2vEyXxk#MoyQMKrCa zm)U+bQw=^crmnmLv22UGFJxqYU@#flrk*N<0%1;$56Y}A%WZXv#Jf0-*9}4a6f9`} zj3G+s>FL!<45Jx4$t_MHgIQ8ub!b6bh=O66rBKj5-aIp!>;!B#+n75z-0D#ezs{N& z$@m*3nUd$=Q7-5gus@rMQ!m3(@06#4-Exw*foTcJ63V`?G=8RO#P_B_SD<;V+4X(c z@YXNihY#ToHCSMGhq)jrt5?>O@H?6is~zmywA?g;`dn19=vI*$jMkl+8)6#P2^!Fy z16L%K0~Y~K6o24J4Ku^l;(kYYu?lnEtxX!WxekFo@BGf3x>o{NW8H_{lMh(jkl>cu z4Mb4yQ>GDhx1e{DvN(%kYI}b5gligiM)d9l+-rs)pAMEO49wVKeoz6R&S9Ox?A)~O zT4`?7?PKl8A0b1}R^LXmxTUbTm3HPdy!z2>@RUQ!1+l^|rH&w4<3rO77d>u)Exj+V z$#$7?UKIVDjj~GNuE=4(&Kr5j-RDD8yIaA0k`F?Mq}h|hw?!;ZJ^Fc|mnotMDC|yc zr$tynJyW8tEXZh?udKPKu1R-2VgOnIfAFWOETu0Z8VWh8S@;_Nn#P&q?=9TdicY&9 zEU(TmTxA(f>!>7B8N3>Chrcuv@$D`78%%%i2mA3<Xv4{l)5+WtJ@eDz7SD=ML5xKj z)(qGfh%@yX_n2@@Cc*>BWt$86v1<PQSlX!3&xg}08XE5ByX)5*NFW=9IVKV7TBu2X z(}j|=ssesk?RTozg1wOCJmV?}V|gN_^4mI{_!tKh6O#~&_gJmV+K~RW6U37mr^yK_ zYaGUyW8}ibM1%OQi6iD^e}Dg2^6r>htoJmsE-n2&WD9j})vZT{Pwrr(XC^^i$Yl$m zF;QIb%4#J+gDK5Aq}2@IH!A=Xam~9;E%K*tpJ{(-Dv$nnbe+u;Rr3+JPqDgz)*a%@ znoj_O6xEGDx;@?*{P*YaKz<wbx@NU{9()H6PlD{ro|pXkqbSMr*)k@i;|$ZlQ)4NU z9f*PL;9dL2=GHM8#ru_c0Nd}uzdL`qyO(@XMK;_N2GQ($24tl4Nx4!Y6C}Z(+#_$6 z(als0Ij_6|Vw_8dlfIJlMsBY?E#7ZAe&WR<-W0tb7XxH}(QcF`coEImv4fRK@Ex*{ z+56%^4Bq%=Cb{vwbl2|t@FD=`-AGVP@ux%B+gEn7rNRz;XXFgk+9MZ#uFM3NXHmXf zOGoJ_U3ce7aB&lv9ocq4RP6~Z-l-IOI#p(lWgzlv7Q(L36If>%{~9eI&g!s$yBQ;# zy<aZL9&Ha4Z=rHuk#7pVg0N54<gTAyAFL&7=4|&}du!gD*M=KaqR_4*;8cu!#n1>E zno(xoq-8?g6nORO)tRbRw#cVHoq9s63_3bGX7XcYT}k8hUS9B><-!a{S5nG(2a?~; zic4CZ+<v?E3~qNKa+?K{I~peV#)1iTjPX;LKRQrs60QGpZYmibbhM0c9G6U`J1eZO z;eHRMF?nK6tESA)Agd99ocx(EsOzRg%LDJ_{1~l&)1R(cwUo+V^!Tp8#2P@)!-v$- zuh0sVXzrMPUE}W-q23z@5#(t|6&NgD<UImrNT?IEd*U2Y6@1$mUc^0*+*DF~^)$~Y zvghTlz^jbxCm^d{4In^BP>0m`I&=4nihUh*Fyv9g6G-hdQJpSCRJdx(-eN-8NMoW% zVV#JXe;p-2O%2Vz>L8DXj|i7sbZA6ydtbcF&|xft4WzWS>Cjw!`pTrZb>~uOg0y#? z22&lVFotEZ!5i9HEpWfez~#YT)WS)1s+RbgELE=FLn;CM06=P$7I~=f9KTo1b3=fu z8m42(YYSo&oARIU&KlQ0o+^f#>^OjC$4)<typDJ-WzJTCN{Ac!Tq)HDsOp6v2FI^o zoPIdXv5M7?Mu15>3w??L8N-w+jVW7&-^I{BeeNsBm^3IOwG*vEg=L1k2p?!5?5cxo zrT4a<=WYm1)vC(D;8%)|?^-917B$?umSoG|#FrWZso=4tUgQYy7{S#wz@T#VB}QR9 zUdRFFWWglS59p`QOII;Eh$re{nwf&C;ywKi6K~?t*sTeOt2VUavAJS#UX=N|cNV-E z1E_zj$}j_q53zpY^EIk3x70@eh|)2ArQfaC6KMO#+V8!i<mq}f?eW-*WS*^X9tZ)I z6-C@FFnkDX=`!P*wx<4S;Rov+ve@X{K96v=N<w4R|BG5nFFBWn>e_Ar2wpO-3l_X( zVZH-~l#iC(ahgOc$K10MMlsMDjRG$06j-I$**A5FPx>PX5N6;0oI4P8CT~2`_Tm6v z|5xy+F&ciyM4i~t%xEr<YUW!)n=qQ{KXP}~W&{CV`%GmI9XB;mCxn*l@IV+|kO@T| z(Rv57RA9lW)voc<VMZiyBetFO_t7Q+h2mjdVe@WonTj5ln#1vOFYs;fbthivLR_Pc z<bjM@$%yLdkiCm<tHG!NP|YFiiVwiA@dJgqgnN6C=Z_b>T7AO!{-|a74W+b%Cx#-r z)669oA%#ZP*V%X%>j;oQmrsFXjYh7>xkY05qU(9q@*FEB5lEavdfI&;OC(S6yhu^h zKrs0glgQ)uaXB(SsO-DIguSN^2{ujHG(1vy+}q5BBM7_|<(H|K?5jAgTP>X>9)cj^ zNA(Zm!hYYEXQ-bp*ZzJ_$Y);=HM*0knbb^qX&quAFJ`TIWs)z$oR3NDp}q)YehEP{ zyT-2F5$Q2LA%XE#*5~t!(ZG*A2-&-|n35v2Xr|=24SV)iYV9fHJOGkGUIn{et~NbS zt0M$Nyl@!TKj;^R8_mrRXv=}tqk3{q4(9=O{oFP0gHdmYIWcdiQDjHK<sp7TYV;&t z3srE<A=(%|>|2>?9*7~KTt*qgyK>|vSN({iF@njja3H5FprOPe-sJmz8JY2skx}$9 z#zYj~MsAsIB#;{B(jjAo<n;;&M8TN$7ll|uULuu6iWfSjMl~(|{PE6eqNAPp*TBu3 zM~N+k9eQ1x)oDC*tYzxlMpvkG%TBa@E4!3kI!gF%SQ{B&$k#TAQs;hbjoopQxfWMt zNz+CV&GUU7bU@O)8vV_D{ZFoTfZObaF1@S=(@ORn&rEr{`ZPwIC7o*CxPi4MtkNW1 zzIJ-fcUf3J(-!6Mp*6o|j#A>a*1PVgW(|v4p3SK?P*+Lh0V1vZTdZ7k`xP(pc9oej z<P|<y_SoX3>z}2k#&<e9?Ihgj_T4cdxsZ0Tx2Uy}HM*i$#et2(8nHza4!d?ZN8m9O z`*j@k!g@7_^Oo{;!qF?HvNW{V=KJi6RzWQ<m{$6@qmw(EtcHBGu>VP)$m4H5Q*LC% zegSKyjc}d@88<5hUYpbtE@Yu6%Bfx+H3O`nAj6Z5FJCzK`%@cc8s6i(O{ydf)YR2M zuLch|9|wU>&_iT^YCe@XMAGJHgt;1B9Rlw3#s4wPj5ZJmwr5Hnuk(<)Z);Cn8?Pr0 zZJ9%8ux@DS@2QQ4vu%t~`s_$ByGd5Ij9*=Yj9f;|i6jI`L3wsAnN-$L7%OIHXS1Af zLp86UbFb+7g?e-ITjno>xPBVYBia8{hKlFDX?#X^-9YY^{j6Rf&7iKr5Az)!oj6e? z07FdtnCP_D-PV$AOQJ6jkEWI%Of#~sCTy)8JlriB`952h0%O#xF!U3nj;?CS>3r!M zbajV6e^=0s0=B>9e&vHg8e|q`b|rZ{Y@QK%tRPMpaEs-q`Sw@p>W1Hios%XK8p>Z` zjJgScSgs#G<~)V0FV55Y0yzlmQDkwa<$eS641zf^6oKBU5WHg1Ob8^yo0s6rljyp> z&}z>yHO+Yk0W&50V(XzvPY{%7kQ3?UQSCE|S+d*#c;J@px5@%51iLKof<{%dT!#f{ z2`bUHnv*!Nh5f6luyb#)fiGn3od+gW-=W_jJnh3e2T{hYTFm?*<gM9eO-@~gYchgI zLrm{09)2X{Vu0UJ=N-ku692r;08fsJN)y`hanO;U6CTi*8hi-AvlpWz1_6!K(Wnq1 z)3Cqhf=f@mah0#l-P3^N&-cOL=M9vlvUm@tRrN+{I_5#!v{-W1OsRgE>ChisN`t!z zB4$o~UtXp&vD{#>B<DIo-#zT^Nv$0;>tE!)_#TDwah-q4?{1lW2=&Xml&Av^4#eo! zFo(AA5gqZRtO7!Dnm$2^&*>V93PC&<`|Gk&g1zuMVDx`6Cx>aMOAwRqtTr+K!2cy) zIJSV6eZF`9-SdAaZ8ZLTu4$CP^GBM{-xGv?7M_j|V}+xx{?GjX&+|q6%|n}V57$qQ z;Zb*=Jg@Uuo(puCj4?@*@k1X-{P-a$I6jgoOIgTo8!PpCJAVp_-`M=dtq1hr8V)z{ zLuFO5e_IF_dBb*q)0&AZv3hDoIB<j3XD-cVCWMA9E>fsY<vOb*_wIxrd}ekQWBCLy zsKnHA>S?S_@o_?8B3DUC312nFWm*YXX%SLxj8coaC&3BF?TlXWc=q>Icj|v|82M4J zS5w)o&SU1Y6OWG$lzq{wv2w>ozow_TS|_}x>3}tkS*9+{cZ8<)3xosOv(BJ1==avq z?xfdz!+w`j-SWyF$*EB=)ztNq!)UeYg^=KDY|=(B>}H2b#yWN@2D?9(kq{Thagq93 z+-WF|_aK7!%t*&u=0{70T;~mF0VWnhEZU8MNA}V-O+W~|vhvmOW@=+?1I{q$8=>38 z&j9OE%Q`6xr^`^EYzP2PeG74fSr0S>9DK}+CPmoTAArGN*CBmFiCZW40=oX2dHa8k zs&VB;xy-v7%f<cz*X4>DrO*g7BEz5CGyp~+(+6k0!={1zvzr4s$9lY4nGbfyy>eE@ z>kW^8vL825IjxRO$I1yU6XB_6^xXA(&p2-JYB+0-mVr)A5oq0%L#hzy&lJYWX+ltI z4D0Oi!Mc~nX#@~j)+2X<#s5Z078De~=vi7d#m8qZbc*e~&R0@(bcC@C%yngqdl0%) z1WjhxPd3=O=F2r%Vp(h6!UHJVB>-iq##7wkHF2SdA&SgMTN}eBBMBg$^_Qot2kzE8 z!lb;`lEC;BOq6N8^=P$S|EaHPJI4BKjd^%>&spL%OoNWdXmvY<3+pS=4;tIXguqRW zHMu~MA*5ihY(uj2V_4C4<I16N`1dU!KRuszqI^J3&%mHe*I(|`fJ=`a*l5UKMBIT8 z%1cm<K%}+);X&hx-v=SusU<rG#}A<SJ6$>z4<0-y-kV9(e&j&vwsRh0MXpwu)YO%F z;u;&@{0P%GBAIQ#Q0NukGDs`-?et(ds0KnjKHhDNjcSKgZ4w)ghd?%#8xiD<Var$y zsLW>7myDB~C?mg_$Ngeo2YHR(@xT&_y84!k8z<1KBs41$T4qyF*npGufi_$am#fYD z_3oEqmse<~058=_8qx+1J3UwGjd|_xf1RsO9Qv1YbzMkL0`}E=tzSJ#@}^2dkw4jr zzh$N4C5)tl8+_F{-4}ZA>rAFd8dclAwt^DR(BN7oxWu;rRPX6HP(R@*z$GpxXI`k0 z_Der8Qn=w60-9E8U{G%K2QdBH=-4STHR=9_un|NK0XzijJr4IaV8@fkJL0=_-WzXs z?HfH;hJUu~=CdC?a9yzy#}=@)#IUkp2JumX4<EXWG~j&6u4!2G92`t*QgsbvLNgp8 zJGG{Nv1TpVTu}QPz~0YY20p8q$&{mi-fwOxv8!v#$G}N9auwUqV-rdB_Sb)Utl%?` z<$Y^~Yky}WfYzJxt_00n9?+Ch<LRKOh!C|~Rj+jz2Rhlkqxe5GeEasTre@tV!#(s{ z2-deri`2N$!ZMz4h2eKKm|o!70c9C}M)Ho;Vaz}#Cj@?U00~;-Q%~nBvpeRdUE3XX z*qmbJz0u6r-0<hh$x-9Uyw(vh=qUATLBS_$Uc(Ktd8^ppde*8(y^joN2=`jSX<t$* zD3Rue&sS)_mk+1fjvUJ!4aljIgRML+;yF>jsLWT@(M!4lj~&bp$=d_kk>Cnrxw;vJ znSL0kJ_1~7d|-YsN;I7-4R{SK(#kSDw}1B8j4@ZIjQg(Rc2AuaZJ)!qDSUVoy<=HG zp&&gwDHTpt8^#tS7C6YpywkcF;@6w2Amj|qX0SrDlhD4N-4R^_gry4nkp3Lw-)`Rq z7~FX(<%<G}9z&)2YqWLlGQ%o83=fXZ-j25sv-S0@qb;3q#S03(+aC9tjIMr7Y*`sW z&UQ<!Cj}l+Fr|bdLxE@Z^Q)0{4kZ`i!;DeD5uBgb3~jx`<b}qIG}qmykA~oZclO_k zNX>UO1A=foOy$QH>7_YNHib{#>M!Z9H5{xxnnp!BNE2XpoYF3uTxi0ppjT({smk3W zh|B&>pQnHQ-QMMI-FViTf`(q0cJNfJjxs)lEhx)V!!==OBBY*5n@5mqh!9IAn4tt- zA8`s+6<j#IaK<I-Cn5x|OgZ5xl|0u4J}-jNzRRT1<%Pa{F7-#lWCFUv9HI^|^&A1m za};MGUG6Y4)(5U;iknH<KuI2Ag-i1*k|wPLfH^L=6m+VEvBPQ9mKa+`Vl;~4y@EwS z1AJGF{lq+bx{-))upq3bV8K4E|MYRq><|qca(oLM_Jr?MjtyMa<E`V{YsJ9JzgI*f zNp0N!fw$A-d$MH;pd|FEZ{)v^+z}WzrETy%Z*+14E1&Pxc_H5HaeoZ3w<_r5cw+I< zd}+=6WQ{OAlI$utFc<+YG3G68l!F{}@WZ33S0^idkL!-z#AHuCAI>k;b<2sLcvsM! z`s=d5F-RlDdkL`#o4)gRAw`JMZ4M)rNUzzaQSA+b<%;3g9YKbW<084E5|f;rr|vHk z{~?if?yLtz9ukpilu}yZp|0@v#qq<pZSQ3Kc&qpKKXL|&IE+Y$HF4z2zn_2i>&* z#lznGeJ{;_&JVfEuvcEJA}e9a_JhmHR?}?Cxx}Ag?@PP(yDNX4*rgwA0d>P6&nm;U zbf)5@cXFKY@S0@8R-G{Sd^;WBIE|HDZmx{VrvkkB$u{C4u=YM891V?k8f$!cJ<B=l zqM*stO!f!}lQGMJMB^)B8~Ao%4;>$m&)H0*{8aY}gUfMCp#%Ozj#y|4z4*(aO0V81 zuUKkgyKuSMIiyw$x-95y_S^)6P+ayU!Yh8|VS8rf!!Kcke*S69+AXtjSNX;b31zKo ztHhbj4_1w)LWV(GH+{%W*_+?uX3`%KruQU_TLa5i5<jK+fm{1}*&6>Vuc@V(+f@SU z9y$}&)*l}S8b6XI9>yI2@K!&b#K*v6?~47uZvil(Qq9K$l1)do=Dn*`*baw^`s;(R z(p77f($Yu9m<7)GO~r|vzN3V#P9Y!e^<ty3(&?A;9Y4Hwli7TsK22h2zfE6-73j6G zld)8Fj>mH^HwU(p9-CpX@w!69>zHTNLA6F~CfilgyQ&{PQpcW%uCA|%ngVC!Lk@jk zf5IA-&Vx*{P!+<;T0uKaVm=Q<IM$c$ebt2Q@3W4BRcc=BTam=}n?=s=KlVT5o5blU znfbh#sq2UiKy0>yHZxdT$Me=?Zq9_b7<R<ih_$(0$(l9H$2N4#3ad|gw6baOms!Rf z@c7x~NmBxgyUGS`&W5b-BwbI=Lg>?nfG{RA6LReF7mat9s<*hc*1?RE9wtBL%Vgh$ z&y2L9+XswmR`K<-4gEr!zd!CExOM}4R7j5y%RNK$R;CLQe{?0HD6@+2q^i{LwO*KL z#;mxqBxMa}hI9(o*c-Qj?LMS;hzr8yBO0XIg#XLR6B#&=J73#t&)h<pJWX_cLxz_T zlD@tz)Wtl3R`y|Hec-Oy9@j+c%n!xZ*<I#h+*U@G>5U!a_$<OR=R@;TEV-$5^VP(p z=;QQ9>gx^izW%N+ct517JdpD=jZnkSwqJAscs)1VkL7=1cDPl9z`v8GR7t<~jTs|M zUMMQq{BzwCl8a70Y^{X>)-zl-XQY^?9Bv)ERVYmR1);Rfq#58)5T_drY6!j45rE05 zBXmTf+bguGW{`uIfWNs``N`|dwMRxBv${UdFV-e_hF~A#>N|0#KWY8)6PsL>e?q;< zMHDA8Xb_ZgQk?kpHZ`}+E@OYb35$=HqUvld{d!9H1UzmnHAvMyXPObQSw%1U>cDHi zy#fTT8eQw)PX@DRu6|%u123ms7@;&N^Bp=&pmjZ0A}dfJdgwvMSV7YeEo?7A;B)Uw zn9T1F4!xv#FflOUAV!0*<u%c-pK?+gc}?O}EZw7=Id;(yr)TCcLLH;s)DfCr^julb zSb*^^B_34mXt+<*YMsq{Szql~?60G9Kj$8@II!3s4L3zoKM(O-|6KhkRm$<1p#bC2 z9E)T}oZj>GKQfd?pXqJKI}pIUTK-D3+upAScb&LAG)4ZBl}@>YO{zo=%8Z}IdR1J` z3m@BhO+=+CogOSyJAW73Z+Q+%+^STOJA&BdHJ=>DLT1b23$Awe$?GpnPq7NEmnn?K zS`iy`Mm*kpp*Ev$3&SFua}7l-XHDDFhxw9JB_9=s;4f~bp&`Kf91PD5Nfo(BUn;d3 z;OYXOoLb@=km8%#^7n$9t2X6ytUu5fH(}K&RB{95AgQ<nfvxM%xOU+n&hUOId<;>P zBjYoN`Wm*sTP;>f*XlFrkt<UYgPx2#w;3gRK^Pw6%%`=dZ^pc|EN}Pf7YwVhmg52} z?&e`s@uIsXe6Sq2KO(A%fQ+B-;*3drV#pieZ;?08JomtFwo3a&;M2UCC=H1oR5CgD z!zbKh%i?{Jllth}&|$t<2Bl>Ts`DsT{Y%y}NUJ9nRM<xlZvRg5!#vsk{FysvtWoq{ zC4aKbiN9Xmr1PgJ9B=iXO)_%F^)u3y+F~nzFcEfdVm9}C3J&Yk3(UpqX;cw2ts98^ zVvPyGh}8S<M)B;a>?t6MhM7g$%#gZCKzFRKI{SNVPmOr^^`m-sBgUlrihdt?({-6a zQy;A<L2C$dnRoyh#n=IV?zFX3H2j}!U?IE$@|EZ-lhSAX>(TsE-@~E&$SW^X6;$Gb zv9G;VD44bdiMJy)eI0qHIBI8B`788orfJaHJc5w&c;QBOSVdq+;0)Gs=5x)Z=Mhq_ zwq9w}*4^<*S`G4rWF|I3%<enpTTpYJ#{|Vx>p1Cptlq?Mp8DgjC@-k~Q8K3-yN^6? z`Jt&JajH@<$C=b7jNcu&uG&(5bGOR3OwQL-8#7-B1Jqg6NT*{=Vplxz3Y|I5$)<xl z_|1GaKX3;=$G#GclCEE?b!Q(Oik^Lc4>);`z9gq>u_N+%i1G6L3XMJV8mratE-X=~ z2b%CO1-Ehs#O+-|{lk)fuXq>Ty9OPiidyw?-wBs<1EOCpd*a2nTg^Rf4R$MGb@#&A z1mqYxE~S3cO53i#`LG`h2(#Cq<UP*_LRpkI#;2oW!!8_rQ84?&FjKK88ADXhRa6rO z2CQp!6$<wSeJv3XkJU)dF(YC&&zbxs`f#`;a7q4OF~{#qhvttxXNvJkM}0ggcJ)1F ze~`)19_cBh{KWDGk)#ijIz+E5grNOUDGhmgL3`=uWx4g7nHaAHtEO76^rKSYpX-ua zAE2}SdNRe!6UM>a2fh1z>_+FhAMtezF?;(7VV}NZE7lRh!QkZ$TJQW0BDih3iZ(Nn zU%CdI@LT<iy~W91w3Z8OB6Q2_a^q!`)xoW3nazdG;6SSem6Ry8_&`O`ioM;s!V;n6 z-(RSA=Lpl0rINP2q`7KCn(=yo8VKxQ<5o1ea2~L33VLpVljP0j!xwGG({|4Vf7ux~ z^M!2hVdS3;FD>nbmaX2LQF|Ewj4oUFo=eC*Nz?l-&|lo$GKxEw^y!L%5XZr?r1=h7 z5lY?sLN+uVmsN6dV~XDe`sn0V)5$eTsh*>OL4|aS!SrQ!tVW<H4mGyBU{;f|1Fi8) zUEifU!r5kCxBW|-!CTebuxhvwGpFU5yt|{mQ8DucY^2d!Er%%Tz|1$vf9j$`Z8A-n zfjhZ#F7DNLA*zq>-Q-WEk9>+mvz-?>wd}XvS1v)0zsCTK%&n!#;zueJMrI?yIAwsS ztDoaS51FcN!d98CVxq>q-rsYZc7NraKgR3GMRhS}D%9}^HWadQtPz+6Sq28?nRB9m zEy8U?hRE3_<%#&l+sSI-w7N5tYG-bv?nGK4>?@(GCr0On8#I>8Ku)`_NG}%qYLKR@ zIm*P_`^4*aHV@>Ml{a;z)EX&Pr`HE}J}Nq#!7-k-uDkS7#0)XkA#O#c3d!r>1Y&r* zQNh?^n`__{AscSELyTLD>6xjji7Yr=xIcomuRrLoe8oY2&g9uFvH6ptO=e?HzP>8i zmiL{0wt<h9E5sYp%<qzAygc`Mq@c{&XheUC{z7=ntgT%5Hj}HlMyla`R;)6wyW}<r z>~Gi>qP=4mJnZWAu;^v(c<SsMP>SW+xXhKoYz7PF|A>t_JTD!dFiLwWHLLuq@|3$5 z-Ss-{u&m<egbBWf&(v(X^{1f9991QSPBSU#L&4_i!6fXS&llmXzJt)p4rCqqgVhPf z6oz|Ped+na;D=4*m2`43bX;^<#;drVr{1`*BKbWVVkQO(I4;q_kVAC59u%~uS{*Mq zI@T*rHUQQWyC^Sp{k9`p-K%s2#e)VAzen*NjI4=Fv^DjXJIkXAps!v@=f<c~YZ7}H z0(d98X?tFZJe|M3(K4(MHr8u!T)dorys%6e@eTSUsa%$uR=4XJuh>Z9zZG;RJ#j(j zB9~~SXi7&xfMQtHQ{EFJp}IBK{e7BsydpoDcEMmN?fQf(bKc3rb+3cj%|t%AV%J!j z$zC1=pi%~I_KX}_-R-)CuLp1DH_Yo3pU1dqE^gj<_iF~@u_L`KQmD>jTK4)-`};}r zRM1)h2x}s>pZ9^Pzbc5ao%slS5;x+g5#rfiH{on4rt%k$b0hM?yq@i+=8z}6r)rqe zyVQ`UFkr|&*mEfU)t2xpkE@ki=>C(N3#H~Fv+1B>rXuJ~E`_mCIDcx-j=zu#NH|Ks z?iJ9Sbk){mo-mkVJwB@Zi&RY%P@~P!7nTeUE|f87l$93m!}#DI=rsbW+1JcdKP>dZ z>|c4bM$iFV6tURf77JY4eel@8?N{F}bV9!>K3~NtH`dwRtLQ-*=17Wmp${vq1D9{! z9$Hub+Awa3BfF%7SXSFV4h}>clU#cuTHY^X4JiUk2-=h`^-lpIx;{H^gFK^d{KtJ( z`0zhUnM-Ba`=RNHR)c5Y;T_eeXR%Es%9q|n^paK?acgIK<^tWIlJKa(b7&rVYukUD zUs2iPdS5ru&+#=y&Xj}x*fFPkXjVIX!qtVfX=1^0IalFrN6D2zruP-QGBB=OlXcH+ zV0n-0-6An4OzE#Y_xp2rj_Qx3PVQ4Y6QXp()-BuAYnHKpJ%QG0M%2IQHP^@f|E*zM z|I%fG!A}dCf3<Zhg`l&*!^PdA*>nGUXL)A2{K9gxb_LykE&HF%JTFfHZqeno*?)qr zmS=tA*IthPZ5`<u@_HR?vHI|WtHj?k^&Gu-FI<AKD8`HZ?eeFm);&e$ei6Z@F@LxG zSqeDpT+?XFtFLr_e*pQZ+f<hc*_<4yTz`9j(}3lybN$I}yNmy45!}eQusUtr9`4uh zv8(AxsWrbvPo|8Y$DQn+y7$k5Brh!;_-Ds7*!|_Dl_kF3!oZ>8vnI!<f*~}H>ksAj zr^O!fpZE<hKg);qUtoBT`acn&N0+)wdUYC02mdLdbi-C7BwNN$jf934=$9Gj?AnO3 zAZ<qf@y|a#lCKndL`(Dc<-g}bMEK<^cRGCsSpGq4H_o^NJ%;O?{~%KvgHx@ikqgED zK`9)ir%EdpxcA~8HrQQ$Mu#qII{lN`>7DB2HSpQTe=v$n;OV#xA!Fj7tg86b>hclJ zH~v9B&yc6%J>}xKe|o&+^{G)Qfq!!RgM6H=&x{V}<oi#Ln|!%?qddCfyTU&iZRhE@ z402*S>>m#J;*1eW{_yS}<nt}<bllGxw@CNDPW0n~!j(%GY-+XZ{&P<uVQ1g(M`q%w zOgm{0cWN4w&tIf|5$F)KI*Ph^jau7hh0wA#Ue5)cot<s})f}mf8GlDZU+0MnV=e>1 zaYnwPiXsP7@94)WOM8wqqEQ@>P(P(PhjO;It15GM{Q`Ma%(7xNsydlO^Z?>1nUu<R z`vB{2y}sK%S3y~yWVPOS_X*LZ+*VO=A^Y8~m;*{1AYSuc`^-I&ucs3yT=jUy!X@S! zYn;&OqABMG5M>t@k&l~py#U+dZc*i9M)yjIZ9Qs_<#Z=?({$!dN|zpJ`v}Xq6<-5o zdiAefqD72NhCgu=%XWrN{OX;I={y|v6|$VgNS%+m_-}!c890ngoE|;m43^iuwYOy0 z_{eR(+e1!l=b>(48&|CK%_|5ociEgkN{RmgX_CPYrK6|EU1kV(v~`PLKBf>GPsMRD zdI&}|6Tlf)5<0Kndo~rOAFyWQSndKV1JjDetuH?{sx+8m2)q8?eosqjL<46Z$IbJn zvV>bg_^*nZ_lelz`$Ii1*y)%Iw;>UR)+$QY&w}sb)HLp`N<0<y-wj3ZT4q`?9ORTD zMgIIXwvPx}xYs_O#1AQ=kCFUX<pu!Hb|h00c|=+xIy0Zi-gHOLKY{(h23;POnRu=2 z>`UK*sn^Nza@}^hEoAaw|JZ~{AdYHF{3YDqAhxC3&C7sk;eR!8+WtCwN@S1DYVR_~ zE95tDDrgSTE|9-6dAvGl>iqiyquGsvjR>$i%owF6u(h*VGYPxdM$SQ&o04kIEoC@0 zEDF^alC;&;6WNb{hp&Aes;WzQQs=+F`Di5HEXS;+Tn;%HgF9HOheZ%m8$nWkK&6kx zD(Euabv4iF=`vIeZ3UKR-zi&eBv3XZy82qIh{K<uW(PZ~TUzyoClaKcRNMJ(xf6dI z0t#YCbR=U)WK<VX1Z`MPzhfMrkteyX+MW3X;I5>VY~f(#Z+63eKm%xUPvTKVO6M(A zHCLLBAK@3NFaSjnTinWz&au$nY20*!_7%0yYRuzglzF?_6FQmlI_u9X@~LVmXpVR( zjC_{h>Yw|Syj)=46+9!5%^)i$UkIKHn|lMyRJ75f<M<GJ=lwf1Dv3zZd_WRN*4ntx zyY<Jr9o!{uzZiIIvqZ9GZ|-2`l|*h4NR0Ji*l0wQg30ABQQbKWmg$yfZ?w=e^Yd-o za7Thtjvt*{ReWt=p(>%HQ>Ade`u8(2p=@rZEmSwc1)wCNc=SZ1ez0ClN=kj+B<%`l z>+oHIjAcS+duNiJV*bIUO(a-nZ!Gx9K<QZH%@YY+&B*@Gs3ooTx6Upu%?T2AUpqY% zwNmZ)ar0lT=PeY_8lS6;5Xf!WsP?2-F(Cp5R*t0~HTWdO06zAG6>czC^~6PueBjKm z#@E_Gc!WCS9;^_T6LocYBqV@Ab?t2>ZdSo7so3wmiJ!SYBrMkpC(i9<)8oYC>POw? zf`Z@K{}Cugy|7j1s+-*a-{yp0x@xuYwHGO3@$GJjzxIbmw{1xiZu8kcRY;;HqsdLb zOw+`8-JQahkd3NH^CMmO{>X3YIh@k5yh`CZ{R@}1n?Q3gXC6h=By+E`3y68W$+h11 zBw-dTVxo(xeV?5yf#^T+;%d#VvhB&*k%ESnZ{zkO$?J)`8rfq9;!l+W{~ZNn2A<vP zlb_j6uOp>PLfGHW_eXjH=MWI63d6O`$8SQdY;5ZP5CYZdtzoyiRpPeJvc~f_Z{D2Q zpU+_=2@47)pQTSJJN5@>1@-t*)VrLZV+^Tb6;1kDTWcidG$DXqrMk%|Xv{s`8tWCX zK8nI;A-}<>UU;pIEsmnT6;Np(t&Wn#2z)vI{X_d_Wz{>l+$9JcH#drsFsiEZC9MUo zryB0&g|kK63)uS^&c)QmBIXcxUoouq36RR^p1~vq-_eoKp2(*>x7{hyQ`-QQwSK#` z75a^#7<Cj8adrL;$?P!^kX5m2>jsB3cvfIW10>e5TVrKlYTsr`rDSq5EyjS&#Y90y z)}lO$l>;Cna`<}wn^M~TufQ~bTl%&BT>WC(UdvxrBXXW8R`9MADiL@BCXr7GLBCrL z<Z7P%DSLqgK0=Hn$T^1^3&vG36VmD)*BH0vjUSe`16<Z30pM(FG5cJY^MvW@6V>N$ zCUa*x?+WP7x3-5Sk1)4o@P%L!!I=S>CKum<b{ik4`=9@cO&$OzepTg*7QQoY8|S#> zpN8d7C)nR`)3AV9eHDh?JdEswj9R2MI5c*4bS9MZAgvA#O90+s;uEeT4R*Lr&;x+x zy5C&pLxfW6V+npacT7fE7!OTPQaP36F?awxR=W>yRZS5{6Ez@oW($%)?x++@ZAy8L zD8SFGN~1S0rLzy>aSxN8mj2WktHG4c4RDXpU`gdQ+Y@+t?trz<ld>%e@R_*12#npQ z`R{&&*Euf0Za$+-!FR2ishfGor{0-7NNQ+m3DY~CqG8IT6dqqKUV%6i1_EwR;!czG z(tQwo?^;_r88Q=R?NS(>!>Nec$$f~l8q?2m$A?;@BxtM#DEoi_&4kVjQKN?Prh)IG zA|A)SCH$j1?$Jg?1=){JMq5Y^1r=ATLk6ovhd*S{%hjO`5iU4cW#(_15wtnC)8w>M z)tz_239_WTgSUK<$fEXVti)cR`u0AE;~lzedP<_yiiZQ3C~Au<ETe8AkEDyfn(H#l z|5RsI-wd#H4(rsuD-47X)d<)pl<bbUW}ow3C{$J+ls+9LFA|vA)-}2_=s>GRcvGS- zuE8b&B)DgBrcuP-82C1H5_XZ|S(HX`hr2t!ug9rUXnr*>rv2QFrH&|SC{|ZHbzc;( zA2JihWuCM{dnOBMEYjlY3>qwt@YY&ME=Y1f5e(^gy=`R?@?({__7;{w5Ki>jzvvMN z1lS}@<do13NsqemA%X^YA8s6rEk3*046)K}zdw#(JuuPF*>x(G{Ew7ScU<r>yY1OK zX1yzy0=F_I^@g>{35kiiE?uHTy@i|9cTRSLP7F7u*-vVJwZ(J6(s6;i^^+Ce%M~?a zK4ms!+?OVm8audWH)(gYI&lKCN~)=^BNR5WN;%Cxm0zTwjvek99Ion3)<_x<S<0d( zN69c0raMz&0A<-|=DWz_CF}aF=8ebE)&v3^Sq6dnHZL8XE?Gk&x6G1PB}RPcv<%a7 zKo+e~2hVP_XxRvqB(eMh(z^bO{KlhvP}IDhz>+hx3#*Z>@OE>TLLH7`{N0;HC(U11 zx&7c|-P+~%v>%T(^f#{w0#>cJbw{k5i`2bUU)U%veujX*oll{=<Akj$_%)pc$4CeT zoaCChe0{s9Nz@Z?CEd9rm1>{SICgW9Je6W@KVERh0BL{fja24cCYNIQ>DfngToQ>z zq=v#T9gA6b#p%H(tEMioj>1=K4qTc8MhU{=D+B231_DE?ex;^+fz7ruJLw)Cf1-bE zMQs1n?AH<=^2BW!>=vqB#2ro#jjn6v?dxSN$4AUA{l;G&?tXBzSGbg+ZmV$|c-`Po zr?uWzU8ReHu`3zRdeGc8Ul>96$CTt8e79`r8LBJRP<aju?$f+O97B#0;|c5m(K{y% zY$TvdY|Qe3x_Q~&o<%`g*@_q4Zk4S~trlyyvS<3fa6nI6e8kXXqf$;jU7kzr2536N za`v}9yVHVCc~|$G<$6(uBQxlUZ*}+hPS8erx4inWn5(+S`<>3PY;t<m_`$C!>VT9o zna1_y1C1P3$iWnYU(dMVPd^I(*n!LTRT=gIs8ffB5!;x>dQItS1AKS8@a4J*9Mvd} zmHiG^9ux7^Zcd36uifq0>}9`fQ~h(QDdJB4vR$4?DWy~2&m41L&d!MAfvs`cEQFPG z$L~UFbK2aB4vrf&4Ne05garYSOF?C&v3<M89;p3)zo6qRNhQ>HxEV2l^D{K{7}CE3 z?S7^4+3_sW|9s;CKfl{_W$e$hY7vCjx|z@6Mk|-4)O@C!)e(j4I_^Pim)RY=)!v=? z)GlGnf2%9r*8`gAw}yeK`TGw^%L}UyX)Uo^RvquGjOZG=IhHRjF8)H<0Ka>UxhN+? zZr!@YwOZ{oDT`o*{z&=wdvx@y_amW%opx7EK_R5vq(*D4;lOeI)z=1)jb)Wn>RD~p z*#0THP+l5$AJE)9D=QMPB%wRO_(9yyFqRpq$^96UbWR;i7+t-%M;CE!>JHswjHbx} z0iEN!^ss7W+Bf-m7w5fa8Y1`S@d+#UR6k=>k^9#6VfK#`3?U;9!0E8|mG9h4Ql7<~ zAatkb>g;98K^1p1w{Wy}&9o%9GMq)=HU#`!yNfwGsdp(I%_7k0b)?NMAz!H6O=>yU z#dBv-)EhfDr8T&MuebVrtO3mT`3Afw8Y%Lb4?;dHT;u}F57C0P<+siSj8oBWRmYz1 z7b)44h+Y>}(U}E8oA|Fxg!ySMNoWj^Q&e1>O>HN|4Ot9zGLHy50uTw)rF8Y;^v0ZL zszWZ+-@n0l%>B&jli^oxu8&{y0G09CXEtV+0kk08B}I>JFDaj>yJJ2aB}nEKvC^e_ zgVH%fGoO!W77BmnoaWO?j!%y(epm*8Hc7YN{d^B*vj3}P1;9K_HY5Cycqozi8VX(T z(@4#U`?MtOk-O3}*iGG)@Ki2-`4NW?Dn|UN;R&wz-Wywdi-h~=J*KouRbFj#-jYOy zHl!Ebw*Hn^X;0BOqf}XU&l0|?y<uyk1R&-wYlIz_G4W*QYG!C0XCLM7Hi5HbSj_~B z#t%4h>F4x0lPt@y;?IYc5CRjh)dH>Ga&vWau$Vp_i)DW?cYnSlng06{n!I#3)9S1W zxVbwAYNiC3ikZFxuX7GMLKz5OB@7$HS5yiz=(_k(b>7K``$H~QD7Ot5mX*KvfM)v^ zOdK`H-X}_p>G}VLb4BXG7ORU11)xheK1!T7G5!|nov#$_8lo&b>_r|jRBo{+ss2Q% z3BHnWol)^w$L)@_t_UtH2rAydOmT~^<nJ?FLZhLo=S^U_va_MILeKKj1)HYmd$V8V zWz$G{t*zJ_cvXJ02Q|~G9W2|;IarDF@HD4E#Hx&54bM55Q>>RS6AiRH8yNh>iE>Aa z+P|n~j<!lF;ID4;?VljM#J}n5?@qJ^y~qAeNRpSo1(WZ+@gh3(yv=1Y=Jzx464v~D zi=wHhFU0Rrq0>Au41-^adjY{QxgySf{E`<JAM8biVa)nT-*x#rKl*&_y|BsohwaVx z=O)~|+t1JL!vnfiulp$9&rDs<=AF;P5zYK6dPXhw!C<JSAb+*_VqixEgFU!Uo^<qb zzz$747rG=MIH_0CC)87AzMgILw3*f-{VHgtzFJ`2aJFn&5WvKI^%L_g<;Z2~Io~_o z=15f@n8aEl)oiqj&Zw=4o4#?SFV3Gl+mT+Sqlg1YxW2YrIutdw<{O2sYq=Lu*L<{k zAjnVL(JvAEas?4rA!&rz@Ux$mqFu6=Luz~3<qjF%s%pg5u<r1D(fsLKt~%+YzMOla zpjuPwpnDWztlQRK9m3$rs6Ipze4ROC=L`09Dn*kxhrfj67ZoGyBm9+jNye~9Q5%Z? zol!+>x|+B?gmFXGy<<d(2?HLczp;j3=O{-vdMydYWmSy^8r=eZ^UKLQygo|$m1He7 z25x0!D6w6*Bv^CKgMvVf%7NXd1xL!g2V|VOEmtj$s4NZP(FS?>YWQ|kzW$~JI)#q- z?a*H;u0S+{;WOx+_@kff93yY9nT?ZHds@E!&Y|O9MaKvrT`Tm5WZ_wYLJ+8@A#|%J z%<DtS<OMp0?4C?PO`oQNCe@J+PWY?eF_kr}M%Cq2t1_$g?~mDR54L;brvey-QW#v| z=HA?<p@#ovYiw_-L=?94GMrIFI#+ASmh`NWGXWS;jd5R;W5Dolhu4gAN3+5~@fmlP zzW+G;k3b6M4IeHG4SUcJxc&^0nzJU<x&46r8Acj8bn^~^z+qZ7U>h4hILuKTiQb>< z_<#?KJ=&5xK{EQ*kwN2gl&zoP?7q<JsrwD^c;s7<`FJYH5xb$ZE_&ESo`k~agtk3J z-qFyrm1D8eM`s}n(VDpCn&GjugUKbxRCiW1EwiOq<DYpe_;^DnoN@8+pAA7d$8|ug zqgW;Fw{fHJckH{pIW>f!KYY>*Ch3K<m%3W;br5?zQ<S4*p5~SEiYr<LTd141Xk)v2 zDH{7jtBf|gH<LC7PKrNX`}Gpt^-cJ(@;sKc4yt-xz)Aw)2VGdj+E4k&(8wZRQASO_ zrckVet9nSoE8`n=#zD!QZ9{Vskrflc^EWCzjOK-|%47;4G>>SpkWK+4P25O1iQ2ES z?@O8+R#a<z6z=Fo|2Z8qc;QWbK!7MZd%e@6e<t*!Pe_yNYT)_{^HG_}>jWav4~da_ zWJ62w91b!GGsYJR)9s9~g`%u?G|JFM7<7>Lr!HHNILK+_;*9D0+MpktT_XaTf*mM; z=*~A3X2Ki1&0hMY@58ECQA0z^sDpEsvm-G6=-itfqvW16OJpHmnR~4$EV<%n2krVC zQvV#19)k{#yh9q|?V21kF0noc?VcULSGTj}5-lJ*jz&)h3~Yt;UN@jnK@F%;UK$cT zo&DIPopNJu|6=6o#MPD$Og~!ri7=GKs?Fxe<Oe$jIL!Phkw7gbEFK2Nh+S){8#kTM zj4Y&DKe{e(P@gu*;M#*0Ee2_>g*YcN7>2VwCT!r|6jj$10R6_x-_-AmHZ<R!zb;^0 zQAN&Lt*;K$+QLQef)>7wMl+;mC`ALMhiv-}1!VsXzh6Y26M^J|xov4KTsCzLp_kp0 zU*pFf?X}7g)`L#`gkQKHm_A!hx%n|uVX325xCRscPS6D1>9^j1Ny~8D5BdG$`<Rc= z?Q1<6P=VnV7Dl$ZO(BiL6=V-K++`$PoLTbeGd^Lgd&mL#B$?mP>{TSBEaQ)RBL+mz z8q**2<EF)wesy6{q5Y{Pw>M>exu2JvyiX&Y`RdcSXgwc-XZ0HUNfqMQ=;v%S{Ky~1 zzhI3~l3l>F(uU9e^c{z6{mY00YpdMOV@*8o*NWO6M1UE_t!&lWe;e@b0Vy}Tzfl-V z%O9&ZlvG@DW}-5-Z={iN>-WapC>_CBy|*r>nl36_kJrxLjZi);b@_9VSqAxB#52|2 zx1^u~J<AY_TK~E4OPE73xNBy8?cZQ<^)Z3T#M$~T;4~Ll?B!G{g#?i1c%f?5yq^_Q zKa<nV&8^8X^y~drv|atoav$dX>mcQ5h(;BS;s@9pdQ%gmdp{Leq}0&XKmJ3lBfo%d zb7$X#330lup{_@W1A_4wV`QYIp?YT{ZZ|55a7>U1P@BfnqI?Ig(#5W*EWC}M_Z$p@ zM`P+MdS2!sTkY+dH6kxV`MrnP!t~*)JC$X>bB^013ASnv1Oz+bxNl@3H!^Qfm?WE{ za`&*ndI)e9gGAY_e)Y`4>EbvZ4`%k_dpB-Dm$t1<&cAtE31wv4kp;W=PB{A+OAL`b zeuCfOrS(RCY(FY=)LE1_{JQFLMN*r5Y<g)~c<_s8q~i2|xd?ws=_uQdzA@&Tlr%v@ zk42y)s?Qi>-O$0SX}CvlqknE9BlE15N_T|~_OQNk?Gx;D1IDF6@sCovUzNz5t8A+; zpuOWW60;WlYMImQ`|~4FmpLOpi-{LL0tVkl!q#_p1iuGOj50<421`0`FcUf^`F^Hn zOnO=3c_AD34v^E1bLDTx^=%bzJX$f6+?^-ZKbrhEjbEpdn_+UVCKA>RKJ(o|x12-l zXW-Mjiv!AQhO;IlQ(%n}L`zG{GLA)P-a4K@AfTTy$j(!i;k*AAd+#08^w<24DpI7Q z2na~AD-cj=N>>yWq)3NQr4vGt5;{@@1?keIOAVoi76PIa0qG<_LTE}2p@-19_>}MC z=Qr^A<KDS5_x^s*OokZ(Ip@4~_nfn@-S=)nkIqLy0T*F;!exD<H=JoB^9%3leYZv( zpW*q=hGf}q7J?w|ZVokL-#2Tf8AlgKR~{@SLI=Q;KK88+>&{5BO_;~XiZ3Jr7>EXd zCoF#iV;h}*DhN5kL)=BVAr-b)#UaJO!y$0=Y+cW!S+TKvFrCe%kQu>fA4X$roDHn8 ztH*W72^%KVFo*0;l^pUy{u&>pYkJf2B$~SIdd;&y*db@>g!nhIeYBWEE|FAQ3@U;4 zE`X6Uxlj*q>DKM5<qlOBnjh2JuxY_iYAFxqX+<Q*Ts-r}ea0KyXZ3_Iytey0u+7GY z(6BIbkiK>3{-<WE#=LY}4KQ$PxK<{`$+NHRivAS5HpvIteQx$~19;dtGwZn$+&df4 zc<vzck-7hO5&<q=K5F5<Y>A@8)QXSppbH8tN68)xCr%94VJqXv2pdozCC<jGR<vOi z%IjyyPZx8iyE@iGIjN!gqmZ;rii&8zD(r)F`Tuy2hC&nf-hBLc;rjLK?@O!j`?Xho z=esn>CQGXd3;ArZg!s3^a8QEpKHk`?A_iAZYnLGRg<D%&R|NICt8hXenUK-JZ~PYE z^a@moE*Z_w)8CWWjdL(8rH}!h&v@b70ltoF@6@tkWH<XuB4&%_9UVxI^0IGRQrhpV zQ^Mmf(vDq#TBfcPU{7UkZmX9&`$NL@O9hn%Fg;|eSK{#XA|j1WTy6{s8n?ijAC3WN zouO4EK57zSNnjdOAl&J@^G8leF!1QO6*|MGbyCVM_1wEpdMSfR%(nth$T{&kdQhAN z36%)JPfDexp64whTws2CQr4}LUryJ{!>54jgtXh-$5W=@yu@2UC#=B0==4`iCtitg zQd%&N{47Ya<?-c{(rRloOlTt`W834Kn4cz>xGtxQy?uk`q_kgx&YRNBwH<ZIld{>j zj~1wM_vP6W0M^u#1;G=B5-=wvUR9`>&~BmcADxufn`YrHLe@77o|FxDQG8QcrSamz zNts{461lZ$SlaLT{rRu1Y$qIM8^gw68ua6aNtBLS<Px`g`2o+@bAN#b;j#-WbW3=K z_qQC`$pvS)k#q@pihm4s{%9((%;1#nD^d5!1oM4}#!qhv<w2%glG9p0e;LEX?o=NR z7lh6#K!$z)ei#d;^R_kf0%Y&6PFN0}AH31+-u7A*=YttxpBNn~lj<+SZidx9HLFgj z{G-#T{~Qx<QFw$?2FvlXikdhQHMQ@VUY`?E;0#Bqn!8A)e?r50YC$>OlnL=uxDy)Q z|8F(D+#t=C4{<G>{xNvh`r=<x{X$10t=@~-ICEq@wQu}p#c->8V%tK`yL^$WQ+b}Q zv+tGEfqDE75XP}-hnhfD$j*mE!8zI2YLX0YWllx!4F{#q^%`q~`=n_}^JyMHEvJ=V zq(yMW?%~EcFm9VjDheC;E4Hm8BM%=h%dtAkyCP2!0}J?dE$5)uvwj_6nB^&0e)slL z$+kV4hx#I`tePG)$xnhC!8I2eZ#*dd5<29TIusj;%a@f&Es1%EY=qDXZ8^K-Yg<6^ z%?7yTuJ-qT0hdQ67;5s5bGUT7f~B*uckCh3#l1o`F!vY!GD-YbEhWr{<h<{;tJgDE zj4eSovM^G6prBI(TVxdpxV#P+BK6f%1@lY0Y<$TDClmYFYv)$t1I84kZyIt*%ow=^ zMIe%QElIs4Jhgfr(%&c+;J#XL)+HL0VN`*KY$qey$Gg#JANLX_=`=<I88Czx<@oW_ zRJWHj)+3%eBR4T+cWt^XDbq_mNpK^Ft^UcO3MyiMObN<C7XsdrGTEQYeY#92@s*6E z=uurNX3H}y;h7~rQ*R~-Sx8vksqEP);KmU*dWtpLOJ9^!A>)AX6_c1^$$^ZHx^<3^ zDVaCJVm4+L94dPhNADG;`}!Cg-RiYRg!}JHiW2rIY3X}HTAPWo*d5vLmT$CemINWS zSCcnd*<s$^QRv1p4gaZg$x;IM`KXGxN>b;c*CCA2IztG0j@W(J7{n|wt&nYbH~L^_ z@+HzC*7-;f{pB{|w<TNfkLdh%(@4!DB^#aFA;?`)IE&<k#CwmJg%{wHxHCK9IAg#P zP{()juJqQ%E!;#>>fp{a!e!BqQQS|Ivcfgpeqb<EIBhmn$hSDB*!!ms&$k~Uf4x>} z$jN>bA<5rq9+~*+Wi`kY5LS^<wVe1u`G@P}>|OpfAks%lODS)9ZXS=Y!L>bw58;=d zYt@(a1Ynjoeto<IXq1(wa`VadieKK0*nu1<GXmAHJ!GTP1I6gXpEuzx5kXdLXz-4K zFkwrcG&6_1S&R-6wi59<5aSBV_nH)h?jBr1isnQz*vV$DNmua(Qsh^}U+SxKw$Ya& zZ~(YdvRrw%&_d!AemUOwT}fodW`iWv9E@srVP)2;UabqNEhvQrKLo|FzThm>iZt(V zAgUM=Emj=EmS-z_93IZ7%-23GM)y<zc=u(WZY(4j>F+#~4Hr*IICL47<acz;TQVkS ze0elH9XUPM4r&<q3ULGZfE}02zxZkI76LLj<8yLykeWJ#iln&1?3mq>Dw)p<CFwjv z3=Rdso7ju@Nic@Av+ic)!<@`|hmGjdpeJq*d2k7Yv5nr?YSL-|p)Pw?3(}p_)<hVN ze&e<kaJoh(K{kVaA!nL#a{ypPmb}~jl8b+?B!^`A-58=c4Fdotp?zrZF5Ij~2hcEj zP-jxi)9{PMZ-0#RSdnLc&)CzQkbWn(q}4E1@G#A9ZkjMYUrXgoIGE3?uM<vQwO>&U z+DNTRdjOTYO7b8`ZxARBipvL2&wJKqAdvXto6C#Yb^-c5Tk5`&rOu62Rj>V)9Ct}W z#vMv8|58|I@anWB+US*9q5SWfsZs%_J><}Q60o9PWeeb4emhHFcwa$i3o+S13Han^ z;47plRV2Rfxh)r$(cfDVT=HTh*UK(9zglK7FHb;ZF`Gqf01fsSsL&+Ucd2a1r1oMW zyBF%PC4IkuRGwbkep8a*M95>Hz^FjGogOJUVKk{=&0$yF4;}^D78au&N_}9R5x-My zJ;Sr`OX#(*Ne@0A>r8a-(=tLf`tB(0oBQ7S^uR~Aggb`BPpF=*8FqgYFTEv>+g3rk zeL{+faP~{WR#Si_kkz7S4jX?AearY9Y55uGz%^(#TEFy3`X>g#veKVDGPi~0`FS`d zQ&UK4#wcXDe2MQKW89uyewSJm&SRhWVimqQ^ZADF280VSWNABQCv4<UrB{?9k56#x zZEfmmeGI`SE=m-eiQTyBAQo*1)XbFGS?%hE$Dx8XijY>{Iv<g@4Z%mc5I!zJ57N5( z*C)la_Y4ovmZ%$k&`?r@b$05&tIqCTFLe6ch~14v#+sW7tUlQdJR>h=(r4PICpg?H z-c}mVe~D(6xWlU<%j0SQtV&<|oNDU1eqCID+mC%e*a)f)9spr;Vz9;Fz0(RCi7mcL zWNnQvN1iq{f|E%zeYa)%zt2c+fB4HITUUEKWV5q!!6M|pT}}1VY~ar%7vTfU@Z!+H zZZN|(bYIL2o}yqb4x3Dp$%^EHWd5Y~Q3szkf9R<Fs;0_imvbnLQI%)ia)f(tD{85< z<U6>ei-QZ2Wr3S~Q0oN|)%6|azxe5`$`8)C8+t1_1LM|6<cmufXhFv>dn2ZKw=Jlu zM}?iS*FZd(HJ|Bn-H6>YuTz72T%NKb{P%K9-W=eKbZ%X;6WizT+S2s<NvDWkHX0g# zhsS8O(c^RBnR>b1Vl9~SqupMauC|K#0TqHG^!9}6y9RtysCeMn$oE+Mw!$FW%kpp4 zFnAd%){~)sU5KbYHs!Me10*nwQ5ue`^7DMB_4^Pp#N(n`BN)`$y8q@Ynb%<z*mD9Y ztl0hnRl_}Qoei+b-1r=}1lk&NnwcD#VKbz@S$R83M?`%&=TMo{XeBFRJ6bni+h*Sz z)LVW%9O3a7%JA~YiRRS$_Rx$;j#rz!e;2{K`GEl_;Vyq4Am!cx9M{+c5ygi^nn^y< zjf^}De1yt0c8<(!MXr==7FmLouxk&$=mV{SF#(mZ;s``<g&yv5VpFa5cQmbQrnw`F zc7c5)B7(4NbGiTpoUM=(_a5|0)Li-H0_2vH$Z6xQeaKugf8+20!d?|o47so6p-P8p zR`X3x9&6h?xa$5YWL(&_QxrXZHF}@kdi){nn%#U**a*hK?A8ZlA`Q&W_Vs|@f}r7@ z#GG~uT%3KUV!fruE+Bgc)b3-CcKisIol7fic+61Xv-is^#n)c=^C3Rd#8_z@msOtH zwKMvi%R4`f)_kPSC}X@!d_FKuQgogxo!$(Ra@jaPda@B(*YLpL++Rq?ZO7FCQwhDh zEx(<g8rF-BaZ43y3)3vv${~pQ!B69Pan{iMr>b7hbPE+el<PV!-$kz4gp*nAV|LOJ zL@(M$fu@tE;)ZvscNcXI4_~hob<M!xa!}HIf`blK!t*(7V}U&ouiX&nNfZa#?GME+ zh+n~3#!zl_Y9U+~7oT%s*WX%#53~anEOe#3;%@v><UCY`%fO^Fzsz4P+=`qylT}|f zhaG~Fx*&~%{=&E2aP}Brt$gE%%b?_^G02;8D)Po1Jsv?z&Ihdl6Y^~v3%P-4iAHHD zaEMWbUS3Z1CL+<+&eMJuy!gVx3XB^xYfH(kw=ccBg6*eu-8@xk43;f%5xTJaLYXVB zU2}eevvTVIlqH-`Og{X!^nQlS$8gNA^78$_5z8nqfA9OBhye%dn9`h9np!Vk)n@7O zq8lZPkU~i#o<it|lZ?@M{|(ctm6n)O0Kepn&6qdp)PI<#AurRxO>H)VP^I6$^#PbZ z+)UYrCyt_fD(?}uicU*x?wnIL-XfW_^%EYNtB(HavQcgXC#GR5l!SCH_3yH{-Iw0O z?=<Z^mAUgmwE_9mS!dDyF}vR`D)Y_|$_Ktz!h_zpK3V6LFES8sFqf1U$G9{&2vM0k z@Mw~It!BgnKse;<^hEO1D?k7bK94w1;t45)c-ON+!ci8)9i%6ZQH`hz&fatFAy6T+ z0!XfE{wc+Gy-VNI8Y(RULvwFw;ZfS&RuSAh(ep@%#Z`HAQZ11^A=TO}#q0{Pvyu`c zKd@xH7S4KT`$2JW(qh@q`w>aXLA&Zh%f*xk1GYY@Cxa{_JVSF;*tv+{Y8N2CxK!JN zdZ9Wap=s&6<@YrLweR<+rbr~QCyS0bzwwRs(xjD@Fekm~B6h2wcuO>yq~<t1mvMA5 zh(^-<tlQ!KD_s{(F;}t8u^dJY4uf%t&199ZKN#+_Xa4rHV5RSA12#v@1LQ9$@M7nu zQnl-Io_!g%<Qx3b*%lKQ?h~rj`qANpk;*CpMR>Vhwf%m#W{M$JO2B0rQ;fA-ud`r{ z@zTQqdN#V1+$yYqjm1NP2zwB?A;X7lw~09WLF-dAyV1MJS0HPFLm%v1s#T}r=e!_; zdNIS`2C=G*kjDANeay&f7<{fD$1Dcfsf4{vwlf>;5SadAlY#<wzOHm#7Om<+kg(eo zeY#QNeMjtL32ALD3;y%T<z$Mr_4T-zn5@sAuPLz&|Kn}nD7iX{STGp;wlsWNqaR3L z|FsQUjHsr7O{xQou`)usRo~p;Mdi+35_77veA}jAyS{3r;oLAAzsfkI3n_?V61Mk- zcXWI(EeUooaoM|mHO|TA^9220nHZ}zp5*nd&Exng@!yvk*%7M~l$$x>OW@wfJw4)b zT-5)|7k2#j^T&L?mq><GkF6}(G#@ff<iFw=O|~TCN&;DlE#bRwy_`{}HTWUzSx}<v z^T!0&lI31!xh5W5c_a7g><=$qW7Pw<JQa!tr4I}Porx@tr;8BAk`+$I5QX>m67(lt zE%hn+fEWIV0`m5e*QHhi`XrS7P6`lNGkx#r(NR<kjfsgFtQ|*u2-Y5;JR#i08$odv z^wZsOp5ypnQFFv8Q}E&k7QhK@2kx^T@$jEbIiTak$s~Cs%`#!_$_vMfb4vG3saOP6 zLh%V*3l`5Zp<BCk`_xYeQJ5Vm<36`R-3iaYmt8$_GbGKPD4o#5{Qn;K(E3v$|Lz6w zf3zU}3;w_0{|o-V;Q!wNf2~bL!{+v%ZwFDx9Ip9oKv4+S!b!wRag8S-F8;HJ#+v8? zh6j!<afet}uT%S$R*;?r2>1OXtnGi1dCqOD>LN(E>(AogNeV^dgBMEN?3t!#yxMYF z(voA7iHOufcY7DazB9wk9&e~Ut_}{22wc56ac~=pcuHbej^4sQkp4&3<ej+x-kx{P z=g+rp-+nF-$mEc%<o6$F=O2CP$`2pPK+|X7fmW9Eh<oI4YNyWXxzC)W?$N6N6?3Y8 z0(vQMq@k8T`GI5gE63|Zeip=RRWyJ5cnv)+JJQevMh4~ME6Dtt&+!&1e=5t(J3&J& zM;dx5bzg-3cnzI@dZZzz*5tI~(}8jqXqnIos}sE<$D8M~OGoC}%ntGlJ>ES3AA^^B zeW5x$_pj!Ypgd7m{{nZ9SNY(lm1ZqIrPGaz?|&*+CHUoZv3j>V{`d^jPcq4|@vNlu z^u`P}pOSf)MdWDy;zwFH<8nq<uTB1_eN~Q6(Vp!Kdy_1NupCv!etLH0M(eE~Bb4AR zdAQM-w~ah@HmydPIR@|A7URPv;x&q-NQQuVXg8mq-k<K-6(unesxOy!e<wx9!43W3 zD8DP^)|&N)+sL5;V^`SN-kzprWr)H*m*bd2o_sLg9%p-c=+ABEU(EbW1vS<78s5<m zAHNxY*!x`Bht%2WvLCCz+kGyMN5U&<;m{X#uorzvC?AJd2kl#;68H``f+BK0+l=Nn zjF)_M>t3sN{=tPQgQ-mW758Bdt-xx9zI%<7(3(JJ!5PQSoe+cm9idzRIDwEI1FR6a zynJuJIfFp!O#aU`<TIOCf(PlT>HkO^PQ0eM#xFF>mxH}tPH@%3u_}*GCD5`AxIV(` z5C*;)j(gJA<nU^&`^GQFp;m>6DdSvP7S`&PtAsNf4lVKkqmO%D4ZS7We%Xy_6^!jT z;^@_HqNcsKk!3ad%ZOy{L&K0Z1K4#4qf>hER(!&|K38u%3RUO=8*$Zagw>Slsmi_% zQw+|ffTYR5LP^zlxM6={Kc}dJW+=m_XX;~bCS>y#HvM2!zB+_BF32p=vu^I`Lt)9~ zH(0F7E3d8fGdl#MWlfkYBwKqF4Xid4!mTtqpvbv~q#c$>3=y^Kln8rqq}1VZ)7R9! zG41_0bi$NZ$<WX0U`(Mirfyy-&ga6Vi79nSH=u^>X4><Yn@MKqG+XIyT`YLF8H0*X z#X0KlOvs9MTQh9!d3t?2%>UKx&#}1Uyzc08XX2Szy5z`{(0>{vlMdOBqHyTs=Rcd_ z7<~9Lq~C~(fAalBSugQ3T4)^n5d1&U{>J^FT+9y*HamOwp#Xhie_`G_+*UDI%-j2g z7cOW7BjnN}xe40M-myUyWqR5NZLEc+VixelPSsX(to*MH9|m&^IIcRn*rjtzf$5*4 zekIrsP*u=WPK<#>Ze-a+%DjfM4b~-9J7{wE`Tt7e^O<19&2}rQsM{(QuJwaQf|QLx zcqdw9$mW3Ah}+5ze&Z9ZZBJU2nd{ER<4{VhB9;HUI;=1DX(WSl=ao+bcRQ5^Vq@dR zvggx51@mGG(kU|4hN{4)J9AC%c1m^=@Wc-k@IvWgzr&tDjOVrISHsqbqqije2JcA! z4A7@d83OXi67z1Al)&2p+^gY3Rhx^x2O8qpdR2qpbUc6d5ZA0egTBJsF*;m(rVl6H z83P&0=>kH2{G-U&KZxbXg1<6IbNwe_`b_FH?QVB!zjTjZVS{vCyWdQ`!Pw5Pz`!`q zol+xd^JN~y%j)Txq`Whgi%pI5-H-+N&qdT4VkC36K_m4L7=G#QqeG&)ngc#vAiwKJ zsa}Q0Sj1v_j`eaH&Xd6C3#)f1t@7T0Y(J$(f6qh)-hA9d>L68N?S@Q~r3xb{NrVFI z=n!lKvokBrw<{moO0TRvVUn6#A~ONs+{awoU(FN<-%T)TO8RQsTVfXsO?gsSr@6n{ z@PgP`nN(P9sY~vy0-6O6rHmy}ZHx+3Tf#`0C<kWl@}K9PMvMsH#POeJuWWiabRF#4 zb>T@obST-D08E8%m#1^&sBK;2xVN?g(gjAbC{G+_SJH&>Os`kttCzBPwD7fg*!ibs z*qv%nwa^8bJgeOKm9|}%L!Phrt<5qJqs~H;-`q3}B7OK@qBQY$J8+OEgZ8@qdC#kV zq432KU2KBg?Cxi}F62^FwCd{Gj7)cH7&-1@Qh-DZh0k*Cm)bGDq<&RS?MoUXDS{^0 zyt`ttZeu?C@D?(oZJ)YtWE0<EC2SL^jNN?FY=$6ootw6AWn06dvRf`U!Y4z~L1pOs zp=)?6m(*49=VGpERR>!!UPF~c=gyloIoub{ecB07Qm8>z6CsyLHv1@_v*6P@4XJ*v zT=%zRC1y~!xk{u96J#YgWQZ~K+{1p4{10T+)1+U(>}Pd6O^Bw@>c(Pc=2VS-_*Y9d z<C^OQ#*9M~0~mHEUdL9M$^pibIie2+&JW$wH}j2$MT=84nhQfZ$Ki7B4%HKJF?tnZ z0iUY>v7xE?di(tBnLoa@|KkZ6raZECn`B2|gJLiNwR62~0~^`c53Y*0^K@gxuiTd2 z{7#?j9^O?a4H@$#$e@6+=-9cWyz9;cogJU2m1fSc4m<WBc=l_NtVS;7?p`X3p^?SW zH)QR&k7-kn#Mumj*+AjNer_LXrFG0AH1S=A=;k_R&vj`a#N>;$@{i~0%Z7PHC_TlJ zeSJuShr!Qch^ebwTM_^6f{M*3GH~%Tx*B=loP6iYg7v;5)C=NUqeKh70fqv9en52# z=Jb}wryklU0S66XT0-<M-O{?eQKl*9yfs~|is7!WR2OvCH~Afr;T7SK)bU5Ic(Zx4 z_%UdpZzZ~lVbL6PMOJFuk{>9UcF8qPQGhpH_Y=qzw(SMH1!wU2*BANvKfbVaIgI;y z7Msr>eJFTmDC$KucV}!yhL<qa)1~MkOj?7FYq~|DL&I(k!|=Dy{a$VZV;x*OT{pxB z24Gge9B~=gOWW2{;g<%K1iPKF-|w=nrLD{pR3r6kQi?SXhdhblhD}r;im>l~do>YU zj8xT`sXB`-=wLvDA~VlLSPqF%dzH9PoZBCQ4hHC_9-z7BwV;g{iOPZp`|yeG3qIxe zAWD{Bw(kKf=W2_=psvGx?&>ky<O9Nc@9@s0ob++OY(>i9Vz+zW2Y;Y#X$YJvSEVg0 zwAygKsc8);n3dNmu=L=YCt)B~EVimzdJoT05<|bsS>F>WGi=;e6zP9@UvxRzl&`G4 znFWi}&6!_q3)Yj}sT_;c#-bZ=W&;WfXDV)Q@}NM=D5!@*YI1bJZfh0Q>(%{Px_=7p zl`?OgZ!;Ijvy$x(7ekl%-4>hNn5whu`0Q?_BT+{A7H4Lg)kt8Pk!(>2n>{_TFa>6n zV!7;vmH%1?GHtnxbTGEZdnpGig1Im*xS||aps4Vgu6?lYWZXio6zw6auO>8{v!Rcw zXUu%MWMea&wc!w+hFIsrnKVZDee25H9F}k58yn9AY&vzu2)PmmYU^Ng`ulwiqi%~6 z=az@>FKcj)%Z%l~zuEUSXC@_+YG}C{*W>*ioj(A_7u`7@E(P!VrsRNxRe3HJzjs@^ zn+`xu#K*w9XtDCMPZ}7x!}rE24Zg*PHiEwO_9fpD0jkb&^?xND6h`|z#n9pHfHX~% z?O>V4P5pqn68i+c;PA>-0%+f{Y!5PaX?|t+=z>YWmf?Y33OUsl3rTGb1HxkzgeKP% zD8Z12OA<iO?HR|-lbrc2MU{N$%x1?5{l7f#^S?<)^TIvkpQK}xVw9uI&#r82E@xh6 zqH>(}+<@@cRfC$b*eWU5exdhkp%f3SR6wO!9wD8zy`YNj(XX;M1V(ZzTrhP07szU7 z*c&#gqD^4oboR-u)|Gci)tN4K(EsFVXp~zH7-jf$KNHZE=U;V;tLz)P3DEr<z1kD$ zdD@{lI?M}Hp&#a~?&~g1FhmvK6&yf+fah?_jNmOPpW2}hU(voJ`S?D{Q60_g|K*7* zySAZL%78&v8487SqLh%T>0nFyUGRh8u&SyVqheXAbLZ>-32dUA=GW{je@lF{qN3u0 z<NK{n3=`j9`o7IEufz*m!}Y{s#Y7Ml)25Q>1&0NoJNC*j*kdzpxT3{(zYz&ehvjgD z-oWys*AiiYK##kV_MIF7UJDJiBE(9qMy$io)@N9i{vp5oY%YR*<XlBL&VxWK10ytc zeyv+(mO|*U4xq8}f4Wgob7awnwaPBEJO4{}_TJDhd6IarL+3~v?1II=GyQv~j(7^s zo3?_#vYRVsHGL~foZ`V(HWFm6{M$KSjLx$=o=qM7(9wTWx~Uj>YUrd#2VcA?jmMtw zH>P*L1IxEAk|&=q`dKFQYsQnNe#v`8rYHjCn2#q@M-cUwPMBAYm*$9RWt%WrlN~?r z(a@dJCoSr+|8EXTN2dJ8fD^AMJacZ?sCKo7Ndqi95Dm35Zk4t7W_!|?^DnmjRQnR{ zWwjK2e^J8lpJdw1|JVH`PQyQg-1ZbR(orRPhh-XhWaBLsJcegycZU0BI`(W)OEs=@ z`G@bl>mm9i72MVLc8|yZ5#V^Gnvt?E62l|kHdfR3>I4~|`GdD}9U8s7<dP_Ol1%#q zk7P=?`gr#Qv0eU6P+uj^UpqlEh$G2VMlumjVCO+hN9_EaY3>PagP90N?7UCrQ6=LE z?EKLYJHH&9q;di~ul&u<chC08oWRb{9$8z^MN5feJMI5}A3X1a%bx7lQ%4bAsvj$Z zERP+fSDjbLPq#C5asJ-#oK1Fo%?N@iMd{dp6O$R4Kp>OZ83pGPqGd9_qh-zp^DHMs z%My<Of1tnEbwadk>jH04c#l(#&Iy3cjsV{kGZA4s9`KaLk+x;p;*3s+mVKaRLbndT z=`%RN?p2Qjuyskt^X>84zI)?H+y4dsU-170|6lO`KLLNOP1oyZel7hP7c4=DDQaJJ zUaxi`{oDwWQgmz4Ss}Uq3S^!8gu&I195os`kTOaidEdvsFxe2{zWKT<Rd?=f1-)?* zs)j1w`g@U<zNCeFMa=3!*+WqjT(AlKg_e2Iefj?Wad+A?lhg4J=cbxU^dA^Po|41g znzh+J(=I(1N4q#Y6>jUuGZ3(DvkP(B&6;{mk4k=E6SH*CuCep=+q+QhzO%=!QV{yP z9EX4TZQQP1)#8Rl({`o&lIN37tAu<%>+rw@VwmXs$ZJ%BgC^m_Y6o>X2Mrih2-R9% zzkT(laqVR6R|}4a!a59~zyx~3oL+P33oTkBs;67SHW-%A^r>v2;*^M)NdzV4JT063 zQVl{SV^u<VRv~_)U?+^jfjWc^*pRtRG<R~YNgMniFg?RyXK_2E3U8fH>U=wBJfh=+ zRHfHrpIpSm2j{<ZRYn51q6>>gN40mDMpVX*t^Q$>B*S%MStYx|r{l%)U+vsS&Xr@n zj_jCkH?y9$RCW!gh-xya$i&1yOstga;2YEh-Z6Fd(HOrew4-M6lL`|-sRc94n5RXH za=9$iSj~MK%CpU|D5FQQX!nHK=h0LYYO?6{;I&nwp>0*!TFL9N^M!Q2YYl7+(S-tc zyOLMq(W-!z&Fv~3>xFMZo)2wnthHASV9CY{6h&)#(#(QIPdT!5v|*a<D<2r}->vN& zYBqE64#tvC8HL{2WuojdNgZs87m8}<FO41VM9`9LZ*MC;fBsTkJw}%@vr|F9gz*Bc zksbQO6zfBn<h@cjdp?nMFqaLqIXc2uwK52vRub=!_Igo>Qe+#n3`Z5|u+GQT#sXO3 zFxw;}10BNH2<zDf-3cJ7KCLAsP)Sf149yEUgT9<B<yCAsD%wnIi)*hfC}@(1upbOk zQ<HQH?xHg~2rWun;5QyT69%onr^P?x?!O#`umo)bJBb}d2)jcaRxv7IQN%(i`xi(! zfX=9=fsK_7^t$*-S%b1?2dyow=q_<u|G;wvV+`8`e$QIHFn0VVjy-akdM&=qR9K7F z<h=dX(`|sYgxQzsLG5SenpbOgzFNY3EjoG0e-0RQ8CMt}ILklAMi&kit?Jt|Tln2W zj^+-E0T)Hf)5;zc?zA%(9?2P0VLM*MUTIIcxJD1snlmiY{MpuEq9iQRg~2s+FTi2F z+@4h;8@&}@;S~LI2zaq~PNCK4=j^IWf!H1F8r6eZ@q*F}wd*++w%;A&6uD3@CCv(q zbd#YweX*4zmS=j>WQ}XxjO2-IH0Z@N$@uJ)VC;*@tX01CoV!qTQ~7a<ZLU8$>k{Zq z6@E%o$~2}BY(W=XUhxYESkqk97_iW@Yd%jdT4*5klvXUn>_-)UeMZ^`|BmXc6!{iT zvP_d|$54A3%fhkfOSF%39Cfi7xD;spzLpYq@7(pwSWaU%Xlua0*Y;T0)N8Fc*&GDY zPF$%)*wUu;*Lh%krm*Yqi?LpBV;wlqc<5!$G^_RN_%6Pxq}Co8$7%?w=yFRk@vA`G zg&++p2l4UaZ-VE)-Cs^IFJA3iHilwWuqAz2(VAA!Pa>zLAsnbDu6Lg^>8DuwWvs4I z;fN+Tooz)Ze2&Q8p$gUV7;%a7sxZGwQ&-J4IADhcf8qHA*C(vAD!;4uHV0(3Fo}G2 zFINN*V2l>cdJi5HmcZa4zM}blFOy`pOLgNo`L(wF_~9e0?J$GQB0i|_#t7}(O!g+R zkm^(keMBzcd}cW@J>UJO0@N#&ZwRctuM_9FIjNZAvz1hT-TSKQFX<C+FRaCx_}o>C zlJ97i(vQwb04-jar$u=%Hipu6g@Wfo)#rYFVQr9%9_Bu6HExC?;3;jM^1#-lAa#|T z^Qv7Of-2UqIX>R3lSOx%4>S}?tg4iIUJNf#z-tSH<zH8(XfcEJT5fAN^#3Zj9_}3I zgF=aMi4CQkUfg|!6r-TglF0e7YnyN6z<9qx#-XGNZV@J-6_TRMxuD-n^ug4)#o8z9 zzGBp=C}B(H9@ZwHzj0l>d;R{Dz}T^rjfwy0Ml`&yZc}?*f4yU7LZWn&sg%n1m8o_7 zzP+D&Xd&EUanYv3bsNk{2&KC#Y-gxjtp&I>(6RA=?|XjV-c3Qld?Md7&SIO`5bHYS zc7UH-jE{#G(7O|mmiv_=MGL;97mlr0iM`3zVWq@fR54N^Z&}iZd0(Kv_oZU&E432M za=(1bHpXz<tu)PFZ>$Itf&UH{Wi0>bU<fV0&X|^{o;8}aoeb19WxNQy3DC_#+>kYI zgWw4hg>)V5G(FqkK6AI@4+>$j=XVGC@7q}0x6@)uZKId?=qO>z55e)40{YoG%(Q}w z1r*iFz~o0(9*BE1H$mHUN4pF<Ea>G{mn*xPwG)CzPDt_h?>TGaj3K_3!#zPuzgl-H zTD$wRbZ!{y@@30)9^wJYZbSLwMQawF^%-KFn7eJ<`ZJcB-MYlkP~2pptNyE|LfY3y zpXp70l9^P)g`N}~F>V<!Xe>%AS<r$bTA@GV*jwx)rGMDHj~4)1EeBX$KO;H!Nr(A_ zZDs%ak=3xJ8?8=wJ1)I+e40?k-~l_=bOBg?_#Tb++mFdklb+S!^uDQQ@?AH;MO|9Y zGl42iV0wMoS$k=qUP+lV;IUvAaWlA4bSnUl#XN~~YPy1GI?u%g$&uh2FxkJyj@Nj6 z5&wg%X}hI>UG|H>=sBZf-L;y4KW?70pppr>$2~cmcGQ7R`X-DwI{5^&%U};n5%mU5 zT9m=o+re-?^XJ2J?1K6M$7xIa$P%4|KPD7kZAj*WxjRL4fJXvW;w|vq-KmDTSq3qf zQtFap{W=51qoYQtfZfVfbokyGd!;Y~Pu}jGXOQCs$m;*SRP2F1#}mmc`8QEw60QE) z#|?TdO-_BvHHrJAlH$IbN1m*Y*`u%%Vil*4JXvPP-uZjSd$Nzyk52cEaB9Hu1+o6* zN1m+mmxp<sCwQ_xzhf2RH!4pk=smA?<jJ0<N)<eQ`EnaaZoI;HV(*pX-S}s6M-nB! z<Wl$Hzu^B1{(n30*9^kQ@>J)BSD9&Cs%DM0J-2(@HiL=<eiyZ%s|He+ly$@+K*u>{ z|9k)l;G3dd@vtRFwZM1L8?3LLRmnd*5S+cM#XMJ%c}BRdfyD~6(TWe*IC#I3gP1R) z3bC0gec|wQVuCHXe2TNc<PCbyE}tNoNrZ0NOcp!H-&`EnD$~Jlr!$oGP>B+@^$E0G zHlFjjEzYgh=Bkb8!!{K_k@nA7zr!wu{jqV)dt1dJGVb%1sC}!rTn7f@yn+|wj=*m2 zK?hcJp*nJ-sY3iVE_92uI5-ILmf+@-xm6MwFD)`EiPn_wgdC(|U3zRihFpoI$6>sd zd&-o+a*;&9cWNycBRt9qBjWS(4_T}q&&7zc#EKO7!VA+l##+Kxpx*B(;0H^dOHEB2 zu|7uW^?qucn_KmzXo~b$fi0I<E2_6k{dLN_|0p0WLCa_F%zc?fC2#kcS}=C@3k4HV z^)@(8tJ&Pms48#wXC+!U`H{2KS_0#+A%<E(H-|;5od;eishQQj@z+zGc<hu^*1w__ z%K|IwCqAhMN&?=)hAL4q^xc)#I8vOEzPm0buFSE{)2-1`*K2>s+#2=q62<1B{J_|* zLWPV}J`03#&DLf;1#kRXeNG=7KXt5)e4;I-d!)nY_{|q!tew-oo&Zv?N3!bpp6d&s zgr!T$hw<@=Kwf3i(9()JwE{8Yy_(I{en?9;sz?^r9(3-0Lu=r!czw<*$u>!c&4qXC z5w`nT>|?$VyVfkCgsrRZCYnxJ-!d;jwXb;u&(iRN4WEKyZU}<=^i_`NH~NMfS|wLu zsYN+i3rgLiZ8?BWlPO#&Rr5D{{0b!(LH(TAN|MWpyNN2?7gV92?wzH^989m~*{a3o zk+0TxU~^}9@0Y5K1)KStAg$rPQG};DPz>mjf>n)Vqc1xprXhYId@w+2p2Yf&Qb4qe zTSP5T-gxB9XVpT$9M^!V2RsCjPbh9{t(zkvS}E(E!+of7Kr3&c96g+$%$i`}d7lz> zBQqbJ+r$ZW+6V-`kNS*O^?ssQE~(ed1NT|2)oX&W&CcE-R9l6|blV}9a@;#xdu+^b zx9Sq=bcw>Q<>h5)ShYJVM5^(LgPp`hnO8)SIf9m!a+?fTsdE0pu^hKK;po(0i=6Ev zfZ%$pU*kV$w^zQ>5;F35*gFr!6|J#p+g84Xfwa4I&@&eLWp^)*iVhYHZ9R9^G?p?3 z@u96>uG)8b+h((sqwNx*&s6~fKc+#IeP0LPH?$;cZp0gOd%6s$cim2i*RdOH4UOx7 zeah|<rSIU7*0N|}RbfrA+5AZ6@E|yuSRrcBeUGKbxFA%tQ`D^*B`kBPm9i31sO~(Y zX*<(@ZyG`59M$0j;&OYyGkA7s7l(*3uPIyQ`_2jjvkn7y`FU0z4QLW^hY;oPv(AvM z01z_%MWZsmpP24QxGM?GOPcJxy}UQE#Eh9eKO}6$X*C!eHUyR^0xaa-JZy=7_MN?0 zwm~z$|6Jzny39xOo2y%!C8C5llSJ<}el1MtxYn@uu6~J+x3&-M&O-2oln+1=ML+Ku zOWc%p#M!s-wmnud;{nMmq<W(%!|bOBkJH45UF9P+`0gC*rmI8NtEsm=53?l*D`=dn zA6+9#-;WWH8lOE&6SLvla(RC@t(AB=S^QnkamTaMEk{#NmJqHF#e&<FPX0N$u?d~9 zFNLcbanRfP`y-d6MI|aN?ciKSwfZ>}f^)w)!>qMRI8eki!>z<vU__#tKaH=fr@uE3 zUD)AeMU;VeGic?zY{)tEd~AWjtE@w1pdPy4e3raZhUeFBySn?Q71E_$53eGc2!G5e z<1n1)uJ9Ci=Sq~)I$tzffP%tD7Dl#OT$J160OL_P)0{fDMo0ahsJ5?RwX2x*cl-1V zA-kf<-k{Rrw)8C(&Ka)0c+8vDc8ZTyBGpqx+{lVXg}F+j-MP<}f+IPknXw{YqwrZ4 z_S6|18i;XKCpGHkOw})8%K4cLc&eVRr$4yVhjjx_6D#1hDaov7DWJ+;2Fwiu7ZC@s zK0P)tK-%uwvRmQuKvgSPL8HJ-tkX5j$9vVd7>u!5CS&uCQQxV%3&N-igY`>^o!|p- z8&M}EX%{VgRdkqeQ9{j6;I+eIBAWrJH+f#%6UsMwXU=w;(H_N_&Rspt6@VvEDy<#Y zz=k*N=uSqwb^(dmJcPRpRf?bn7fHoZ=!S%n;ryg*CFJu$!BamJUB?5PjL}~V3YzwJ z8dR~J_&7<x_?S4BqY&Qbrqy*@Yw{CqBx;94#B}dc%0o#lRpr}6h8fHnwUTk-XMZ<p z$aPWoaROW)MEGeK&B&?Li84>|##_!&R@3Fw&bU;j%FIxFqLP*QEV;=48te7-EnJKl zRmEl%-WRz`8CiUBMI5)?ZNpXSU19wAJBO655;Gm*CC>{iw3^=s1DUG7f&GBP7veRm zq;+*_KKZ41tt4!?tWK;HYa0!SZYObSc~({TgR6?L_K9$v^dGX86(CjXUtN<?8$lhi z_tHW4II-*kxV7Dpz&xp*JCTQTNv)5(AS21=q&?q0nrp>@>z||Enc`gBcApCsF$jfW z6-?cZb0eDH|2~Wuep%sl+;xEBR)y#%M%A_jVq5@J&_T3h;IjPPLZ9zyzGa$7q*3y( zu1+xDr}%8|-H#G};qfCMhABHK42M(D_xqePas~1SKeBma8ogp!Ra3LsLTTVxl@`*1 zQpKchh-(eZh?5ZWR+*l9X=%=@hb{%+rCDI+Tsf7u|4Y`#sGz+-kr?nYOc;dYtY)wq zh)*7c&C7Ex_ft*JulmvRNM-8q+k&~UM&Ui%uh%s@!SfUrme!9{?u*eUG_Hs`?tKL4 zgDPCVrAYtk1gYMtcSY=bEnc=3yGklcKhUVrgqDm94L`@K+LUNb#49>t{R#Hk;804$ z#DgI&S*-mQ#|WnG>MVeF>0F<X&eh|-kVQ_4R^)Jh)qM#cM@W(W1ez|lWx?oIY8{>S z#wm-YhOF-dp`&A_yTJ(`pW}1!Fy&ovDu$9!9pa^&f@tc-m&CBwVx+9f0A5U`QDVxc zf#YsVS;|dByCI?eMO1owLVRW>#S^}cx)pUIkvMjqdeXBaFTsOR5M;e#^DQfBj05px zo1HD~!p^VVS4dVQ{PL?AaLw?kID>KJT`@mc<0UB&Be_ySqi4GBwwtS?n1f1$uRWB! zes4z`41*1o1sX5ppl%X=U9b>O(ZbeT__~VREG-A<Bi2FNkwex5zr`|96EGz~HN~=* za+7CpnGlpdF8wTe(yB&FxkPklI%dDlYE_JIU)_PorMWE`uZWeXHY@jf8=5+}!wBeA zUWUayJeO&&aXoywyln&JTD7$JW9TsVj7%egcb&4ZtZWIe)o8jammog%bO9uNI9-U7 za1-M_JP;Bg#=$Z}A}JDr++7EBSZC4({SQgvU9c*xd%;ATqIB`&PUuykFF!DX9A@L2 z;jEq*&ywrkgz8^m)RY1IgCAQ!n!*+;w@mCp*>Q*uy>ufV0&eRIH!8$hs`Qtu0fbqV zH^x|`>ebirogzpV@40s{ACNE@SHQmgwlH19@F!acgM~7BVYNvQ&aNl^Jj}}0+apuk zK|j+(T0_)Xy(aAuK)*uwo8gm8_G)EVMMwg{2>KfIqxm*72bR4qRN+50%M8o?Ti6l? z;$4kK_g8NgjAXOQ#Yq&AH}kAli#P?{pCw2}frX8b0A!?Zw3mTHaWOh&EW+M%;~<ld zoyq>CT>4(SRVV#M?=Mq=0QUrrct+F#b9;XQ(k5U+Z#W)+dAi()j+Z=(g8bs~97tPr z9p673+@u>?v77jKS%2+2d)F3D+|zxMp~Q8_FulM-mg}OOS1Vk9+axfz!TAxX2fIMv zG;a$8ty6|AVjXo!-Yzw(!@^I_1W;`q*ZnGr>30Gmo=G|!sv<W0V)%`^26%s1Eebm< z4LozXh9&?I*jppKmD|L9hxM5<T#fkkD*ad;b#&(qT|rQV?U~d3oGPIyDA$)fJv-CY z?4<=_2(e30g*2Y~1d=7TZlpRDQ&c}5fZ9kS^tcf;4c#mndn|iy-1MsOlZ2>v<rFmx zR9OZAwxiPeZ5`x?DsnhItE84ldJ>;Tcgi-4JMJFG!-g;Xr<(JzE@z6_Gw2B!I|lMA z-}KQ%;en@fXip$*yT6NaWP>-3rF^H!r{s=E8v|wZ3D3mHEz&ZfTMsVwpE)7rc;<IS z(#6MhNB@49j;!{7kFQ%lXdM1BJoxiI_xU#Fn_TBZJf?!`t)tEluua;z%?%{W;O@nJ zecV1}P0LSF*~i1ja<Jezs#xktqprhLuwsm|D`e1f9bU5hB*mVbmm&7nyv0sDbJg}; zN)o1<>E?&=)+X+i&O^u&a{a61@O`mgUIN0TvGq;KbZ6u4ecbpq*LmL4$G!Yfs=QuA zaeu(^fByGBJ?Fi7ld871R=3)o%UTa1u^Xixdx|>hgjdmBGEH=G8H0uMvp3`?y|izh z<^$<iHNLd{n~6mg-gIC@(V2D(Cr%diW#O8f1z}-PTv3_qn%oJm($=$TdWcquk6o8f z2CAD%o?m2`y01|1{N#0`FCMLXNH?VX!HJW}kwIfm#lfK!<F`crX5AcDkJinBR}%|4 zak6J7uIDq#-CQ?0b8h_2y3KyC+l;GY=ETX4l%n!mDc!!=gMYJb(1)XSgNo!wF8#eV zc)5lu|DBMYnGl&1lau>7%It9xz2$C1(oNvWvtBEu{H+~IiD>1&F+<(`-zfKezO()v z%G1A5`m2~T|DEZ{{x&^7o^p!66UCd~qR3z#A^$s3s2<rTYCOd5^xx^3_qU$s9*g<^ zt-LaRi|O+J;bQ6<eE+_=>l(eqzqYAA{JF{d9&GdZ0hsbLI~MBEW^#A%SaYg;-~TML zIPPc#LyC^?x0x>sU1De(Jxn!fW;WGK`1qyo;wh~vrJxRT@lSHzTNzF&IwtoUq@2$G zH2n~it&mGj7XI2tbF1{nt9YH;8b=3O5eJ#6F=5flvc;F~Y02vC+U8mCmBpv;r4l&L zwC@fUK79J{xrr9D?m^-M|CR4&vszDGIk#y;VsLnOHB`&zikkbs5N};#{(f+&dS4h^ z*IvgN9v7Ebsefk}=bxEK;bk#y|NgS6;N#-<AoW@M3-P+9J1?%ASzL33lb^pB<*dhe z&V@1PrGZgt^VjopP^Tv5f;N+0SnB#}Vu$UcrSnQA_l~5}L*<W*gO>u8-vv|lI?plL zc66;!ahf18GeSfU5GDc{fxA_;R_p@LPl_Zj4*pW!_G8VoMGF<6zs$Qi@*uQ<W9Ena zzm@3dd@jR+V1?qDA*<owm~dN`_rcj0pn?m7eH@oTUu1O3^7DU`=98L~S(UR^O?e9W zIVRV+9>X>Ceo0JnGMEjI)9@-dNB+APKwf#TtM=6>)4O+M&dY({+SlTXj81oE_k_~o z^^oMPfz~`^0*KUMKpr6~kL@QrjD1ry>y;lyUFuSlb9EMrX;R(rxV~Vh{&TzeV1z!G zhOIvJs_Djd%&a?w{+Y|JnvCynk-^|Q+d@O~W*}ZI<13e<@Si!T_I(#i9KV*(nE&1b z)8sdv_=X%5xgh!+GiX!e7T6zzCOW;p+4{6sAD9W8=#c&*UIc7X*qxS{vioGY%CojC zzVvV)y?RycRQT)hUdzV&ph-?TPGN(ockNF<E3;NK-St0L8>wa8V@}0q3%vVkbmQLg zLm0|ak5A_3U1Y~@z*OuPt7j$;%q-c(H4*wElb#Es_w3L1T+VkQa0rhUl6D<olsnFv zU*-SU&#!)O)w>@%Z{5l?lJjqW;S+N!tB!%*)cQqwISVI2{!V{Ld_1=uM8fnT9pKe_ z-Jk4lEBdLM1FUU12aRqqU*_p3OuiF@ToDn^x|1ak*^!6*EGRE=<GTO#b7$#YI`ybE zhrHB`2~jZajT{kX>c^ftOxtFcc18sIoL-hbR&Y|`N2+z(P%ARWfcjYAn1jpi`hyP| z*s65NrIo>FZHAs-YN&fHLZoY|uRb5ABD~|7tfoy+y{#4STG_>2>i&hYJ_#MOAF|g< z#m+WQ?R>j;j?pwj73caP>TG6l5zT9$oR70GAMMq(PXcWZSKD8ev9uF%R4cZIG(!3a z4}ua~g1yaU9I~xl#WNXIM5@KI(RV}R>jVj7!H?<Wqc4AGAtH3Y149aPxgY=Vddc52 z`CW~%u)`J}sr))nevMnC4)-3pMxoSF-TvVW<<YJH@s@s1d~jEgL>?xV6$LVC?XAV+ zjoYvUdlND6FeK4>Q}fE}e2VF5s_8<DKaQuA*i$&((Z~B)!O87Iy#^K*{0l|eemtAH z{-&L`Y|UFeX64vIyQqhsB;lhU&VSA?q{MuD;(rE*qf#@c{PcvCJxDA=rzkMAGhPB< zh-#A~Q@YOdw)*<5JnQR<v@gE*lmtB4#MXav<QdLpd38_4nxNTzOH4<z!ixjrXkYob zds4w&(%|*A)3=o$<><mi<w741i&0t#9NpCKS59fVM(n7#)P})7=ETzsZn)oJa?8?` zyfW)s!3dC=rRUhY?2l5B!$}9LY3ScWUhby3Q0NuZXozqagoM3q@Z5@HJ$-$8ZjR;) zPAk}xvo}}ZVA{i)gPZAX(Wq&mk_ETYi(TCd8abhlHX|1xh$k8=@t)=q@TXm_(YIWs z*qeL6UO+Wm(4F3C^ps)F+gou|&Iz~7rQdpfMRxgKx)mGZmUYSOx_vX<6NmDP2Qf!y zD4qYW#1T!k;NtG*_YJs3c7E-|oenZ6p3f-8#b2&<<LvYKl4FQ?lJaIPn1TGOJ-|oe zZuNhzorxJ<xlT+<HqT7-S4t-*C`FhaSl1*ib6Xv;Lu<jLl~czVbl&5xmQZF>zWuj+ zmM=%v7eGFB^~`<qk8IITq=Q?sv~P<$=3BM1;+{Wwr{0<ypxo{8@~b)J{>LE=NeEj` zRwy4IoG@%&NB%VP*7J+MUAhaW^R^%m%*G8pKFM=-w+CRW;VI96S_MmA<u1Ub`Si@y zW!4g3>O+^#Nv{cfFl!#aj8)ORFblmfZ^HM;Y~Q|*8j{hfRV;MthOba~*1-Jd$F6x! z_aS(a#E2MMdsfDpB!|*?U?@#^h?|0n{gIFijLE2fhNk|w$oLr~Qru%gt4J??cA6fO zO1A1e4-!vJ1ODffaQsQ#TfW&!YJw|eh*S)RtN76_Cbz!0Vcz=lJL*FHkdc%UumAkf z<*`vUAM#2%zo6gPbK}gzZ&{MY>_yLYC!RbDGoA`~)eeF6CF(Zm!V9zfF7^64y9&F2 zfqpNAZLoVsH$f?eI-hpj-*%N`#3b~vw34B$;q+t9P<TsAOlZ=Mifl)Ci1DK|pV(SU z<xE@FX@dPrw3wEb&49KY-2R8?(C4GeEkp7$ZDP2|7i>UPgaqA3`dooc;oFpf*-<G` zZnw^Hp#;3R>ZvTQOo>r@Z<2qw`)J0USK}<e6C%9_n2u_<nYt!>`KS5z=h(HUsY%J$ zWAK+>yVIJ@?(yPQ0giuH-g=&n_nu5dZw8~5meGskg369lEnRU}n0OxQq+hTc2~$aW zJ-5F7t8vfGv$CMY2YhCVs+$gLpQ2j>&m0+#G}Zgqma}*9a{zTbRSOwl>S>AW8%HUY zyR*UVMpqclziG(jbE5B$^wqO2X%)Wq)J2@m*>dXPZ%XoT;*)xDqEfH6kXzB3|M#D? zHiYs7ZR<ubAoXIzhp=*2Ca{+4S><G+Tgqa7Vde9*cZ)zZp!R2;o<06B=7J}Zq}}FZ zwB3_T9|S9O6#jx%J-()2Tm151)z01F<)_FO2<>U@xb7S>v~#Cn#F5W9A;Elyy_MPr zi9GxLRsBFfd#*7;9y~`!XC}qnlF<`b*M0W>i!_B$$^Vg=__@>i=&`77HD-hr)DZPD zOlB5XHKSO;HD$@q^`Tl0pLV9)F_c{^ja8G~c>wH{qM;!=z+Ur&Y)FMyYB=oOg$hJ5 zO-pbbRNK~{f{2i|j+t)`oT4iJT%>NvTRjn#_t4<R@I=(Q=tZT}iPD4zqSe&kG~NZ| z{?2xC=E$9-xPJ2&{2Z^I4l&I=uFs{ERyT^2u!UZb?V>N&jjAEL%ih6$Rn+hI&Lca$ z?;BkYx}YWU${~d|L?3g<;Kl(KW^vX<HPp3{ioPJk`1&Y&b>I~Ud^99^ke>EBT7+3E zceB0=p5<90&$_Njx-Gp}3?3R#5T=RAm!=|H$)Mz3jRSx}o|iTa;NG9FrM@0R^9p&k zY_#*O8<i4Gx>UFEks2+|tFiT6F|&kvzldIyS5@T<@Clz=?yh%hQEhM|h_#dD&g1L* zHL71c_`mpgtAIF^ZEH8UyM;h-cXtgm1b26L_uwv#ySuwfaCZn2+&y^X&P~=j`#<;L z>^$<&RCQI&*<)1AZ>DDcuOt@W1=mm`^K$)JS9~HRl(UeOVHGm!>}_TEi>#Ine2Cj3 z*~zgQ5pI1h(*l>$`pZ>mZ6=?S%B0aBp&aUW{zjxmw|~$vN4Furt4rpV49LkD^^BEt zPimrPKvDXwg6T5+Tx}Sfb;eu>aJrk@uA?N9bx2wNe<FDdjf##=R8|&wp-Kzpw>poe zl_L3@b2mX7QC^reJFEY}%>3WA_wR&6_}dWZ5?0eC{dbSz2bm1`t>aC$4GsVMh+ycg z0>4#Fr+~Hw&EE#31O8U+<9&kzfAJP%_TIk@kEeHQz4G4%RLB19Q&NI~;eRuvTTiID z^><J9CS`vcu$J!kGB6<EVEpBFBev(3__tHJ-5yi?s{_`6tWQZw53dRDiJQ5vp%!HQ zum7{>maMknvg<^HZ(KL%_p$&#XpWj^pVCSsn8f|p&#aILal%?v2rhs6%l4~C{@yT^ z6$i|Wzf9By?YH%`xuw(+`OCsc!u__MlDyG|f4ldg|KlpF-i)pO<|?WGxJrv*1?#`e zyXntCYx<dEjr5mopdpX#l-w^~`jhZtdy1sg{Kl19<6UrZ8Wu!+^fglgrPLU<<4-H6 z$HY{z?f1v99w+<urEnZ1-ZG@|>~iNT)Bo=o+S-CQR(6IzQO1Rl639(3Dv%I^9Oz;V z-#VnCGzy~uCYc)3B>R)nKBV_4>&<x7r%2V$U(GR3oE+n_I>GQ34to+40?QEKD)qVv zxa)l%uK?O@UVy~L6lP`+_0*u?U@$@gr@E!8+&?!(u|hj9W{fw3aQK2xaM3wjf#C!5 zr%#kqUtc7=*a(K_2bX8~zWfdaBUrLMeuG}Oa6D3MEAsz$_9=d6dIpT8+ppPS$bCvG zp<U|r&Iq4)JMFO!DN%^<&4Vk-D4X<_k45^k!Hop{-&8q2eWN=fIQ<ew4W{P;rx{ST zHzY<69q_E5?Xk3^R~lV3!d0~-`cYR7X=OGlprH<fK#f^Cp6RqA#46cO@=YMlS5sm| zmShFR%>zRI0#LIWExHtnt~Op7)U*z<q{gO);O{;Xs@SsEz;2kkSX8GjyNaFQS@)m; zUNZ~P`F@4Kr|=!-#Bs6T>jeAd?)?qA`{EhNcC+qtQxsC|x;G&OK!Vr72RuPZX=HK| zYh1H#=pU)>k40)v(EmDY&s0c@!D+kfclds+i&>aW?C^4sw0jg4@v9rV9`qu>>q@@6 zOL^I#W(YfU>#5YtjY2PnLnJ3f>+!B~<x_dsd0jpEu)%r$C0b!NUl1XY|0xt@>$%^< z%iODbrIi_H+WT4HH2r#p-9P6uqR|emTfrR|>r_b0c2O_a+iEQC$>KKS{b^5&tEp*r z&xNjFbPGlBFy{rw3Mo3JK<~7V3%c1Ngi=Z*_6SVV=NNT`#~%7J3K@L30#FoOp>u7E zT`zF6ixtbaRWJxgq)dIyZX{Wf>2L@W`JE$Rsy{)qZTSGny*FuD&B;`fF!Q6x;W#Cz zx_1J!<jQw{wBXFwvViZu=U!g#^Z{uw?a&Q>BSNtefIpOaf1Hv15rvc|Ee71m^s!-F zDyW0X0U}Vig(D;@YiEcsJQSkTjh#3ZeGppCjdBb)dx2h7>cNSA$s-kOo>JH7Z9s92 z?LbP3z6%SWFlf=LX~!h4!Eg!ZxH+TM6w`r2Y+lG))r?|r1F>A`<P^?Lzh_7_pUfF1 zOa60;|73H{j&Ag$>#+QV8CX3X+^b0k#AiP9Qj0HfRJvzZie;Dyk_zoDZFopU96?W- z3UgZl>zrX%0TPgRYPrAUr8Vn6w~2X5TP`jm`gS6cM5f?{S<dpwdE!(<0LQo*mhAO_ zRF<F3?|<ffh3=gZCR{^er*cH>%lekE0kri+q7ySUVYZg(5;emth0eud`Jf`>NQP%V z;Q9U4-WXF~*Sv=we$TY1R7Lpe2tYrjHy!)v#@vPjoTjsKv4zonC5L|23q9NLj7!ZN z5EqZ$s))hdy?Ppd`1NkvTMa|l`#_mPL`<R9vi6Pkio@p1%N*Q%ClS0G^glre29A-p zo1VV_8d3G)z5xFYO?kP4r_ksl(pf6kb3ZLU!zfm!$FLkRJgJ7t=LJ?KEN6%~+07M> z0(gCrUanf=@gT4Z9&`huZ9FX&<d^=uK2PTgt$ybL5_S*_3VPYVN%}#JNAJ=r%pYiQ z=B;#ralKOeyxn<pJRB=@Jj}0;9+$k*q&Xq>_J>Xr$6NKWdS2D4%xBlU-qHEI4t<OO zXtayW4o1J=X4z#XxJtyPAzLJspX#Oe9sL4wbvt~9zgj55Y&J8(A!8}4<PT>kDqW8c zC4Bpd?4hjNBknMBPSFn+r-a$W@m%F@5K|kLgSKDOXcUL~Eb@_&AiFQCdD0$BJEZ0v zU(**v*~sU{$iWzo!xcQ0BC0^!c`v<;EsZY_zR@xqo0Sr1rdII9V&;y;Usi~)=++r2 zx4M<Dh)gC3MpPjqZRgkn@XF9?s0)dAih#pnblPUWgNKF(Xi%Kz+1JU}-5{5CKy+Qm zD=UW!9%>(OEMyslxl_T-_i0_1EbC%)>C&!o-Lte)9zRU9q7}{a=xV7uAwOH&pW=JB zqgXyjP8I+2lf88f@Uum=b@$DX-@p>B9W3%*=FF&C+O1B&DI^lhm-J5S5z3(Ym{r9k zuL{{P8o6@?VeSH+T`f$+Ll?2~g^g29a%EK6N?BG*g1GWgRlRET{Tc}wyG$g64`DpD zoTEuWej`}F7K$87RmSw0fb$q2%!3;F$wKtjk`^0atH@E&xXE+4W!c&e*ZgEUzp@8l zTNkAs_J;w^K2~Y!d;`tAsd5Er)N{Bv*RB^)53b_5L7?$xxohea+Fb2iIOjGAYRnos zGGgacy1Be#uXjVZ*|HjmERZeeaRm;acf;_~XY9RWYx7|BzdyPWZs7Xhk-k3?x;MNd zb%0hX+)vzID=KHk&ceROe>@-&;&4*fuEU~?bp&JbkIBz5pF2-*>F^cRn78d=jj<Eo z7J+)GZym^Hp?jc=j<kqa8P28?+80?>Aex3*<UAM7lbH5yeNUufTg>~WM@+!jiWGd; z4mw>tpRJOo6bO>TY--Lw)7%Ipd<~!y12E!p2hK>Jl^oD)VVd&5sn=S2^!nbl!Cdw& zc7=r^G;eQ<U(D=@c}dQXry0PT4G#7U3_uz42)jSv-51>Q-tRcHH!l0&ye-PIN4AHh zCUYa_P+7`tFhpz(I|8^pxvMf&0l+Dh@Qa6I*^bN4yj}N+FTPJc^Ik3)5kLC}A*06^ zjAFv`7sy-(SPoiA^;*~$(8Dr?u-{UsER&KPq93u<MJ>{i51V}8#pQ}nh@;g)$v2Z_ z%+ZH}?^bI?2Kx7)Zaz<1XW`GS(H@=S#GhkPeA&$}g`(;5h`IU6!Pli^0=?m5<%R7@ zAK<$H4YsQZ_z~#8hbpa!eQKM6a{i?DbQ8-IEo4QCj~sf}4btz<bQxu0aA+!PU0L`r zv_B)@Rf}DXEHSq$1~3wGV#bcwu$C=AG&>UxQtq2z5{R@s^a)}?!5i*N8&)P@Mm4Xh z4qjZ0h$z(F=(VVx*xB}B8~dn~poLi#xYDXOP8agA$^7=45(q0wccPq>I>V8hVl@fN zglYt*AJHR)ih7-1+z{6edUW8ah9xLf)lHo;*(w=y6{}~wxL=NnES6}DNnY#b8!^L{ z)_50DzjOg`sqajC%{5(PS1nvQM!^?7^T}$bP~eLUY!d4z0N?1fm)ru$e`unXZGs)) zH!%H3c-L3vVh$r&7!zOlMNzI^j@@I9a%h4Cl|Xv@yfpUhD<{4swysg|)Bv?N8sgyo zs~95*F<nK4*0xM`U_C!Rfq%<FSyM~?3{0n$Os%Fe!7D-WeuYi2Uh46oEfn%y$tu50 z&jYMx)D=E5r6xq)O<Us!UX>wjZ~o_(9EOZBPQmsdAD^e!B|D~>sf4seKboL_A7Zx3 ze`{LLpGVbtLq~pcA!;l{OcT<(1w9*%&yDal<jA;n(Zsgvq>?kpiP$S-x|qRYOr!cl zv+E(6yTs)vJO{oJ4C><bKO#5NSWHDHJ8`k3V9}<3)qVn{`<Z8&=_hN9WJ3t2F(^kY zW3&aBTS=qz;IYE=jtX}v$b0P(9e?wi;=r*kzPS`=$lkkaY##lf9{gY&zy5Dvo4CAh z7`0=xi~;X$9<>ZQcR3VRBH~5Y2r^&xj6g;ifi|nnr0>nEARJ#1*;uBDJx|ud)BDTN zPLyoWUeQo^9N9U*snkO2XXza>W4dD-T)zLeMAZiqrpmR5BZ!+lVD6Jj;O)HU&&oc) zsNQyvoBJKYU}fPrS8j2z=~%9foM*3AArm`*DbeRdW$qypMjU&TO}z2AWEQ=!%U~id zDD>-AI$T)r@jZ%<-+|hD5aA13Bw^<jv(FxHh=E9j$EIu%S%)8C_Zx9^s6bB*;G$)` zS)zi&QFL9@aeE~#l)COMa*$Oe596bNE7Y>vdO+yDhJ&kir3mG$WPi93MtZ=FL%ZTk z_Hg&3>~^8*u}KG(M2gcx6s)E$a3{1T=ZE2~AVNx3oct!=lbOsp?^%Y@IXp!)LDF4x z{)`*url*CplCo*Jh?0r+3*<WiIwukyr(sI59DBim9sJDG8ROKhB3Sy>o%<1K(BS6j zGVcAd`cWyB=O9d#^5xqI^UJDT|K+QIC6(y(ZdOa*5ghe9oZ6Nrd!+Bl`-g51MiFYy zoz#(6{{^|K8d1>8^v1A5(dX>2U7b<aZf_vPw}+PD%Vy9=pTkRwvs6Ce%c&D$zV}%N zgC}N99~XSampOwD(pHxuFJyvd_+TLArD1nHWU~Dm_(skQG=G3^4T?WxbjTOjQR#G2 z*0<0N-T?Q5(8wfIB4Wz$0`w&0T<XWj7?gfe*3o1BsHLn=*AY9Vb(k{z%xs?CmoA(} zjRjyu&oJ!NLolo4vO~UaV2BUx1}9d1v3wo$gDRzNW2uuGF=B3L(z`6zQs}DVkyZX+ z-5)>R<a$%RcFe<LK!lyui5yM+Ac%QLI`Jo|GtF8)l8A&3{jmVmmh7EBQX#IV_4(L~ zm_M)ep2lU=y5PGkBs92rO+-QUT2x#s!Dm9eFLGLplIfk79$E@Zi_j^nFr?qUnG}Q1 zv+>L*DMh^M3WDboF;x9R^SUiVQBK1}pYfZgXI(Ic&Yr%&C<s!RXGb(26TE$6BKxvh z;gbCESSTZpOD5>G)G9-?VH%~o1_LERn*D4PlwxT|sJT*5ntbQlqM9%FB&;Sh9!l0C zWx9qn7Rf8<HA!x6cii)XFrg~k(6<cX^8w8RH1w8LjgVFr0u1{{1?Tn*zhhZMMC4p8 zI>Gdn01H6T3{yf8?Cq`WvQq>YQ0gScJXhhVQH0`?tJT#x0ai%S91^#pwz2k{{35hj z2?_)lAs@<J-jvB@a_e`;G^n;t0$l}pj+CGuB!_wAoN2ra7l!;t0BWzkLEK-$Q5Enr zR~!#K8E6+)!urZ~R$i4T{4-8sVxyd7hZ?2oV@W=xP&}W$7vrXrS$(vw3dqd5L?G-| zn<^@HHA4K3%KK=_B&TPW?eQiBNUNtGlI0cTU#Cj0tNngJ=a}tmqKzZb_9*r5{mCt) zA}e@J7wmzy1o$znmB$=$9od=e<GRuX+ua$<w=vkqRfML_c`jm7h9+EG5ev^2M6TT< zn|QE%S_%khkOi&Yq*=)RJabAU>v%>pqu$(o%DB+DYD|410%Q_Nz}l>9TD{2-q37y$ zoIh>{g#GFvs=VU#tt>~fR)nn{|Bmk|AgeVYtd}-Ihqsa(DVDi_pzv*|99g*;CU-5H zyt^5%ZqCQFrRoEccdvy7c8aIRS-QeQ`O<o91Dc!dW>6+l%ho_i!pPWUANLIIz#hHt zN#{F+93P0RxR|2OB0=L?!;``X8HbVKR%Qw@ZNGib-n-Zaun#bVP0FG-^rR=I2;obr zy6V$k+>;ayEG+}&PSxRcRu^6z{UTW<SfgK{A2%PlIlaEnpxHiiwZgbG#zd}Z#VM<B z(wFyQV$@u%qz*XN)VgF~X~C!9O=R|!@$8;}Ut)FpL_qFuMNXtzpP$_yI?V7}G<B;v z!wFty$t0zlb)(32J`?ChXNpOQIw!l?2v3Sw^1NdT@X(Jf(Vtvijb9L_&clq&Z*+S; z2`K1l_edxZoU1cNY~*yojFv-PpP9bAwhUtVKlrOG6tF0KFx%u0(Hm~KoL{sP-n1%l z04dHcSInoBgvcu`)zM#n(ri6N#8dHLeM8;!mC;=REI;+B+06x`Lb;4vIb>pL<h&1M zwNAg3wSIV5l21LBxal^#jK}xYs|?I}m-Qc#;AJ2jSC)rg)DRX`bK6ECHJhP%_h()j zpzlR6JS%q`l-2Ih8fLJxkQHOxsy#B89+TNWK~EutU#YzjxoliJBG1H6vH3*^Tsq?i z`SCcyf9~d?b+i-OZMZia_DD;9MR3r&Y{z&|2#<idn&_kUK@{ZnLPJT~>%R(hc#$2G z-zIfP_<_|H_Uvjic&)b{ojHKp;q*X9XNXkkbxPBqzt6B;r8ZR5T}YUt9pme@3r;b+ zo`=q?tp-jZJ!W0)Q%9AF)r`5l4C6Y*<7ET0*NebQGr-eSQjD+-t#K_hRLiV97V3)! z9Un|727rTQdtOy2#^uKBIf)97S>}jjOX@*a+aD>TM6lam0kRA^56VLr0!zJtCdsNK zJozOUKv(8>v1NaOL<@12cXfq*hcK)959wp`pHQz5&r!p9q;Aa|O%<21U9wxBEq^Q; zQc?MJYpkV&=QE$zlcJl0xpEd1Y463xUf2p7*-@`RIMTOPT9$^7+15N{vP)EcrhhZN z8Le#k+Q)vlf($URRo8s7FP#h&DHnoMu^rCb4VV$iP<2xa+~^Ak(N*B8Aj&BrE!XW< zumelCT9r4W!jXZpRe%gd3kRS!Ep1skZ^<uG?aXqTj`DYQvd=2<hm})19K>pGmd6+m zWwFT=&-QNeN5_8)Pe3Jv3!9LA&>G9jPYTr6Gh);x@Sr^Mme1?iE2PWhNCW2AL%<#z zRwS0`Gf>69(R@k3r>4i=Z!c|nmGKT(iV0z<Qf3P)x{6KYM=ei#ttQ_6WY-fj^A(d6 z4FSJeY)d}oasy^HOz$Dg>$9znzzLZ9aHxFBcT8p8fe20a@{RK9`aDJ&hO@B<;~LbT z*cL{|%z0C7d(qj`zCv!-25K&@jYJfTd?B6DduqaTB}P}Iw!?dD*f||0N32A26V>?F z_f2bytW&;KpMC*!nz^8{jVZ6hi*s^*Cdrsb&=9*UeDiqupIk@}X|CZ(f1}D(qllS2 zl45&$7pC}?e{0UbUYY;HoB<z8;aTbM%V}=$9g3m7JTwnEfT}iS<U^4XL60z^_ztWG z?d*bwteqs>_e7q9cm?{7*yg*6R9mbv%qDUM8`Oi_Pw*6Itvx@<ub>=yR7mEOfbtte zsy&V!o=hz5+)nt+SgmC5MBh+Ga#f&v$m<`}-HIA(wV-=hXG2ZwOJ^dGdl~hrJz)x? z)pHQX#1w7RG!86RBlEG7o;6q58@e)Fd<&>7IQMJ@N48-%USiNP^;+QcT3>$~_}<8N zH-0)Lvu?lJwv2(#yJQr_)msxKIH<g&lHuf#z?-eycYVv1EuXs5IEM;sWkQwl#122X zVqR5u^8H8)Ef%bac0n8O^2(}&!@z7ei@C`mn9idF|28d)`zZb9Wkm)6{D7}+mQ3f% zFPn7w6e#Ql?JS9IJA{!U?7NC2C<rA-UaOfL=354h?l;<du!hffh0n18hOHI&Eausm zN#T$#ohpST?`2><-O@!j<2VtI#jvKy-AjoRf&L%vfGTxrx(mRy$(@PsP_)*3nbgQF zf)|jY5+#YzrV4#Na>eU*$xs6X&DLMFSfdE%a1OL{pg?|p*TYjgRSrqJ;L$+9!QfoJ zytK7Ye?#yCh?5hjw;};T@{}eiZgeD#yXK-D8%yq{7Bw1$9uSP)HS^^%lAlKRtv5RQ znAxYgYV$C*zTAMB3#CUt0Q7zSU`f#VbA(h-ibiWzhRWo?!oz=h5asPDJ5lBAXv?B* zXR@!W#JIQ4#$#mkxes4JXZPswaMv&^J=jc}7pY>U5%$`4e?5dyK+BJC{9O$6`m~fx zCn{?3oUnP~+8;cdz2Mz4cJjSd81)`a#<vsU{ZiSnw~5c|gm))kTVg+l17SM+If#(I zMe1e2cCG@LJ>)ySplZcHA-e4FFhDK?=H<x8FS*?M)<O5+ijCuREn3!vb;U0yRq%pv zPt6I}hUWsPqM0F6osQWE{!G#7zE>@BYW`91UHt{tcRi%<_ItdVnhc)BgVQ?P>Do2h znCma>+0n6u%{SP$gEGdVsqH-w)?-xIaf!O=;mAW1?+-?VMQFg|!9pcPLcxxxv1not zGNxucB`{OqZoL*4TwN+-Aixz9>D)1K<eHYBeBGX)n9iL%wX*04b9^Einp4u`E?p$M zsNYFChnlJ?8RQ(Q9yx~LDoRMJY)l7ht!(vDIE;GiS5zxKl+$U5Mr{Nlw&;~t8hU6` zem=rXcus^rt|3?3TtHTbFG@mFAj?hy^vpJRXKuubiqEKPlCLzFLK<6t{;l9T7m76k zr#R%pj0!2CwJh>fPbUOfPbS&RIKmudzi6*$9XRHdd7?t-xRhGLfj4WDsusyxBoO0p z0Ij7KM4ji43XC&fY~$Y|em&2`5icK!wB5*EdH4N9k2A8op}fzZ`X;*aNuGiA8~zSS zFDKpQA?#>fJ~p}Lq3*K1akYs-y|6BpqS2TIAS}cGd%dGFyNi*1F2cSFJ$h9ILqUP} ztZe9MQQ#DLC!?9XrMOWlNBhrVv$CZ$ykA};>?KpHzsjVkY!tEEZR(dC%ZALm<p}W@ zCu~7o$-$JxYDIU+J+=oPhIK1s1<o80|Gt7mpvjvOBXWZIgA54AEH(9)R}tUAUdJmL zlHoWge=N`{`HaO2=wQI!i5eHnZ8sVyn6jcD&z-PU2qXwl#2=Pcb>M-OFc-!Nr%Jrh z7ezlBvn`LI!G^_ZG8L5sgcH^b)qleEISaPC6dF@hm!g39DG?`N6qY}p;?YCpa8CF* zMn?*zWcoCrpe#m_(1zOXriB`3VT#5rP)yxr#6?DG<E9ap?AX<8f>~h4KyhyfYJk_y zf+3-#Fa`^K7d<ud0Cl-T38HjFiQAZ6ZkJHnQ%^^Fp4XDNN>=`;)*jj)SF?9;gjY+p z*1!`H_e9KMQJLbSP{nd#|2U2Xw5St}Q-exlS@7R7CSS>rYPuFIFHR&M`$1G^P^WJJ zROu_J6eEGK|2aQ8uHZ;+k)&2hMn{llOEEVGj$|JD%hY5?Yni72Z|B%(<otNvAt6&M zE*lIHC)`nWs(tk9hiq7RMgjU;CavnaE&;McKwIWM!Wg;0*N|`D^g+&jYEU-|^SQzT z&5&ASk@c*;iA0XC$iN+SWJ(IsqxcjxaqlJv#?*n>k@K+;7FTmvxO=jACCCg&8OsQL zF`kb~ELkMtx$_|k-Rj8Wi4*7kx|5&uWIRsf7lyK36Ib?D*trKRDMI4Z@dqCdCgNLV zz-h&VGy(+3fEpIW&m4UBpZmd8FufS5rDW5VHZOH};pZ{Emfs(1NS1EbpD!<)={o4E zk!iYIYv_u}+pf?1SeyGFhDV?>CpQ9Y@?oR3$AqKQlW2gGlPDUX{T4ygamBWwv$1bC zEZ=mwsrL`JLiG}O`UywY&ESZ6?Y8R)I{}#AbG9fM!>6_DzP#qq)h0b2eNUB_9Kpw= zNsD6gmJOid^Yy^A%hn6^u72KMkt)_4vqQc@e6RNa-(L=p;d-Cjb-y3MmG-izsJ6~X zd~U*Y0nOfMCKOT9Yb52XT$kyKN`G|PnkE1iNZoAH7~4$*XpE(`HtI?}P1y;4dEvWE zOpmg6KnyigAGBR-o{`@;eoXK!QRdP3a86kh-gI-8q2S?$ET*RhK4BzWIe0mJOCo>y zv*dEGC<P>T)Ob`+(A%)-!*{K$zHRwaU8Pdv<TFcFr*QM<Bh}(G7J7bMX~S)5pI#=4 z5>fwAu1}u<14}`p@Ga_@-}xPa#9?Mse?rDk8MTk?^JQX7Q(>Ph<gNySE~#E@R7x!v zglmn48kV%_x^(@q?Sv{n?=S0IV7ctP5Ob2!2o!5WpJG)=u<iucr>#Z`t8{HUjwgPa z|73Kt2cxGlw3pgA8(?{2y5tG*6=ipyf{0IyT*4?yQ(Kyx1L#l=lN?Qhi$OMEF2Y+% zLYAsPbtNul82j_>Mg-yIXAK*FZ><_MYSQ|V71b<qB92PWI=}CMv2H@~2!iE_Y~d3X zX-1QLZ|z9?7htXORLT5<0DVK#5`A)^?Z9yV6>~R|4Ev-#qHEzZZ$agJu|@lmG*Dnk zsEjbiKq&p}D}1sf-LdWCS3=B&IDY{XW+dEqOt^ks`rttda=^T&RIwxn>9tv{MLl)_ z!1T#uXZPdh8=ztv^kBWY(=U?K<hjK%Q@Vt#F;19SWrwx@sS@D%^T^6$OPfxMxl}`K z$u20R0tgG~haG?4TM>(fkBJoFzZ_AUZ>53=9aK}062)X-t+Y#$f9hv}m$Sf?v@~G` zPn*KRsSxmO7dN!2&rPAyFvgmFdGUJf&ikQL84YEUC~Q{FCt`t-GWa1gJs<nhS+y7Q z=PD-qr=J(pSmVK(4jY6?%;k*|FIKl<K~sHaS8i{yUK-JNp7IoWOFzLOBP5)cP-3J3 z4O}iz&E?&<xm`U$O_gAuS*l743Phf3ux0#;&~!zpyYyH0Zux$!&;W6d*ctz%xa$^c zmqEnWVNb3n1?>**gY9JAi+-E?^S)8w@(9ajgwj>s*7P<hm&X;PY*xhf#B##y@S%eQ z-BdDqAx@J;;2@OhlF9e<ZV%3Yde|I+4OKJuB6VlB+yPtm2v(_RZJYL<v*7NH=%u4D zQ>Ynp46Ue{(m2_DELx>BThkV7{g`xHiW<&2m@68KFVKBx8oATOuCv6m{-0VpI#g7` z$B|r`HRY8P=MyK$)p$+<9A(Bb0y|#tW6NTp45_u|RH?rV?@eUTmb!}V0gB*NuDXk- zNEvZh_NNWx$diizimNLjfX$!9u;&c%StK?QTan5iM^od|?50vuFw^2KfaXdpP3R;f zrX^He<5H2oJPg4MF)U0W=HstX;3_fwr57Q}SSV$!eB^BaEx#h-ZQSyP7(~*gls;lr ztV|xzNu-mHjVdE&%2C5K)M@Z$CmA$-17K5Pu$QUZAJ{NkjFlufYP|0+Uc}St6#vRm z9UG_Pb6$+3HA|Lt+OAJx>&Dn@zW{1p!LVXB(J<iFM@22Q6Iw31&jzsFg&G}2ndI%% zV5`nk%u$YKJafX}0W6}dEu2{VSGpr|+qh!AVp7&a7cS0c-`+)LSvc(=T)%3+ykIT4 z?(fnbH+y`O#M~YmuHB)2C2MKE&ZiQj^<?em0OmUY&cl~?KJ75jKZ$Bn&zI0PnH}uD z-ICTi#UPlF>-ElUdf*qIsL7NYw>L<(Bh!0Un6_Vy;pi1P#w~=;ve6k$1Vwsiouq%z zDmtiPr)g08WD+8)JyZ?_Ag5x^4j=6^V)ob=YXv;sRaPej=kDyp=jMLJG-x)C*XSny z85MTR7JfAW9>e<jl9eVu0Vz+(&^rHvlYxPZ&n0wEm<9+X^~E!7f)ZnVMYj(9CuTwd z8oo7O*j^YQ<oKx6VsVv>A;v4pC4L;vWi)jkHw)kGr2j$NI%O%ul<>=pL*#g>R@Af6 zN~^Cc%JTTJNrW#F^4LesGO_-8D!bdax3rz<6;4{$xKd_;a8eQ@@}D2s!8Mt}W`ZKE z<&}KpS4c0&`|>w_Qg{~*u_*?1DwARPwse-~B*KjrMt0r<^}N6+MKvpuk{alak{DTk zMSRxG=6*L15G_I}5;Q3S)@x?8{wQ6<hF7}y^jhV@GB@QP{{`)v7?TxnA?k}quRJjg z_NrxO$rm4kw3o9VQ>5f^nwJwlvD0iZ3ea_1a;M|3%AEjDU0+RQRwBP+o0d#9JV8D4 zc)ZEsczc`{A0|2R?|!y6#lQczq$gRH=ux2d24A|Z57Ib7G6iv?@dqXHuV=;mMNgAD zh{sR1G*qEA?2u}K>SfJGGfihc{hVqvZPsKes;cfUSv!^G(A6xsh!(xjaxGi|Is5`M zhB(zm4!BX0ih?uxHHhf9TV)PK(W}Nx>$E<C_wFy|K~$aE`(>?T2exc<h7`uEm57y| zd@MRL&^|kd96!I*NuFbMYtTf-+~t>usK&Tnq<JzW)$`~U+B8#r8$4z<r58{0c4(_< z)}e;2Fg9{><!G+dV}#g|13@{Qx<A`!#nECLfLP520(StJytm8@QZGd=C(Ps*^BPz0 z@umb#iO{lw61NtCJ|Mh<1(*`-lMak3u?`k`xtHFv>dGJu?5iVS7*y~ZgT8VmXg1zT z7Rl925{odyhm4rg>1yq#(U8eZ9ScY&WxL^)W?%6FJ2~=~V_Qb0Cf3}5Y&dDaXlRJP zK+0Wx3FbKIPD9%mJun;+#eAW;tkB82G$pbvkeQsdwAh$KM#^wJGoHKCs?k}5I8Ne4 zjwQCoOtMG*LznL!X0)Is_IrcF3qv{W<vHr)ZnQWjv6ff%laDuMdzS~N{ps{Wn)*t4 za0dr)E{HP15p>ck@p9T?w8O|jSkR5r0zT{4?e%qP-$u!uk29K+a&dI*ct>A&js9iN z=5fh*O2k33f_kXA`!nEVo0{(?mAxOUkHiERag`NQlpnRs<v|v)n@(O;`dJ1KbU9VE zWIh%@BGK`(@R4AcyW>Ic7LiOWmW`$jVqzfGc()o0m$vKG1hbTv==NH!{GURx+r zFptjJ#G(2~!WujHs=0m8k;4I;zn&{)cZOa*68Zg&w1Xc0nD=7LJaMnB+&|9+0smxr zdvZ~r$9uDJ#~_WGFd1ugGt#cdX(#XwZdLr@Vg&27w*33R<~glHRWZNoYjOSIjP{L` z@5^P10be&IAs*%Qw!JxgdzT~Uxw|>W#Jh{6w%Fbla$E55h9@E8IRB$;T69fiKCUgK zzcnUbAvbMTbP_P1?r~z&Eq8-hHohF+Y2FOGySRSKEJ+JH#&T}g#DGPw{d{;``$%X) zCD1sLD>t;IQAo<HnU6|o@%VSFpL-iKm-k7eNH^IrAJ>isn2`T^63sMb!b*(rwnjic zs}41a8_waLB_Dzta{8%&;;U1q8rf!^L)VCvfGf2B%b~KB*&a8^eA;TYw2_*+-?s7j z<Urk8jU^R+V73MKwjMQw_c5P{6kpEl*?Pa3j1wnZZs~wZn<eC&>A1qC>PPcUo%lD% z{N{L(0}?l0{Q4iN76)7gE!0NR$zCWk2r?-qV*Ns#J6I~S1S$m+6LCqqAx}5Xs8;*7 zIU_mCa{1Qx3nNgBl>P<wi0mw{g1C1Pir*Lzbj(+bo5Iv%=#DvH7rSiPhUeSGSZW}u zx;REEepcqD&hw0s+bL2d8MkaSzo0AlEaq#QeoHbhNrhlBKru=yGLGJ5i5YL+iN*Id zxtfnR*^@GzYa_p(ubJ?pYsw?O){b+_Rz&Lia*BO^VsZGcpF&|)UV~$ha;~K_HQ`GC zgq*z0X8Ujb-Gmg;Nkou`5w1f5TI|K<v4x$YURDY=n;UHY)<mXkqy5zWVx7GQ!f-j` zdIAgIh>loBaT1kKB5%-|wn4oz)f{~5_pHG^UAnhp%T5o+*X#G^ccO7;+Bfb?3b6vC zhX4;!jtG-8o7I*bDU{798|<_lN}t;55w=a2Wr|6a0LRcDH}^2uwn5VS6|pJlrl1yU z&L>uZN>%n|eWF&BHiMc6mylL{`;uy~{lGScnaD10>_(n3qU*aEA|OR+UR_N-BtO;@ zOu)cIhnNmQS%vvZTY_KrcgXdkZ(YjVNjn!@Mq~O*dh|fO(`@nTpoc_S;e788&!^!~ z`;y~!i%S#ntbyuFYG7(|`!|CFeLfnn1v)SM_u-SL(ms7cdtp|Nse?sl&OT`_C@nnl z7-_zerr-HTTg<ZTYFA>CS*$`5*U0>_NQf4UHwE3{gFVlOoI(^C8}?#0UNL;w+=;JI zyE@EZXwG&lh5E!Vx)?!MeoTF0;}kEKyn1YvUrR0*D#S0ZjU;<3LZ1hYuY+rB=iGJ_ zUevKiB0f5dMO<IpVaaM~yk4G!g7T?|T2`(=1vR*jjW-C1-XKVy7dgwg$~0medSA~R zDpk21GsaP8Gm+C_$pNT=OX|$`*>ywi%qZXIL74ij<%y1+-MeL-{IA%HsPB5}N<Ff2 z1_L#O7}=Ca6<qv-S#CCB2?kZ=pP5r}Qr1aX3jqrJq|*407+v>b;6D{N`{!Ib#+*?F zJsvSPaG>m2*7TftExQY~)iV7raE51c;`tGLHB9?k*a)${9rx$I_$VZ9{vraFoV63S z@4b0(+<^J~@YQvi$=xZrH{pS45!i&BPgRSeKGa-O0w#cJJ%;p|^H3_4jK12uaB#cf zT6{N9=GCTBZjd=>2w)oeSY_BDPh_Oi#I>O9SjHSe5fEuPoBzuQ);VG(<S1#E<;NtJ zl2#igHj-3=phje5p33qSh)2hb#r924B~&q=fl^M}6mje(FY!$WZ`xT!zm}0dTZ#Sn zHBZ;Yv{4oBg3&*)a8562_A#a3c;ks3AG(J8E;!i)@J_d;Cl&84rZ>&^ZWhsw@5*}Z znDcMN>mwvQ0zzCuLZHjZf=(9L;8lfjbP{nacdV9X_}G5$Ro~T#y6)qgQiik?o|o)& zQXOSr+n(B1WWl1h)1RWT?sIV6LwJU4{^)=#Y%k#|cBe-chU{*?0rIp~*KLxaw->WL zoi3S$&^D-?FuWjZkU_>h)P4zb6{f~lK6abhvQEM*7f<~Nq=L3$@nWQAD~OjulfJb_ znU$cXTxqa*X$jF^sF4#{j@tzkd{o$oapsz%M(79;VGr;KDPLvL3|a2P**pSB)NakF zQsOn?Sp4E@>wW~c${*QWjesPr)h@_C<-$S-DmV}upe;h5nTLnl>4eV)ERcCe<hl%X z3TMPqcfEWI1sWT$YvA${^a)QBjcMLZ8rAWJe-&NeZVs15B(vv-O|5(g?QWXVy84W= z4#YWgz!!87rjuUmH(ZaH#5K)x<8vm|rQ-^|ECU+0JwctuLbcBl!^HTCVER)E%xLFX zcc@g#OmhD+Z@}7oUZv;qxlyV*{cM<)j#g2$dRvGj_~0&i{4=Tl*91ahR;SF^r1EL8 zlZDo@7HG}Mv~`FwwsRkQQWJYejuW@*_6FiX)zNIB<{|I(9Kzjo0kr3T_Iq~A0qWA& zstKNhrVd)h%w9_rO8RIA9=ySiQ_9D`@cK@JFEp9a1W6ej9gX7#r8io7Zk-A4M!py` z*WEN(w<BS@Opn2~&j;9$ldM{_DWo|LBmsEdO`rK6hTErz=)95UpfM*5vlUP|1zUa} zd$%ErBtvGsHR+;U4xfw~RB9P|c+I)_z|<man`>&zCe3|Z>i5KwTyWfzDM8gN&$TMk zn}Mma(B{1?L8o%>(Wt>ax#Brr6U5HQ`UDS^&*KPih-|G};p*}lTH&pg{Ptf%<ZrX4 zG+x;o1Ql=1cVD4+DAMF-C#9S4DXtf4l6+k{;`4Q$FZyovqD~PG6(q0ssrPF-qv-yv zXd#jy+HIon2<!f*WShyqGV}H$kYE@TGaT0dQZ+Ui1vgyQ>(KyVd7L!!#wCz5eylHD z;$dFPiMO~ptj_E=CYdv|+`giZLk5K|=2AL_<t%@XcMie*-g`4o%Q|M9t{EzQlEEP| zU8(rdKw@r^tjeTaIto!=8+&F%O+y7ugns051q>+dD=llLERjgS&U(~T-dzl}uSjj$ zNjphgqS`EhA-Yx+=HbAip82aRjsnk;)}&lpr;Vd&W~VZ7G=!$q3*A&2P1#}eJ5EM? zS&DvQ!B{*Lq~~6VN85!p4I{*F{|M$0x8`sUPMP;G!=O&|t$_;ZFh??n(xe0{q(L-! zaKM;;(4)W4WI98JL{uS7PzkI<{>fy(#10cs_M#`2yiYO73XJ!dlFsjGiimfe;@Zs} zY0+rQPNm&jCkgRb3?J9N1$~5@5biN{$z34@%5jf3#xyyR&7h24FCE_E3Tzz8u*(HS z;&tfmtzfr$OeS0(@L7NHxcESTPtZ#!PWn~35jaj0x|U&9u3{(qiyG^HD%RIv!JPx` zNlP1K(TV&4aN4i)v}xctDLeb*TjhEX=%hQ*!q_169J75V9x*ND7jE=QKW(Q(o<-uQ ztaNx9Y>I|Hd?m<|k~AyHgBwgs##0PVR2|v0zS3u?%&Y+M{~Or&LNtdIK$kV~FBU`y z#(sNjS$s$>r8?I{Wr+o^g!YLROm4gfK0pJkEtx86$d&<6HC9s$JB3q{R5Q$&3Te>T z2&u5F>Us+gB5w{J{lCbHYf-=Crks)uQ!R;qoD-VZdl;POfG=&oG`K?~qPT*(bxFM| z#i#TC10CpLfiu=zP}FFbc9)j@@A!cbI4yukNkfVgmKKn-{}-$zwuk)>=kaNanf7n= z$?ro%W2F{BHvX4x5Px`5A(J!q9wXJi(kIk^pa)Ee<iF4pLg0%+eq$?Ee#4c2rB4+9 z@W9mZbbo0G;Rjjm|A%+~5To%|`lJZfxJFr+&ddQ^Tx?U14^8R6uNV@^ANmAOnYBXY z_xP`f(-7IGImFhgfdAg!BJ#sJQDr@HLF?Z-1N`ZMVb!3wO!GHD<xhhTl?4OLl)nKg ze|lip+|g?N_ZgAZj{WJ4Fvb(P6aSZOm-(|-lRhRDe*;u-|C|ktPzCM30V)zio;Do7 zDiSdC)@(=yo$uh<*?mcs<E^Pp1XmDq-|@A-JHn+Hn|Z5p)Ytpbs#TBJVKeA`50kpu zG+uG%A2eM4FJGhl59~;B+$Bm9?as&CEgBv)FkB}T@p#R^ZW_mfo#bH34@~4_eT-UN zTxJ;Y72b~QYOBs_$o-IGu^0D)YT<B?gx3>-qjK7xni56{2VK3}hu_io{c0cB>i8Hz zWx;4<xTBN_^o>Bkp%7HU)xiBHGtog7qaUh?VN#nN?~Gv%D*hAKV(4E-cqhNq@N+71 zEc~ap3TOHUdMi6;l&`PhM?`!oE=NG};JVzpIRrHapQ{gj{;I7=wK59-=>?GfP4PLY zN`UQ@n&}SX$j+r8Z#dw*mjN>k{Zb_*mpoO{)_UIXw_i9&3ypdWK30#2oQseN+P<C7 zrC+Dw!sFd`!0IQ1>+iB`HH9nPyTEuXNh&-e%YU^`;rwu`d-MJ5YmhgUL(_z$`YOMl zH{iMnH7wMN%0)^*ixm2s&L`keEujlLfv92;_m5K>ku>jU$3mSdTbysP6NJOLEx0Z= z-eqgpB{1vs`?bZ<m7P%=zK>AZRO^8*Z6^j@E(ku)zP^E*_pi_`7faDAL(og-T__3p zg;`vJ{-b5odj|&*CROUYEdTQk#}%{vX2kU|eO7X<)dV8@y~0x=_FKpRC_^o}fRm>9 zU2|mU`uTJzDKaLfXIeL$_~YV*%<=(WBcF~RA1OPN|7NETzMYI@+hzyvt~*WdEC)Ja z{`Qsy-}Na36$iW^-Ww|q_~B)qLSNRM7u(q~M^#7J5%bI5B8L5G8-m<g6^ravQJ?{2 zRm%=xH}@jO0iVykB_t!ER5MQNW;5=z_ZfrE-2mmoa?KE$7USkG#?g5g?YI~#jnpq3 z*^d>T_Myxqh~2l8H!r_fw5y-xQ;o@8-Vc(D+^xVzgvB<bden^Rt{$54(d-bj7;^^N zhupY_jaETx1zK}9nu%^azZ$E6l%NLRN2;H4Jv?4*#&|S@V^p4+(C1#~uw-9KsmcP) zx|oeefash|AD#Qz1R{^?ZIw}+bKRp2HV&iLCE4B6v_nx;bBjsye{P%-il(u<G-yzV ztN*9>Po?GW=-s$Hm&%<cjnEV)^>Q&8;T&c@z0S=mh6CigH;pd=s40^2UG1DWKS|oa z-ZteI_d>PXq3%N^z@F9!&E=&w8uL0v-KEY~H{iZKk@UDb1e8)7;-xTX!~BjcilP5y zOhzoloPWT$i6BMb2ilix6yE2r>OlbGG;oWi*j0g{5T*9)!tA4Q*12)Rb7!HX1s@vb z+3ipPRt<{t<wPDg`Fp8UmV`IX`JMB~PJHmb4R|uP3eeNa*24e=t#ZsJbo_5`qV7UU z^Bm33@&_a0d@P7D?O-m^Uv9pi((I=r`m6bd_r5I}wBPHJQBZ<r;z%EkNe5dy-dKE| zy0vOgdc~REMk&9B!7b6ZY(#X(WT3t~gS#+>^=17d1XcZdM2}jFOI`TtvGk_e{i=K6 zIv&I@t2X5$Cg2|49;u!Nb8pAVwLq<p@ByKWVVbkB;mmCBJB3tIPM7}=NJ&ChM5!b7 z6+6TWVNo$f)XreGO3vGwAJ2vjo%xt5beA0U(2mYJB|g1fOGQ)?s&wSFPe<bT!%>$l zf3#LNvFOUTi^;`;zw2ehl+Sij?BUYlMr>;5@M2Km+V303m^6&XkL<}V#7W{PDjT_h zVtZXpw=d<jnFRgQ5R?Gwa>?nw<w(n)T@z_N9=Ev*MAiMuUhssH={8r-56w<TUJ{s1 zk|3>SD2!0K{QEOz<HP+ejoWP}w2ks1kNzU5)OcJxEWPERfDYP+^)2cS?gzB<)i(B` zmuyZ(QUO9pX-iSg_Xj!P6p_MFBYi9nDKTdXK>wF^zxl5)A*I=L$~dNsWEGVEkf1$> z{yh^dfzu)xcJ&<T|8gV2;0kQ%ld7i<i{T8+VR5D3XeIS?s{oiae*;GnRaKpm^l7Ps z*f-%T*dKkn{7*?-!st)?Sf<1@|4(it+{mv=9kWehxpLO0!qkPgp>g}1V(B<T!3x6g z7lkAX3;~_wVT+~9ueO5MDtp)lW1Hh6{dOs(h!)QCkUQu~a(W?grZ9;8!P@lT?w`?D z<(=pl1Fc(X*qvC>@Q9LnqM_|GyQShzMKX{xEd9#z3}=XaDvG&HbC#QdPnrlM`~{1P zI>EZHNY7f%@5pOylaWXo3F^Mvhy?BL1gDMG@$XvpzmyT*4>!Ht%^qwbUk-h@Cf_(O zhpcLLsy1&onLKK$4fj{R=ma7<p%G=Ym0m7IV0>*uN$nAzk-MB}EtZ%s_jnJhFJ1RD zBiM}Y3x&TlnGur3#eTsMA7TTX8OdRXK^?eaj$HTNMtLeG=Z8Mah3C6|F2Bdx0R^ne zn|I?)Q_#z!h00+zQQB<=9S=JW!rwY-j%F<P05N{M&P4U%DGai=$`M`%&BUlOGK`0N zA7;79b-&~i(d>4+{{9$XWXxu=WFAL|-sgT_JaI+%17&!fGOxP<iJ$@t0#vM1j7_@4 z`g76V_0`LP#pW-|*<FOpv#HH_cQqHoF~9$iIeu4i`$Z_UzwugoB)Nf$2{;o)zT>x8 zNNOv4njaGL+RunryR!1gY2MXxD<d{W&g8vjLi>aRpqB?tdIlZ-0Y_RT+@Gr)s?HFu z7vhh7DR#oBO)+-Pi4Ejg*F(}v&igS?j$R*52~149pe_i;tv$tX*R=5<_aNHbeA)kj zNoIJd)J$2(m`>O222{3keW^%gXUXy}IaH58Q?HjW;*Bvknzpz&6$32W;^dftp_+|P zuS<G)i%JTfsN0d^zV1J0cY6vEeekU-0Yt3+s^*w56|`F@CFF@<-yNhGrEv+^cy1l> zr^FCHS%|PWO<5#fBz_mMyyO;Fr_yPC*DsHZ5VH$;`Sy$q4Zg(a;=cLzxja~$ssY{v zjdu8kVsOT{*5T8&vLbs!<##lHKe^-bp|3Q3sIFz&MVYU%DIAD)6^^7#*%eW*BL28G zBcj|eC<G+`5nQsrg<?i+XaR)44Ahw46ccMy47lg`*&JC@5|?NWS4gW%3>5;eyry}A zyGS6F76tH#w0%|H3Q^!QmZd(IlW`J*V=vF_sG=6Di8NrM1?{s?M%bbA2$2Rtx}SMv z)mNnE&OifF+o$Pl2w~?osW?~oxJZ<I8R*G0h(~3F{XtgN0deH~YM3Kyr(V<aVi0@$ zAlfH_A^jd;dAf-Gyeh7e#cgA`_DMDbtZSQsImYsCT9KLUIKmfk#O5)WLuEd*V(rP* z`=#@NDlLxf=9jA44TlUW8-N6fEsCtqRoz3~WN)+0YMk%t*#ofK9o=M#g)2+e>($rC z2t-j)7Kwa#n&Ri-M8UMA8D)8K*+E^+LGr0o+#*;{cRx`JZ5L|XJx}p4Q%N_h@q*e( zm1w~mOV&Mf_%O0_C2-99>y?+>Yk5l7BUGBMiXncU{1b-Q$Vt%k*2oQ;)Uwj6vSz@W zvx3y<ARAdNAGl%E<7*&c?&D9vZ5TnMUGW;PNW#Zx19j&tnza_C;*DK!pO>dlE`p~I z-Pp7%I?Xbg+IwN&tq%LhBL>PIa0hn8DCk|m`-iKEo~yOk$oH2)tX#BXz0OSkVJ{3* zxV@bZ7PdJ_%suEM2)ld?O)>lII%5vsCFsn(#X+5VSwHEVk{Z8eipdkuqIg@hw^DF1 zMvStiH(8m2DQ%<J%kO!f*2$#TyCkdF?SOytc_jGc%O0|z7M;JX7h__|**v{_c_Fu3 zc*=dMbr6QLe_Dao!QCe71j<Fn^zB4t^l3pIY+gRzPJ_xs>Wsl5O#$uKe{K~aaT)YL zCTNzVWz6mYzT(`_9Wrjc4j6W*%yPY*rG$cBq{Kn@5zA79Tfr$LTooztZ=N7TAJ)nz z%g+QY^gp<N;jd{jgTvt?1*68Nv5A|$pme%Hf;1?Pn^f@cI7eD%;PmuAbjhMTtsMX0 zu0-kj!eUiXe1>|w+Iji>3C+ST0j(BL?T)o)B&E|falR6*T7%McVA$Al6TV$VfS^H` zZ&!+PhzQy-5;+1n7pQ0d>N+=758?U2o-4SvL+l`-x){>;<ofW+vP&}`9o<FDjGxLK z-PqT~4=%Twt5E)x86DN=L!DG?ofpX`p|W&h3f2uTMcE1`Ocx}GuaV={tZCe8^bG^h z&@YDbKLYQFJI|GcEsgx0XWm}z*`0H%=R(003RMSI2mH45EmO-^7H8%m8%jPG#jFAU z@FE;5B@qN5&Tx+}Xjg;5n(uFlY|eZ6bA&=Yi_xu2ZY4vo2_KQ}^2*9kT+VLGQ1r?X z>FJUxs0piwzR?34bTRw;C_kBFB7bHfuGM;Kz-SjQLMoa=Vu;jy_>a5J!2<`zj0kd4 z*+z#@?2UW=FVZ0L<=J(d4eYuF$MU&tE_!MyJTkAbQw!SH;fCX9-V{~>So%X_*6yn* zx61_iZe)7NMS0E9z6^_DmAHm*F*f@jn&IJi^1;ZCm(PWvhxbE^H!@h!Kq3i8!A;$o zqVw}H+Pe|s@j#X+qOQW}iUGZaUnKP{(JiN{OKv@X?jvP}lv&lvUbTfplD3ZJVzbNw z%MJ9n;_z+MQsnDib-g}S=nVnSID9<J;@(9_W>l-wGsT{DD-@+bmZ+*N_EdO=Xqp1B z>i!Ld4>XXFnw~yTEMq!pc9!<Qt=-W&&&kc|$SRirfIV1&SD;dzp~cHLxBK+P#0*&N zoWjte+?=m9MURC(Lu6^mw{vdT(%PQdUSorDjxF_Q!e(5CRIA*#dbUtvPjf=-z^JHp z*pvI9uiMyMN@&}1wc0ZMwW5{Y9VbnTCP9a8!ax1aCk?CC?3|5H5`0losL~j48;TO6 z<2UI;+w~9TQ1sKy<L>!#zWri*f5f6ubl~o~n!eQI2z!({I7Sx8;yTXL@p9z}o1H8| z6Gpwh$zSzStJ@=y*41s)N%hV5iGW12@W|1YbN8a#=Ak$#MwX_K-Y`lOR}k-d9@P?_ zw^^n;B(c8fwwt1;L&kmEs)f|<1><F_$?2O$31dWr>X!$R7oGRQZQX6IbH?wVoAl66 zR)9HMlwcAL&!&9O<_ul$u8Kv4YL(hVneXo4cGc5^*VU_Np3fp61yAg*g2V0aTGBwu z{D(KG62*v5*8d+fXBib&(=F)W4hg|EKyY_$2oNB_-Mw*d+zAjMIKkZ-_r_gA<L>V6 z?lABB$-Qgtn)&AM{H%4(sl97g)vjGt&pyjPrIj?t(4`j^^KrTr7AJ+hBYDK<nFuz? zbG1x(m+Et?zp(1KjZ~4PQE%x~Mxdz}y=;3vZxQ3Ofh<9*J(XlVl|YSkcP8?&{!csQ zbARqmLtVaMD${;lJ^P+9P~|d5YS|Qr^x&0&lFUY5)AT6b-0iGwsuOm83@2Df+B};9 z+dyaR7ELK204tLN7s-=t%@r1G%!p_@0%u+$G$vi9&5iWDLcnmbe>Jp8(f^Y>#dysh zpzRFvyb6k+&L7LNl<%VaV%mVevlxKls;a@0L(hQaqvi4G^G->ME%PaMIoT162ox(} zn4io=)#IH8aqyPuqNY<-jX3J*^sEs9N-a!F+Qf`vL4wNoI3ubucOtUI69__sf8`rb zx*wP+CYb&hmpq*^CXe6urH6ukG1_q>H=sps)|Czf<ZD*2_xl>k{%Ltw+dIL$p-~+z zyI8i|D2JFp)itp@oj_uUqW9$8b?)T^P1rfM#?#x_>e9Pj7rm!Uzt7nS>O-+aT6p#G zb~*tNlI_N9hJbrGZ_@KfaXXSl&S0S<3I)ndYxlV`(Gu8?23vWs9v`_9a4ZIMl@rrd zJ5~JCh^h97Hq8kbMO}m2eR<~cV&a{3Vu`;O+{|!{|M>HK_pr~}4C5n7Zmr^+<#fAh zUHKwd*m9?3ep0u=VjV<uKo@u~zbf@7{H8^*LJOg(>Z-DlE+mS;w|3%P*`uOL-d#>X zdE{OVx=#--=nSQHv_Jg)dswkA$jJW0$v@m@^~Gs52+^<Zw@I6BxKK?cEM_~_@F60H z3xy{Nk|f-2s`CN9*LQB02cCE&DIP_ZOT|Iz1n1*{wIkPN`3;6fIu7GaF+9cx1lfC{ z<3rIDaFhj-^y0Reafq^>g!P1oG$jWP^~xf_<PN(aPb<7I>wSdbt(GT%8SSoj17CXC zTJ&gAdcPxIOkZ!GYZ8b1A3KeGnwgmOQ>&knLoEtd5&OqL;&!rH7c9i5itS<tL>3JZ zd`ZTy88vv27w@g&ojLTn+8S_sAQ{nPGN1m&(W^UZWUY*{hOxu1Of5g6Kli!$jXU*Y zM&6;gM?9-ibEi60d>-`j6ET83+<{YBa-D7hll$+n0wT?;I;=Gu7B|ALQ@Js24j-4G zmH{iR{{1YL!0%|2b$bNC5R)j&IL{TD)!HDrjN?e3L@E9gNXVRx)_iE~;z?HwWmLMc z>cRoPI9085%}sR|l+Ok#B!d?rlA*$UtTBK97dQn#W1JvnPf)h*cHg-B!TmAC?EbwJ z=HOrr%vhdpT#2wf^{%s|9H-}?s-u<JJ20Fropb%UA=+ht3R#aSBexe-p(P@~6<nZv zX$B}Q^Y1Dn2Bl<#P~pb5rKP>Yh#S<j%KvcNQrpb51#5h_kl1OqC@F<?gy!V<n<<r^ zT^_vC0xp5VM@3AWdRW0$bYf5240I~A*GGUXX(54<qOuB>j(|*1`Ub3S<l5jD+g0rQ z=%<Upr$YSU<%{<Kr4A=nhEszN>gFUJJ|WQAUKvHHvE?Ndl`0#TTr+3&AgKJo?i$uZ zO50g@gHc}tiTh$ZvLBgHRNJ%<Yg-6_OKH{{$lRehN(j{rV2jlkMB&!qH3Tk}>n<Ou zk7Rq8ExQvWN(Z_q5n<#HU3A)#Y({4FqS<?n96kzSG>hbHs1P<Z{9)Uc#EV)b25X$r z->bcm>3mE{X+>@qw|l<i+k*G&jf&{y)b^ch@^HV(Q9;7!v-(|Uergbz_eb@GB!n<h zWv*J`c+Lq+8>Ao&D~}$zjt_|l{!KKnYD!bpzMe+6NN`Zxc3;oBuA|^{u!+AO4&E}< z!41pUA;G@|*X0sKk_lgFWWD^5(h>Y5DE@T8Yejp6#imy8CK4I8pct1O@ErgXMIwn* zGtIY{NJ1pHG<hPFOLPhJ!!nmPEqzg}4j#fFHPbBfjsp5bWQ>gI{Gb@*JGU8!UizZf ztH}FGYFheC#b!ol%mi5!(~Aq651U@yd40NXA!Z<JAkn&p%(pjhj`O8U%40=G5*Ve| zz6M2pCw<syCAZj!ASvN5f(kUzZ3IAJ#;SsgD)_kK`gQwxzxJWZa0Ib_>fIY0gwfl~ zBU*-FWq1!^8aQ<uBZXXdLDpbX<0$|33NRF(;O+Qe3#Pg;<{(Gq;$S%4?6Ay?`bwVc zqkPJqBe|PySTBmIwyB_ZS$s~712{iQS9%Ix2)nw91&A_XeMQb3ZYCc=;llDepN8~X ziC2PxABMX9=U|t96@q*9hY8eGm1Xec^Er43kxJ`}0^qtTbHQ)<*@ab!LkG&&L+p>> zq&et>nV$I9XI|*X9nCRpec{!2i>dz0y3pSzN5LVmQd~U^SYCX}%#4EpS?q6OXmMIG zDW#8-0X3*fjoznF`PPZD?Z`jE#6*qzI(c^v$3$~aN@EaqPxDtn?>_!EH_zbk$<~mk zlfsJu^F9ZbnXnc+g^;stdfBn`zK1K$<jnN$;Q)ZOkA>x}k+~Fp8P#=dMM>v34nRR2 z!qT$?C@j~y8fOIKVe#gS^gz@r8=3oOi9#CFPVK<SI!Z`Qz(p3PY&5o711XsfV6l0S z|D*zuo4cIO*k<Rt=;NjambhaBLbQ&%t;gaMTa3gOQ)SC{1>Qrz7nelKvgGo)Zwgqj zgWz=hiF8kP#DVr(*ZIbNJt_WiEhT><VH*%Po`hw-YXar-Gv>I%a9d{{Quz&wiH1FA zI~olnx>>NtD(ZM4<jcZmrg|pTtAeU13nHTQ#l2}_b<Bvd^s_Qiiktn>2B054AS8Tf zKXR?uW9vwT{=l}ZKzZ?Dq0R&xzs3+KEaEs>wh?QhgRIK~I|$zts$Zuqts7*X$pvhQ z+Q3I=br2)u>BvCogY>xjKXp7uA`y4A!Q7S0cY1NXOB8bD#m_fBnXcms!`v{>L}96_ zBPq3fyH1x8L)e;Tupc)~o4n}s^6PC0c_8dC@YvJ0N$n!&pi-VKuyS;v=WNzsc2k~X z*)Vs3-Qr=yi1ReynW}oM6cO>KIHM)V&54^e;hNZ*lVuTBb-dwdKTRBC_pOMv4eB9j zn@}u&dY6{3^6*ae&UHj{Y`*U8@`LXIe>l}}`xIUE-ALSa;?KptGd4!%`<1)b55e+^ z5X-rsn`lWFQ_USpTag!1K<WXmZZiwY)0&BBL2+-f)0Mo4R1JZ+W|e^%M~nF>l?ws~ z$>S>2O98yIL*;(<68E@i+9g&E;zs5p^F)o#^un;mm@-|tMX-5*nw|J}?bx+=wS<#Z zKEKQs1gcHMq=dM-e7`_yim@lF`{mEC!#EsZ0a-{HLb}t|veP%5tkhN;2t()DzPN9+ z)%A87tj_&~CSA)_pOe%vQl&-}t@1oW@FkA(8-I=2re=)FEV70cKyu}2qOOeu7sJD$ z?(5rYA7fG^dVS3DxIf-16?|<DK<cJMi<uDU<D}81<8-fxXJK;`yw(SiqBg%Q-b($Q zx&_A_CC7`NkHeKjr)HZ&|A)II*c4-=w>Dp@=un&-WZGAbLoMza^y8n=!}1UKKQ*^R ze8oL0tX9F=+6EJfnFy>JVXjwex=VB|d6`?Io}M<C=gC>&465J>pfDu*_=j-CMXqoM zvPXih$q$v%=j+2Gs{-`-rfmF3rgV<X#KeL(V#Jk)#bgyJBJaRUba13!BXLk_4qnlk z7G}7{S=`*ds=beJ8!`i-)Z9=P_0#l3o`*D!Sy||@;&f(nj>^E2PBbNSSQTW4`|<1x z{vjdbtQkR-+LK(1XB~0pbuLkDE!Sm-#FPDE;)tj-^J2V`Ztn-iQ7Ky;*4D6@B4W~| zgauYOnHl7SsRLK;-{6HRD<L8Fw_Y*RqMe0O`*mmDO4n0Ld>@ob2cXT_)07mS^Yqw3 zYjNXE6o#hDon(5l{MP^%1o=zRuD;ViKF}tCydwlMWiEeC61_#zwtyEq&DFA^$K4NN zLnHxwZ6<OgWK70ltQ|Z=WtA|n#<=8|!T_nyew(eYvy7WbIR`C%UNNe*j02?e6w|6D z=@+o#PI1oo!+I*fU3Z2yiYijW&99yL1I8*`#RjGV!Z=pHB_wffOA1CW#Uvz{ZTC$w zs=COx(RfHHH|ywZkBTZRgq`GHYu;GS*?kLW%6~i%)sx@{GO8q%c&^66J}jh|!K~_Q z2QDoJ%dOQ3R4c}(^=2?_@0my>bsM^YdE{z-ho9tYO~v#P_iMKxjjROULHd%VwbGGJ zUgNNjU9C8YvsbfQQT>O$8a}31!%OBvRPJL!PP9s$#d{9xiu$)>g7wp%4%AwPQ#(;n zzRjE@YVTZRCx2y{ilY5VNMfmI>Wkeb-lLL7!6no;&qJbZzQgu2FlF^bxZI=PsycR| zez0m>+lD4l%{X4lvNv!DQf`P)FWd;bbg9f8ZFIDl?_OcSeTsGzu62V9bdRdZO6zW$ z9F}b_v`|;L9hr^;{aE9}T!w%o#@&h4g^X3OY~TA@paagXyq24BqKoEhjV$ZrxVd`H z%D)QT-D@-NCBF%+#l>_vd~mwRB;rg^*^3Cx`Q&L~Aw@t5=<$}DY~%CLV>;I8Eu%e4 z3h#V`r473z`@@^HOv16N$FdPjax=AaK?GVm@Hx3m#>k_}5{Wy(#kdx`aq?ylJ1szc z<shQ+=VGbu%f;m~^t5b4kH7>s84GqWU4sJXO)1V&JjLftBe;<WTuUbkhbtkb`Fjae zNr>aAo;QXyZ1;j`TB;bw#pByWeD`)N0WBxJ`poFv_0oq2NRuR5{h^ne+%Bpc*v3gR z;!61$nRVzL>pS9FL>jbOx4i|vz+n^VU*2O&>R1L|q^fjlkH*|AhMQ%ib?+VYfV8b~ z&0TXtDI#(jLVRtjA-7>xwiDbg3gb(vK|cMG`oU^*a{B+}4SvGc8a>O+pIH|TrIXDx z_l*}K;mSv)N2snqgOE7*4IOd7V9R7Q<Z+pVTbu-jw3hqrrQ9=k1GzXgfx{NpfLRj0 z@Ot7V*Xgq;5rE$*&+Z(1Q2=Da#bt6&Uf~9J)UduS6;exZSCie2R+l|7q(w5!XgfcW ztX*)y=+0-{Q^C46)Z2c@?-CIRf;M5?#^?`ZaPw<FOuS@R*yr3SXo=<pLg+`X1<Yg@ zD>8gl)uyxOasHS;%aOXI!hB*A_?38jQk59rX*9cm;ZLvH%d!G=t}WE}_&_``Dv^bU zEk4cUm(j*5Bm3vFH{2ueg3u1a+-F;=PRZX%d^1(pbUeg0nkf`@H7wF#!Cv6rk=gm? zlzKEHCSVmwXEH>WJ0yWG<j*m$7R3x0wZ+CCT(2E)^xWD`Oza*EV)qof9{$x>i25}A zd1}6ByZ77c@BToTOyJexjFV*3zUGI)qaNdW{XG4_VQaL}qk@p(N$2uV<hsB^MRs9} z{UZ<&uRjd><u0VP4CSFBDIl}6Yg38XzvyM0r3ZWrq}6jtm)61;7-nvP#Do=?Zx>Gt zo)8zvdpP;oQNa&Jy>BFeS5C5kLgA1UHv3=Hp;<S;N)2AjReA7k#vQA~=6hh%>+5@- zNi>`g5h&xL>XRu~V!`_FGLz?aKkUj@&VW5~>7G}SNtHNHACEX+W`)SiaWVP`@~OxQ zq*mIh2%g@VBXz_=ua>oi=z<)2n@3|$O*(j@9}gR(BEvydn3LK3LSgciu|@=xA2p`N z`NIr6Q_l2*r7Y&WpKju~8d<vG2pcG<yj6Js0k^O0!PTu8#H94`qKsTq_w(>kjuW*X z$w~X7x-3WHxTT(Kl+DiQm%qcgLN7n3Uy$_@>#J*KVqgBr7gbA<v{&em2o00<pK>4v z_oh0<@#DkVjTKfw7UFAns`3w^S~uL8Vha-ow{kK@FIf=@Y3V<g9=MO5_TTAmX$+F4 zbBK_i<t<4*`0!xPbt>8H+IuV9(Lbl0{D6$taSbjo_HfcQ`sL%1bpiNt0eRI+_K}wi zQM1ywl_dUO`FK{mcK)b1DmhVW^Fh(xz7KNap$rutitW4_tK!^Q2+X57JyiJSt4fQj zX>bblqJs_5Q)iADzP?nXbwD0ln)-&Ku!lD?xeJ4HAkXO=Tks+ARep8xG=F@Sm2EG? zqU951<25GT7h}5=<#W~~tknte1+E++9C}eD>I<r3dnnC_vI0u!YZl+C!8y#V+6+VN zJbvkpS~_mvE)6-nhc3^2F4eR}i8}?{Nim-H-(_6k#H_THX217<nkLO#D8e6|RpEC^ zBHtJP>ggio6lvD0vv<V6<Kej$F7gWS-ulMVx3Scv^XdD4?IW~dHyRLlnSXZJ_LVzu z{PA}pqb5PnWgAk<R{(9sUF~0llR0sJ?v2gtq1|PfE_Fa|eNa+Z+LO6h(oBxpxa4di z@GoV0{x)4tO)4)u$-4W=JyyJ9o4_Zm%qVozL>2`+2T46lOfU0-Np>OWwdt5&4)@l$ zaMYtv{Wb=2{J>tgyCKM*LIR;v<<g+0&-FDU92?RljkI}^Twok+!AD8Nb+3EEn)loO zG@AJePk&veS7$~&naBkFnU$Fn@tr5G6+RrBS-S`x7t<(bfaJLJGOpdIeV1r8efhc= z48d-*-jqv=Q2T2uhqwA?SQ;7#`{GViO*n^fLv~LbnU++Voitm|{cJW6P<Bj7W;ZMJ za|$EB=b`xIUQ!zjD@T2cZb!?TZ6Mb%y{8=PWB(^9rW^@_2VtP)ePbE?CYG}LW^rrW zz0n&yksm~4eisg*)FoQ!NE@01==2t`@~a5J`33=XvF?`E+QgA6kPH7Zz|81$de*S) zfpU54T@je-&aOqQ15DYtl#h<6mZdvqnHhfr-5aBb$#SHkE~My^mCtYb5;ydMP4>OR zS<1M&g>UvbS}zhs_7R#N7_Hf^!#_B?l200QGc*~nJnH7<s1I<qI;r5Ltz~e*m)83L z?>8!)drqWTjBoXD*VOah0SrRM9L4&ze6lJ-XQ_*P0-%RgdF+uJ<wDa>D6a0q^*`3` z$okH-?56@{6hUV;aJI?cpl;u!^t#~n_erJ7KXi+3y~L0m8riK{EB@Y*np!9Dy=`G< zK~D<v8x)AnI>}fU7s$kilAV&0>~%CLlSFn}Cv7~imPaUxy4o?p9(d@~UEq>3b2Da9 zw|bF?+wDZ8aYTV=AC_#?fXh%t7#UA8ZC&)B&Sw+h<VXV8sqDq?A+P|D%>cyF-7(&U zC`*RSbZcP2>iH#B|1(>Jt=Hn-v)stSU~f--u*`G=Y5L9%LrJbY$xZNqYLBlfBxC== z{3m>A;KuLG1mHaa?qsp_!!d_MM4|beLXvf_`mI-DY6<CToN6)qyN+3=joBGwyAO*8 zf*&4gmLk`Ql+@KUeD=Tk&Ipkhb1{be{P%)d1i!h4v{D3UuXw_>jM4q3q1qpaCWF5U z4H}4Mvdz&E{qs(U!|N4*Dc#c-d!_NqKx}F!Ha?W~NpdJf*a<%BhG)6@CqU4TY-;PH zE?UUc8BGEE<wf5&KnH4~j(u+-dSFaHL49!p8{&5DrDvK5do$Z%su!fD<Q?AHJ0gZf z{<roN@rQ?qD7>93^rTdtV&i2A*|hYI6-5*@;Vk>T>!BDJNkV%-D+IK6AT9g&3g>du z+Qm2n?1l20G88Atuu{v=PlkxP)z4~ZS5IhZjBVv>f-CgoK43lS=?BMDvDb>$@R-)5 zYH3e4Z|6(Zk{>9oVWddtZdSHpX25CbYDPlNRFPvmp%vE4M14RvY%;92fa9>{&lC;_ z$m5@`w$AeUaJ`=jS|C(Y(Nujj7RY+Cg-;2ZcswOdK2wOt4(UIiwz*;(_ct<1F&Il} z*iq8RJCKN@eM$iP-?Shk4LWjxCJgo7Px>~YOVyc>3nf8)KH*;1hZnp|g4m6|HKM?? zY5w_$@h?~vSd1}^*keM#UJcBQT#*Btwm@q0o2=k<`_=HuQiRFT2@zKisyHpY%vGrw z#*!XpmOaUqZaNeD4c>Al-l}<G1~sRu-xiP<LRCu)l-a|k5*Msxx?*{@DZd=eFcg$o z|FzD6Z!Zl0f{kz8vWB(R^p$0_sP&gWX~EX+V@nmVoLtIBMe(SJnM!49N`sM(m6r`B z>iZr6w1mCl@gO{@OsT`^Vz5_`?40AattOMAUb<;LA&ay8cD${g2qVRb4p$-BH61uh z5I7qYC9=naZ<Lpz66(RpjTGI~Im)=Pi8{Q{5&n_B?%%^tw*kI8<YCU1_ABTwH(tTw z50A)6azWPhdkg$cTFd_@ynL!$D}wp{ah>rE={M<YwV3cQ=2WAyukv6KL8nAcYkV@j zap--Oga@~0VKt$7y|mW%NE}mQ)lBeX8y0|bH<_n+1{00fFihpfoO+3<;&3i<B9%$L z$V55lmYb5v3dyEvW}1;!l{;A9Q(`FHGw2#C6qVVH+*Q`rD!k|z*ob3J*Q5Sxw}L@W zA)GWJ-*s9Q*II>V2E(jgeR4m)KH|oe?`lbDNaCw%rpKDa$l{=7sxZr-ItePX^5XmJ z$2n>O$9P$mPxGS<!QpM@Y8;<Y{AH-W$c$zj?KUD4N-eQV-B!<(c5lw=XLCfb57prS zX?GWDS)=C{7!r?8j+`r}+^ILo6l8OM&vG$IB}mKq+t%3~M+`Ozv=lcu`q$8Hxo8eK zUG4_96;)0s%4O~~mWk(^$RO*g!!mr;^qbq;AbQ4f_fGGrZXsFFisHxklcWaofd>A+ z96&8Rwpp^>;;KyFUqSZY0HFlUZaN-;hLb$PHD{c9f4D0;3VQD6N|GHe3%s;axjtL_ z9Ks~gN(7#K2slV9jfhB3in*~Hcp(mEGq@VhSQ=Vgfnbczid}R1o=P}H&C1>WJ9_`e zTK)6CLwODkj+prPpAzAC?8&L0|9;lV{q2ifNI18igRk05?SKs1bO|DpRuQx5w?%0C zLz<35=uq|??9${sNZMpLuRt0)G{vz0;DqN-92v<HZ^w!)ZY$gGsQAB2`e&iD_rv?K z#qcefzXxCA1Pc7J?l?367HXe>Bi9+-1;fhW$kD4w94YyKR#*3vzr&a|`>g&aA$peo zQT6{QH0r{4N7i8@Za6C8^8epn`q$Nn%%@M#MVTM8YX3)}|6NE5|3P5QivRsL)&D~_ zJgjk98@#)++J6!YL*dYb{0nmH_#5Z{V+B9!vxrif`@$mKktcV=#Q!JhepIkWoIKBw z+KFbkFn@JY@6i{Q+frnmRP6uo(HtQRN}xkV2Ah(`e>4Gc++R(zAHHH}`%krrtqV~7 zWvZj&pP|kF(WcAE@P9PDfSDQx3IEZef2sFZOU!9yr*Z$ISm@`!#1db%N>~18!;k*m z;{t+4xfTCWEH91!AL1IFNyfh&@@IdiJ+mKID#_pZq7Q!dt`jqb$2!>Ul8l1PL1L8H z*gsNI2-|7bpPMYxw>o-b9jRxq7yhpbRG|DaKjC(MgoP1#e*NMd2@A9P#4Z(j?}DGo zsX%;nNU$<0beS7I^m-$@zJBh@Brh##yot@El@2eXj9owjtJ&(#9^2^m`pjiEIyU~z ziwp?N+9-SDl$Dj$C(roE{Lc|;Xa@@{1Z|I_kdWR0tvpY2V;SKqh+%h=Z^AHZD~XA6 zE#P5Z$e1=`j{i%sfWMCzQM>hu_J1^x-|VREU!-u`6s;^En#-qpygNOm;X7Ike9D(2 zEuwcIc!Ig+NysT!30`?A@2`d*hcIJBRv3bSU~Hd?@+wJkp4&YuAccVBFO0?sbp!vC z9Qm9oSK7l2{;I0%79eqY4UX#Lo#Gqv_eJ^6rSR%aqU>gj4AT_kM!}dpn{>4*M>q0% zv)&_$b@J0MzJx~$))R9F5yl&|4c?JDE;{6c9Ke2~j?}?)i@xJWr=iUJLl>XytG5SS zvH{l4-0j|~3e70D*S@8D;Mh{*$tZVGS-HQ@3Zm@fH$fiZ;DKWL&$P5tHHoW@vHzU5 zk)3>qo>;)S^LQF|(+6y!yFV)q@P6XY?oT&V``42<1~Q@UcGfgJsSmF}_Z=5<UEh}$ z`iayqsJ%eUVD;158>7G~c^@s5vmid+MCd9KW1e8kyz9O2(a6iG!T4*^m4g89ryd(8 z_2PLXC?=`c(JIKs(}9^xtB`9l?r8;X|2+9+B3h2Qz)nHHp+(E0;;s|Lxz!iFO;|5@ zr5$|?P_KT($rhC3CN$5_g<|R_SIg3MHR_Pryq>dabWDJ$WpU==K+152aNEuwz$>J3 zPJB`+YY=wkd*Y;7a3Yl%p3uO4Mr@X;B<e-nx5|qNJmar_sdH)8_gA<Ww3lBWHnwsf zr5i%>ck`tn&A(eE($}gF>Xg7f2e%aCxtu%&+?*Jc_l+ineIN=&s$n}MgPLg5OtP*& zeNufIv`3I!IhQZ!0tMlsqc>1gqVKyUSOT9I*J=ouBQOnhChTmEtVKt01;`J{@{;d9 z3C}$Dtcl&eJ^h~0e`g!yfy{NaN;L}*M|atY`M0+T!hR1t5&NzOafG>^o>ENH3y&(H z%+q=y*e{ZjlOV0Oa39&m$mEb^5I@l%b_LU{MQvo#s7~|!UYLkB?)%(qz$Cgt#{E+> z&_rAze39Aai-rr{duNMUNkUrjjMNs4;ZoqY*!G=M%e)*O;t^7{{!PP)r8WQRR8$kw zJ1~<w?Tgy+X~~a~qB0V~N#OGM<H`yhXx1_?&!#3&GUIVYuOIWHVTQG#w77L3$8^ab z0i|4v_x8v{jo_<V0be4ktAw0Hdcl%cq3XIv-f@{b;tol_v$U!;A70qFI6lwwPh^i` zn4_%1(MfM(k~YuJ_-u~{g~;POhqJhhG0o2O&smW<haN=B)F^*XPZl_T$Octv4$l)B z<HeUlc<raYsx4;LR5FFaYj)>WPvo|(PB;%n$btae+&FwdU}h&Wk*^DE)+ZDN{PNDh z0Z{9a*)bmT!vzaQT`?Dr-H<M9`XhRWw>^pAD&J31g>ufpKYnRMq+P5n3ggISgP+$U zEDa+JsN+BKg*L1SgpKwzv%4&~o9uwraD)oY9732;zVE_S4OpgcVC|o<`-+GM+>~R{ zwag{`h?Sa(@x15q<@ZLc#E9NV8CJbtbp!T|<D6#0%pLGWN3GUaJkA)5-w&?@cO`H{ z{f5D)yB)@LZ~u}0QfT>=8VuRunwAFwXF0a>XnT0Qi7GutHxt|xHXlZ0Aa@3sIaltm zsO~JsuQl`B?s%-vkMDhNO+Jr-&&Z+HA(q~IOp)3A_scl9S*cL>K}tSld<2YobMKF; z-y-TJ_B3x<(|;swbu{0;ILGgQQBo&*4ty!v<ZGooy4rV6jrvfa8?}^SdR~76mc*E> z?AktY>^`s#ETy>$voa6m*KE&~gW_Z=SwwsJeXQw5AiKV8=+v11`3e=1^?g2@w|rol z&lLL<HII+18iw}Icq;(;8^KQmqvqHkCOSKpu9^Mm%pW@C2Xu6$xy%zmqLq&iSlRYo zR2Y?V?!|Oy>fyNjy{tLK?~CkDkXqrmrp>Z*a^g(`)wOKb4abJQcxnqwPL23kr$-G> zA!a3wm2cTVqBhkVbtC(o@~j2S@#1q*5hsO{=ICUts{tXwx+)FMw<3VuxCj3gmnse3 z>`BafF}=KW8*gDoRS`XF8T_*oTQQ!Ll=5Qm%ZU64-KuUHn)|h5*W83J(H}3xm1X!{ z#P21A2h<DH`+H62n8%V{uG~b@C#s({RhE)fTumm3jaiQ}1wnmQjESFRjW7OKdS7I= zRIS#>zYT#-^RV7-moUBA&dCtpUKH-d&ve|6-0as^+S=x{)@I^)ZwTXY!hckSN=QWM zxx&I|>(p@tgI5*mEbq*SkuVve7pdJnuZT=+9M@rj|73EYCj*hBxWrHJ$z8IYr-=CO zpVqyfE3!k56wkgBS>YQk&7#}5mWfI33fQ1{CTl}>QoJsnfmuC1Q8SHauPs~)=L!?> zB#8xm1gPtuUzDh(kY2c^qo|FJ!0N+<`Ch|V<UPm{k&!@#Y#Bm9K56k2^mg4UF~G-k zYT|2_-c6ioK#KpFa6<9RoDXO4UIkvkx(W%us{oU17vD0N^P6r9NpzV(<cJM0-wLQr z`18db_(OonAWXoqzh5^<FwVo>5f%_K?35iw5BPYFg>b;-1owSb$4F*J{gCwj!i~px zC~4N1Dg|(#%<{BPKbvoUY#$AGx4i;GJ0>xj#Iw%t1zX@_ej$3VQTF!n`5F*N^F+v1 z=A=VtS3|BHy_Yrp^t@uf8W<L$epQr5obV&{L~UU@Sg(${e{@vR^*i(9$_IROPq&#v zkKxMvi|JvEbBee6K^kZHE1B_Ga$(AdJiKJpz-DEf9llz2Yft%19=z)-BWIJ#-12II zC6B5$CagL=J1U*K;hAgI=Ho*Q&t$3Dy<rZpft+MVJ+}+cy%9g5B)Y_|?@JZ=p;NJt zFK~#|RNs`XGS*QN#n4cLI-NN+fUfuiGY+=^B?HS<jYyXtYJ0@{1cUB&CYF;U^WBzs zc~P7eZ1>}ZcT8#{eBTknY7|R!z^NZ2ae@cdnXC9u#i?CufBj<cjpXyG{xsepNi~{B zd)?EgnL=BmGMDdNz}7LPDt`Z=Z?E%n2pJ6e+uU3hx3p{|bz{%nw)@<RT=`8c2HUb< zu-w7H)r-QP{Z5@eoJbf@oUYRO?n;Et?+w{Vt^PaC|N8Mg(3b1Bwc*;*oT$zxB*x&h zVn31dna%#ft=m=`OcKd;1=eh(T7(BeS1YpWPue!MQm3m?gV?}vPU{%rg$e$pUrZ$@ z5=R8!Z`&01<n=0T-8PsdwR!Zv7Wo1tz%jS#=dozzrVs1|xlL7VJY0$x<V8|CJ}-eS ziZhtU%cnnAumQD~;7CNr_|vainE;ET8JF>)5{SBImyAPQB1Mn<$_oX?ULq-j8<p*f zX$KsmyGjRxE%l_mfdrV@{+{r5{ZC;ZVIL1lsYa#fV#(6Eo8KK>7;3nprsl88=a;Q3 zs`d4z&n@o*ySh%i)nNDS7lUnW;jVC7*S+oCxG!az-NE4QFoG<qEkwx`KHN(h8Y@}y zS;V#{Y19cGHX_&KNnW-4_g4kX_hhc(oc3t`N~<`*cA6nes7j624y#r*s6|)tS$%1# zTKtZGZ6JkVuYF%uD>`yFB0JWDl2-0Fj`}WoqIw9}m<otz8J#xZeJ^)u`8b|6o-<v$ zB5(7xpE3gvWj+&*-V`V2-W86K+nJH}yu-*1wYKl|!CN1uYZJF*i%i4xDH~{~a!UEY z@`aWEIuR+d<7yMho-Dj5^(q1V_}&%K@mSOe__h5J=3&kNYop14q+7&|q}$E!LPO{c z4QsSY)vAD0(Bk@80HCoo18sVDOC}^KZZnUiR24+;eZI?PN}glaH*udv<^H-Se*fjj z7nQ`4E0#>y|2A6Kv`HyFd*en}*c}d|k9^Y1OJUbhF7_#-$9?R+_}OqDCpvN~&~3$n zTs?S&(7AO3+Hw1eYwzdGG4FUE{1i<~Pu#!INa^mrb*RV}60f?`D-@X1v+I#Vd)<*9 zAYzIleN2)n`6A1RClwssJ;K*C7_K?F7Vza=NN@=Ia0(X^_%%dC0NHOG_mSfO>VMFF zdvd-5+STf_Q>{D@O{f_pAZL4?3x6oG{0<$huyc0f>gi}hHSJpC6w!TJoH!g3*O5X> zEtxa)QeziD2OHJ~M?Ev(1ON}Pi9T6=u~|$U(^6e18f%ckt)nb$O*Qq`75EVEqmS@C zdjrCgmDwcBRqK)sbc4HXnEv$E`&!ftt(ailo&y8TnT1YV=oqa<FHSL!3$`Q_fK<2E zbN9=RQcr0MG<|h?KKn<D7+wmbw;)C1A$lnnioW8YnIh()FfvRP6kaQSnKDxjd_lqH z@!5D8o=8Pk2YWZ>!9#66c6;7t0ar@5H&?zZxjv*|RH~j6fc1FZ<3dc}E|jb@)y8=^ z96v$VnqT1YaeP8otV!N;qVF+tvthkoxORG`OM5NCTd*T=pXB%1_Hk)R#{TJ%q*D{Q zTCZs;h#TO9VSZm1Ou_~mSY!>NU<`b2T9q1WCrh8HP2Os*a&XNlL?R7*Y#bJu4+1RP z6Q5ggzdQ*-`pm`6rg1uInP@$#f3>OZ5l&=IxNMCq$@JLCp|y<rx1VCh-w&|bC%F#2 zKl7H5jsg68e@FofIzteXFgdcqR$P78>*BTly;+dJO<|?Rq++9!ktx4?VEi_=Cu(Hz zI^t7D3Y=~ld4`J`$@XJaOEkMJKTViC{-h)mDR@WXxU_Jg*M($X6--9}E1GcriNAx8 zbVmJI%AE6%zerpsT@%7Ydh}}ZnV-Bxuw>&cT3(es{U??!*D*(wrap!)iMUnh$y{PX zc5RbRxH;}dau@7rg*H*F%!FPX__mgT0a_xRcunct99DZW9?n|JAAPLYMQm;TT^aRM zvj*q8j9o8ejOKSt`j49Qx*@`5O^>^`04XvL92J!~&F1Nn-ZH?5W#!ZqT3cKVWeQ?^ zP=SdTB1aiJ%V7}eFRjt=-DaQKHQqyB0im7xNt)x`x_sr%BQXgHKuNU|Q1<sU!lFnP zTImg}K(0pG+l+cx{fg-$j?m6d_c^7S+QR;sGqjOD9DDC%Q!XcrwPA*?v~lEt8JoIu zzRqN_hos2jG{5G%=rM<*DzYvEjOPG@(=lxbZLQ_q+K501zCiqU6@}sy;`8Yca!~UN zJ(uSX9M1@K8|A6ZLWlSqSnMR$ZtF@P_@rv?l0RoRev_?=v<?A0eS-K?<4>1T=N2io z{L5y&B7Qx;;;cyE+5jDQf~hdd%IDAGrNiJwFX<8@F}aP=8Ko==;i}2lYHR2>xQKyA zuQl}Qj^yCNhrs94Ga>hrdCC<&>)Ct?&RO09vYHzqeXk++_qBW<6aej*SOrJItx|-8 z*$ErSJT|(adt};yd7YNtY|e;0o`ogOYg^V1V?+ASMrWXB|EGlr-WL8yVknkP2}kQa z)>fhT)O>sr;?fg1f?Ti%meb)%s8Rl4gHS%gF|E(GwnVtwy>4URZUTl2L*6LghdTYJ z2wz;V==$^=MW{M;wQ7oXoU?3*P^3^?;IgkLmG*i{=M;MA7Tnzn!<4J(y~!U)^9o0$ z2yx9SM5+=MsBS&hqkzSeb>z{oXA0cAWU^^;d)cwo@MuZ=%fEvXY33#-{a<Zp5pSO? z^R@zG0bj)DWYAl3s;8>jz=_s`Ts?ZTVa_9q2B8(H#wQIdQxgHfuQoP?ZsnXRZ=}(R zv#CKG@^6O=?MOEyf!4*fBpyn^g1$1J7-<dAI(EiJq!NjyCLJ0xwnl<0%y2AsNG+_d z*b|Rj(Pwu?^h3Ii@y&-|2<OeLf0}y{_pmCetD_u~cv;X_`N=o&h&-?r2Zh9O)+kPG zP2N8I`srBqY_m%lQZtqt=U0UV;No?wn~nJx7r13w&OnOK*TdA1gT^i4*_K+*a|~2m zY~MhQ&&LY<2(vJTHxAKP`>L@-cUeL+gDEcM42+Il(kvS?ZHroz=R4xBIGY{|R3G=g zpd$|zo+j`&Luw(mgfZu<Ha;AShgO-^Wjt7%?z*Mcq_=@4tF#Lf?r!Tqtp;J;vZc2x zxagOXW=?wey+VDawt?>Sl|O(5WFw4?g)2dlt`?0gdQOYuUKPdJZJJXxF=?i>W8N9G z<myOEXt-O6<UZV9T)w@J5}_QKbMlS^=XMfi%U8G*UtRxwY6Xw-%iQ*T@0zbTq39Js z8ty-#b-L+)LhBPqPLJ>DDZ>RBY(zyKpZLEG4h2wgVsYCF@{c<hb#C=J=zQ-NtgISo zmFf{&{FM*ZHvF`|(|4fyLI3xlV%pv`qJyn%uzx6#KzjM~SiQXH*MI*DASfx_BRw-U zXp_hj=IZ{`7t3Hz0WT!(=4s*~HZIT<>5|~y&yC)zaVa0rg_-m(dL2tok97a|YP_Vs z@L(kn*<pM}b4*vTs<IS~)HcJA#nZLHNO6QVjdq0IE3<jd$@SmhdViqEv*r7(@Wjo; zCE<_@YW1=ucXHOQe}L=a0C{5@E5t&Pv>#{J3kWU?P|o?ax^S}kX5OQ}$@Q_H&9C)p zr@8nTg$RkYkUWHgMJMzg&2D;kTh`!Kg@lH>gQ=W3+s%>QaOjP8fL>cONLU*(@yc^z zR={Lahg!NqhEBiPPcNCExAOVGC$&5YgNIQhW4E=H|9Z0Uua3B8Df?>wr?to7<Q`x+ zlD8M~;kD;?VD+U<Cui|WDn}=G;Z0kSNB@3Zd=iSi=EF~8=WL9i#pQmyZP26fwK$rZ z@G8z%7hW8IDSK&|KY6^QuG!wk`RL&7i2M&kN#QsD1j+fcOEXVG{P!(m_3%7fTTv4| zkKO6vA8Q@pwnE0%SCrI%uu@QqbwP<hV?z|HdXsfp1085%ZCr$)S2CeWs&2G7iMhqK z^|Lyn)m37r-*U9Zst9SW@UE$@j;Gh9({s09J7agLI<BM8SFFXe<?yg4@l|lnAgKQS zM}DAwo100&M#_^06+OG!nF2|VU2XgmS=|<`4#|C}69)d2tmI&mW$W!D1<3?zRE|^- z$2a*2jJm_*pw*tc%H9k-z1TDG$9qoRj{~y#Sg(5^l9~GJr1;(~-S`vqf;bh+dwmpP zCr<R-;`_(AyX*rcXrTmbrV&8^xp2*IkhP^ZhKxDpEACsXTkM_<q3``X5uh(Ns_=mM zX<(c#(<_CnSA=|`)m^QC!)<Hc=-DI&<WMtf$eCf^Hv>73Z$=eS^x5^ZopAI9dB6&B zExuky54veg&V2qS++O5mkaoh-eu8#Ct74FP^T2k+daD;{Z`*~{5*r&uDcFNG{*hyy zumFNt#E3cK$&R0a5g8sCuCHb~NH-W<>GR&)I6^By%JRXLh;pgfve7xG5{z<t%V2X9 z29O+IWE1-gFBCXUO-xv?=#@CE%Uu?clKYf@LQAZT6yY|Tu3+csO9~La0~eGLc#yCr zOuNFHKUpYun*=d#k}mhK+moH4<SKUt%99OZ8a#CwBZbT^5-_c=RNhRH>9eQ!sM7`v z2sTDn0_ZT){I_kc&y)EBw#+mqA8om@&R0#y5l%|cTC&yyI>^H2_yiS|EX4)SY~z(` zbvPN4hEqYjYc57(<;KJS^pkZ-^Jvl*%ZO2zlY+Yne4mpqrqfK4DlJX!siyAT<9!)E zF1<Oz<BCTckPpGrsYl+BU!VUS9n~OPY;9{v?R2WqvI%rbU@#CFJu%=TcoqMmq2tst zWQDJHYkt2TXZPa%uEG_okk9n|!0s4lJ<b(z6?Ld~f2-IeY9h=H+%ireq*WH*RK>G- zU;)7gx1>p14Fqu2XjP1B>!^0+ENM(kyeW^XXfi@AzqV$e9Tl>#avl*)Zg#L|(n%>K zo?mXj^;d=AStB|+*`7OSCxrC<6OG?DQc6^)9A4HXniV>RbE1{vl5YoituwR2&7~xB zj?n8|r6$)rx}+WO^GKcz`-PnG*&h~~HztpIHLm#*WqG@z?<toz9^E?M%V&094|}AG zC}2Sb=!co+Yi2_d&9Zm^V*+B)5hbV*pQnI}Dc|+2tbk~`arqW@{c{z5XWy_E;UtQT zDq2b<uVPR4S1~gk_!tS^_<OFG#|tGqZEh@%81|eyh^D7&bAN&QC&8mX4FKo^D|kY7 z8+ALDXFXr=B5PVtX#gulckgDnSoSUJ^{D^=WV&ca{T-*ne7R7YkaAyIfkFS#Fx2Vu z;6F2(CjFRxDq-hWf?s;rv5;s07UgafEuLu?dTgOS(<_APrY2*;@Pjl)5YwDgr-#E| z1vy>CKJslwJHzz9f~LWOYf&$H*Ce|*e^z`lQhD2jO@FUKq45&o)M>uV!sw6B{oljy z<ZxDh*r55N(Pj%V@UnmYk%+CakwPnXHp~9J$!pFxBm9ATZS-d#Vh4WX+t8YO)x{Dq zU!4fd*#w>T<@}0nd{~{z+@vAj&nyob2O1E+`qcYl{-mF%p5`pT+iJN3_w}}p&6S?# zh&4Y(jOMJ(!VW{-rETha82tILtE=227m7+<x}mX4;<;d9PJFKSHF<}UkZD!lQ*}pm z7<`GttZw}~0%_7_O8Qb2bU5pHV=m!06IOgJp!Y=<;DMjS=k1;E{VIIw>OH(10!r$} zb)Z{Rw}SP7ij`9S!3T5+!ry%nKBj+Wn9Fl`3R=m*x8<Ob#@DUBGh|bTqxQbjE-Xxs z3mAMX8Ew1Xz$g^&Xzv80+rYbf!EU#)b>z&gj!c?!Jx_qn3FG-z-{kL-%}tK{OA|W~ zQ}6wd)cHo&6v5Nv;E>(t>7}GOcX$#kK#<f}TW~}0LABizY`r(o={o;?<zWzc!{?Bh z9MQ3!9M(2G=7U3(KWiK;wL>`&JIw7L<GG~Vw_xE~DmWJPif)b;pV?%W`Gzcy8@f$# zoP@F{SgvtC&DmD0S7RuIdt0*opjpetmCV)XXIAL?Hv5^cJ0+UI`D&{p^8uapv8YxX z`RU8cyuN;jXYe=c{C21O>j+)n`QQft&d!OImiU=kRBz-GoL(@Nk1&zL0`Cx!Al3v$ zz>?^=C&dXjfGY5eC+d#)z^N4WTQPgHhh#S@bh);>qJ)+=yCeS>t)d2HtFO8e_xNPk zsjmo}`uKRNNK00ta|;b%)dfb1=j_`dq-_96!<D`7K823u8r+`azsHDAdOL3}P%t=w zG@x)MhNSJTbf~w^P59LTw8z*?xPbq!yU(;vy`yrzXNdM!d|f^9$+h%Ow!k??ab~G7 z3%ap@xs%|uH}ChQ`Ny%IQPGD=V-iTuT#lHvYT$_;QLFg7a)vUfqIdfUpN>R->2~)! z-PS*2wEcP`H$rxM0s34qj)U&n+NrPh1kQWbKzUNjbBsaG2%gssI~=QE?QCCjekT1k z1%0qe+s#A&Sn0O$hwB(cpWMG9b8e<#&7QgY@8p@K<LV@;dz^TL_!5e;t#Eop_7`31 zMa2K0@vjlcCc~}9Cnx*g@J>1`b$I&X>MT?wLE(YyW7^~MMSFF%jz%0j1}k0kmR8dz z<WLqChYw>DAo+!h7SPJx@xRD>;uF<n&pyPmW-lsvSz5}jW?0&X>~-LsXgVJVowjLy z{(zI#J*p2BwQ7U*T_}8B4s0DoMVfLgy>HcTT4pF*HqKDW*oxzm-ky|{V)sjB>g76( zMoNpgxrB3LNu+-$1I=arU=Olp9k1eYVEU-c4p1SbbC`9^%A|zu4b%N;cz1i}weN0> zMXIcmiKiN$0M2bqr{JBQu@YAwPbHVBRJ`H8N!`wPU+CHXr`QkEb5PxeHGfigB>Q8m zp<S`Br=o^Zl;f+0>de(FO8?j>7utCN$DvtIfw>l`7Tw^;raa!IQ+2Kkg*U2kDtDv` zA3wsx=|sUND{LXF;7=H9y&mIcp2`6$^0sDh(_us5e-jP`k;RuEE}`<4t0}i-YFy}S z<@(`avY3{maz-L;R!LeP-P!yl+ZD?%vNza24ApL-q~@rzviI~3>`SDUVTIpv2%o~F z3K=AiDVCN+T;+Wx3LfF&Hd9x8WS^j076(_?J0$!5ai57SWapri&d)pSj+@sg?|2R) zDD2|LVWL#^9u~~;sl*Yw=090KxwHR*(!l~H<h_+W#9kf%zg`f|^A>D~n$`$#=l5o; zSVTX{qlBU_34~@;W=U+?4!yT6;znDT&ENXX>Vt{3+JY^$x;Ot*V6Bfml**j?AD};( zZj^0w#TS3MGZ~a<HQxcQ(KO|0FKlJihL8B6IXomoYRmct>tB^t1Mhd^(trymEa5Z* z13dTj8re(bV!lNX`!*i=VV$0%-<-13xpgj)8Rznci0rKRr&g$l%6mv%4SG*6%4XuM z=838&8}^#7MB4AoqqWL;$j&wbmtTz{9MQLSldI(;>1E8{)KfFA9$FtM^DMpJOY4=C z%xL~D2Mw>Nsv+TSarGD{w*R{G*e-dUb=>`(^#U^4p%}X_=heA<;EPg>B32qm)q)rN zK6|n`41PDz>;)<R+M6#Yu0-v`P{Pl1XAQhsEnqm_D&k`e9G>Ffdo;cWBkpt!`9}RC zMc}CzN_`l=tzw5oB$yyS=pa0RFs`3oXPBhU2bD4Vus1hRQy-T(mHOLtvZr^)Rf&}< ze-A92wnYw|ld!xwKF2PZZ=I762s>bCwU0&%%3nxbZ;cgm_q+vxVq#+;D;AgCtIobp z_g}p`hmf{S*ba7Jt>hlN-L5h!(X3^p|8<!ZDgDW1#MYtg`*d?*$7&IvjpcEt&yZ0n zM*C1SsD`%4g}cxp$<(oPYdsfPt_NLPfmJO^Nwvi0l*1T!@bp+}SuHK)GbcZu3TOTS zNm;uZ?0aX&Y*q^Tv}yZ~Bmgl2x7G^z`-s4Q<N#y@F33Y)n2OF|X*1ZP>_BXlwf>L+ z$H{;v2+uLJ_VPNw^SEp``!~og5Rj+gScvC_N3bIXbHe=P`#%!^xVn$#h5Fqvb=4+A zGM7n7zsfwhYRd5aLYv+A#n)J#6z!hD$eO!;(^A9q*X+P&4W4`ZZ_=L)?(Ja88<s1w zhBkUj=xU5vJEHiCi{kt(oy-OVlTj}j4>85LC@4kC{6c6CpKNo`b@fpxMljG;Eq!ob z%+8X&OxGr_Pdxhlm5Egla}L7*7f<jlW&JbNhZf{>W1dPqfO&j)6mCwdFq7Gl#9{t$ z>xK#-E~&s;?rRaLYDn0HsJKD&6k9zaTYvJ%j;UO~TN}<bJSJZBA{)zD5!h-jIbdH| z<-JE7Vd61VRY7j7Uj>}7$Sa#cu%sOOzOe)zeQVP{kQTJ<%eXc62$>sVB_g`CE2Ov` zeM+MI4bc|#^+P7^sK@mF8mUox4mV_xE!RbbPI3P9`n~mX6d5>CVDv^Fy$+aty`*tr z&gw+!dq|A^^%1F!ultNAA(n~0(f&o+R;R7;zcGIkI(TTP3pseljib{6jnlzPI4Ckl zM`bdxr=BM$YX#JZ7-h`qH|E)_urbDj3VoTKB8Vb+j0o<hA6XahJ;sUBY|8RRJC&8m z|2-866HMpsKq@$}fL7U>pV>;g0fR(r$j~T4*mgXJ<$D5kLa_XnA{3spL2qMXv$&K* zOQB@_#D+?4-Z}@&TGuljYO+O1Df>fp3%;*0M|3M-l)1Hh-gHSw`4uosK<>T!^)rjB z>kp*(58l6qp|z}Ogn1R3{*m##F2^d8KMexVS<H3?_h-Aw=z31gs27`|zXVHUWcl4u z+l0{~n-7i&Rn`d>y=Y^6-W*SsF<&m|R;g+PXBhz0FSf{^yCL)pnisfAe@3;qCD{BD z7~EV5MR?VrqWKe5%b}akCz3<1o{Q>VEg&5;p+aCsyB&GeUP532{tVctDk`|Mx{BQt z;A%e-7Gr)|wqe6u=dRw;mIzVEm<~dVa^y*znx<}vN3-dTqN?;=>In(861lanIRtt) z&7udpIH-5p#3q{760R1gFYWPDSE4?gEO32k2x!30`E%deB1oh-+PiqkFRxDDQk@c= zMQCAsWXE+sJuhTHYBngT(&q~HB`P6Enp4pYGTt)#I-(61@=m*Y*TS*1$0fI`xty{U z1ZG;hW|z0f1CA^XN(_0Yf9RDMjxfHR46aHM!`rq8i#7yYgveBj2ShOIO+L>_n1T4m zS3|KqElN#BCL`yXB+GP945wwj4JihD$okD0)NuLE6w!@h;W6cdbUq{>c_W|=1^)}w zx`rQhjPP0_RrmHj=K7nG^rW1_cqcrdP9+fTY1~$o7bL!pVRWyW+hncpPV6+4CaB>t zBk$Os=ndl&7W3_sm9)BJ^{Li}-?V}n5uK%PeSYErrU?2cuW+|sQV!wV2>(h1Xm?%{ zD67{xfUt)W%2VjaTTF;i7dariygg4Y3$O<}pq!NvJqiZ$;=jTWQ8L=>Z{=zZ{I5dJ zGOUhm3DXG@AUGj7Y}`G#ySuvwcXxMp2pZhobz>WXySux~Cg_~pd*;r}Gk4B({q3i# zSFP%`s=D8=FW3fMJ_$1>L-RvYe{xd&`H@%K#(abx;_$p6G|H-UH8(bqr}0~Jm8Sqo zc(qld>SS|0F`vRmXPePobnY%a1v#o+{ED((F-JF>-9GF#hr7=|s~C|34*0Cc5yr~Y zCEjIZZ)kbPKmESApbTi}Qt9ACC_lRpV#8EjUf&eXT{ibM5#W8vAXv~u=vyT)9}x?o z*gzk+dZTQnKK9mKZJ*L8+`Ky)+E<0uA%}>*eCpDrNKmXrnjB!nB6z)Gcr*m^$^Npw z4hZB{%ot|;BqPqh$Kr=WKc3uo{La61=eIt<9^$si5w1_5_DPS|=BN1aEpk<H%PG^# z-eJL2I(9GEgvHlPcna6;Xq@Qmr-M@wZ_Kr(=A^`dgVUz>rbv(ls7tN&U4n!Gb4!WJ z!Gk(y^bggKxYbsLYsmkC>8<{)C!^^OJaD)FxV(7LW4#=8HMe-y3q7cEOoWr*HWiL1 z6-D_>VBHvPe2J?wMq4>)88|;Hzf|`l?@Mw(^RBx1RE2e;mQ+t#)Y)S@hPV(vv#Y`} zW=}I6u7iGhm9usFkcC2wT=52=^BPqPIm}Vny6o|g0$(sS5AUR=)l>Ou)(kJS&NX<k z7miQqa}hVzmzLO1W|HjmAJ4&XvPV=-<^=h}-aR9EJC*1PkjB1abcPrTO{qe9s?1Nn z4U$rrhT9F78%&^(&5fmErFI*?(heb3t(VqS;5bz<o$u@EIMcUj5e)rapybH##iJ6% zN4kXQ@;7dn9z008e$Jz_WP>5;vT^A^+YJ^qN3j}eMgAcU)?n?A1GUrl-PRnj)sT#T z0J!*+vh8Nq(3Ho){@oIshW2c}U;4$R%=&siUX~m)6CHCAGlGB8sEPj{+JWu6swnIc z=puW<#-AVEYXhxykRWEwVteW~LbX#BR({{66XXhP;gxvH${6qM#wB?AeqC&8`<ly) zAVh4uRJ@UIBoG=+>~!37)K_YC0h%a>(C~&dFEu|*ZZRECVrd3PP>tt%gtm5OF_%R* zvD~%tm~Mo0YG3{K=H|&7G$n`67U$8iSk4|IIq9AP14=906l-kM6&Z?RlnRl9F089+ zRG_k5?s@bgSx<rrKi>S@-2V;>hbxTBQZPMKOE5N*xIo6hoBt{i_hdU&Ovrqod-y>e zR6Hap5b~kSjHhR?%7Mp~V*A>D8iU&<krb*L>Z3H5?@RVwYogtzGrOzFlf&K;6t4#6 z?6EIdYDkQw?PlXgZaj)@K2F&h4bS3gqz3vKgx22<IE=^FWyBtZl|L7YRd06-p<P(J zpR?nyS#uz80ZqFhyUNz;>`0mWY<$hA++*2Tm$3{EhV{>{SJ~1gozCkdu3^W8tvNng zfPzE^iQ%`hcb3?)lH@4tcK@96X^R4_N7}fkl58VvX*6M>^jEpwptD<3{;q^!s4OA} zv!~DNgynE;UnlH}^LxBL^O>%y)db4=)C3pJaXb~7mOG)UF<Rbs4_ylF);ZMkg%zr- zOLLS<*t=oykK(*MYL9N;*2(jzk7C&ln-0_>swKwY#tHQFJNc@erm>!YsXH4o1Q}1b zRJVJ!8mMsT5lb)`C*}r|8-hdFG1p?hhpQN0gv=vFYEBL6IPUI)W*FM*9$k!a2gjeB zvXNCyiEJ|KO@aD3&+$u(ptFVQUkO-ZS`FFmW8>Z)f9GRnrhi6smH{mko~yQ#lW@Yu zUnOI$Jp>#=AIA=FAjyz;LUKI>99-5}raSxuquO5Nyc;1^K#PQqiZv=exP&9-?QBeQ z0u~8;m(f9oyW5YkKYtYRM@vA>ph7glmOh5JZeS<+FEJe}lQ+3vwQ35Z(!j{fQ(di2 z19}y@6-P)dZUL+2lVyMTRJT~L=(#^#ONQru@I0JNIh}5`XVX|&8a2~tfG`4Yii`$} zC>DLlhLCCf*Zj5$sl{0%@$Y5$tg0Y$!|tlu<RmOrrTg^C&l|3C^VZ^Yn5K#zrmMHI zf^&a#1hoIw5iB<or_e~k>fl3oZ@C?|bJ7b9PP>jJbVYxXZ0cDOEgDd<rvpVvdxw9$ zS8X=nlw8nuIK=arfg&rODlNkeEP$pMA0~|$G{dndpwYeIyUzn(fEwiTuG8PsD#Kt~ z^<WDzU4Hg^Ish1@J+W7~j%2;MoYn5o{};>q0ghH1!P_;NXeyl)Auv=>?+-+~06WHx z$k5%L<$GX8UlosezKw=u!tsfIM>NRP!QSKWk&d4Bkol;oHncHBu(2%t?jk)U`q<-| zS0957dV0N=5v3|*g=H42YRpm%>Hond*TKE?zh^|n@pJVz`C&xVv9S?zQvcN*jLQi` zZMOqIRxjjd;)_PVb=1+VMntchdT(Kg?#2Ii+_{zz0vj7!LQ1NSm}!ANJPjQULTJmB z6ve*4Z7LAL7_^m%D)_?p%*3%JDkgUT@?sdmr2p@*ye;(~q`ge8#aZniIdZEMfz~?L z>8A3+BeMSwB>&?Nt8L1)I-~v%h&&-wwdNnsrt&eA<o|TRo^cU@=qC2r<<#!a|H#~r z|6xyAy(~qT{?V;1`5(7GCYta55#kT9O7+LGs##VhiG=${x8G3zay#zaTvYRq;Ji)) z6k3huxUB#P>4M)L@<FPd^#6U$0u+thx^1!J5tn7;KZ1Z+a?EGdU^>}<xRZd>X#Zfr z)(N@vQks7ZXN=^Za2|N1=>7A!vj2?B#kEgF_n*Tl^Cz54lNEPT{}|4{Ztt&fHhdvJ z`R7?QMw3`;Fq@27{`Mb*L4Y)2e0;qB+?<N_S}SUWdQCT!<bPLS^z^}!dOsbPe1oT< zF8YsTfd|Ue)N~8{%*4VHJf6u;LPvLgaNK#P^51e2Cm=c+fs~BQa5`T!o)K0Zv4iFB zd0PDPabL5;dYO66>$1!J{S{n8F)#YxGQ3p|?vGZ1*CD_8@2SU!kWQlq?d|Q&TgYg& z)xpZdZU4%X|7(M_h=wk%KJSJeWMcKPsi0he3!srAM42*GzLHf!fUqo%_!;r>fQtit ztL=7lxC3b-xs>vc2Ut`I1e-UTmWdo3=+t7vvOLARw@o!}i`N-AnccY~&77V6))mb4 zyJcmAQ4L!?owSV~R_c9snke69QW?5jT{<l@UeBxBDi%a7j>=IK2%4!$0}HMGCrn>! z3ni=B4K>N@z>bHZEYH8;`wGj|br=Krf3fsy<XXzpkFqdIOtD>d?pG^@4FvXaKG-=P z)^xWRIfF>;iq8vJfe(|bsm4R>7aFzxRF{S?cVOdR^cqp(3n5y3PYJmE>)fA!iT}nV zFp!JGZtg#+0FaC?+sNGCtWKS~Aai$8HlzDm(kG86$!eDn5-}(YB7r0F{0`inu5H^= z`T@B<bh?<RVAjyH*6;Vx-!A$eMS%c6HjN-I@3t*DZ=WvK$^)#2ZV#wSxf`AgF5EV= zHNY;#x|xH}s(x@{KKFGvNvCZ()-pN-rc6)VMX}ag(<S^uqhAvNw?4I4<raIvg`rIG zcj8x^4yZqP+}EYpoGQ&;U!Bw#e@s~r$Q(>%p)Z<tN*3%VEph|<pHAdO`{U<DB9GoD zsL<7T^-p(gBli2O$UVGgqFTkmR#wgim?K(r=2mo39^<+r9(YTtfsq(-<oV6pnvJf- zC+AS1iizqWPj3V!KY&qbGx2{5X#z&21a2#NpABi$c&Fup7S33nwpZP6`wPSdq4>NT z-~j~L>AF`+u`+-je%n?UKd$ev5gS1C<+J$;<Qk#Tu;MFtOg7Bi5a|wQUW}Cmh0`zY zt^55U7(nX%;&tF)sF&+j5|N%2a?4=nLjKnu3g6Y6wst175;+1k`MN&JUfvoCsI+5n zik7+ec3kMclU!J||2kgz0@#UAmG1#D1U6vW=g?~mkLnRUfD`{3*~-1sa?00$KaT-9 zgmJ$(i?GcDrrJ*Kjd>*xYXH8T2ja2uk^6nTX{isP9hqgM+D`);r6WT_11LlwPElTJ z=t%zRl{~bX$*NEsTFC_6Af&!VY(`CC-at+`zt_Z88o=UU8rsqiqH08;gXb&%Qbqv2 z_TqL(m>O+uHMJ`mw?04Q<Ri=bWXMU3ParvtWzvGya>@540p%;Jnm7Ym6`@tGr#C~K z%#y3&y0Z8>ti$7V_^cm1ab-@2=7rF)kHuTpvRmnvMoi|NF=*(<?9FFb(EUhlVH15x z*1faPJnGO=m$#3v+9VuC$=CQVScnWA*BN0?B1dBoLrA;OIF>^;W$xAHob}2R1r3>@ zN6Y-DhIAvvC>k6e?c5*{o1PUr8X$dMeU4U^Kb)0`i-vKB#((h4`fh%!=Vco?oUzQn z89I^X{%ciSm@cOAmHzI2UIfchP=8f}hjv(9AP)XW%>8tG)hSW|+Gbe8{x@gHc-nD5 z!x)_W6>~i?dw=Mt-8YwlgwU1HYTwqUr+71Mg87LQcIioRp__l>vV?3O$2B@A1MEt^ z2(vR8eisM7*||S~b3ets_{sAJ<?IUbCv06yFLOLiR6Mr4-)Zxh@N~!iNh*UH+wF1j zz>{6k;<iUxoxP&dx~b+$Y3yhYi(#QC{S-$p{of3a@<3mLiiv9;T0QJrttd6p-w(k4 zclSe!rvW`7obw^Kw<{YSapasMXFA8oh3meDI3uv%Z}vuYOg)XJ+8IfSnFoxrTNY<& zjfti%>{GAd&I2P4kj`os>iM6w5N&JDn>S{=6s(MgkBBXUjHhxi_#gZ{0DTI!%xgFn zA5V~>!uMJcMvA>Epg#fWaMz8fzx4~j32%fvR<j>2Vp%4BMSMaVl6GKD1C{%p6*lF% zHw@mX+HS&-nh}{c*A`q;)p2162S*t;uM2*^UI}Cd(M^<o=NC43pgNt}S`NnXtLMQI zTq|;R&kro&@&I<RD>Gr8U%?2`_yh%;b`Vlg3w82V+hZ!mnYV_YG%ud`d*wH0yJAv4 zvT1DA<D|U*CV08Z1pkzK<!{1R&TufIx`5Y$O&+2{Y?orUQ}I(3<5{MjlrS#v1olnN z`^0Sq6;oUe9?0ZWj5R%m-Ai3sJhIR<0PyXmtsa_-mL5c@oiDs4%u;bYHzyM%OMPYn zVq&?k#*}Hy6Ek}4Hg7XzN1hQSde+y2M~d0b%IO4MUD@iTEvGM$w3?TU`TwTPZBCKp zrjc7a>Z<DD@Oxj-8t;dIdJst?-y6|IIqw|z%vgCTklV^bG`H<K%`0dJT@RYl_Vb!Y zSq@He+A?ya(saAp54lH0DH{G8YF-{Uvdf;c=HCKnBJ=F(TVZPreVyZ<%imm&S`p&q z?}&dnU}Ss_>rk{vB|Ft?dHbzS3!hy+^sJ!wKrEKjALCW$QA+&!+&<MPYu8ceh>75k z;drs3OUd%2E!0IKXC>idGdlS|@`OTe-pVZ{x1_G-zLkGv^SEyA<)9r-Rg+n3=|34# zeRXO|c+(!SYT7gYwvgY^5#+NPDtNARUjRG@E&Jf(Z~ZQYXHfRggKLNF$*}Dw?Lz>) z8J?BXGTqVkR_onr6?m+*c6U%}1KEggS$j`HxVkhXf*9Fb($ez0Sg@OqTva%~CCIvG z+PvnmZ39G<zvoTs5oNT8^;at^`*;5RjbNYfr>RSMq1dQ%(bksx72sMw*C#M1x}w%n z`U}!j$A!Ql_}YN?*6#(DpxPJl{i#67JFesX^%Af2g2z7sGTVJ;o6g;JwBNHUEEkkn zPCR>8M%2h-g;&y|ce?t7*<IdXIp6T8z%ZC-c0Gvfy7T^Ihl~?+`|EWYnY&K(xbXO% zq|?gtKIaKV7WD?%{JcD^pxV_F_Qa+6<>=7eFCHu@c2Sl`&ttX6`(honFliuaynCj= z-MzUI@&Hiu^9;y|?H8x<{c)d8@E!P9RyO}!|L(~emtS$LnGJbgW9z|v<iO=K7XskT z1B18e_=OH(E)Bky_8Z;^9a6MUVvczj!Sa{e_Epe@%E@~JvhBKYc+}^sypCrrAzTcH zMnOx(oslf5lRH3Lrs}3zEAouzl9I41$LH1dtOl4VOTFB)ckrt2%5{Tq_M@+|*OAt@ zYTbroWPK~K-cePJZ@e*WoFHJ%P95i!DLesNP0@*3YY;x0_Tr|oABNnvDzmxEk7~i$ zrPW5!XPxo+lE+0Deo27q*89dCv!lA4dG2~x3r`f?9kqIH_LbGEfER0y4S+d0t0!}F zGf@5b9zB62v+9iu)j?;KGiu`U9ah(_#p>10AzP?(QkCU46~H^{RI*ZxkTdDpux`O# zvwaBz#0+iE2(-?%@lXa2<Pd-|5AKWkAUg*qZm8YAop?#AGdYisgOVaA-@Ik;dcYpK z7x?pZl$Xtk#-n=cSdI%JW`OEJg)ArD%oIG-zxuy?xT)uRua39KQ1-V#%p;fI{flwC zVfbN82CWIU8a3Ue<X1`T{Jja=z#TBlgl*$#9GC}YKHHHw>r|O(pC2)Iv$T-vTWCQ4 zHwhiD3e!TKZ=N`2gE9s7jm^7QPrFn$Pd=^(H{oM>Ej;Eg*_iz9w;BTun^#0QfY%IE zaL<<E%PF_5^UE|Y^NC#U08Nc=@XBWN&to@|(%0W88+_<9b|bHg@4zm*j}`S&tKFOc z6Ozw4C|__wMDkt?WF)_Eg?|&BNMoTYDv%?1LTl)ux_alC7m%B>BY7>G%{3vJYi(kp z4pAC=QRpzCmB5>d;3ZIii(mSs`Et>;;Rf*UV#2q~XxjjRe37lH%y>`rPI=c)H7EPj zPTUT&^%6;&4;*>L?~+9J58Qy{KRgLmM<lGDI{H^DKhj0I&G#Q|%S9P<@3<IJjYaHD zq&eT)myRp8<1r33HWRvqm9IXV#dn@oaz?6LyO{XFzj9O53f0V=Lce13+=l`0YoA1i z*q3zWFuxEGz^1%3Aw}iFiVgOYpjwVY{*b~@1DgEwmK~C#ukRjL9XDspo^9s;08z!E ztQUJTTjJ2Z>i0WhmQl-Xu6t@wBcQ+SM`?^yfL?A)p&_(Hw7iOBtr~iDte9ge4cp;9 zi9Qf@a7={MdLJH$AchW@0Hv-_?j7C#lE4Wa8{jySG+p^DI31B5N-Hv{6Vv(PooGA# zOB8BB1jbdmT6n3Gv>2M4tcb`k3jo$i$VHPKUDGPuKgyew6Bbot&R55D8Lc2FzZbg0 zIbtvAiO-A-4yGOWewvWYh6{asTpBO3>9Xhe*~>_W_;V;35d{OXh2p-%`%g8jQ0lyL zl<DhXfgRI5z^|b}53yo-figr`t%@7e?D)uL3yZ14;{>)ch~evL%E}#Zl0KGFA*ujl zqSDT`*;99X(NbTKhkG5t#9Cmy=w||stPq)$#|mnln8!WZa#0#nw9IcYKf>cyR#F&M zD+uo+<wdK?)dw3tlad4CNexwfKcgu%Fw)WCdOVG%s|a#VWB(lK3LWV*F<Foc;(Pya ztseyOkU2gi^Aq;!b1evk%wdW0Y24@mH-+$`Ym7|=9g~nX<<;3Z5f96{YE0P36nEy% zLutqX`iDm6bvl%}o)+4rMYl#qYM|sB)V%vg=r&CBb;<f-5emYJb3u~^n}%6(A{tJD zig8FJsrL;Hg5hSfcfHSpcE_4-?EC{Iq>?{o6D6M97)s!kR5kGN<7n4;j*w9@W4?Ke z4;WXh7)CN5TxVzm^9=6qljae+ka%vtbx15Au|WOXY>_^ORI1*_W`nsha3^*V)9&4g zOQ3eq)QpCR#fr}c#Vz8tdd>X8_HSyTtbF-Ct8-UxDJ&B_QkWFvwc!95EQhj6?`JX! zcjV=bY*rgeZGoXDJNm}^1(J@QO+kk!mHO|LpDIFg@$vAz-v+dJ7;iG>@<$zBQ3p0V zpoq95senk(ZkNJ38W@(3X{@_?m0%By(DqMRe2=jE;za5wAl6(W>nCQJWyL_#15LIg zhNb)k<YaJE8NB@_D&)%Q>D7+BE0LwBo_Z8|v5T|y&_N1(?d(4L<4!;5sOI1@78(B3 znAft_0^yX^leIiE({Kqh=KE~Feei8-oXPk=;Qgz^fI?XN?DJIfgCcEG;i9NDY-TKC z(q@W>EAKZbpwE|=cvSb#uf;niYgXpwc7wy~1<QO^3d^q{Pp0<dmVT?v1TdWk1+hK{ z?{RC<WKP|EC%1^D+->-)YSn#kDeo0yevrAvl|5MEqv{2IeKfpJGHz>KI1ENZrz7xl z3F-y4iRbGAzy!o(poeB+^5u~`bmk&M&~vBT@<wVmO=dLI7GPn4<T!wkKo6OM`*oOr zjr1I2LNn?+XufqpFUD*|-Dm@s%u@ciz0Qa3achIatn#Hx%91_Ru>Xno(PPZ!%<tjE z1n36~Uj+HX>e~B&VJZ%bvoT9}ImeObVL_8+E_>jMjTLH>XU*9u{y2z3(~j7PTcOJX z8OLJSnIvzw2Df%=8ehYs7Ah{Lverr0WyqU!!FFm_r$Nb8`8Uzrj}e=){%&E>#IaHa za=7juf7vtX@i|`mbG*vpdnscO{g~!y^iI3$U&VKU&3^wc`s1EETQHd-@+sdUZVp=w z@}Xfmqefg-ztPV<Vm{rnp`51Ywjr96N3SX5oJj5Y=QK)bcpL~Eh|Mn$>c`3{`IEUe z0dBuO6b^YgDX4p>qmX%qMi0^^LL4IAOO#+&4Z#9vkuc@YTy-ibuupfx-6RO;H+_*R zn$>s8*yYPeCEzc41^mB6Y{-(5-yg=;pIh+&PoqOLtjqguqrEI=7u~CpC+U$H#>lU& z@OgN?X3qN)?Lcm#Su!+j{nA82xlz$og&(0l)&^Tw{HWx;@%<W^iGNJ-pw`(;>W|U8 zSbLi!EyWWthWMK_7RJl?!rje@put(*ud;O(8h_B#q*FicR<7E8I}i2X$m!ilO$&W8 z@2ge(SG5DE6FFf{7y)P^ZvdQ9iZ?1fN=8Mded)$mc@T`j0xS#xyMUh<QN35%dhDcY zwlGmH9e5M7#}j&Y|FJjy>p|YcBBR9>U9(NaAl1re9#LscPI}7xtQ6jPf~Dl8de-Jr z8}UWNqRN)=x@Mf_!nucTcBr)}H5Y`CT<<{n_E*eQJ+zCYXEs=?#pPv**r>v<9$0Ag zca5%egLR*~F`L!m)1gXSYeWlyfS17h_%e#?A5Dr)Gw7F@(g|sJVevl+2jUUPHbdx4 z>nk$Lxklu7#s{uGE)*8eC<I<N91=;zYwJP`5C1Z6m-$FcE=nTvC|gYb16n98CcNl< z`e&`iUi?@e%n$0iHPH_+3Ui*IP$J62P=sVwZf=-5LqXW6><9tno6}#csRyVr7QaTN z1j2#*#JdYKCySV$3W$HQ@MlLm;><+k=1#<QYs@B~nfDC7NGZb|*ogWT%XE-&VhFwo zhRaSEY7xE)aKcEvpnju@zWA7rijO_mOMGeoi7eKFBa(fCA};+sKpf}3yc7)pEruuY z=5I;mzy%~EH94rA&^$8jp@u)MR+qVvL%)nJ_=vP0kN(v$F`~dvfi%%6I7<hwR`{26 zzzdwzFF`#eSW6nI00Av#n8ci_Ql)}<UtxU^L>Q$qkdttyMxVUQ(VDLo+Ch<MM&cJ; z_(G+puf!sbM4_XrxD=EnJhj0bG!e5aTHPEGb?P}u`;U3!0SyQLWG1+Mx?9x2X2dAj zP(G^o98UCnE$k5E_u?F)xo_lrArRCGG?Kne)Q<fR5kEw9AW+Q;@J^ElXS}@$pOm>y zt7nPAC%o>VD5O(|L%>TmZ8OxETaYipMv6UdE>V8&R+1~-q5l6e0ezyMiA_7(chotp zG#_HBs>9O>5QpU08=F117UIjW4q0Je*Rr<Gm>^n0oM!SS1&(;|j<f{!wBz=$Tk@Kw zKPKh;BK*+-2bk8fwLj|bd6p;ieE8-LuHobGcoP<x+5+(!d`_i*<qR!na1nP*wfB56 z##$<i7hM>NF^k=X+UNgfgTAj1(j7(m+5W`o&iaPmG2;KqFd+!6sKVl~MMApaY>HqY zj8WBBDsj<Zwjss&ad@%MARVa51H_q3Rv=K&OOL|T_r|B-hWz;Y4oagg`$fqb?pf8p zdP*Sb?@dz|gZ!iwC+#=n1v}KO`fY1!Dg5od4i<5K9_w%;99T^!Jkp!SG*a;;o3CXT z{H#=Kwv4)P&GW!GSt5x%%p>gE4(0WzXMn<LQQ22AP<Cq<R(lOnuYHcP^SGh&))0GG zq+UaqAoe0Lx_WsjYaQYH#%D?0w@9%=QC)R3hiE)T*c6P@*%7<|aXVNs^za;gb7R=M z-U|xwNRDOx-BzRcLIXJ4$cj*{&^!FCcp{!N!xk6Sy=s2kkzbq9&*^^XAcyK$f^Aa6 zaX*uLb}tAfa!+3DOAHUY9=qJ=rISy|zgmvilcBNLe<sb5$-k$j)4t{KH@MWo`kIE| z-3Y5+`#ukN|AI7V4bp`iCX`SvRi7@9JF{zk4y&X+@M}Z?Mx)z#J3mhkwv@T}^-S8{ zi=3+R$KC*8te=w_VO^Z>LV`$uj`Le%o=eDdOSvh*ZTWKY6Ck@=x#7ZC7rg%EmM{Fc zm><&08Laiy)7rt~9`$x_>xymX&e&8tVO;zzg=bDfV29N}pJm+ZnbVFf=Ad#0N|DS- z^M^Y(6ebTgU$7i@YA#RQdwYK-snp_gB39wi@}c#%#pTnHz}PH&-lk^cU<NaK7(-wF zRS<`79qQLhyTQH^V~%UBfA1UI5S_AcH*(@=uA<TWoo)V0=iL_=qjeb#lqi6B9nvTQ zlqv7#kK&dhu^3raXy3fG6xL2+_u5F205^jIzUJM7qAgRs9|6V8Smr;lk7As)T#7~7 z`Za6@GKWA;iM>e!c9npf?n#&=m|NTVwea^1?V^D)prG3<=6PbB29K{m+HEgSE|b2@ zy!skr;TttN!#Emz8dH4qYh{KuvbsC_e8CyZ>ty7rt2Vb~*}PdJ0ozqu+6yDx(n3Yz zRZ3;yFPi@E-WtS>C9u~{O^AMc4w`3@o7D_yu7r%%SmgDLUd?@ksIQKOnWQa;TBuWz zDww2`fEWefTRPgTK3@Rt5xe?h%(*HXCc|_5Jq`g^cvL7{-x_p|ZxG}6d|*gC*>b}3 z0w<o0Q%}~TV!3M7T<2o$REG~^mPBX!JyhbmJ;bp%$Vngm9RW%V#1pzSRgG~V7j)V4 zrQxDI4+QRxy2wxQ@zJeHd?H~(`9)T-Xi0f^4^cQ+ru@QL#7E7iTikSqwD0qal#nA; zMAMcEXT)htd5eVDR7yxyLuO)>bUPy{ZpY~9`@9(;BRgu;m@SfwQgRiouuH;}C1nvk zD(pj3@*xH>Ec0rfSJz%$MY&5w`}c*@;i_`Vc$0z}Ri<j^?VnI2BgkL!`peW@V#L}5 zIt`H*k;IY@7Kj<SG{$MzY@NALCCHMM9hI%7WjU>Wr!c8Gg6e9@<kr;hjI<L$ygj@9 zWeyl!5}$G0F9H?mqMxN|i_&mJIl0?#4ZHd>wFynXL|-V);T_0Y$Pw@C91?Yu!fKnd zX4(=)tBj-3o>NW?``!vt0V9CYKe$>ohnZ6ogX7}FEnQKOtR)9J?~F9lW%8R{G7&>6 zr1%ZmOX<4<UMa>+b~PK(ZA_4=xjJ4EyOND3CbP?D`d{b-vQBb@TGhkl*{`w`rVyvg zGMUEXBZ4`Q)EI4DFx~KF@}Utw{>uXR1bg-%1g%v^R1#Ku%XWxa*b+HZUrAZqW+FpU zJ*AEWqB!>Y&{MbM>g7CUrm$4xmaR&fvNrchBw6?Zc7$OPz!UGi=|gHex`~WnD2{@% z2z^Cjd%*%k+~S=ObiuRh>5cOx#gnaAxqIlJWqC*?G&oE<80ABF>KV9%co}*{e2ZB_ z)ABSvP34{~OmUBlmX_`0E=Dm}6i0cY>F5MVi!|r<_PAmAZmmYGbO#{|oa&P48I}{# zwITAGr@ibkrUmx>LpNFm9GY<8EyEFiD{0<LAqo}2ic*v>RCI&1bS5t*IY_M$VDp=# zop0(#n7mYY1zDoFF`$ccrYUGx6WZ;+YVi{#0g@^&5nP=%N5t&&`YHN~V)oQ?A@Y&~ zTyM>8Y?)P`&`>si#I*>h&kOwF;`}-Oi|<|-2jnmY{juXW#;Yn(IX1K5yzgBfYdYH^ zv)5+yZFZfz-b@ORLy<sEVW&)BJF=zBcfOo#ywESBo1l=xK8N?dko3JBh#@2xge$QB zrn%Rm5R@yw+!GHFtL~Y7_xHRNDO{-@KHD>{zMsuq+%!kS>DOT36SY|BVr?tJAZNmo zI*j1S>Oj#(xT`Bx#Ugi(Q)oq-u8g^sT{bGtEoEvH$jd#(69F(`Q&O0;o~`9^&Zz@# zuMcZeiu8o9Z~xN9(LloEi%h=e0AGF8yyfxSu~cV*@Pv#VU4S@G$*&ju0(N3@7{jCW z19PZt?9T3Yn{-SrxBH&!10dH4#FoPBNEimO-{kqC-W|IFF*hfJ<R4VVbiT!x(=>)E z!JMlL3kYvL3kmS-_F1UX1l<zSx(~3RECt(KI*`L$8V<t?qmW|c?Od;3VxzR%v)BT5 z{0kcKvN^LcigzCNIU$@NMz6~Apb;ndu!M-0?B}7Qj!RO7`L2+_Lwg1Kv&5;BGuMIE zcZICEH<btkqMJ<}a$7dS1zDWvgeh$k@~f=By)Rm+Ee*at+7bg>GPUc@lhl3;E)Sz} z`F1VNs|oAV&A1W<sdW`A$moZFLhfp~-4Jw;^m-KeT+L=mE_mN!oJ$l!3UYM?j_4q_ z92*5kz9sARD8Hx+!K*2x(%XN~%eY{W_h|+*I}{)<!3?~vQC}$@GX-L(7C$pd+9&Ow zrY$D<v`pb(o!Ct-dVG7h<OmXOq|5>Ee@Ylx%2M6#I-99yaPj5$))aHYkVS$e;73P< zk>6$&X4miP3ZKe<LJIiVVYb~}ak-V`i1hNj5zvM#fA+*Q?IwC10*d@iysU5gp;+{( ze?0ec7{TI+c%WW;v<8Kp{q{MA=ioHarPV%KWVunq9p=+a%@GUhh^!WC>f&FE03w}n zN^BW?WWvHvI9%j@EOGwkg}|}rNL$<P03PLNcyE0sZ5%b#9s@ZyC+@|hQ(TS+cBTSv z!0D47#R!Q9=2(msPGr3iT)YUB?Lev76j8c8mXwECBr>zOIy&~R(0Zj!PD=MBDcjT? zvD|r?t&C!E3|u+IsB=?kx`p0UJte;V+J|*oNh=3`)g#?~oINv)*%R=G#D0+q^2FqW zF`0%yCC{|nl^Y{1e1`m3cD;kTEEz+i=)gTjs&Dkx<Y@IB;Vm9p0NR!2EM7egRGPfz z{BUl?`mS>l8|5`Ou44eL)*$9nzB5!_ieKkTCGH?U+A%ap!?;pVRFUAIh+fP@1a)UD z`;Gf+0oe@7)W59tBNP<x0!gWN$?q3+%t@z&@1rn7Ab89vVo9RwR(G7`XPWOT%3j}U zKgaFrJ-Mtt?-9C};Dge=2>PV$I)x(}5r!&i1RmGceso}BQeCVK*=^76SB%Z>b^tn% zvFY{?@!Edbz(_SuiqFlhn_uGu!nm8hl0VrL5wP9~bKi&5Tven`U*Y(2S6!-Y$K}Fh zb15`CLB^p6j#&MYZxshL^7V%2V8r}<kiVADf?NA-sH9vEX!DXrk4-95Fv{&^-kn|a zyu-Yw78z_NQHsk*Jjdc^{am8G#zY@7n~<{{s@#ZfnU_1Rej!i6$&SsZ*N+;9*7+EE zwJ8ZN`(&^Cz>V~)J*mnV&xZGU{ySie_1<^Q!wLrT>u=tbR-p<P?!RhLh`(B$!GR~z zYlac6h>~xBc;(v^%4Z+3!PS8-)DrgO?cazD1`l@;=G?C#GSuNi7rlkzLv2DlUOOHG zu}Z6T>RD%C3a=%WoK?scU%tne75S^jB&(mBZydGTEI8S(jIMo9XfbYECH!5G0Xpjw z8%>1aGgOn^pI#G>H6Ba8|FwW%Hfa~hxCH)HWj=|MZD@JGS^+-S?K$5Ms?*HY0+k*< zpN)q@nvQ`q&`t}XuI3jHzx%am+z{l@p37}%4Zz}ug~|5?!?|7gK?sFW19o=yueC~U zT&=+EC!5lnDp93-T_Vx6$!G3Syqnr+kiufJAKo+~ee;qW{O&{=&-BAsbM^Z|;`|_y zFJ*M_eb`gG(nIheZWt`bMySC>7`Q$YSt1u2SB-u?jbPlcL%?Kj{hm!FSYi#w0r`$5 zZ94`#im^IZY|d3wg?k3&(HHgTh*_XARkUIbEio#<Fo^Itgovb8gSOeF3I8kJ_07UH z_OERz`4GF59~tAjt`k?Ohxnw56%w6;py6O`m&_W`t9U5#S!cfsXMVN$FUof|pX8C5 z_Cf=Qg05!z6ilw(i=d4k0nt-$8yY+ym?)!925-q9H3kHk4S6eYw?j&d!nR!H3+|fW z0r(MGf(1xDfzP6%)p?K63CiU#)W3tHpFa@}s`na@f2Zq`CTlx}(Wvvs_y2HkMwe9p z5U)$u<fvM#rqOP)rKeG@^6r4E=Jmzkw!&w;<@chnl-;v$IrEm723|dC+fV9}pa|gc zvFHSa0ZUY$?|<cGKN6r~ef<)*R7&N3mJngeTvik1<Z>@+b6~Wm9(l;~>^p%Y=SZQ; zDl-&C4Ao~PX!#_k(nMvV{}q#T6h%($`&NgkO>x!@gLz50F{i|ff2Zah;{zG~%L_-E z_?t2Y+wR57hYv^yfBpp!G?8`)zhIAA?>J|l<F;SNQ)ud-^n7+P`}W=Ox3ac2h-$mA z@n}}{C^3B?q~3kaa!*J(qO6m1oQ=WUeAorjYcb&z6HnSuQ%6HqGrlquJ{V+%GX@_W zGC-e_+Qe-UK`Yt928n64I&%ET8zl4GYh+!duNk2J-SCqVaulcr!i&7wX)ro0+kL+g zV3hW0rk*Xy7I~#m&*m<zgR8%uBg^F>eu=a_>8N}$e?CMe|JSf?)_~|?G^tP9l8zX0 znm|E_OYKbYf+Ov7<fWBx%G1S?R2s`C>B^lb|JP7R6Di=dF%$Q?bwqzmTG<zNFUaQz z+CEreRQLi<4BI6MFa+z7tx6?)M5z67e0xe%Zo)JMJcz7bkoZU}uVqDZaZe1K!VDkZ zeTx<CxK$7nwOUoYY4qTbuh{BI<tU<`FC9}`%6L-ppVILX_hZs4l&m_fs3wp$uHB8G z?`<~?tLwdm<Nla<?R{-l<84XAyU7#Kyjilh477zf5>gFSN6s0tsm=~}Z$g0y9Wprj zwC_FU_=Np>EYOJOhbf(U4(fjIgaptn4Ti+{PC^B~w1)G$au$=FZCP-%kw6>o^wlaw zdZ2X3^T7l7Sk$l|41BjH89lp*{ich9(!Fr$2)QYY7js;&?!TRo<`44qQ2mxV!ov%i z^;$5V(=Dh|$jJ!g_qit6*A+fKJgq&8lP9$GY-PC;X${JdUSArZ_&Iqm!Py3h92?OO zThyn~@=QwZ$=QF(PEor(rXdoeNAmTvej^;W-&didjJlmWTW>zgPl3swjX%-IXd4&f zMyi&8?E}8jCl{+=QQhs+tSPei`iR(s9b<WZ;n2o=rh06R$1`c5>|G90#=y2j-l@Zf zdmMc?4j{FqBf@Kbif*Jl59q*c_-*jCupi#)2c@?&y#(VMfnE5J^K8uY5YA^_U=wSt z=a0QAZ(M7sNnKkTm-OoDeAc)Q1A}PUmmnL(c<rjGOw9zn8l|6CTv=whKB9|ly3&SW zo*HRIa@p^B0t7Dt`{<BN$$L$+j|@?ppN2|zajy=d&mXHW$E)UkD$JSHx(cBrOFOZB ze&>ry?TEnwN8N{OUw;VPK#v$I=cH|cxV;C^*Q(Pl&Wq@>an0)++byahk7+KB*4ud+ z9?;;{zPv>^kM$DHrxWczi}J_to~99J&@_%R+CuYfVulcwe6ZHKqb%tv!}M8lqI^2f zmYK0^V;}<t3pYPy#qiCn-V=?@U1r?lN$%ca@$XTuWC?R_iCCI!n^?S7QWn2j!kWXr z%%WU5r<v@Q&89incE-M$#XMG)C!Mq!Q2rkEzt*#-F96QRO%mSaY5O<$4P`bq;uGx1 z22MhPgWGm?^VvEjrRVqEp7VD6ICyj0E|D=)T{eyU40$0WpkSU`f99PK^PwYz#f5=R zlEYG9XyO$YVz0Pgy;_9~8u6|A1H!L?;Z^(dzwpn3u?yCyfEa)jSEB{tI{^2>iE`&I zgkw|&3LZ07o?u{e(LMqHTb$$8b3-|~%(Yuj9oly>=_3^U&R6HVO{%0}K-}y-Wu;4h za@|5TEP9l_7e?*4EM4m_=;aeRm05K=n5<)NcBN7guvph9K`6`%!|r*xr!`?3GsO%% zVj9lXJ{iSJpoqirvFm4t;HYbe?#g48Lvjvc789(2g2Jw1x%O)F?n0g}Io0{z%o;>t zTWks3LvodzZV3JM{wr6@zT7td9|1F_qCawgJX3wh(f;28`(!VXH_fI4me2t3O1aFm z>seux4iSm<QcGpx^PTPkqGr?yu!TkEMlSlxD%KI=$r&CqGvgAC#xv)Dj!zavWfHP7 z{+cU6R`I<2l~Fviy|t3vj@LzNJ?QA?(Ixbpb7TSVI%RDnrcMFH?wKOZG$Hm~JWeP> z#fxUQl5Hd>OHn#N$~_yM$kqW+cp^y5-*P*US_G2~@YJX^;8YH5lWUkY-<tlGKI<r0 zM$78y8cG01#3gMc$g={cdmXN93Rw;$j&jNFKQJSyVuOp~%-%pZot;_uj5cd=)OW<r zTJ`x_&693Cooe?h=WXkePGbfi1oo3maA}~(52@h=plvvrsb(^!;fab2tE7w#Bh1t5 zxDilNO-_V%JzS({HgA!6UaT<{J+&4URR@Z`UE0w0Gcz6wR+tw36Gl`IdUX;??~M%B zDRDxTd_NC;DP|R$#K0MX$zWJ|Q{y9KeO5jFs^h|7P8lAn)PeG-Or$=7GCKw&5@*y` z0muT#1nc!Q0-0T}_A0do#T-|uzgnq3wpEN`|9FsTSIs#SRu~tDd~$M9h=N=_MdM8h z>jrIfdU{Gzq8#PU#8pwS>wv0$o3?4ZrwnPo|0u-qSsi-fBCFR=vz-hjaG=yhIx4|S zXhStt0JqIOk>nE+UU)`^lYRRFvQ2FET4dU7s_l>v1faGN;{L%oq^=F0fEK*EqQyDB zQK%ku<$RGR472{Bv5^u$H!(5M$Wipp>8Sqt)HcE#a$zLZigrjw7nHsJJE1TK(*@(5 zSl5lG9kAM0Qgf$pGM}r#+8=Un*>yvQDf|V%De(UGx^3SSl1fitPhyLR=nUCwkS%Vo zCxE74Ff9W_FK)%q660?0$;iMt0(6g;<0nt=XZC6~+R4TwZf0wI&XS?0H(BF^tiH#U z^1&&}*%_L9%clz_Snw(4o>&;F-}Gp$UC+`)zD8XOXeakgpH&U6>RufSIpli2H(pLv zH~4}9p}orSyHAaKrC)4rIm&c7KiA`k)@N8pvjSgxF)-Sew)cx5c&ASJKKxp7Wx0KW zSa$Mlp~)}YYGOEy1701=^6_-xhx-T}ygog=akkc$%<IW~Gn(Yf%Mq8r9o&N8RAcdJ z|6K99ivlQveFvx8`$uEN2{CBH<$Fw9t6j29WN!g0L%zLaxF=ovD4R<WYbNFFTrQ6V z(&31)<u5P)g5Mi^=jXD1E7@D;0(z@LcBo_EqIOFihpUU}L+g9g(bp<qV95MEk;w?x zb+`G9q=B-&{$@}#rbW}$Wn51JiTKr45c1oz`rVL<uof>b@SZu)*tQqKYDQrG+Gu$5 zN+{uGjlGPQll()2a4;?;(#NzcBc9xEmRDEzeeL36<=w2S4txEx?$4Ek?kS91b8!Rb zD9jX?8n)S%h(!YtUPqCSxr99@tBuxn*d;r&^GZJfdg&A13xe~!%nxc4v})mM(swOW zmmKoMszl@<4`hA(89<xp1U+Mk^7l0Y+~DPM>ClJr1`Tkx{ks8NKV(;3;04|oq>W|r zT+Ik1E`|o(-gnGd(-)8D#Yc_K`ZB{U1BOa>_d?lI)y(>cC0}~x=7yC(DjnXdn?OU# zBXVu3zK^$up~N#u^mK0u5d~_yDY`q^<yS1v0pEYA(;Be_b~{vslP1lqJZydnxXJpF zRhSbH7)<#4bxR7E^#XN_ss+;V)H|?MLola#oe?8z&o3p+5o>e)+S92v&1;e_4@)D~ zow-6Ynib1kuS0E8rBp!~rIK~Q{neDN3jDgUuVh9dz0aN6M2`{Ch?-K<_ppYjp%fWh z|K|E#v*^6p3O>$OvYnuwR<x=b%T?BdOX<|S02#JorMVdwl=VHz3x9Q(&D45R?`b?H zm1-vHV`$E+x&^MqZ|ic)w5nH6H_3$|n0h*@h7!GZJfEjl&kT-#mt_D}h?aHN%snC~ zcH-fc%=zZBJJ#sVA^eoh7p+#h`M^;B&>lp>DUAn=z+!U9QSesZhy=Hq20P&twZ-pZ z!Srb1$I!x~II5QvPgx6If4iJFB3egZ8P-MT-|FH5BvyWfbid-ZoYJ(+%Z{P+-vh2N z3gj08f;3aoxLd>3`JoU{=^@)gL!~z*fMEoX-i#_{qHeA%1<lRa<2rkz%MF0gr~9#} zSaO|8TeG%TFO(u(={lde4HFT_l4SR(ssJv<Ue`VXvrLBsnu;hFpy$y#$vI*UN>mLT ze}^1_{c-HR+t>M(U@a1uCC;e}$rfZE)RoL`P|*`xd!BtCO7m^Z_B<wzIkT@h)JTgM zVICVUs2n(nO9gD=fmDR+=1|~y_sV4RC3!NpV1;7&->e%R!gw$`!K8}O^EvF7)=)FK z&OO!|DDu36@@LUB$`s1a6bEhma@;jWT64;kkPvskC-J8wn{8sQ>g<^|5rEX&kVu=W zo**xsK5vyS--|JE(;5y0KP&`}=5tU_<=1?opMM!4Dx;ceerVJv^m=qkdEMuIR<2+u zi-kokxBvMb;*UKp3KFugpv%e0IfiyNqz}?+tY*SxSLfg;dVTA$@L+)o7brOuK)~6X zIuxn;&@wxHFD^d!xoZXQ+2ONeTw67<)W5!7{4YcMnC&+;t_@1uYue@%6;}IuKlyuC z5s&g8h7OF#b$NTaogDY2@N3kvinREv#`^!;3oa31xK@&ARcWeo5DMq^gq2Yp#We#a z{EjE);v@KcpDP-R3F00xE2k>Q7@}@;H%EKFF<Ny-qeK}D5`!X3Sz@|$;br*Z5|aei z2>83V_*WwP!9fk==ksDx9&69T%q-GkN}X%xWw88jr~Eky0wS=oZ3NWU^e4Di{e%Yf zMosEkVE0qwQ=f!QXX}**SGhu_*C^0{%zJUC(KB$#!m-c*+<^Y!uR~H)PNZ7MAn<<x D1yv1N diff --git a/docs/images/plain-diff.png b/docs/images/plain-diff.png new file mode 100644 index 0000000000000000000000000000000000000000..0a49935bbe03a431eb6b81dc0abfab84498a8554 GIT binary patch literal 63298 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 O<5QATldY0A3;RFviuwlt diff --git a/docs/images/post-strip.png b/docs/images/post-strip.png new file mode 100644 index 0000000000000000000000000000000000000000..de3f83f397c9610ac931c2e68dd34b6a115f2073 GIT binary patch literal 200695 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 W^x0T*wqzy&&e26u#$>b~O2CplUtK_r=MJ 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�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%0D<XbnWu8-A(n#dw%V8|mdGw$S$_F5w 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%0D9hu$B^&fWi2-y|{y%TEY>YK6Zbrum@%_r_c%f6y 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 diff --git a/docs/images/pr-from-bookmark.png b/docs/images/pr-from-bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..05c11b9d8b6c3948101c529941262393833c9f0e GIT binary patch literal 130981 zc${>)b6{po(<dC;wyxN=or#@HY}>YNV<wr{wrxyo+q&ZKe)f64-F<fV?Z3LZ(5LEG z-CcdoiBeLKLWIME0|5a+l#v!!0Re$H1pxsA!a)5q($6y{4FUpJVI?M}BqJt9qU7vg zZe?o*0wNuimJY3^x`q`#+s)NIhbEeY=8aygdB%ZprmiN6CQ3~T5gd((=>#zv91TMY z&g<G=55gK93As_YT8BJVSQsAysjTdU?HT&A?cKQT&1ZAsdtvZ?ed*&o^HT^U_1!j! z8ZjN5L@$#8>EX$6WN3utt`{6k7zB1V5Gp5y!WkJB79s$j_y*L{y4#L->Eh<%%Vx~Q zOPc_s5G578T|3t`Rk3ibA2q5GRCo@8cd}7JRX3VdFBU1%`2gd=qRk~5-2yn{DleW% zH8BW+LT%fUi45`zUcu(V?c0PL7T?gGNQd(KGOPifDr;JThxq9A><m}c7sG6DDBx`H zyEQ**A>WqMV1n(2l@NkSB%M00`~G_~{+sa3DtT>ZPBJB#{uy3O6RN|axf~Z%1&fjq zF5e8)qr*Qtg~C6naccZNHph%{gU&FWqCDxkaSCfzfNsoOVyb}~Ah%wSaYV>?HERO- z!$Mkz{D?dV*(Tj31@PN~M+&9cGQCk{5d7Gh|4)Y&8f6}j%q75Y^s%aajr+14w;=`a zacmxwG}CwF<t6K8RNSPWdPRCg^8-F<`C-BLkGF<G+vA$;W8kzi+=h^8jbfy0Kp^xk zC@Bo2Tq;-)MI98@DYWT>hFqT2ZWifJ8m!xt#;ohp>OB^1(fBprl0WTXh#;ySj>k;? z0ReCJA_xPylr4~bq{x^T$4wNc2vl=}l$}lrY{DFn{2+RP0MwHy%gk~ndhbRvP{J}0 z#6oa{AR69021hXaK73$^AquE*ze*qII0<27zjGa46*Oca%q57AFm4%0gfIg)SbUI% zBVI0eMjwYG`X*$8un-PdZ67rdhLQwkKuj$Xs$4ibk;oKGTl6^*{tyvT)JTaw737YT zlsrg74F4Bd84hg-?JwR_>{AR^qz<qrQRG5UO9*dhzaZ31utg&`En<C;jlpY25CTx9 zpjSuAT=<j0ja`*CIQvkYU6)%9Amb)-Z}2EeU?M8i@32g==SV8F*dbDxNF41L3^EF7 z%!SY<z}A>uF|k*i@5nAQI|8~%w9^34h>V3mj?$dLoUQ~xHO8u6w{LR<!BCQAr(UfJ zZyDku(#*)D&iB&U7PJLICr%)$JF+{5aKL|P&k-RPbOz}pB4+r{uEt)=KGJTsQ(l|? zCW$>l!f55L{Ot_TkRQJwj;ZfvkZXT--(fG}wgAR7n6f{4S1b|$1B(ws5$Y`py@$02 zX%tK?^%ua4780eq|6|{M-^iHn4$3K#TO^qZH!)WRwHRZ;TZN`P$~EaR^D$qJ(k6v) z?3XDhPlE0b!5=+xL?i(v)Jm~5`Kg}Kp$%~=VrRwtg<Yj8<!@?S)&v|m9dSRU1Qh*# ze3FZ$u%sA`JDM$zr%pDFZ6<pGWK)+?+%oiNbLe!)d~~0~FKu{!=l0~566n}h>$Y#w zv<tSgcx88m`PTV%d}zFSztY_g!g)gaK{`Ozi1rMShCRTAu!ok2Jrp}x;#);nVOxp0 z5^M#|{4Sk~Ih8sUcvO~vl&~459>$D5inhRb$Au9q=r=BAX<>_Jxn}91E~jg!yGw1M z=AhY9!PCqyy)2nhWmL1*=&AgW2rJ*OPOfNB{iA*qMJu_a#i8cbelD^UQ&D>|f5J0; zFh!T^VY@BHp*5|=AZM4hPTG87ZE}ux-g8d&<ad6uWMIS0zR9k_?r!618Ed(~uE!3U z-N`X)-D672x|L-$rE&~;T$Y}lUXU(csZuFrBf25Xr{WXh-uR48m>l1&kUV3b$C#(A zC%;9qwbX&wf&3Kd{p>yN?eo;}H1dS_SoFko(Rz-IPmN!P;EafeK!mS?sE5dgSc!0h zvln|ArxJ&Rv&9}BXBV3iHyP)U*+<zz36=s*+5J%eKzIy)qB(uT_9wF==Qxuy6DgBr z3T&D)vpKt4yRehQzJCUC3%)03BeOJ%m@~lim*Jj6egE&R{k%W*6r&BB_wkrZ6QkC7 z>N!g~Ht06_Pa+rZoa{LyIn$haoIAExw!<y*EdcipcUbrLtGCOuXVPb#D<(ceLVki} zo?Lg}rR7EDmFLtQ6P0SITB&#GUKkX-7d$c(f$OrnIiDu)ODD4)ny$a|na7f|S*J$3 zpv$7uL5F&0w<DLcqLYJbz=6><=`;5k%k|l5`$*#={N4Q%?c@2K#%=r~<AeWs(beFK z)h+H*^PS$&##zJ@{O!is%BYHkla^bRasb~q#}_sjHRv9w8R#rn9Qbh1m55_vz+6q? zXv`xPEOs+gh@r-9%`O!w6loS|Z}`5bnCPTfL4<Z_HPQuAX&4iHE%G<c9%{Y7zH+fq zF?j>s4^CRa3Px-Gb-E7j4k2@qsq9Rf`ilDC)fR4FT{T^|%~j)@VIM5y;f*2ep&cFL zI@94~I$8CM5(a@rId@#2wL1t~QCCsF0Zn)2&S-)3u^*cS+!J?)mq%Uu9ZnuDQl2wi z#@jLEC&l~4Mm=l+*a75g9PQ+<&3&p$l%6^J87fJv`FOcMQ+Ttm@|JTIq!p!wDAZ6& z;FwG;O{>OEF|#7!#6Pp*vwT>khC%nw>8WjGG;}x#Irvs6!jt8bg9tKm?{gI=i_(b= zNP9)w_TPRSr0Hn%j6IEidSRMlTBxsBS1(;?B3C&XsJ3JM%xP<}$(!l;a1-<D@oK)1 zxlmpCZt3?Gy9-CgFXC!BsXRG3Lbku(`m02uO2T-$aoN<q4?Tq(OzhpFWw+LP<U`te zYn|k!EHl4Som;IL&;+c1938il+3;@Juor3rZxw4h*j8A{YaYHIZXXWm40dn6G{0ut z{4|<v5YYTlB}@C9{QTqjIRh%a<!W)O)nsR-;jp3ei0Ekged*a@O~^mcXLnhoHAEis z98&_*z#r|ywRfSl;m?oWibIrZrI}wR5k*KI-?rZ_dd=2u%1^C$M)Co6T32DbogE$C z&2LwTjv@a*%hGdqj9Lq@lP{4^n~pvHU9?+vcsgl-=HKo?zpJ(4^nM^u^{8+uB*Uk@ z3f5d@i)$xuf8`KkcOh^TP*J&6{&`qy-n*Q;%&X@wc{lZpq$1@%dbqaPXp;APX5|EU z0@a!BCcsPV@--7S2QPpP&ZysW=yK-U>hrQTIg_Di;MC=OUh%oKY}2yxvt~nA=rw2B zfy&3$=coPZmSyLeV`I06k;5p%iq46>&sL9XgxksbmV}4Tjl_264))GUK!HyHP-H!% z71@PIfq%j$)=w8Gel0Vu+FYvMi~qU3>97%C-e<G>)_7}?0L2qh`!)7<aG~_&a{iEv zoy~L}&JdxP0F2%AZ3iCB(al#ztw07$e7Aqc?d6~cw12w!v75V|Rs*jNJF9Qhw^w}Y zzUDZvSf3wF-bSPD1{7%vtc5lLuD{SekA{ctYk{?Yc4B*)1CW7Vo~(Y(DnnR}rPUz8 zl)0%8eVuq9W%VF)_F%%vS$AWLpwqxNE3kl3HbHM*B?FZMsJ>Kn_;ZLtIK3z30<s8m zm<p*j(A9|_+265M<aCo+`iB~Svs2|1dZfBZw_ySu{8CcTt5Z^TD&~!d!RB6_MsgG( z>#+m*y_!m25ao(sKBPXtYqY=|Y}F_gKtMqAt<<z!wdCb^O&shPjZ7Vk%@{rH96|oo z_&s_5>DrmO8j*O~+1k7CdJ2&J4+-9X`u`ecA|v@9BCa+9WLok{Bw`NEW+WVp?2OE0 zf^Z}xB>c{%=DaH6lK-Xt4<$fm>FVmp%f#g2;lb#^#^~T|!NkJD!^6bP%EZdb@Q(z8 zi<iBtktc(_3*g^I{(n2-W-cbqR*tS#4)!GfqK%9l+*}37$o@;_-|gQMnR#0MubJ#! z{>!a@9Ax?zhlz!endyJp{+IcGjq)m4d79a3iCfv3*}MERhad|p2PZ$%|C9CqRMq}p zd@fGr|6No2|I*}V`aeAScet4TD_(+d{7nBd_JVK*e`pIqK!ibL#6{FRK`-;512H7N zK6gUp>pBl}Qv$^yQ9)s8EhN>%#hJIu%b+tw)RM`(DW_1|dvRc+K~WMB&>+WoPP%yH zfxVgnjZs??p{fBMOLcr~TTALowUs^{g6}=*HL0nGhRnNQn}KvVhfKmudt8h)Tm^cY zD7!zoxS;gjW*>i)_yN~uu@hRtURF5GMzGCFC9Ilj`9QEI4;^au6DBl7zaZqd`;}Dw zc;wt~t!ug|>!qdX%lWlaakUS4+31uh9S`t6w4RTO&(u5SedUCxMA7nta81JAs;^PI zL=RxsnDBBf>cmw^wh*q_Om8P#3h3-0|Ek6D*FJq0-BIo0ynM-iWprn+$K#nrJKh@- zBo523yks*yT~p17V4okfd~Pfkyl?cIanGNvmMjri?U6ps-a9gSx9Jf2;CO4Qg8I+~ z1%90Q9)$0JdyawbvT!j&G_0B>?7}^-eg6CtL5ckS;Gc1(nlt;6i~!X(a}ly}0u|86 zG;^h&=W>N19_V$k7X6LN+{>RFsC|b0vf_TsC|T(5m-y-a^zy_*?O&)-^t2D%vGX?g zR-Z7-3k_Dm{mqwVy8W^H%wogj%h>Hq%%v?H*zDp&cyY93W!P>gum#$WOjLAzu&KFH zIeLiCt519(X{1X}Rh2Y}FD`D1vH0K#iKC_YjzEJ5ED$oUpIy5x`BR(?MPO=@N@TAO zVr}>ph^^20o1XI&#?QRyxi0BkMwM$E#6Zth3$$is>2TklvFF8SHHZx{KQ8l1BTgeu z3%jVjZ0f0keQI)=-_@+nkQl#ADo$-x0h@2~9>R|@Z~MY{DXfI|4ZKTbt<I}DCnml? zPEa3=^LoHH3%*gso+wEyt-k@ROF5IjO%Gcv@X6yL8us3peFd8C{0Q>wKmw)!c^d|~ z!E^pTWo_1)obX?edU@up{u|W||Jt=1|94;0f`m)9V!s(IkUBrq(i`)4n{OMxpU)eR zg<a<_@EUhNBIjPfYGI$Qrs>{4L)B|8{e^;ZTawrutM@>R;q0H@#Sr?2d;FC~aIbF` zmxiCfT<p!u_~K(W2V_Zb9_z^|RetpIEZ$JjyVN@{xx|%)-7|msFK}=@z`~JN1c$=u zr=LB9zJDGP1xIemA}IC6s~fflJD6e_Q$U35Lmzh*(D#c`pQ_XF=YxEgvoDD`E=b6$ zX%kOQ&cjG6Qmi)F4&4J<(gyNL1(1dAhERey7VDM*voht^*`-@-PX<)P%tF#~rj%GX zIrUrz`WZ#(xpZo+#)3VM$&6Og-W%*#4LEhdS27!EMh9ae5VaiRunQRbK!jqlP=6&E zr^H{Vn1W%VDus7>HcgW{$PL1a5r5j=+HYg%((i~dkJ37Ge3uh-Q9sh+TvH*W`Y0T3 z+DW(FlUwgwln!)dW=i!9!^>TW4|$>Txs?*p&sv*uG+d48+dTW5-mE?QO#8oF1Z@ct zpRLUZ60ccEzvtS$leP4kzc;n)FriqiMIK36#1OY55%bE8mYZxL03(aL8l2x?kAW!H z(YrpcYBKFW<;PWk2SK%yU@&{F=ug<Dk4G10CKEl5XAMr3_UWOnZhaNEV>(}k^UG2` z`59hRVd6dA(3KcNEKnneD2~NfnME^M%!lXurP7Wu;|jRBa;o!bj1MX6Y2Gq^vr-O- z2f0C4+IZm^MPsTJV%Z}$j74W+@Llm<$U~UxuKmNNn&?0qs)HH8=7Xa_*iHqEw*73n z<j{4~=lQLh+(M*V5#}6m!%77n=<<?Qn6?xTO7~yQ08$v7`&sYCuXxF-(sRl_+~vr3 zUOW~XMrW8GfW?ADYe|4TjMb2;a35`4W(Hh_WCO8^)RyJr3bc#6*R`8QaZ(^HJg4^s z6Y+;hD2+kj;-7mjdPeQ6taj()0+cciSlZbz!3vY2L}QohvWR+Gw#mTU<f;gCh09zi zF|BGz4Zudcr``Wp37!Q_FShU9B{w$jTMh*YkJy&~UK0;Veu5339E&&KMFk0e4W8c{ zfpP<a)n))+L5fA@7r<n~OzOXo;g^0EQ<5yrj`}vgK%x%JHXJj=*A{stv5d9##VC|Y zbBrPhBat7YBnV)*J<^z>Att~iqm3z_i{G>qJU$`=vY{jt(olO2@^^;{<DJCeqQ;_5 zqr7=e(Sh6e@wXH8putT1qIyZDceB3+2p)1`lEIL{AWX2zx)+~nxETuwaw1oo;Cf@0 zJ+KC$>o9^0eQF1^gF!aNF2=uliUU&<CfFH!5=|oMX2T^@M=YD%ukbEc8<D@JT#u&? zejhjNHh}$ufus_n$Qk3V<pMMAPP7e=5s+Un-;b~$$R8|zeax3#!7yI(V=98X2)dP( z1N*r0p`y;TD2d(hP7;8LvR&{FN6wmO?=5nSzC6Zs^4q$aRlDVN=%K3Qpb7pOP&fG& zx{>t5-MWnS^rMdOF89PrieI{&z)LCgH$O5zN@dd0SPQ_Xy4|a`?gij8>)!Kz^^*O0 z-8w7v{5mEmwtix}f$j9>^Za_6aJ?ugF8*8c$(p-W8St!~$1FH0NiW2!^D#!pEcQc` znu32cY>s>^Q3crmbKx8f5t9xrevcP<g=SaHYW!T<?KE-Gz$Gh!z*C$L!ol0j#mx+@ zZJwnxh^$?RjWggb6<!n^0443W3E?H!UK30{N1Ky4ktQ*!4#7t@l07VtwVjn4e3Mm= zZav1|ra!~^2OWakg)MQmv`dSqQ3Eoo7FiokHO(ik*@I=7KT{?GXYv-^8F#EKMmC=F z0LOGYn(ahSQ9G9*j!Xb`wa!Q&IYq@$c`}`v2pd0GxuR6B3QPmEGElvb))2D}P7CsX zBY||ZB>qXssi6!yt=R=G=YPdZ%mC@cNgR0${^H(}nkfcI?9;KLw~|shd@;;%_7#P? z3aGiwp*37a+)R1$c)zDH@#vGHVAmR84w}-G61-sNU@ajJKU8>~c!+~CC-y3-f-ll| zWv|(JDu9|wJckeqrwjM!B~dUPXUk}*Y=KjOeEV#Y8*f0_%xT<EwG4)b^pKbtx`Ssf z$axMa%hQiPd87S^=3P8X5{xXMq9)e|-a%3-LL$P1;H@AC?ML{yi*2{l+6&auB$>I{ zfo~_vQcu<#D5(8fnw|gQ>3=wWo1sZUM;Eg>7{Z{_lBDw&i-E*}q`B^&J-?{2FJY?8 z0L&h)_wVDVb8%Fz6|-ym=@iBe9Qct>#-)vO1r2PeczWXuVI+whVAt5JjZcgYU^)O` zK5*yM=uIe#UFJ*}$pGZ49;j;-o9mOl{C<#+`dbLQl&WBqUzIjO{}8iVKLs)x>cTRj zqsqdk%G#J;ykZ{9uA%z`cTZ;YC$COEz4lhd-e^n9L7!f5K#<KnyP#->raKB-UC^A- z@|vV$Y=ZhS<(C>*?4~@lDaroY!q_m&%a5UqCdc@N_2K^;=6{plniz@Wls)1yY|B0W zLOIXQe`qc2Oa-v9@Yok@>zoX0Iu1$InzaqlMjG75kTUl}X&S-z<fLgxJJcoA{+fP( zqXg3?1z(Yk04D=4Do^KPyf65-*Ka2<d-@P!n59#L2h<@eGzc&@<kpxZNSOVp)R76< z8P4gl3104?M%_^v81~`%j9=A^aS7&`WS<V38NRc&8N+jOUIY~}_e((6Y}Dn^@_Y`> zs$jPx99O5Jg5AW}WRgU;{dy~3>^Sh!0|6a8NZjj6QGUF#X~zF9sq5fA3RHwYy~top z4#$hzM?bO60sTc6sNF8~MGz_DUPD|2+W=nC1=Kg#Uap~`sx%Rq0*v;^NXz2o)1b(O z=@~eDFYjHF2E0<&xF{ycVo^QPlHxdkB)^XaaQ;hPO8K`dzp*R^7kYRJWict;R)mWB z0e44MkU0I%qX#W*OcUM%sXRTzhhwtQA2QMs1A7o^{H2cpxx`+d*^H?}@_WS<!N$tq zuB{SvtlGA2sCbz<YBVv8DV{jLX;DgptiWA!QS(rHoS2yOToBkeMoG~q9VxN#2<<?5 z@4NU{1LISf<)`FRX{9rAHH8(f1rD46Wd}9(JgYcg=h)nAIa;vQ7TudY^aH%XT<Lpc zbLc82hV;R~p;aj(o$w1**t=Q|M7%Glt?MZZ-cvFb?Yu--<k$ruxxqGJU!KgiAe#jl z*}yCmA{*h8JOa0hj$awNgMMzhq;ZGzrn^il1wR3CohK;bR)*OBUHr8mznEy0D%5Bi zpix1dZvvq4Wq!yF$7U_oI}g`#`yQfTaMD@mw>uv>eZ8LSCCl=WmSm1p3b}Bi)nDyI zB42~B!Wa($qIJbxMXeT8r|bLi2S2%kPD+rIw%^>4Fx|~REa&<x97mt@oQxJr!j?_@ z?+tDbQ$m<O+Knux5`JXRMNPO(;D(deU`#z4&8G+*Z2I8sZcfe`5srC?mN1B&%2gMG zWB;L&qSdb9CL8)iEpPNO#>`;+hu*oKZGNnBO;aWlraH0+$Jm-1k8OG%e>tUq$EEa_ zE&)^AKM4&(oB!w6wysDpbI7=sYCcu_TI9f#zo7j4c*y*ekG}}_u@&oyZ4K{<{t?aP z)V;)yI2^f>H9d7=tO-*HgU|>{Jasl<aYyhihomX7qAA!yvwDJz0Snj<4C@Ol?!Ua| zMfV}aYoeBDTcKC?+ybFCBR8WBa*R{FeQ#Fu{0EOF>v1_P#>a|_bxwnl<P=n-jEqQ6 z7hJ+8Ga0`Xy5DA;9)5pVK0*WEg|0dO=7K*T%}X~fz#XI7G#J%i%higpjZUt7#3a}c zF!cb*zRxdb^*UTde0_bNE#61|yWK-0NJs;;9v$(|AHgq~Pyf9*(bci3_6KIC0f_rB zt?+Sg<rdqu%V=nv?l#MLGPwdl@Rc1;a9(#?19E)jVq*wGeSc?!w`v?^=?)QeHG9tB zDvV{8K)En{xWhwj2>E*^xj|q4rCQM6`>3ltkf>)gxd|j8w&55Ox)DkTuCGb#-rjR; zZ4Vtbh`D_JIv%2fO&?){dNr);J+JveMv6jD2;l-R1n}>lAJmkbKNH9Igr=x!e$Y>_ z)5bs|PfOiJ&6mv=b~H}^4gDA?rmzH<@HTwms4SE3dakoz*x)5pP|)TNB^(~0=`AE= zQ1wgbt0zjb#^OQ)cz!1KE!wPNf@+axVejE_;j?93I#)qxHUym&OC;L9u8no&&Izkh z;uwyI9!4HGXylmmJ8{B<_4PcT!)J21V0mwDf_MA87?;tIX6E?Rr?1aW%1|Cox?GUo zo8qmH-KtGg8haV16*T5gP4&?UEqZBX1di0OA#RuF6kKz2fGMh>RBBX@1ckgS|4~s_ zaM+yF!o*CUG-2Os2aE9U7f+K}rR1hcEc1TNEDbE`D>jN#SZd2d*HWrF$TfPJRxYaZ zyfYpe86l&j90@I^q@*;S$<+q#McmB)`W*JW4eG(+GNPx9C64I){_<Gns+G)s(`{Tr zBfala^MF<KEN9aiOHN8MiWm8LtiQ0Zz-&H+BbWWiP}4ah+OfI5`tsiv7XVDh6puD` zxpZOO9{*l&N=x>MQOO=WuAp2a)QMD@xSt$0zwA0&%<soC_Yp|tWk#>J_*eq^!7f*O z2zLVB8IZ1oLUVjJ)u{2Eq~>76!;6^ZG{O!(&?6ID#~v`u0nzY>R3^V!-(W^@YKpM$ zaJqS!TxI5s(qSAL0|qvL3XQBvS1N|v;NcgU&c3Cy2}6?kM33y(g?pz1$J37c*E;=Y zj!6oRZ3zgb;0fKJ9Ayg6`&+&6u*lmn?xC*q7_<DZ<oSex`yLN~=#$7_CZ_(`4~3qC z+(RU27o`s3%~0wvTwZeFiON!xd`{H3y*<r%u!~4W4|@#Memc0Wwm!H~XaE_PI{@1z z-mtr>3pS$3%m?CB5l9^SN&l#cU|%YYYF5OL`2<hYc8r}c>=wH8LiBRU;XKzKhy!s1 z0p3aeMt@FTVuQvuWuv0(zP;fjK)vmmvs#TVZln1u+2wwe1!uOFr~>;MONeuK{Vj-M zm#D<&)Zplg$Zvg6L7wqVgrGEmzkRID<iULHYo5L%Mx}Sxz7PSZo0@;q7*MFtl9lU! zaO9G(>vWnklmiA0Wa!${;sr#Rr!nZb@UJrTkEbt!4P!U5A|P(@HHmU)mzKDFc&$Y` zQ~$Cf;4y<-EZ0g^|7=z&SD{d=(n961S!S<Iqtg_*T5qm5KKk*|xD%4e?*&JzR_2&2 z2?eLZr%E~bQa`hxj(3KEaa5>E*lfzu!~KD-Pv!VB&6Pr;1=PX%-fPa}cA|YQ=JxtZ z_xoC9m%1HJq`DhCKGYo!U&-sMaQG&sq~A`l(dlXJ0mu2?#-U%My3Y?fI{4Oeee>-+ z@#RnPb8+U$^U!|J*zbN39BwIY^s#?t%#VB-{f>QHET7Vre;>8+dafY0_i5iS;eL^; zdO!1-()Amw;%@TB>iM$5wEURSkH6Xu40Aa)+>2gXb*ZXjyWN-^n*sKo%D?5W;Q;5T zZO6GE+zT4sHGR3Buulkp3A?3H==H~rMjhYSQ8>J*jpauH1-#FZ|5=(?U>Z8?I3k(2 zquGot-5^_n$qHT{n*$#F^CSMqW@L_aT{yIXwr)A`Stl}h!mhBgHlX0*Ms>JZ@7HWx z4<T;W!1S0+W*A<7w1+jIvOVHhg&RY0gyJMYMSPRFkSNYCwyZ`{?vf+!an_)w?)p&f zj@%-*F3uGb@8MXs)m0E?<{#X@vz}R+P+N=BCwhf?-S1f41L~7X3-Cg>S9C*`Nx8B4 zoe*HzP5s17mZH%xZ(AKo47KHCeBJpWBiP2H2NG+BU)$2&1)d)Jc4iYirI8@_Uw=bX z2CT-~5!;E#oL}%|i(FaKqUW-8KqPsRW4b_n#SY0p*R8c8Hh-%l3qWlJJO7zH-jlKi zW02Q9Pb2!PTc~ka#T;kq^l>+8H3Fg0U<#W`ubnJJp)}BS-u-ZpZb-yCO)aEIM`r<& z6iS6tWFk+cLd3;IrFnaP=qwtUq3@f8V#Cm{j+jcV45rtiYePF|g{Q^hEWvZ?8423) z_rsRLe}IyM2oYoqj3(B_7@R<rF{WU8ss_TnL}Gkxr2p-(4}lgV4Z7x;VUORn$jY`Y zo1-%O*CwqxZA54&d6iD<wk_uHGdjJs1{|{0Z@jVsMnOVCKilKb%)ug0=O>yjb#!3} z4F8Fd_vIW1QXU@MG?*iZ?dz@sg|6EHX#~PA`k+JjV=`LJ8iESV+J2=)v@+!)s2^#x zgkS;jl0=;DVVlX;D)33xq#~kXdWgRc7!l^`qyNUAwMF)X2TVoJ)o$2d$e%txIRv{} zNpZ~)@xi*ZQXI~Zt-P!G@*RTm-(S=3SI;HaqlUac_9Jh=2V?AsTbyus4H8W8WJc3s zMq5~9HqL}(acze{o8L@qyD#KC3bdW|@UfU=Fw0;a3%nc7pD9j|bnVMMBc3>U*IGfR z@AbTU?_D&HDmaX)7H{_+sz0`$%|f^abfuRj9&$O%So!c=u~=9TYxoJ_qHA8WRmNAn z;Vq8zhR8$tzt;m7_i)&aF$9ew->7bS<4&LiLRsKFjxUM4J$TJ>n;ruCqYbDOg++b! z)M6G|zq1(l0*DgEQ+ftC^Fkhrfc|f;RlN5*kf+J5a-s!-A+MSeenrQ6GbQO>E-eNB zM}4C3CoqCQ!ej$``DS)nGFesS_R~WM=XAOG;>mKo7!?=R3PO8~&|@o1@MSAz!{Nqm zHL^gdN~VaiE&mMS%zxJ(cAN&X0X6R7hBAQEi^K)MV&r!?GeL%p%7umxJLXEkYeGZ? zxj#lVl@LfE6mu8q&&~p2p%D1J>+Fmm3F-|vItZ?uZWQ(f+!IVo+-|%kt&XuN3Wn)x z8pN~^=-dnmw2C>}YkEUrr5rR7-?B6MTzjcmuOkpbBM+)ObcMvxD6HD}OTRp_Db6E! zynRTIPFv$34ry{uZ$R!uxk|={$Et4T=jTQp7FkJlauhg#XpockAPBe<=vT=sKA;{% zkwFzPwgZ!JTjL85A5Gc+91Ala%whggZq4bK7tkJIW_M}|_U|GK5JVGeHCD*##Y@&S znM8Fy<JNT@dc}m2Ejt1f`y3r<*12Edsa5`zmx^k!+xWc^x0RHX^#fseetDJJRbQP) zeOVqm4<$=Duiu?EhUPQWQ&jVf(6Gn9M)RH7sLC}PcSaIAcfryamdnC<iJ+mvK)vJS z`FbN^2z~U-mM$VBBHpp8?a6Yr5LA^~XgTY3Uels4_gL%Bc|C?6(y9@aEh;7aDTP6~ z$>AY=TI==Vhg!J`q!T~t=i8H%On6&~>Zu_fp-t7s>-6ksyxoR8uo5a9q0U$k>C_S- z()kD#>K+7!Ri;8)5S9wIWylbh-#p)`172IKG|X{pTy~YgLfE)wIx8y+XLxSomepuL z99`p|=Ml}AYcZZz4kLGZmfvt9xA3tnP+MpHZiGL$pqdTt+>5hBbEv_=%JA5ly)v1r z60aYqMBRY!X}uKIjboKdi7jK*XOAgyx%Z%->5)i%;=8AJ&VV_|9l|~+%&~By!BU6J zmsGaB30NMm8lBzc|Ilup*?Cr|iNGHItw-J8uhaau{TY{kO)&C)IO_XlYAEydU8%y% z1EH%EJ(|LPIP=6{WM5IT$SsD{G7+)pzU4+W&FTL6`@lwp)A$~aczw%-6s{AHH-qXu z%`r3{-h>`NGrQyQRG?5EV7qSVe=|;aX|^%hm}|!HaA+s=e^mFmDxf^$5KWsztl=M@ z{*rTEKvO((0Q@nNaJ})cQX0aaaj)qy-cawhL|nD%pG$#l#l_?`i@<kNfGL&yDW}fN zIGX#-S{UR5*8V*mU%`-MFajpRgzb<Q_=js3O$7=8UTi$6BpVtY?lp>cys6$%G<vmj zJ78R6%%H8{m*$UAy%72wHMo4*>ZGR&U!cac`0cKO_zn<<jL8R{W;C8P_o4N!h#4RC z&`OFbcR(XVD$lYQG1L(|;0_V(<>sG)FiFw|`CU7y-bwnTJ|e?bdem`6(K0<z`{JK_ z!=@9G$(|G20V~6V(Ul^!a{4J{gBrv_awD@7kgWJk)p7W0I+692IXT+QP<8;7+>D%L zj|7p!ts<K?N;az=(rO@CO8IsCl=ATptgK#iZY)U{tuO$wce!zNx~*E%;hM^PI8Q>k zyjyGpnAH_oBSj^)Mxq|6>5bBWizCOfb~#p?o2UP^GO5*V-fX3n{S!E#f&E*@qn}5V zR*`(z>}OcBb52%dkmCg4K6{uJ=LJWRck-@r&r_>yQB6w_KLJ-MAr0#_%|=mIR&9N9 z#Kbns_eSFg6MhoBhB6Tgdo~<Ly#3yFAy2w595F{71fK?<;)4Em>{Sv0ciFbV`d0s# zG?BUjD_>oGd2y}L0$+zTfk@N94RaqxffZ(0*Y#TlfK9sH`z;V|GWQuM?Y0nC$jjnA z>3wIYX0U!-mRC|Y*W5pwd!+H(=2Sr0Qseg+#bx254Umd~fskwKufS|Vi`7)ePD7Q! z2ZKKGJ#!w8-<-v+OJ=)vd<P)&_I@zaIq{8rYDf%xyMNuSk$Ja2qj1uE@6-tA?aj2f z&V~EEJIT}R5yJOwo0%#>@blG+H~xZTdfx)LV}bKA_c`+%0d-KxlM@TI-gR^0gkXao zYt^pjC1ZoTelB%Fr*rQcnhv)7`7x;$>wPczqpW2f;sx;?PRetKS@uoA7bq?CQTN9% zV)uSls!+Aj+|wRy1ClB42wi`~ZJJD8KfgrpcBHk}*>1+!^xd|L?<4-Qf#?-@qPxLX zC;gh`-8T2p;h)*O1k0hY0pwsjV~6Oq)e1IR$q;oNZFM4}(!ppF=w~M}{Q8SL*L(3= zG8L)NYP^45#N$J0H_)lL9bfW`mFbED<H3VBK-m#3uP=3lczWA^uy2L=Gh@v$!>xus zh0=;o(3~jVpK+7Zk^cFF*D`Eq+hyF#ytC7ail5)wIlqJW=Yya7XY3c#;X(l<5UF+u z{$)F{daco9#00&1pgqIH#(!)^%&d$3Y-KY?(c8c^PxRy$?nzb&<HF@<`9;G+;<6qe zV&9b4&R)LxJf-}@McGF95)epQN?4Ah=$HMz>HOkrHydCJ5cKl0bocoNc4n<+)WmFS zCwnmTNqsvYC3_-X>U0iNU2Ycv_JK3#2GA?|+B-6tvKNaCCL2@8cZU~?525qd+3ybg zuM4J)jDFCA641VpPa7+{0A8aTVrC?nu5%4}!W0*VXWT%p(V6`>ReBnq+bf^h1JW%3 z@B!rp-GFH=&8Ae1J|74Qb-4cJcYXEib6OzWDnG!1HQscGIM?=>p&&}EAIfqk6@1V9 za;Ou*A;9HQt4ol1#m{7~MJX$H?L1Dz(`I5hm)Ei&2>IZ1^TN3$|6Z@(8x%I@<Y<$a z7%x!K>t>?+Qs)j_(sbp{0BAKXdM-fjD)i3qG{t^GuG2|cYjSp7C)R%JbJ9XAG-Og_ zUQY`PJS`6by6$aXS|2T|jB=Rn@@X}AGwQ?T739AAdS(oqCq_XQNgZ2RNNFmtzFcIj zy<8jspN~X5T_#2x&7YV4^L`wtD|)bdk@Rxt9{}+S@f``m(*IeT(^l8vjiQ>-c9>;* z4AQwCRUQnN^DL4+bS;wX^QWF?(3%7Kv@{v7c@?`k9TZt6;2|lCdNBxHPF87@m&SQs zoCEHhx_S(rD#lS_cmY#0RynjhTt2f-s{wzSrO(O~cO)C(1~S3LhhRbSMQnL<c5kNx zLc4Y=y2<H#e~-E1j_bB)(>63;a8Uy+;>D~rYwPT+%)cM<1Hew@NNtGgaSO9t!W{w| z_Oj@NHIe`p%8>0+C>(c4X^MLs(N$u#kxi{lij{SyeT(&CJX#T=#cdC0xm*i<BCZu7 z?*!_gzw80M{B@tM|5&<<fL~8`zY0wyZ2sMfg_3GJz-lz!+Ju8WZfBGO)VH}hH)0U^ zSX=Wh@XQMH@+6E9$;rrzzzLO_&#je;KtlFF(3%+(pTzv0lo(A~vvfeXRo}JyOIK7E z?pX7)*_wK!|DF7y>1^?K&7vSnTVc?UrnTo>c*omDk+<8vXfZZT6Bo?VI`O0Q742^u zhDV;nJzZ%INL{Xb4wu7F&ldFR@!vzprN3XED!_U9H+*?bEhhy5-3ndU<BQ|eAu}i7 zoDuKdW|?X!(I$eE8;f|lWA>={LWQ%oO#vfD+KkiH)DX5x`qO5kM{N{zI$e!Z3MD~E zf`H9(nEFwVz3((Ap~ZA|*!|HYx+oei+)rmego|H^dcy=ZQ#|svMvQ332c<eQO142# z3zn#7By{9@a5}M^3sl%V@ljF7rkFf&n&_I;dFFnf43jmGjmq_}W~WZ|#B8Ip18o_j zySbV$bU!$RUr*g2oR8*ibF(Ak5(arrmWR*XbWl`V(9ZK!G3V88PQSKR<(zwXI%sRo zm%+1ijtxf^qCBISU(=-c0A6QWT`c~nwD}vLTiNLY$J#r_%h<I8>aP-;YD`E}E!6{2 zj{xrET-6;r_|oL~R$)GSWG1hbc~tBhkp*b*JI9oKpywue@%O#MBd#x7&no&*(2Ij) z6CGkBrMzfXX<BW_YkUMhd(3t(KK2$LUY?YHf>cdqgjl2GZ?o2*)AbwmSbTlZNvWNL zo)wOW_Z4){!t&A7r^&L2xmFVcUtTMMmRKL6kQ?g|bL_l6JH#J`ukWoay|q(c1)Q@3 z&>n*EvOQbjucJK@DOCpq5l+-U*$F1R*+&L%*ujb(8#AiFS{*nxzIV_+ojwCwS;{kr ziMRe@b8#|+RBP83wRmtrrP_vKd;Z$tyCme-^+(okcYtC1a>Y6(&JJri`pCSyRBt;! zD{!Jouv(zNWPWJ&nG4WhHO6teriW&J+#kWYx3NPA@L-=H`WY-Z`#7@F8NB*!<p8l9 zE3vfPy=VX7an6_erXXDKrD>u+z)tU1!iL5bFA+xBowdZ_d3Vqg`SHZ}NbJZasFxS| zX>uc3<$z99?g*++<?406RqLq#mlC0~5nID00bi6udgB>!g1vn^_3paVuij*$$g|4E zg<Nhsd{1*3?$3mm48KGkR(Joy+zTB>=M${&hqxX6$F0$(&ymII<FrPXtDar_h9^Oa zd2gW1RnWGW(7<Zv%5P1f^XDrR@zc%tcZ|wW!N3#mW|25bs@sGT3b{S6_51*;ZM;Xk z<;4^?{S$m;Dr2smf~n`x)HG3bfi`<gq-&Y}phtY=&rQZtJz97U=k{Dqht=uSVHZ&S zUDwH5ipzmJJ1@Pwap;y^Ad$b9^W7^NH_?f6*Vn$Yf3#@POtX{m^}DCVLd9IO7SenA zXJ{CF&w$7DjMywC#k4=w_ry@_ij?sLBU3^v{CS4-=*LZ|$@-{6k$%z1d?sVRn?ZLh zOXDfpA;)&e3b0m{YA+(8Afonf%;`_25D+Vf^gmL+)lVvw_J_>n4BiOyabdgIPieWO z5<}Y!Y9-I&kqavr)eU%`iTUHjps_RgJN1;|Y_d+O6u-jMZcsMoX^~*x6%2LSH%Tiu zPsH(jVcS>oeA&aQX{4EE^Vd8-(wP3q;!|HeaDsheh~tOtv~xeWZ%ZA>aePW6;JfPd zbEQv{=twvZ&i5TvNhHv9%Y#f&d)CdMH`1fzisPi%L|({TF+X7*@D&z`9bSl6TR(7} zXD6#JdR5_5Z$Amz<|)LOzLkA%oi*j|csoSv`@uQedHvw#vURd^Zt=)if#g(A!`<U5 z=>A7{q~A+#wZW9=W`zdAAKFQ#S_>k<b|95u)NyY(thrzSqxGWtKVDP4&>DgeyoPS7 zyuN=LTQCk_BF9Nbi}L$lW}fwGQpvKQ8>4xLu1UXK3ox5cjY?7zdrVDBRxDM`e92?Q z6AFzy7E|Eq79<YvD^%Jxz@ewpDu|AdxbL^s1G93)_R6xwgd6{OpKl>Jqy(UhnUY;( zXrgdGvJsob<b3L~>p-4jxoBD;E5=nOzPSg8VkmTIH-H7fP{Cr}Xz@S>#kbz^eEt29 zCZL>>6gPm=Av>d`pBWQpm`8YJFRb>ncr;$Upjy$3TMuGaINqh7kdmwo1}Z0>2yat! z#r=HcAX7Xf`y#6kTu3{Z173Tt0w1l#Z570#CZqR)-|0x&xIj^5^|W%E;1G$cV`lXD zoO3&pMI|5{4%zriz0+#IoT8sxQ4zdf*QT;7jkSb+s255mC4t7iIwF*ONfRQnFCkGe zZ5Qh5k;S|A%$q_9ot2vtVA>+WiPwwL0y8k_;yzUzrQ?J#>GV3-qp_J3#PCTqdnhh% zvju#Ryq|i~+z?4(NaCeTs?sS_(|2iwBPsYwMp|7^vtQe{2+#U|flDd%I7^7pEZwsA z{TgX9iCHKv3s>_d19+mf5zEwPgwUp&@!u$Oesw%)VO0kb*~6c<l_lSG+!?yok71vd z02J<4?-8x5xPy3V$5;}0f`wT_4tArkqERXpxE==1{P2w+Usj5-d5JjXU6L0T7GWUN zxfuDaq9HAYUxkWekaSc}?w7dXo=Ora5O`yFt=2hmYZ7hmt7`u43Gy!%WofT;$?-yU zwIWdkt2++r`Rx)eV5=_94hneaS&0r^zgh6ai*TWxxV=L2ZFdl;h>caky$QS*pY`o6 zAeB9xIr=gOkYQc-;9$1g7<W+XPJt3E{pxHIbLmJJA=7u7&^`C?LzvY&6H|+Fgua0( z@oOaHsOdy~TnJ4MUbb3f&}uQHpNT0l-|E=iRN0!}yCcf{7;0|&W$n3>yK=4!tMzyT zjhO4>`6$}udm>?ekj>%D!y$R|&V5Q5q|?fHrF6e-p*$k2fb16xF&qbNGFe4hRwKYz z8=-BIgTA@oqh`YtzQu>c)zb)ZaMRg$xYDRYrHj1+SL^>kC&^a{GqOEU<8U+UCP!)Y zT)Vk}zGBO9;oxZpO8IDGvfY}K5zC6LI6TkZQnf~m$NfStvRsHV*3s@Fi&5z!pr2QV zVCN&TA6JU~ORYC5^KJd<KGd0h%suk??}$x&J+e=LZ-gTwW<jk%ED>U;%=HlF^kk7n z#s;(9D#va2EBA`>PS}mbh0azpEZ3B72>PsUtW_=V1~&0KM)i;K>FpqQ#2d*;pYQl6 z0_w)k^aPj_U*JkEu4j{g!?tdXy*BtT!r#SG1UVdMrrPe&dcP<5_!<ERk)r)(#}gBS z!kskm2dlK8a*4lZz=O0q-yJ9Fy96cz;YqaX(>2Iurs{+sJ%hndh@8D=SH9UL9G4p3 zNUawhd;eN|PB~(U+i{zE6U-0hascaDyjyygox@J>c&JO?@C$!f{s|9Hi=7rIa`%TG zwSWV9msHub><iEuajxX2CwkrwgWkA$Iu)gkX$B~J9vy{V1PdYPkuVpJiRsQ6^)D5E zt|t7)rIxEvuelS@?@RL<3tcr>oA>S@2AdbKFt84B0vUw;Tt?)*d^(%V-#^vH`b-?E z*+(N{tAWXmGh20h;oprZUL>b;9gO-n-)QNKJ7JtsSg13QPM-&WyVjpG#ArWPK2ZjR zzL8=)41yJwekb)<pdK?%+wp6*V|xtZXIfaKoctlgJJ=GOH69<zYO7yzqtu=$pm4r% zGrw_poES<yAvO=OjP9>}7LhRX89vIqpBMzXZz^(cKbzCPdGl)CZ*$!%Q>nF!LH|AI zzR7##2>|_TAGWNzjyj{>aVf&@VgjHT#?0Ux-IdxNYHj5DrQ^N#GBZ(KBUy0o|M3uZ z)K(c_@OLQ%Cu5+A{#H<Ny3)H9Q#)dGqY2tve&}3p+;WZ?+-A8n+u6N(J2IBhEwSzz z+n+IEIc_57={e&+KjVRPenN<5<B$nsCH3yqMlqYwlHu&SFm~&a>Z75{7NO&Y0wpu! zd~d&esEKrPN$U>j58>O_q}f4#w(T$#C6OfUp_l@UxyX?r92E*iVzox<=fwFCY>e#V zbK=vx%T#i+p8O9A7uz2i6f@dA!Vk(0fY#0;?fmnRmY*2DF{J~&;Ty)2iPPiPQmZ2& zZW4`5it$E)J2b$g4M%(|@;b}`a$2r$mCmi<wMuLKRlLp&Cb3Z}sC|$KwMxfJ6yqO! z=5Q1X^>E=>V+k;#95<j=YchCNimJ#x6^zc<oNX0E@ipAhCOb~6P4Ef7#ZpRE1#I}1 z-#81`;N_jhkMdB?Gzw%XYf%)Fn@IhOadrOmz6Fa*@~^N5<F@7uCcrI6LbY0Dlas}t zwX2fCvtW%=_h%KNDPsh{)SQAX4#7oRU~N7;2-mjl!&PZ_kC>LEHr(GqDnpp;N#M{= z<%?@`lo@r#Y-H({gLgHFzX4!|4)qVlCrqK>tkNiy7}>$=GP9uAs#IeLLy8YRhIs4d zWzRs6dB@`GV_vBZmkQEAJy@7>_!EMj#>u9u^(6$%G~~Q4+On3F%ru0l)B_VoxR!$o zsEb8yp7dGvXb61oxJR31<)?)qJg_VlVNr)<C+~9-Rpc#ENj6oNDWy7IrlQOTmrPOg zTZ{^HT?xeJ<XWc&io+)JhQUqbr=89(vARN;`fhFd%N3C4IP8@9`0y307RQz{A(V0{ zVopTcg5d4ae&!r4Iz(uynq$~_g@K=>hRZG@b!8q0$Y|>FGFlJ5H1-U&VG|Fwo!(n+ z|At(5|K`KfbeXuvNRT?yJ-DWF&<-@vUhlSZIai<Sh!q$5iPSwBB&AT_b~=*ZcW@A! z0;MiSC&uKwDSx_%iavE>GgqW@aS0Ju(*t?xBVcc<g?3H3Vk}&H;k0!yTcn=1AUEjP zI0VA@`o4rD4tIq)%f@dp?a!}e1n4<hlPDOS^AVvTcRF5bYcp-E`CGfOhYZ?*UC_mY zk79<Mdm%5fQG0smx}G+rvv3A-u}QGi8`OIv**eqQG)~Xb%rv;6CwuUVDc#thlUnsl zR$!eEW%!@7SZBMPpth^#8JS?UeYETO+6BIcX>VV70WpPpzG}mt9Ca9o9rE#}|D@{~ z9A!$d^qhnozMH#-$l(1fBE^fI!hLWz|H;>OkEJ_LTY5mW2*m4Jr^iy2yQjAveuvQ) z-`R%1BhVy`FLb+H{oH&5v``@mYX_}dQcTjY?eHM4(8SpT@**;>JLs`d$|LPxcEW?$ zG;!;2p<L}Ya?vN2VxUf1rNoQgsBhT4+khE~KlxktC;~S4oF1vU)I};?CPPz5I<ALL zQ9iq!pv`NiUL+eS6TFTX==o5^%gwh~$~<B&F)S((cv|k6@;da)cXO9ldb)%p^E*Kw zdf(wLIIFp?>8d?+ZCxi&1?3Gby*$hR2JMzf0UkZS)J6XuWpY1L*{(J~bt0FrM7ijv zcsQ^d-DJ25CU~^Xp{Yar?Rbs)YP~$Y96w#W6pXUQw`P>{nseJZ2tgY{f^K!3?Vu9q z2R%%NDTq?%#OE=Mji+R{I%s0`&g=x{(ddcN_>aQ>T6GDHP(aN6WIB82uR(B{Cg}EU zN_zO|R6WoMkepkX&2BvJ^pGuZTg@4`g2=GndT$s-g_ybOdx!hxzSBvsbI-hkm9&l3 zK&1yPo}O*jBXc-VzinsD+)!?n`oYzfbjr&b{ls!F5K<>3>tL5)lN<VN;IUVNcNSWG z=lX-I|M0HYP>6AK+stOKVjZ$s^eE@Ys=<H$BsGe83m1-Rh_QNOQ6Q9p&@X0B!i|B6 zX{IHr0_I~%u}XE|Z^TKqoj5)>s^k59_||1hp7u$_uwFnKB@RGBnVOYke-muQS>81w zG6sk^!z36YA!0gDM~#O12wyjx^tsGb-`)VTk;vSiv$hvMNFh{prN6U{n1^3W1JGYH z-pM1zBgrshj-~LH>8B)}e@y3T_TN-CTUv2W5!}(^p_(5X6kCaWjE$bk@Xk(=qrGw@ zH!AT{N`tbhvL@BjL2jqgvs-HtPP$VXEzPA>*?>gI5=dm}R2EJTV*?h3<3k`0uo`a} z8cF!wfJwiVx>=o*AYp;8W3`)`={dxCRY}m<<i>aV!)tRK-*;zhR8cUn)sAxcIMd>2 zhDN{hZDn=2jlcuEU(Ul6ac4Th+1V(0q0VCSx(k;eUDMsTsMJ!(G6OcH&}GN&%Rd`e zSCh|}*}~Cz{{~mJDP)e+0bUM7oYGM#F(i;Gbcxz?ozrYIL=ZjP&^PE%C^txoisZeQ zlW)LQ+ijRsaHCaY?-poc4;ZvN$Z0idgz>3M!IxJZ&J%HsU>}=$F%DSZe&8w6RC|gL zQeCK2YRFd=$|_Mg^v}XOX_qRHkA&LVUS>;+9Yrlqm|@pc#!!t6AF!Y#U2xRopP!Kh zxljG6D)nw!$aKKKlI?H*eM^CGJW~?F7?XIfChI=hSr<C|phx107oKriL3lS~6IXBi zMMkgPPC$n($0Bs1yGD%cR!*#d<^5!`*1EV?<06(nPO6}PLhg|^Ch^=9%{GqF%|246 z%w?k6Tk0fJFt0#O=@D7Jm6qanIk<UKY6NG|LU=c%_d)7{-wo!lqun}3pQoh0CmSyJ z+zSyWyQpU+C}H%sQxB*KJ#uo8sjb?gD;PJmo@)SUH|ykdRJ_O+UpKNdEP6ehYo}~3 zz;~$)RqC8OlxydGGJ&oudn>)NyOq%-V&^ZB=`AIYAY1GBOJ>*@1<=z#yE6^0h0H zZVC-U838QgXD)AcYrDVKv?*b`21$jiL6emVh0oLwwxpg&A65)2sbMl-^)|K!l>>}| zgv;*qW(=1~BF9a#&PpMOZ4X6~W>aJCCegz&(RR{c*D;(CVl84XksceYVmC(`@nq4( z=ga;*W!hj4@a=ul@rVz3oWO?dy94e2Bjg>UD+{*u?~ZNTcCy2c)3I&awr$(CZQC6u z9ox3wKKI`LxO&gIANF2r>`{BxsH#~tpSi|dKQc$;>i0LWE+%UTI&Ecpf%E&{h3?Ef zn0ySK^oO(EsM(fht7JaZ5`SId3X&J=1r{BecG)^4rMfdu`V88O^E0S1SGF$3(~Rp< zD>Bzm@2$%s)Ju)fu2!`cKbAM~yY1JqfKbmO{bUDHnzTkju*!3j^A}{^rIwWERBCBs zaox5I%+6-#$uLgja`sOWfzYywTQ06%u5Y!v?KQeq9gY2p--ynYsYikFj!eq63rS}~ zc}8VKzZS}~J#T-F9)GFzy>C1M(D<7j&-1x}QWXVB&j5NkT`6*p0}E}g4P}B&N@UQz zvl!Z;uuA-yF7;~74rt3O`f!18b1lx6v^adZHXY8ZLV4?Ds*T*oHGY9DmH)joMV1PY z@zduHiV5{=a`QU1Fs45Rl*w!P-~b4XMrB9`zP#CZ0UfY!RWbw&Y6y=LpGloCn@Qkv z!y5vNmlGOowbc*~<TLYy&&wX!Y)-yJdlv~gfQprbJCj#`Glny!7(gx<MH>`*#p@6b z`E;#iowMgy6q~qSy*nZG;$qL3>w?gyc~1S3_|&IZLY1%OUKHyyFBNwhvDfB?do^`K zsHk3g{YxV;G#Ygz7Wl8wbm^rjbw9Zo=7Dxdz+0~e33n{XH+XH}{CSd{N3I<Xc1yCG z{ez(PP-UtXiCNsi4L_k3SM;rbBuw_!u?+CF%gqWjTpRu?oW2=Jn+;eQ<%8qn3FxEg z%d`o{i+4gr&y5CQJxkLO_5*QGRO8(Aq_%+D+X-c&n@lx(F#7JUuug<GU;&@qRrFfZ zlZm|r<BH^oO!`nk35j}=hGV#Kd^SkViaS6RpKFO!1zk8yPmm8t7M)0OHmCdM)zq*) zBaS|y(fZ?MKbFI7hw!T7Tt<<~WD<N}z>Tz^IVp=Mdx{^B7)P^X+_>w>hXcP3eclgU zp9QHdbb6R5G{fLF>cGOh5HCKOZgDikfRcO~bVG<q8cCPs%*w)pRxFV!01bf{#efz% zfks`oNrjz85hgGOsK4b{m7~ILBy~$dOImloD?>P+(53c2)LATnOQF{`5p<#O;>4H6 zW)n$oICKk0*U1)JR;6G1^h7Xt3EQoT#39M?jA4l$!j4{5Py>(E9yn_=Yh2`oE_l4N zV12XbJj<IvZGc3y80P`k77!mih5qBhb)Hp&V|qE=su*<Y_LGKH-Qet^eO0JbdP%Os z`y6nUykNfF>crinri_HJ?F~26`G8#m=lo(yFNzGLoh6R-mfQi9xVn43%AV?2lIJW% zFS^n2wO?Po4F)PT)8KfDdQZ+wP&6m8--h#wpL4Yiz9MWZ$`WD#-yWWbY-iPg*SIw> z=FWP1#nM{n-MY>h_6Zba)V8_6Fgp}R{3H9fjMp^!$=J#&8_&&)^zlu03apgJt+<tq z1DX5+y-yD~Tm>rFiA?jRQN||?aSiTvum9_LNTG{aR?`lY#q%^10LvY}Vkv^vIpg!* zVut(=Q<E+;x)jj|?fRA%y?hC{?#gb+JO1eQMDQQ2yIRbrF%0r3oLd{I>u;VX#chdv zToYIuzuxFJJkP*btj|=0v><KSrg0batL)Ee`+9Am&up%qa9y_Uz>!@p=8fCzbPBoJ z$i#fVf}d&x-UPjT>yItZqpdf06MMMdb$;i0VO*EuUFg3G(g22F_-1oVO8c-=1kdy< zTmI1Q8*cg2r5;pym+qV`WOYb5uPezNkGQ{ZxO=egWkDOVE!rC&3Dl!Zp^go(btYR} zm&VO~OtE-FrXgf;{fSfXAU2Sy)DnO>Mi%AJCJH^=1(@l?)%aW~Hl}R`HJ`N)swT8T zseql1Ji>o1&~Q|DHj=%&-i1Jc&uDwi-dx0O6-v79NlIe~iYa#qN;_VuFl9AccGvAY zGU!}>)5a|LyV|+~&6AidJgPL2_p!m4V&Q#W(JEf#>z3F%g#E$2X1GqRvgmf0BaczU za=|V!m^?D<dSw++AE=7n$ic_w^1Jp9b;VKDYOBt0fPOnH_mi}3+byE&NCA^`d?=vR zK&y(%^avIVc)dlWXnwV@1W3%WnqGOsm>9}lo2)(eY))dB*K$khKSotA`jtvr?=wGi zNUap6NKN6t^FA%xM5A=M_Gk`uFUTk6FXmeoGty;y!F+jFaFtmv_0-`7+?Vcs&RJPb z+ZOJ(V`ro|?L$=WAZ@IZj*@BGQMpwAw|eStIxtYhA>|>}yXSXSQkA$J8LMAMrEia% z%eVPLY3#o68QCku2srT;%nVQ<kjn=qB#y^3#=UgFk2q|4X|%bp<La;gW>g6+|ER#n z-#t3O=qUZ8Io^KywE{e%jz`mDG8Z&xm3~RSo8aGH(MCk_kS0Zhj>~F88&BNCXSySw zX(}=8ZX$^BmSMtXX^e+667?IuS$MMz^w|_p`6i}Cqz;{;md^WnrDb0}a9AlqR~x<B z(<uk4#vUzCPhx-9wJp5QSzMM5<F@)40ey@~hEYl;>wZx7ip1OCYTARQ)gvTV*d;_Y zWC56o!7E$nM$fv-$5yp*Hz9Px=HVptk18SJ0oRD=(pu4z-*X|}SX?OOf$+M}Z9*Sn z+!7QygAeisY(H)R*)S8uhz9|HyLoGhnv^S9SIo>GWGwJ;vFWeSW3hk*nr94m1I0XH z#YDz3v*1jVa$;cVs-Vbpur|8v`WPP05T*T*==^kH*8Q;y&c@sRP=W@9jo4*DPIRf9 z4N(fZ$eT%_l{BUX`$k#&!6{8bdVb5I(CcxBXvbK(@r&AUQow!Xgwo(M%$B^L6g8pZ z;8As^9rtcoeJFV;S-zW=y;8Lj7FNb$KoDTeqwSZMIu>87?0X}oP@+26W2~D&d%!4# z!(@V7w}mpmc5B1m6xDSn&p(aR5t~^&4J^9xh0FR50E-FuG2WDcuaCJgu~g}9;UvI; z9Uky@7-zU;u?S9Hftezd3^%=GMJo){feVrCXWY-n6=cWN&ETXT$hlMiZ^5V!S2C-9 zI5knBGGaVFC9c+HkXhcU-p^Qv#NZvny6$TDIbiSRjQgo7kC6{T;V!n-2$Y%X9iiHj z6+OM)YWO(tswT-E6N%zFcHMINj={-d<U92zJ4QQ_+|ePd<YbW%VjZn%CTUz3I@Zc( z)>5rOpC(1t8;0G<6J<+;#LgQMGI$|aS5h>So;_ph9ybI)6O!7w6$~~SD0UzfeGS(G z?k(aSxb)X~Zx^p`_NRUg0V)&VVg}sPR7176Dh+V*X1kMbWS-wJA8ui-Ry)A=znlp= zcyFOkg}E1uZYaVpXT)>bOqw`HH@CFUs>WJ3tERy41;g*U09{Yl;3At_7hE$69gw|t zD)XK{n^^2F;%%xq^h{9{OHV<#cH`x;dA*<DH)Q>eRg&8lyFXNp>d{kEd(lwPYX_E> z8X4;*hcQ3CWICiLcP2W&WV}P?usE<QTWy9nW<~Pu!?Mko8c_VTX=~gM<O_X2&qMT< z8G3gpY-&A*`CDF0?cg3~%MA&<cx}<x5QiRmAO2|R=S>w}7mB@K0X4NBThBP0XARQS zx*-}qLExR-Uw4)(qeyLJOkj_qtCvpLOWU1q%`dqAKNdhYTE5{G%Nfl_g9j8Z{ty&4 zFK5uX?)ee_kf0OX9WJU9C+gypMQi6gsH@NSgyoC<FuB#SuKX6}lP!yQ5E9#VZS{Rg zrZpUPa(@h&WS!lv;IZjAIm`OlHC>@#bw?Lo?ZC@5I?IIv2zeJ1@}!$c9G*=%iNX3L zFQbn<;sGez%;?7By85-d+i5sECj_Oy%9eKU%mKD`g6@#kGOfDbV`r=3ux##b`CNb; z)CbMBz6|*SVm5VKz3)us%L|3fqs`eJTMP3r7+po-TX3pEE$oLUqG^~;H&iD(!*J(p z%)mUID95c7`H^=s_VAyt>2zE{uwe8}oEW+fMBBTUmg}tmEJI!PMhVq3FR0PL`vSEt zm~xm=u46xzq@J6N)Lm`gV@sdzi2Tc?Eb;T-vY0RPZZje08|yjWzAW`QS&SKKO6$9S z{8ZhpHK#q-D>!p^Uu_R~;228FC`L8As&XJQ$)kqe*G6BVd$juM=F;{`yIkiPW&>Ur z+1=S(aDQsmrK}zEX_b1_mX-x7j4oT4<HnwPZ6AF6`M?VgsSXo7O>#}{g*?8|TKymI z+!2Zb34cR@qb*(|)X64fMmJfEf8pp))f<j7nLb5vTm4GpH)3QK-d{X4Az?9{8o1pb zo%X4ou~jC-kyj&gWu9sGdx6gOBu|O`AmZOC{4!?@*V>!*+}$2Lo;CQ8<f90(OFnSi z+Pxgxi&Hk)EzH3}mm<$bM38G8qy^6l+D@qa5b;Tx7D;=ydWzrse#GW(KF^H8X5_jK z^+DL#d3%%@`M}GAj}(m+Il?gHXi5P&;RZmM^{Pvz#;x9@`9SbVtPT6TU4WD+C1)R) z0kdOI#}IG?Ia5K@`9jq>-m`^(ml7T7L7(p&BTCt?PBRt7;`7Sfy7?#zS?t`<h7wSD zEdG#^8Lw2#3#V$}C`xZj{X#23k|o{xJ|Wo{fLz4EI{TAt(_yn|yLTSlRz5m?vQ_=l zrsI`7qm#6aA92)Ov8zEqk2}A?m|98^SJH(&RZztJZUL&oru$H(S@`4aocbSip}lqY z_+6U%l^3`TXmRgzWTH34;^>gIZNnT)2X78@S0~0_6@Yx^Nj(d=J_?yJ5SZD93OhNB z{CtC`L%s!n4>8H)=Wvu!xeh6H7FL__RfRIO<_0KPW|qo3$N+BiIn&m&X|E`p=`L#I z3^*k)$2mZIM-8AL8_;%`qG@+>LnO%4u{GcIax*yR_I~L){o+(!ULN%sb3|Knh&YaU z1AR!7r(BuBo!(IE0A)^^n$1y|`Jj^DRgg#QRneIhti$yl0qmr2n&oF8FUg@TZ$5x` zow#r_z#_@iboB?SaqAt5&+8V;qQxpe;cSYvHVBI5cqj1@2>Gjqym+7wn{;+mlVQf0 zH`Ocx0{_~4L$J8U_lGuo_o%>Z?+{Jnw8@Z?Wq1#Qi_1U(EMR=c&DpcweuFKk{cKLl zuo<uaAaR+~{iJn(<eCcrioxbJRuy&f!h!CU+}JxnH)zAfdF7B2;pVkhn${<dR)hBj z7t{SjK5`W%Qv0>CzbRL6)C%99#op0KBBPp+LJ4t|{tUZMKkI@lukKPz>E!Fk6a#iG zlH18;7$p8<W|<2I!NDPDhYi9mNaem3H|Ct0ElKxReb;(2eF>~>1Q<P$9o9N*uGJ?} ztd1|8DOERRQUl0V?mLsmqP>mUrtW0<0u8w^gwrW%;OVYc@@UAlo$oWw@9M|n{N~o3 z`@`CTdR)#G_`$5_j}yD=O*5{EH81ntSjG-ri2Ho6PM{ZOuOHnVaC=eBLem{4+95mp z2)RzUuK6GDfRlin%j}O#dx!X#N?yH_+C<$~nOK80({i)5d!VM5K6TeEKAqv&!A`Cf z>5%1W`w>)9#Bz0`Y%OktUP7`XAovVl$0zqL*8>E%aC&|^u+xgV?Xf>(S$9&@9mH!k z0X0DZ>pHh@ZWrM>n2!UdFGruM)A(~}XL-N4;+0%b=5UbKq%Qu<WU{BC?T_jOyJLJQ z1K&pD=MOUYW*$Fn%Za4l*Nzx3sOpa#Fsc1aZ^hIJq&vSFx*MFC?)OwEGiK8AI^Sl@ zwdtAF^_^2HFt}$kYuh)i(&a<iuI|a}OV{c~Ti=OkiDWeCSL*6<pni@Nyl*+y9}GZy z*{!BJxw*PLxm(>A!+hjIkNN)bfzKjYY4bhQY=V9ir&Gu~+SZEK4G7U)>G77kzcJ{V zx?S+lL2}s&b~%b1;4!RN>c_|5j^yU0Theq9?Zr9Ie9rcG?khOvo#usDVmR?L0d+Pv z&OV>y#NvXODIibfgJtiMuBA8!OKQ)<_;LrJ*h;;HH|~BJC5$eb$BtfImDyHntsn1Q z{_d`|xp%BLKIBSNA*?*{5ZPl6S*PfF>fnr}5gc7ByWh4ap&$(Bsy*>ERXPMOL-|BW zk@`Z;eAWuv2Qza&d-s}iW`x))4{)iT(ECItz+R%WRZ+HG4I){)5-yaP7J{GoO|<?$ z-(sByf1+5tKE8l`eg6cK37}HdN{eoT4C&DF#3T3N0a7e=Kn8btVrYLr9u(2>epMc% z0oZ6sV2`d+;G{EogO^C>Mj&UcHBB~abA*%kD*##jf)zGAm@F@qKiS|#C?p)`U)3gr zBSN_)x=f@%bTs;jsG2e88NY;x3Wil3wmN@fofca~rnpnRf}H+ynb5IcHAu}V9ZQUY zx;Sdp)@bX4-(|pCHjp4Z8WxKeR4B*cEddW|9hu-f_RMMCm^>at%bO|yE`u-tC7%3h zD_8@d&l>HT^Vl7oL1MFdpVsaM)sw*tHVA>hH0s>(aniR3!oeOgcs0a{5><jLG5oMO zDPL~veWBinp^a}FlhJHpaEr;iZ3>QvB$?v8I4dq0TOc^xpd>F^vwtjDf^sBkAa3J8 zQBOL4U>s%rTUcyVL_SUg8^vxU>NJa#c)5-!k>DA|)SCBvf9BFNpdT{0S%F7ElYl4_ zSle0Rb84s>WkyXi5WHPwhDDh)q|iL}+k-fTVLvLtdfiT|a>mY_&@#tv2B@Fu7;-mC zQ${RWy^<*H)P+P0tPvAoI#AKt2_PY9nMX}$SBj{q5&$vj4f!$!ONkv6Z(;Ul_meaS zJCZ7<(L<?H4o&?Fc7H-qCjxBcp=;!5tV&vk8^C$%)g`ysx7Zd4tGV=IFX-MNF5v=I z`^SgJo?E3#D_jcxh72NS!vgwsNf=!`^3**GbhiYjmR)(ah@^%v+Nl|O<Fw7$%i>_p z$_hud`gm2YI?Erwo##0rF3vBO4?oc7^X*7Sd*@yLf_B^e81JZnj<H`|Gd%(dgkX?? z?tPEbC5uG?`7}9P(CZe_e_R`WRtOqG1wz2&meSewp23F{pBG&9)FEtgOY3*X$NSt^ zKa>z)+@V|$LiDG5F7S$3R5Pi|nLA3@e)OFa1_2(~!M;_lJ@Ae1SivnmXB}~56pJ;r zZ$2*<7bgbD9_Ep@T5>{JuB_oCT2e>`uIwI%A$N&_J=kHKf6;#VhRihd;`ZpJIBslJ z*u9~XDpv4e{B@a(JcX_YbHaQBB8uu6?95>KpBw_JaH<bOA)-qj-DH?Aw<F^;%a}es z-X6Dp;jAXM#7C3NaBBPx_*c&07-5~pwbV`V_ZuDIN>6BibJWSXrOV^yoPfQqWyhxp zJ?u}OL5%4xM-|iKlmTxeI))kUDHC66c!K+Ur}mdFV^gakzpvW-$Nkzo%WAQ&CAk%4 zfoHg5+`hp(XllmJ0~RmCD{XGKob$cljdf(In9zND)MuOF9SB`PLm6&+6pC#76vdT= zs5Oe)u0{4<m%lo%A!(qAJ6edL0lqXoR@&mfinkqKZU1)1quq^><2%lumqk9kxmT>U zurlqdVLSZ+!F-vJLk9;&LrmE9-tRJI8+r63q7rwnJn_Ct+kTvm$AnB&bADOyct7*C z&)GuyQHMlOp-w0O3u-R{*#6u^Cd5}LCM5BN1cK>9pJEHYwG9|FhA78)qRgoyKf$G; z<2?f0e``}bk>Dp~rx+gG$|V>~5I*L#wuKuWXOr_G<6yBFG1|1hNjO<8P4IWvwOIn6 zACk;bi!37>w!spl3fb9=%<}D5mM=ga=X`B`n0+HS&0ap_D@`YGc<f-BT&RUOUR#d~ zXi@8bH3_#J##fFx65oF2wcpHe`m1%kFTWuaZd%g)ZZZb}0g$cTf{Z(j7a#75V*AFN z;T&gipagPI(KOTW7g9P@g`-gDBl#EFub$!t$%NV;+pA`y$+!^hO_=%yaAZ^N(N!OD zu~Dm&q{k!XnP{`Z`K<%ew80@3drn7eP6SreO-#U<IVua&H<Q+Xp$G?uBkqR(CPkTw zzn$<&_=!NI=|{1N7T`+0m;_PWrpd04!4fLV((K?{iw(d@mt^Bz5^zV}QZ83QLsG6} zfnA9O2m;Ve$vx$!o8t&FWC|ijN9ant;7Z2OO(&M(+n}JNr8p*k`@G>DxWKWm+%IpP zIEhox>dx5JXm`eCq=c-tsVP;ez|qav`a`2l*f%JK%sK=>iOiyxA=Qc(wl>{01^~we z1bfg;2&9fQ<ap9w%+1fCcA3?U@mUeMNy{o*D(3QSIc>qvYG$v$0QYIT7zl<q95(QA z+CpojGC=W(zzk(|y*;eB6+)H!_{!*vOnT1BNc%W$7OIm!D2@@^jcQuNOX5D#IOUTU zM=X*?WS}|gfPF=b>4N3fT$Pq3ruwc?HB1EKTV27GT6h9WHwos>IUE_Ix=*92wTdlk z0u}8B=lX)I-y@zJ_IR<rJA4(!8enh!fVPAimL79$)9Uev*e#OeT{&8GQl~V0fq;R4 zKKg^|;mJ1BKi;0xbfol5FYu?1<AWr~;&KCNkTbg@2cN5!Cz#5$;!b&rstI<bsBDG! zTy8POCG)?Rityuuq0UhHDCqU(VhZ94(-LMz$Kh#h^x#b>Q_k8CQ(%SM4L&E{ETsZK zDZ7&WDmV!K9M(}!?}pVBI@b7ndW@llQUyiVxn+cpDGUL|Y+!Rq)*z8_!|l!D!NgTa zmy&I>g>lq<G4k>0487`#;{yh3Ii`O339S!?kFyHCpV?0JZ1=|&&Hc_7Vsg9D8x-RT z&T{(F)|4kESh>lOJl@#ZeKF79*@(sDwMs+$eSIXl^mC<et6h^RcJS3`DS|)p3vccw z%h7I6jQPujW;ESV6bJo?9xoVl=IV?@O}aMMzkxh~UKC^oLt?CGYysDYG|ik`lGTL$ zjx5JfI!Gf<1c>Xxrsox126=A%hiW}#HkLd|wCWg(KCitmFbU@*WGSlH8PVkemVCd@ z8VRcjb~##pm1E8-huI#9k)cRdHY*KXda~X!>@n&_qM;PGboAJ)-7>8-XXWEmZUu6H zy)6rGwi-!n{3tCW#c?K(I<P%-IO*#I@{Xc1)Si<9x7CTD%@;rQ{DN8!KfZMq5Gy@f z-jC-cr{ON>HW^j0(Ro94gQ$RD`VlY)u#dJ}T@-f4XjOxomtk<8s$7OZN8b5Ml?o+s zE$_qRtTLg;l+IXZy_8cYk0P>4&!=@jL|&~Tx~eG2AHm{sY&W3Dyv&go7~MQDQl`p* z^>0cs)dCk`Kur#diI)Cj!@n1k_Sq^DVzWxB2z6iBEp4}~=n|vt)}QIntX#DFhI_0@ z{7-6&KC~UG2Q$I|W&m=1eAnk!z?zsy34yc4(#RkJPlR%%s@~-vXAZZUAEBSpr354y zB6$&JPFL+_9y%<{C>WzVsprw$MTl$$gn1!QBvX)$NbPfXbx1KZrMoR%Mz|SKiFScI zLd^AdN5U7uG-I|?Y-CJ7hOJnm$O3K{#ac*ObM)q~4@HGS;f5DxxeYn;2ee@{OBmF` z?D=Fy5j(DCk_e3B5m>v5sV1CjEDFXAv|?_Hjn+6iPB3RG2TKX7J=umHKq%_Ye+x8y ziION$tM&t#ZPbJ-D<(4UL?nmPGVnn|l7{mq@E|?LnaAUy<;9zjiHS=JGq)!kc_11l zhDKF~4oOlB>08y{t+zI!`XqHu@94&>2GGkZk~{st-ZX}8Nlt<mIt<?>w3HJ1P1Z2M zwoi<-T;^QCIGa^ZXtBr7TJ>WzUa_w<w{FIcOOS<urlcAFlHqLx9Ep^Ean&Ng8y`)I z2$Bj;AMis}S&rne-wYk)@_Y(YlB{hyPP+#?ZLFai7i4x;Rh?JaIU1rAymCKT_4iPO zBQx|gKr-B^PfIj!q;beh%LftD>CA-<5D`rk!g{`(2WMT85l!~Jx9_)uO{h>?ssVaj za5DB%NVr*kX4tCvPf$!dz5@R4_gH&>>X1TZ_vH9{1EbB<=n+O~pXY<gDwAYyB4Y>% zD5w!HI5n+?S{+&Uj(mY#J*eg5IKuLvF_KGFk*Eg+UnahXV*ZrTeb9vseB%yKw>u-` z*+|wLu-WIZ?EGC$cs5}U)RA2}>PV|equS`dKm4Tmt9wWGDOKBPC6Z{bq|~VUP`P-I z+p=S?DA^MdIS&wsG};x4+vj&R=m#bii=1$Iop8}OzFNpxK4tGnR$8ooatvh+$nq?v z*P@POkqmIPvjsZ&f(c8h3sd}3lwp4Rqb48CbZo-KhiBVhGhtlfy(x7~QpAE~*KO`# zWfU@ql+q6Nexj#{+zl5O;{Hk$X>RNVgWX9vPTHRy2{$_HZH%{Agoa<Tpcm*90FahE zH_WRQ^${{22iD?F@vE|_fdu9Zpg*LthC1)ElH!&MRij2Ys!UgyvLb9^ws3%m=gjyh z1LmZrA<3bTo(U1Ty|q^p<zG1)SO$v`7@fZ~_$QE;znfN92`Jqng-#~~Jo=o3iD;<- zsR6TnjFykf(Whu`2eQhjybvv+Z*r(NV@*`N1ab_}mv291pDiffKF@(KeL&Zq=C3+M z!jDMaL3t-$h`WIlpc@r>#1}1EN<hR0-#^0a27dZo*gMV7#6BovjC9zAVYLD3_;H-T z8fU{3dVkAvj+xKh#2}uLX(tyMTHm#2F#<Qr4FYP7KfsX+<O&^6=10Q6*ycp)^ikZE zmebh@^|aAIId5`ILgfT?Q*II9==3@6RvO4-iH!vBNkWo0PUtg9TSdG1uYgftsB(O~ zL`?m#nZl6zYhi8?hoYv@1WeFLa*=S_cF`^DC_Ys{pi4KvMTR<pTt0|EEPgX-3r_lW z%6^T49h}KlekcMrSsd`3A-Nq`1z3#rRY6Woh|H!P`>1R*?*-UQgJNjB5;R(%0-3Rh zzlBeZDDV`099G)Ba2a9((V;WU)w&3GGYRo-u_yI&r1mHG0Bt(p%ky)i5!99-yG9t! zll7v6rSsiY1Q3HP`3)6q_V3|m_Gz{R_pYAi>6640k%$i{3I{K)BZm~2<J@Y`jrsC^ zqeW{PE*D$Y04n*0A}m-1*80eQ#%rnq_LT+$pnDkz7Nm<c7?rybhe$a9H-P>d2T$^2 ztl4n=Nsm8H!iF=TjBwOEl5llG;f12xup#3WY92GrVx%yUMh1m0t$zC?gQYHNMV3Dh zgSlu?GH-YrepO+LGG8^0aJrI1v7bKRCrdiWvod96q#YgM%Lw-`9oB_PEhit4-IFvD ztOctYhsN{=r*3!5KnZ{;JtzxI)qoxAQ#K>^!UX$q3CPTKBqQm<u(d$&--c(WChZyW z!xTHBM6dC$jl5ahf=_%H{`u}?&-d~Or5`LSVOWK3PN*?<JN^6N<FrX}^A^8Ui>*bU zG=6rjWONg(dA5A&yc_ncTr`{1vU*mpSzgxOWm#W~{sW}>_v=A)BlhG=pd7iLQnLqm zUU6Y})~VpbDtGygMA$lqiqGM4wL^L%Vg|su#vw+e?HFL25kwTQQ1Yf05xO%i8=4V% zBVofHo9>)^6T=_n7WsaI=bj#kIz1(4VW5SDDe+P)r{MkoipshR%#^k!OH`G?l`K$8 zo*lX)#mjnGh^3dkhG%9)Lg{3}PnHfJ+zWmZqL|IvmZd5u%ZdEa4tX_n`Y@QFPA;UX zPLUX*7mpjZeiBot8ROqN6<Zr*Brv@w;fjNVJBd-fFjdLLtP=Q>iuuXPyePrYzyOl= zRVMIM-csBkX;IU{NX4#rPGM=6SL3p*^iirz*e>=PWN}jZJ#WA(`FGL2eWua}?MnVu zCdu9!n{XLs&74YOulV5piiN)tu%sfw;pj&om+qp3d#1UEd(S}wpj;{BtVUa1lamCD zUpoDx_!h+ZYO^X)Fh9C8zBZ$K2&i%<ha4fi#!Fe;##M$=_jTI>b$-plXg$7r`QmeI zt1<f;(;Mo~HS7E4Y$*bd^XhTo@5anI!CCpY*<-q%rTfgKuvVCG0kQ|f+{R1CmdnW1 zFYKS~rJJSBbHb_OWAW(;5mHaRbU5<4TX%(x!?9YLtyU!kR%u0Y8HY-SE%CYn^0~m; z*i<qL4;fIHQXI4kVPW=}JE@`Xr-fN|9<X*OC++D7-z?!hKcIf6g|wrLQ8EOugv>*` zrHA7lI4w}x2KoIVH!BW>%-EYsEz5kE6;{QgnA~x53^I3UFP918*zr&nIkf!X@;(Je z!=L=E+?(Z6736^7GQT(qoeFm+uvLkuc}1O?t(O&us7%e*VBgNcoU3VE4@=InzoQ=Q zH1l6*$^Vn9+v1J1uG{FXv3{-kz1n~@89PJHcgMZhyNwvVMBbXtk9MrOqnmV4L42YR zMB|_QH9@L($n0C3vLKzvbFwRCI9{)geB&-vM%g;&PhLj0L*ZnS2QQGSx?4m}(@_T4 z!oyRynQo{Mez(ia)tf4!2xnudjF_+Y%EeWdD#0?;#_p8)6%)hsS-j|_g1@0^c#^KC zUXnVlIb6<+TOGqFBPTmNu|I5eIJ4)Oh_DSqS)m~Sm3Q}2=>1VavGVU6=-|GN|5)m2 z*Pu_G#_dlpy}DV^C#?B@qjN5_*8RsAAD66qw;Pb;G2gu&JYVCFbG-?$4F*UKSxJ5= zhLvW@u-vcc3o-_iSvY`WY+IHn8?YHdvFC6E^B^BUwTvemxsG9-V$4FVWl*3BT8wxa zGB<GVJD_kW0!qeGvuwzn<c%x1V`H<VbJ%+@vJ87*;{bipB-6LKX?T;0SQ;-|(_Ao9 zR8q^c+)D1kX4Fy2HoU>A86MCRrveG*0U26?ufNew$g`Xl+D%OY4!MZ9b7PVg<K)}4 zKrz~5m&PoLo^1Z%)NZo>#vy%L`-e;0{yPdbq-l1og~8z6vPIVN{gV{T1d`$3PFx|M z1H8{U2x2*x`hOCp|4S7qD45o9u5XXNm#^Sji`YMJ`0wHUy9+q#w&`C4g8#?JG^Nr5 z+RQEPqFebtTJnR@<~2_LpY|xI|6z}^hwjh+(NYg6+ZyCwjriYSbn-ygxoS^TkuIH^ zkl=ww6s`ufE0Gh)G=&Dk5oJ2vTxUy_q14J1eb>*1qcM1^P39<1SDTUE?@zmbbHsL6 z)@zu_=b|8&;QwPHcKE9N&Oh#F5xznvIrc9K3k&UMIFB(AReOEB|M9p$xl%>g%ZuB< z&=6*dkBSOvG?rlWYO}N6dY#Q`qiycvr2AjsSN|jOqJe!i_|Y>nBhzU#^$BBW2boM~ z<p2G+>uDJn5W^GjMg>A3V5e?;eZC{1p&9pSw>upE1G$w%uZ=xH(FM6`z14*^naVIa z5DZgqv)OS&{%-NFXBh285%on9xFZA($6zNBM7~u<8)UO+${z$G3dCkIg$}%dDoB|R z3JQt>suWR0pyPXX%lU_jyw&A(i6AtP5DXC!R1mVqwQ^hyDhza3!7pJd1)m7u0!TI` zIRXAtLOir0O5W4%)ZgM_f`U+>^NBbK-&t#&<I)a_R0+>B{8yXV4kl0Q>Fqzaa~wma z_0m@tny>#Z7O1JIX)+%<Ir#h2<zNz(V&5n-D3Aa@A|mMj|Ha=I#GhgwVzY6UC-Tf^ z3CW8U5rZLX^eNlZZf^)mc+40gp<ho<{GySbj7->kx!z^7-f&c@tGc?HIlfx6m0qL8 z3W_cH@^?N+i}iZRR~vU~G9e@+aDX4-Ke=$rfabJmYpwNW)!G{Wx#<u41WLX2HRS6n zk<OeS<0PL~6Oy4gaH@NlCgqs^h-FXO=@KcFPj8~vY=Ql|h9iGH11(;)*+N-6$P4CQ z^aBYTi|0=v6Ide{3~fiTu$Xp&>14JAI+@ubI=0oTXKXDL^v650vm>K$<d5T#0H5i% zlW-)uu$C5XLPCPw>z%RiMm-iS#9R)GDBZi^2o(!whPRD4(*K^uon9ROtL~2cuxy@< z$&Ny)bY?pjhai+{o=7fKe{Ces)%lXp+XDoi94(sQkYM0vMSX9AGKEffWUHzjr6Hj5 z=j(m?c3Up*HvsSVUgft<-@(~mt9``4vbX}J*HhRiIHAbGux`)UtxR`|=Bpy1B*}nX zfRIY$3b3lG>SBd53_U&lgf8BDndN#*^?YBYdLwxR21CqXC<09YJsX<}l>YpTf*x|j z_f+`LdqYX%uV{{C^u<6Kk+b92J<YLpQU8iD)c@rd0}(&yaP$p@2twW|6&CTgwshJ& zpXswTnJ_}r!ZbO2FDT&`M1qg$vw|JvMM)`0_tTF(@+T*~<1!K=lr&auJrcE9#Q$L^ zfT#~A*u&kuTv{ldz(BY<OYrZGwAt=~+j0U>QbM|3ZH!aBlgN7RL2`XYSXWgeB4zr) z_Za_nAH)3Mw1%yU4?`_DX&^aGv%+CEg8ce=w{<#OggRfT6+NEGPIjk#uiJO(0m4n2 znh3Yr8)sq{tT7r-2#bl4Ni1*e&fDH_&&tYDf*7xi3KgC}%Wvh9(j%v!sFX?1)|wg2 zw5~(nOQumZ3XJaBq8z9AUq1Am3|T}<kswJ1VpRnvCJ`pwz!WaliaJD!y(?k)yDV&d z_3>CGNSiCRp=MaF)kJyX+|Ll=X*WG*wtuT%yqd~7EQ{qgms-GIV+REO*sK<L<_jgS z)ML1?n#y+sseB#}W%CBpsd1rcui-eKT{JY7t@S2p&CRSfq9XcE$03yO^Y6bZ)C0F@ ze)CNd0RT#uHxq;uq@+ccZ(Lq4c2W2|Tp;Nq8ZJ_O_Pmn)v$F`*8qEqg5=}On8k=TY zSSkopBlKErh}M6a<mHbttUPkMe9n#2rL^kwfYc%x8T{|<*E^igOW3;fN;rB2YBSlV z)EZ6Td_HbP8E?&~?6&R>Co4S%L3IX0;OLAKIsUur!$87f1I7d|e0`PlyRQcRTm?Lp zeK(&^)5y5@lfBuH&SY~zX@XQMCnCpTqQH4-Ok$%T>t|a;GtN(i!*+&<ELHZmT2XNu zo5FeCwdWuc#C9UNj-j?tCX8n*N@>wrT}B)<n<vQr?Mn)hF*jb<fu6-}iljd3>2lpv z#>47ZHVa%^O%3z!aSiq)Jc{#^6su|%*%v{#cMa~-Ffsn_oxSK)q~}B|mZOmz&lYm` z<fKfD9RdR45xwA7IC2`NBl(uwK3o!=rb;<Ib4RgcstVz~Ol``*x@~VXm-88=uCtU> zeFzqcY9u<{z}|2qn){e@Jv4KvCUdxPdsc~MVLHLN^VuQC^vsM*b8al>iMduz>@@2e zHo(k}$#A4^bW{|hc(F{iS|ga#@u+AxeZ}0ziaytv#idGrtnJhvYX1EI#y@b2e7SD_ zW5eBWEOa0c^!kdxKrj^53*bZ@K=4Zrf8q)EC&;D*xWQeSErGkXyIG9Ue;z{qR)}?{ zjG%n5W}y+r+0D4(^=)n^vRy2vp;i(ft|B-axr2*ymx%TEo>IE5x8t2-O0KZEY}jPL zzJo>X-`q)0>aUM|VW}B|qtzU%W3y&a1Bd&*hHqWc8D7V4m>1jVyP7@&Z!AW<FQh?> z&~Dy~{EN3#5D*qkOjr1VGXx{gjjDuix@Nk;F(ixy-Eb*UU%;UR`k&pRG9omwdyq3i z--~Y!AXeXJBvx=s%joVle-hnh=>R=a<MWhP2T=trE_D)Q)9s$|O*M}GXz4ZNBf}&+ zQ|3)JbI3L_Ppj>pvZzGsj3gIw5lOsN)>WsoAsc{X!eC^FK_fK%{E&-6E`;nT8Q$S( zW=wmA17Nn=52$y+h0jKe+HdGBtNkG9g=6AA+UI@VDd#M{18`Q4Tf8QR_HfSoW!@yF zHRA)NCdRA&mvrBQ&SEq!`2Mh&;(C+4Ul$P*GM8fwYSmU`nAc!>cSW37wPek_BC_YP zckpwoN^$lk?GlsqCGEXq>1Z!jYd(|i_>Q!eJ?@7B>f<RRMUAY8c+RmSx=;P<>zd{Z z^?YNacmVPf`;`nKZz3Y138w@oLIpdJ%)9MQTQJ>9H80k(p9vl@fpc46;A{fZq@k{U z#)38sYfp`}?LZ*ll!@}>`>O=mGA2yrD)k1!!hl;7BwQz835;>l#lLz3wVvH>hyUSx z1wk^Eez;D5u<z?aZ88>$g}g3}f8W*-SUR;Z(b3Dsr>Zn_Qcp19{>0%$lc8|bp3{Y! zD;}Ix7ok$m=k+jkwadMc80Pcy^LC15_GE8i!ZC<mQg-qD$d*n0(3X7XA@8r18ROU3 zX^r&7gI=Lf_)~S52W!;{u$ZD`voA*lLIHP5r7k0Tj&@ZyTIa)j&IIBAJT7Pnf15AT zT4CL15g!`_Fp%shFdFPYZXfZ~TQ9MX<?c#&fL+gigZR>Ars2y&#=y3~+vQ`F4o~Ui z@TyO@2-GLU*wI{n%4I0u2P37ibkS5Ga$;cMi={C3hY2w$S+Alrmh?a{R1^;^WXrWm zpe>eHcAL$X?;TTk#kMCx93&m~FDPX1@?C-eDiz>co(Ga2Ws<64yv}%|PZv#4hCg;5 z4}=2X)K@v$UIu25k<RovT;*1#7@jKGF4IEKo%qE=8z>D$VLH7+J~r;XB7Dl$@U*pd zHQTYR!txA@LzRe6k&*YzqRsiWyl}5JdIC$sq9lu04T<Sm_oApMk9VcX>&C+fVH!N; znIv9=k_BOnSW<F#_7oJT)G^Ijer+K#&8VT;C}SJ!3|%udq}pbbJ!xm;Ll3iiCwY@p zvrR&{V;!eRqBEvIK0IBX=SvKB+)(C)O$}>Bwil36eW8-B%Be$O!)%d-lTDb)8D@@T zMQU1iEyn5U7llSJxCk0&#Ny#<!2o9F$qo<2GT*(a-w(;|NoEImj~!OB3bzw9;N(_n zp{eI=#Wq9W<l4IwW2`GxYw^{d_Tgjgj_6m583l&E_BxzS1wpYdYa|S;##6pc45&3Y zMhuVoOmDsv4-s4S!EtS}O<7r_Gh@bz|Nc8*96+9;25uS5G&gcArFY8|`Zv8;I8Xw! zlEFdD>*gDi(y`b1+IL$fHN1;rJ=XC!C0ne~)=Zyope1kaaJ{ba+G1)SBgN1BbLKy- z;*2K#6y0i`cnU{otmkV}+jSQ~{NZx>r#Qk+vz-^dD!;T;x7P=cMx{y)6w7e`>Z(R; zG?w>G%-iuR*Y``^{Ih=T{O?WqMOmlIWknOxT9WJc*XL@BHIAvW|N3%`_RlOXX9;bB z6>AwK-p_{xv-zTMi_yPvAxXAZ?2k8Pm{Jn~X`Kt{c4e4av_bLnFDxMoCZ(H(0&Xx* zmWs()!o@LXtoUMjX6G8YjW|PX`o%3J3tJ^{e+T0KR1^p(Kr{rtT?^&R;efrDh;htE z#kb7Y*wn9J6JyD|D2)M&Sp=<Cf1S2v2K_vY##9HZi0t{%hB&e%960QbJ^1d`ZUds% z?I?-qt4H2=LHwe2Cw2g7A^310+cGJ8(18imTCqG%^jN8g68bKxK+vouUd5b0l4z=r z|Ju*Md52foFCaL{6ri7aoLxTT=%kCnt0^$%r(SYZ+;rWAf{4aXbtaRxuXLc2?sP_z zib?riqKj1GyrTopyPM+o&CEsGcl4I%IvdG{Uv``2oEz*260<Ab&8rw~`<O@s0vU>H zo2}g1+E3}&i76yM55gl^kg-leby%(HPMqE(eY%T$x|yD%7KtbEI?^27i$p?8426#m z;Z_hW=IJ{!rg>DI<#Z5I&4Plq7AikhdK9f9_j;P~6fVO!hzK0)p>FF+;SdVPOFdX) zvCG6$)RCUAh~ok0S7Zwr=Q^|r0fTa}%Nk3TOY$k=Du8BARA)aPb>&08puP3m#Qa)8 znkUSFcx{V(i_+FP`*ky`Xo>y|TVH-DM^mfzgi{^k0dB`lFM>$n;F8V6sZ$TW$>!@L z`z(lb<(odk0XsB4sq9#C8}>#sxFbn6q;33R*oxZWz#A5mfw(_a&(B$`rp>qM?#okX zhAdKHcmmO-xe)N51;g_k*GjDcRH6<kSey(EjspRsWs*nsBaXfeN7PY=ra8WkM@Pjr zJhlS8>g#l^a`_z$5o?<93}b{r8!duh1hS~Em9Vkvqln14UsC$?p=cw2H{}*!FP!8A zGwE+?PDQA;5DoQ{eEh<!pff!wLM6sN?Ow~6__Sp2C`Q?irzHfEL;5@lirldvTAWqV z-+PkjbvQ^_PcN^SHll2PvQZ2E!Z-T!_bohul+kSnid0@UpD(`YOcqe0{!~)~C!H<+ z?Uv_tzHBb9UZbMTN}K&YD(A~(>o&FH@?SYiRbaQ-;e7M>C|oEKog`Hg`*SD?izSJQ z-qxl6*IJc&W0DG?<!>e?OkCWmF-{wp$?u~~+Y|q35Ghm-508Lz{RRmH9?vHwQj*Eb z^;QOvD9rqXv?9a3XmM_G*4GXl&r8<k-4LCYzauqUuEN^#{q}aY_VDuQS%-hc1j$q; zH@1O)wmTx`;pm%!(5pZQ@n*xG?vg0O73&DyjN}`2U5`q8*hf{0;t6>k`=#vrR55SM z%zLGQem)965>felI~7-cvOP6Q$_M4|xuSpJ+H29k?5&~fg|sm0EW|0gfS_lExjc&- zh(=L9EBBN9lLP9|KuC{P8LC)HT@ayqXsmX{G=a4AKQo6LMnt#$O_w4Xh@fljIR7le zHI(<a!BNCCkpgvgZv?*hlI+mL@F4LH|83JQ|8&ji9GW&g3zVtXOB5xgSB<&Ii6ynq zr^z%&Dy+cL?<k$-h1|pe*$@9OlHOef&XAbvD8aw+B}sfDEm}KygSQEr?<+l?dm`<; ze}=1<1*`ikMG^(s#e;@?TB~q|<^j{62~R?Ayc4A^)=<pR=pl-U67LQ|MD`m*!^7NT zEmLqdw-~YI8e%HeO4OKxK7LQiA-eT;MU_BLnULo@0ruP8Ha}mMN-<kRtJpH@E>22A zT5#^DnJwZ5>Sq@z2<PajBSp+GLx`F14(3E_A;$hCVhrNc269*i18jdLo`rzxZ)6M~ zaLJPIh!%oaQDcZJ96HA9PzyB{8}0$F9!sKYSlpS?^z<#0FBvkHa<?~^5>^<?$?{;% zcuBq}f|+si{>DQb%s-`2T2c}W&w}v#>#|2h@l@3i(PYtS5$1pfcaQ6M-97UaF;MJH z`L${IPF_!l$Z)+=?h_#=TQ#C;sa2*kn8xOwKA0DeLEZrtd>aj%mz<e5#L5{XGPHT@ z^c9dZlxhn(T_$k-tJZ!uS1+2y%hg24jwN&C2zGZ6f+yMDExY*;z{<1yiV_<T(n#r! zN&-PsG)Jo;#FeUT@YxwI<j<C@nqvZ^o?~qMxu8+SAc$E^C9XZ-9)fRUbYKy(GXf*( zcLiHw|8S)#OsjF|Q??ZP^(-c?TvL@6;W)uRjtBhk<BN|~VT3Mr_TZ;!am!gqIcVKT zP9LPi#Miqsn`)?zR3J1EqKn0>Imy-08t-c;?HH20CstLg#?fAEKu0j|lf6EnYxD&A zW{$2-PuEe^x^uWUPNv+F`#g^iNX8accD~>!Aq(7R1#~V^&w@AWQL+nDad203l%I!9 zPHdUcu8$%YJ+`-N64p7B<}wo-UtKYd^v{f=zuvbt&0&Lgr+TiJ(k8`Sj@SYrpI1iV zL|Hb2(iouue-a!dJ!UpWTs>y0M0o-1FAEzx7TAO%p8hY!Bc`jyCK*}ns8r$ubERw= z24F7nT#3q$7-k!CrTc91y7NLZ4RBYp`;)hH_SX`S5(#?=Y@zcU8&4!9wOr-DFuU4( zAN(NJuN=cVW29M140*bz_tJ-En$dZ`8sIjxnznZ}A3OnD51vVin-VFfgT+3gPPG~m zR50nI3wgiJE>YB)50yg9Bq=UNXh-$-;Z-3lNw;AJ+WRu8E&J^AWQ1gs?wm+cLG{<r zXO&%A$Y65f_&(PHRuXFyq%!KkaTCp?e$|uX_$D$)6Q9DC9lH@ou5%S^!PpWPJY$GG zRg`X(R(L6)yq6ZX|2Ei}CQ>VmKD6HM(MHnLqIc9wn3$Y|ndSTD)^XbfGv51~S1MKM zbZaCVCfoQRz8~lM-kg@^Qr|^EF|cJDUviU=>G*y+OXYB@zxKU<y<aow4}d;gZ|kO) zELUr)A~|%O)0W!z@O{02%*@Q3!AV?ib)y+h7Gc}s-Y#p}QXyZqALkUd24V{j7vbuL z%1AUs11zEM*x!E}I$T|>HR?64T=%@oAlZ8HNHsB~j~TbxY*s)H?~lgPI9rjUzjmbe z88)i2<sR-wVlV`(PiZ*g((0#R3Eey9rt%K0OU-O{2l4r+$KX*E$Zw{GwUI7dh-f$t z_Pi&Jaf)Vb)dRDb&<pi-6Pw*0iMn;pIA4(Rkvv^V-&j~LfX1Ks^IB6YzCz*>JJeiy zvfO~jJH`WbGFl#4T|l<MT$^|^dYeh!o0yGKSu;6GFc2Rn*xRi$sP&u@8sJUlAGg`w zR7J9pUf^EHZFD0m&|ePT<@yNsRsTw|eL*hiT_ddI4*xHyF@#8-RCuY_h;&tUTF-A; z6bq4=-LD^2FG1*VGWHy|vs_i19=P=`#y1xyWNwuTZ+pLJJV7YnFNMWmd9X%;c7EsV zw~5d4)p|7x#yc|gQ`A4DHgjO%!nOX<uK%+9ZlZ4d$;k1RXT2V?lbU+uYrVeguWcmf zGK|mBGrXQl?Lbfe0lG}D9k@?aPpMi+(u2D!Gu}c3hp)NbaKp-?OCu49n`%(yDPm)I zvbwySoTHd+_w_(zr6##dUI9D0w%>Q;{PO-=S!1WYV7IYaIUSnk9g$NN_xP!1bfewU zj))iy4ZFv$$HciT3gKl}phnCOXO&S^J`$@qeT<VXVXAZNVWpY$)HZ&$xaZf*nh2=g zSCnnN)4F_LHCM)xbpNRk1QN37GdDdbL~QQh<zmO$!6EPS4<hOxM9*f`3JpL#IX__* z$fHL5a_Ho?{tAOPTRq@-W%y@$z3Gj1wbo}`TyAW=jRSw`)c#X<;h9aIUJMvY@8efZ zyZi@%&lAp6U>e%hlm`*x)Sph;nr8M{uuB+WSuDsz?JlRtxE&4{hi5H<vv*P#W~5r; z2tOBix?xE+7fiB$QoAF(>2D@UorZmMdFm6)fPO{r53JQod;;zrpV-;m2@@UVAF{gP zGoNz;B++D*t4r?qSAN0xXr?w$T5?A=pS$dHA>k`)wu%~q>fd)<I>C43l;&goPTzD) zD40lj@T<LKo#;dlHN#y^sfv24)^_Y^D&uflHZNZG??RXQwv7H$gV00T!t|Rpo`I95 z^4*SJ9=CYXy>B=<i8`#Vv7uGyutHh9JO}^}2kw?QAd1z>Y<4H5xzXA>vN^UM7TyyX zw$5&*ohk;ZJ(HTSvZx57y2oYgVz+$!BZnlyoILK~Zf{?l0r3?%dh;CJ0BAFm5(0sn z?}`M@mDoTu+9!F86NH}N4abuGn%rRq!}xRyt=K(K$i^{Y!ssb}#r~^qG^jcd<}tqE zjEvu=VLGD{-ZK`vc#M;LdWC*7h{awu-ksVWVjR#bH)icsDYfQ}__`80)^5PfPMg=R zKg!uRjN=XdI9mfcJi5Tm|GE?LRLd^^>cJ~{PdH5QQ|7)E-ywOr7Xto<bc@)HVRPFW zLJTToM1Qc9HSsa&D2*-WU6fhoay6hhlPX)vasBx;Z-pOk5{+#ID%IJSDDJ3Vfi<JR zkO^C|eL0(+m@CJ}cI=J8n>%BKeApfH<x%vCs1uHULE_IkW#R3~y6ZxL*dc;=5si_d zr7e2uV;noU_Xg3u;?#Z(pQLw$Q6WSr91dHaa3s2fB3*P4vs!<OlP}4MYiUzA(7h#v zeu<+q?ehyJRO-{<?Mp4A7LRncAP(anig<CQNcz-i`Sdme79}>$!#+?|lY#K&)fbai zt2KpYf2ekeWNQ7%6uJqcl;-6&?W*b#|5@AZlJR6VnH_?8jb@AT`@h1p3@|e|%5J-* zMBZ>g!$3(XX1;Zr$z+$=rt`$pm*FNgR3DO)n3y<kV|W)6&bPcXNmaKUSn)v8w=xX6 z5l<qTM8%NkU}IzB_OxcYBvW5S^#3vQR#BBL%eLq$917P$Cj}JlGI1yz3M;H|cXxMp zcXxMpcXxLtFmZRiYv1?ok^RnH-|r_sMr$LYXXMDp%*fuy)4FxH?<glQ)pEV5vaHza z{belrOT1%7ux&^&VGsx77gMSlTuOd5+mHqw<h8C`hQa{Qx-;JZ-_+gf<%(><TFN2b zu8~qM4qgKD&QO=@)Bdn#2BiC=@ZM|UW$x<uJEQSQwo9w4H*21LhRR>*e>``<CO?m+ z?pvhrtgYD!06ig)-(E&h%Fd!Zxpla2aahamS$U2({amkH8zG-~uP!dPhMe8w73YFL zmwPyF;WICRWlx@35Yn<RWLlfQZm>)4wwnkC*u#taI=#3tUyp6lu(Mk=II;gT`}&dQ zbk<3dq=~xwy~ex^HD0rNy8!ntC3vs0i|BgW9$<~TBd*OQ5`FqQKp3OWnl!8@^APq$ z7Rt6K{vn;J*)n~vx1VJ7t+(IUk6GMgEc~DyO?vTMF?nG=vXdUct4{`t+9qn{xM)cB zjmC)%RJc)19&F#3B)0eRjm=XA#q@AZ59x>}JH*gUYB#FLO}m5%h8XRTtNNxYud=yt zkjk3_a6a_QfaSfV$4ZoixBA_&tTm#PNVN1hyo<Qk(-Z(5SGZY<Qi@##FsTdg!Qg1i z%PBY|_KGCU?KRJ_p7QMZow5UViQ@4Ag`Luz$?Y(LG4x#4sIpRAotAe%pS#iBRnHAk zKD-1&o#d;>$iDM%+3L5ZU$UR@QHiH>yxjq=w@LH;UiLh)5=plwh6q>EYj)dFX%Sl= zo-;XaA_;dT5!i3b&sZ62Z%9T}-61lXC$T&0DuQ@gC%8{n-#2QXF|C1SKFU1UXcy*; zRx+$^OXVR(mH4HDSNGH%KbOT(%~%Pydy4xhh(n@O%9+fyS3<D{RByQ7!iruq4zkk3 z@vyIncN3=?OI&!6=~raFR$x}}yI|?Bx$GV%Q|kjvm7ZD4a~o`tCkVo`W$Z84BeYSF z$v*v%CSH&<<CzlRNTl;eE0ydM=v<MsQAGt5_vBsq5lw~Ps0odcis};B6VQ>`Gk=3m zqipUeWsRHbjh6KhjYB6sF!Lq28|oxL!SPmv+ELf_AG7vYPw8SfmW1Mu!)Y6ogCu)@ z5L@x<gj$)gP;oMSP;WqlxRM{c;_w9?KeP+t9yH1#>B5q2L}K%zLRtYLr<E#}na?%f zxC9xqtOQ;Nax{q|9b7t}SXC~Mdivm19762RdVSS_PuG>?M<S0mXBRJ5<RlMEyRA<a zM5Xw0D|HvFgx!@<bdUWJ_VO`FEaxoMAdl6=U~cl466|kE-oGM8MV!>kk9~&J903$; zmr*2<%E;;_=cBh)kn!-I7ohanDe{>&Cdaerf>l)%rS!(3O_o<1$_<LhvnGu(m`A4y zA)Wf`tEx@(LHYQj9|-q9nCrLkG{QW}Q-2)@0H<kny=D9F5)079dS}~_xs)7~x?c9Q z%!DwB@1s*mr9t0TYOQ`CwU~re<`|_GTzNBkaZOfdREIEh9qmOi|1d=qK6r1Fhe*<Y zGFUU$k!Kglq1Ii{XKCk}*`xEWn^TPP<v@Eu`za4|zRE!+-|ReAOPpY2POnPjc7q`{ z!*o38%kHM5puDuEm-h?JBw=W@>F)4*l8QOLKhn@2=(U!u;k)8AP=c)fiUzlDUhyXs z{aNsLRZ{I1)NwkIbdee(ym38Cw#_UK7S7>&meE0c=^E8CqLh_1R@1n--}?1`$d^_y z6CvYu+orksjF}_Z<8-8XH2Wh**`sJgfoD=}o1NvgEiY{5$RY}f8W$$C(eDS>?BhD# zt`<q-cy0tKnEOqq<W&UI26)-0mb&vwe1}{sV50QnBpPKI(@)#=6c><#r2?|FdTb-2 zW2?p7*tuR^)OwD7VY6yuejfj!jA`-O03esUyKiJQcz)`+C&;T#p45+p=W1x{pqMrb z&m?7;zFJCQoYfPD=6ITiY|dZ8Yyq%hTML_YZyD;O67p+$v5*$+$?^g1TUe*h9xFZ4 z4}ARt2AYZRxFF41*1g}dCFg^88c;H4(x0urzDG`~7f@=H$?N}G&oxv+5iXJsqJe{x z{K?6{?gj@Vla_ZN`Jbh6B4mg)3;}r75(9rvVF%0YTNHVQd3$WryLDv?AEU$&-<+AA z_{J;}TMx~b_51xwV>AgU&DF39xth!mW*9L(Hr@gCXV$+YTL|N>m*36`*G<++5YyNi z`n!aRj7K8$=BAvc38F@w>KP@TC&Cqt>Z2nv^3{;0924Lbg^yMnfL8)NiR$~=lUR}B z_9x;&31_mjbT~*&FbZGrF*@@P$~bo*nPYEBiuQqhmx+U?kfAFDgYiFbSC>=V!|KLJ z=&HF2Jkf-^>K-iCk<Cer<3k(luSz0=l<t;$jOr>LbT%J`j@CQy*6wbKx|dCy`+w3t z8{j>}u9oFB%QtETYTTqrOn!c+3s{~?k80GITm718S~**)s<d#%^Ox2szpz~6n%!Ve z>n$UrzXPeM^^ARowzrgfITkP4Fe%SIecRKr9MrNBmn_Qhbj9jDbiA*$T5QE*Gc)w) z|M?dHD_!Xh?7mP%6p2j!?+y&rZ?(til}q^4tVamOBu8Z~Hh|VhmavTZvR|Dz*@0wx zKYY4SBaN{~X$Rt_+wK(Wq26aIEYdb>vXbW6pGjZsFk>B9LJIV6j_;~b0y99=l}HW1 z#=0LMV*j<P+&Edoxe}T%vbLs}8S@q~qe}Y1F=F2(Kj#rxP1Cj7`<3H*Mh+g4F?`3J zGsTQ0wFX~ddA&6^nqtXO1vN8QOpv;PXynPk8;|CKE=Zt$#wCWR+><5tT(w`ia;}O1 z2`Cxyn+ylzZuMU1mXnHdKC07|5FBkLbrrZT-Q+ZCy8I0@M<j(W-&AW($O@!BZG4^H z;6vf{0OUC$5{ZG3S(Sk_VZpM?M$Nnajy?XnK>AL}g2yRd+=3wjZ&@A96#P+-==>|< z7ek!#YLi7qHMBbS2jNVJ6#rL{3Mu$*<4qcgJ+N3R*bF#gzFAaPy6n|oQrh%n<{?IM z9Kq3eF-}{BeCLL6XF15bgdn0h5|b=$L&uQ=*UTyRdCnrj|3&+y;|YrOhdxHigj$_J z=-Qo6C?k1r3ML6(7(}d!!%wCLSE%3JigL6L5`AsuqO^8p!Hm_SHC;Fe?LCl;sB*?w zPFX}3=!_;a>AxT&rA<~DGU5shj5?V#aLoH`b>zdQKX0=?OEfi9!zbnr(GLrhgoOjv z<dWDfQ#ST`(ri1Jpo;&_dSryKodjTgyU50+l}DmW#&M(CRLIvH5U>`Q*`*2v#^tml zQ+bVK_uG;Fp`soI&zUrMzO!lZoZ_r^Kq!$SybrV?NUuLx9xWh(<paO0b`$CMS}sY5 zB=+9L+L=NZ$#BPDW4W?{AQ>pg=5<&S?i8)f7*07C$#OC^c+tWNl+B3aSdW6H-qH!= z+K3b31}T3zF?Ali7|wooAR(!NZ5$olL|`)h^v`@t;yq!!AipO87sAdMkFb}~mRD|( zDyh@EM;k0GpB7yD5Vv)mWR)D4M`q$QvTy$B^7>Uye>X=}pK%<|FjBBoPC$o#u_YLz zip=?+R1e=^|DJ4ENOAotn5_3Bg|}I2M5oU;ET?o~cA|R>G>58_GlMI_ySrP#Mx#3? zE0pfD{6X8>u)i(8*)18PCib3@9*pU32%sb|fb_8?)5Nl9Kk-rr(%wIeM`EuHa7^bW zff2#4Th$4&?GdHWJo(8jzmTXEt{09#!mbYaK;^uIOw-aWGc?Dq#q-#GcO9Z%dFaT} zBM9f~z^^&ToO40fB%+9)g3rqJHz(1Ypma5r3$VIF5Cr$5mMF~)%98Fr@mySnKTZ3e z;%EFjw_H3l2Zv~ugc%uR`cFLA<arizR|W^OP5e!D<w400&6?;pOGD)6(eze}CUAl7 z{B-vZr)l*vUVvzP=waWn&D|3bA@2x81cI4tS~JtOH|@jhyJ4DYYq{Jb7jB}K?za84 z$~ixx_l>=!8Jh>QHPm1#>k+e3mZtVd!g*}QNxD!Bw+AZ;%PgX=Q<P_E5M7gYF~wzB zVPfe$AM@}cM0c6DAVj=F|KSeXC$kEN^}LWdX0_z#H35~{N-Q@igIci~=oj(1Facp8 zK6@32k8`0pkJWjbIs=1hX@5B4tvnbi9vbU>|3ogACoCqM@P{ZG!n1W+R1>v?QP4+r zN8U*KIE9lTniF5j9Y%RV&#bFH<7-Z=#~yBjmjpgCM|_fEL^~jYm7LdXj=<(As<gwu zExIB)L6d)ii=t3DbJ_Mn0X!QS`ZgldF6#VIDL(w$Ju+8Q*$Tw{eo{|_JEknEiuVn? z6y1L}iALRj8V}Af1>$cUp(7f^dD<N~3A4GOS)BnEz6CULqwn7MW%+{#{6?34WT5QY zo>e*d%K(Pm%%--XOS#!hkVL1Ma=O8`v?QN-&+rra`z0bc_(D>`rW}bm$*{}PP@1#y zlx8At8U!rRtFTG$E&UjhGfbQVYkD20rqM*a39XdFOmf3yNok!Uh_MXB%&`s2BNyG- z)x2DZ(ZiPlOe*g0Q~@pW43*0m@Vm;hz1QSz&So;!Y;h8co>_C``ZcOWg*^qSG8xCm z6^29i^@pj24pH;ciYSC!1r2jr9@ip`?bPEtggUD37d^g^zuc{7as<pIcRXJos46)h zkcOFCNZ;<4wNsc45#HY3=0<)3YY!^x*{wE0v^w3W?4mrEYg4Jsr)!%CVIPEsT~jMg z7fR#H%Ktu9{<4pPZ%U+5rsj8%+Ua~bDGzJWchz8sx7i@l<a_PVN8+|(A5WL;VoK4O zKt+_}u)PruDw&`NhOpW*bw=^HTI8VB=zy1HbI0yfpO2T6uNh0TySLT|JBRBof@J)@ zgcrV);V=8yd}Zb?Ye5Laq&Z%uKDf~!=vpM0gv0pbw%zi?UWqqnweHM>hgHTtG*Ro% zc$>_>yTAGsa?2u|`;;6MzwPjA<_~8!U*j#KUb|b~LGU(-*Yz|<oFc4s*Q(4YPuKZ3 z&v;psvgs}jbq{7Tv~=fyyxsBYJan`$_NX)T+doK-&;OBWh^Qf8y$PbuBUdUCv)F-j z{aM}*#7|L3)QeUjL0(ph%Cve`8^c@PBVY{*hK7s|Optf(_H{~|i+#^L_50J3<!aOD z?;>i^ZWhE|3L}usPfVUSHQj>=_$SvvFXl*3jLPvi_pc;RO{E9+O?u2^74LRtLAS7+ zwKw=7m%;4NuO#bsl(DRRYbAp=m<$OaiX0yFFhok}dM6_WwCc{^?%nQ5S$@+DWbx-_ zfRuBLHIRwu-1AfI$;@I<0M=@6hFV%G;QUxox6rTZH<!yf5J`k2dUva4s=xRV_YO{$ zs%z_Kn@vQzmb*Thc#z|MOg^8Ai~!^b7v$2Fg=a6^g})ZixcBVb5p=z`;akOeSKO~Z zpw8MRXKf$B&q^gu?1&b~6>IIskwY^eou=t;(c&Zp!#&I{x9R?9s8WC&ejw^IoinKr z=gUZQosryhZ#Jd*deTUKQ~SB_IEw9#Bq&jCy0enJ<MqnW=o;LlZY{TPw*JkVemxqG zcb!K5;7`ztrL@cj6|<1G_~1|{Sguw^tfA~QfGuAXBp+mlavd--QheGL-?Og5V@BW< zo0LZs*6ab$es~m$wBlv-hJNla2Sp_bQGEAZA`qazpDlO)I`(qK#&G{~`)<i0xUbPA zd7$9~WR=Qu)UzGlYpALpjP-}L^>4_tkg%LsN(<$d?-OU+;j6r_FtHpgSK;QyC%Mu? z!*ov_sTEheFGn2KlW7scm)PgW6uK0so<#^1HITz;1nx^q=vANf8K2S{p$^;kBz6v? zF831NYq<kFE&u3IM8?ur&t~k|;wXq=d<V4Q<PJGqS)D}70lh&w;%E)W3u>u@LA4Et z?=v?U3AyrIqo*9+EBb=w!N8!EirC3vdm?K!_^zRzD>9ds#-9CL36=Xt5!Srt0^G@V ziCs0KOos_8k90D_XXfnS@fSzm+rz<v%}0o`7>j%frzF8cv{~<1z+9C>H-YWxfcL^z zzp%sOA`rxAQJpdnAcT1zO-@=&?AmXnK{lP1+1~8S@|;QVabWtD%`kGzdXq}*kG`Ci zQtxD$zLg&xR6Pn>3*mvU-QZZvXdRlso%)_aEYLJ}nF6i1xt>9kO4TKrz@9&2fFdbp zezX?g{U(>%TK9kxuOL-oi|37hly1bHwv}QaIaoRHT0<)4{jnIn=Xxo82G{QIxGzgO zH%y4JwirZMs%yPfr}S(%e_#MhilO9&e`gJpHMFchSuEFwJ!c(QGj0o|8Q0y5VQ<no zXCUwEdO4vfv{lX*MN&e-&>$FQPn%!OCd_8h9bR+P$U3NZ!Y{tAs_Fnyr?1t)s86P` zEgGRn%`myL8%=x*L`wf+uj6O=_tTXw&-OI~e~{~=^3<^J_R?f3i<l)rFJ1t_cFlL* zyE%aMSnob5$OANl)L1*XQmdbc!uQZW>}#vj?I|E2VEQQVV}BR4@;1A2#)pylZU)-4 zZ7dZ=KmUmj=}hvj#2BD+6QcTbcgrr9|Nhg%)Qt+q{TvQ?`{0pPP37j)loekQ5UTrH zOLo*n6nUQ=5wK37Fw^!h|CI2dn3JiBlF^!$6pT21JeyTT>VhRYMIAW}+uXxq9o5T1 zEk@w<$@;@zD(ZoR#8!nR@e7kc`_=A*=31x+!hg_3dxXSv#(Jt+_*{W*Y>y(hQJpgy z)xJO%mD>aLr)%{1-`n~NJjxzyAsbp9JP2=Lk)!SYG$Y9}z@k#H3HTM5rFA6U{;cW9 z>&qS_C6Ee@aa5>n{<b|_nHZ3=<N35-S-p7OeI1K#2jPo$FW35u<*quf(Z|^|vx`(b z(<1EyYfP3vX3c<($s^;z0$Va_ygRK+tx#LD8*+JFQE}>C8!RT|X7$H>*5JPMriM=$ z!t{I}Ps*^#g3E^sQavy7Gx$!dP^w7tSXKu!ag>Kid3Du5<!00dD&2|2a-j<cFZJen zD$d+!b}G)`#f%ZnK~%qEZif?NE-6btd&uTR!50{)Qg0f~)q!dk4kzW@aJh)9%bm1? zXh|NUsimOw{GkW%{7NXcCo;EDzTSrMZc5TJ**(MJ!I~+G@!T?FiTDD%?eDS0kaipZ zE##s)dblpaXqd3Z03}=?Z;zrwY3Wi@TjuWLx)jt_SUpL`Vk(Rll(mZak)5jv`f&S3 z_~?|2AmbHYrD|RI8m(rC4pOf;z5jJN4RLWnmaS4?d2lZGRmq=R=Rv#hN(Oc=#KSWs z&YK}a>!Q8YV8L&JA>K}S(5NU@sTL97F+K06s>(|*)JF9Dty{r_(@f-aey;&LBD%xB zWdy%r<GUUwb*Kg^8m>-F(LIJpY+?$=b4GnVmEX4;B^)ew{0?_>gjS<A)eZOq3tkgx zBfdVnZa94ckTN109#D2#%IH|kxnlTC33d*&5DSE@QQa+grf*oMkF;)+wUlb@iy~C& zdQZtn13IGd6-APiv7QNgvla>m^dI#wNH)Z*XB2>0KBvYxhJ}bQq)_IC3x|IH)-p(E za~U0YrsTFHrd~D)-o1m>$E=zkqLfX&VLVQme*$6{I+?V==Hl00dPq0qalW6nu4PPV za<}7ht$HB-?m9@H%3D+)kgOQ-h?WrLGc0DCVr`Pw_v)uu;3uDX+xF9fp+c09KIqBX z7;S}E&Rhz4Bdj^lnSvs0-6452KyG~dz0t^1Mq~J9AUsz!u>2HD65LY<aAuq_f?B=z z9o|f`I0a3T@O{47i_9=d45*of<>aeIO}o~C!imR_sT{I01lMHmlKN8LxX3V$6NIg4 zGDZeiINo5kayO-K`vQO_Gd~ymy{;x8t+#p(^D4d%<5{1D)6>#Q8S2JGf~GRLld-|4 zr{RAp)k+^O)*2-bmJe!=>8&Sv(yXOoYNf~zp3)odIBIydY)HO;7eI6D5Gt3UzY)cd zs$wb~>e_cHUW})hm*!4cFkfpZUBmRBZ$+NUhb2dT=JG$zO>8{GW4Ee^Q?ZXd)yGil z(gFq=PPABgDj;f#dUYdVQRn^Pq!@t87%*fOXvCzBdB}Df*5!$mRGuH@lyqeorh0BV zGd(1d(O@P8GaK*QuW>fTS(_%>-Od#{OmeI_?1c|1$N@cQv<T~y-UMfy_H31HkK+zm zX5uJAG5*V$E#zkzdz#~&5(J@s)lPM1avcJgXR>i{&vCA$EsjkrC?)J}LSYDbAN*va z<}nB(-AITOZ>4vs`_-}Fz=H$Ug10w`fHP2UYpcON3-Tfmig-avQi4IDq66nSKR;L- zL<kjRwAgT6gfoh4E7#CpB>LC!0nz@efZ^dm+x(gsxziRK&!XvU%Wo(sqt2m*4u_t@ zN-u*f9Gv8c9;s!GijLr$&EjEj!m>t@R|eRr9GEQ3Tx&9A@YAw((!lOW)1NCR(8<n| zXv>T85LLFy5aRyC{{8UudavuJBg~<nLRBB7P*ycNL*J2Gc|4$gp(Q-&dL%r8f=pJ+ z#`W}Fj#3DpFTv5NH<k1i)#Vwny)&<|<V)e08#P9UfzynErBA&+lS-|(@Qnx#h9|z$ zKH~V+mhVlXD5oq+Vd&$<&iCl^lTOpATxj};{UyqUia*&!gmUEj3};^#m-LsUkA95y zz`(6P^ODo?#wM{eb5haeKMN2IJ?9f(JSR>*kH@|G*ax6tT&fDvgSaKV>ftQ4>;^ie zp3)7eu67~E4`26%igGbYMx;{)&8LeTQ8b)^b}VA`b{N)BY5A$;r7?8zAXfT#@$0bx z5hLtmr>QYn^W`d~be|#-z94^!tiM<Hk}r@jIwLXPO^d2j#kokpBb14JY;{qk*{^rH zl4L5gBoEYv9I3yUcZ<e75TAZw1)_Z+IqFhn!m`qBpEcfp47^4tnEWqvBq)-Y<iHP% zl`~i?`Tv)xzg6>pnED6jyZLfuDz+TOMLQ>{`7Iv1WF+~QB)+T;9%T!}^NV{e)*|If za|QOq%u`{Q;%60z`(a1qs`9bQEHvB+wCXTk_osVW8YDp-?5x$3?yS!tHhBD}q|EW` zBpGkXVyk>2_&znq3V$%bV)K8+Qp4>Ne)+?rH&_sitKu7ql|bZ7{BbpkoEDVv<zF=W zHpkP1XNuw42VC#dW7c6)-^F9fD`T{#=VHsU@R-&UWo@tA5l$fK0dp&~rVxWY->u6e zj@A%CDu{!B_!<B(Moyh)29KIQZ|tl8S~fg&Jh5c5&L<k){^afr3IF2Dfss&U`P6NH zZddsK5e>xvpj>d42VO^O7}NrsOdLg-){c66b;Q!RY~i}yQdxQQO{V+EUL=JrXaU2- zH-~H*JWi;~GK7QopjT9PI#lE)r~R8Fcok>ds@TxeX$~1LEJBU(JPRi7fNcH%&eS)Q zLs-&L8aN(ms1$L1b`2DonhJ0K4A2ArHJ-zUcxHfp<KVyebn&y?&KHz@lFJ1OI6_b< zGF{h0Fj73%Ri!LO9^r%G$tCu@nYWVv7eyBl)R)iP%ls63+k`p_lG7EUjJ0lzW_=7B zUS{;s($TB(`H&HAij_GxV5*dQq-|{rE*@02ouO`Gg3rK_yU9u}Y1+LDnz6sN-oR`0 z^uWD9mHHS0ge*Elg~YJe=dIp_S?Q+5lH2}BtaoGv2*_KTE}Q~cWbVSG1Ms|yT_g5Y z`bKKnr!UP#eyq|jNwLlGcY?1EQmr?F=QKtxBKRLATRf~#aSE3-+h7>2__%CNZjzH< zH{?DBU1?J3RU4hyQti!aXaZvRXmi~IPaG{=T)733wq&TB$!1c5rE`YAD^!@serUU! zoTCf)^?d$~^nU0SvPOHb&TxDVhVF;`kJA)=J@40!?@*Tvs2CWx)q;O0;kfJr^78Yq zdtm{TaaFFjhX&2w6kj=q*X%oLd(T$uuWzUM%lEikjp-$$p#Nv(9ISv3A?}ZD+3)C6 z2qI_ax*gWS5LB@%YVqqo>{^A38&Y>Y2ShfDCc%5VDg~72qqM*ff=lkXAusrbTx~tQ zxV0w+zFv#rHCWSx1T3fzSTr54kWU12N=)*qq#nltx{Bc_!f=^PE-GoRss1#lim8$I z(y0tijPWG8dPT*(f0p%8z<e=hXK#+qN?F>^|1O%3w%%;5Y@m@Z8Y%9`fh)CE8@9Jl zs<0S@-ezjSH}LDvKiK*ruv1I&+XSAAun-a!nG%W13C88`ZF&SgJF@%3SuE0b2cLcQ ze|kGqG-u{HXFP)3e6&)v9;QMLhkzhLp;(40+kuLTDz$#B_5Uv7`&arJ`2O3(bB5Pe z{FnbfcN&6NN6Cj-Uicrt{O>7(4k0+hOGYdb@sECgqe2Db(7>6=i~gfM7jZZ^fyWph zOs0PlBl`UmK&8BEZ^7QrEBx<nd*TCq%)ysg6)?PcOB-7}`)Cr_wf_Z03K}X>Tc5{c z!TCSg4<!2X{RrWmF5&AxVWph-8>@24WmbdcKlCYQhLjjeGq*d??#n;A#QoBr$?Yuv z^%h!u{ePY#{~;!f@G+UeI&7z~#Q7(5cmG0nWSy(=kAc(`{R#K~*MR)(@^&-6>7RtD zm~Q|2tnQkB)Bn?y%VGSNOWiK_Ij4ULtYEYcszcxh_89cP`$7ro8B3%ANckj8{T;G_ z2F51NuUF9=f{bnhe;K1QxEMq1!*eFS-k4YgOy;A}$V318koo@fSYfKr`oy6R*!W@* z)>COm=Ww)zktq2MVHlcc>CcePcF_Hb>pl+&Mx3rbD1>^_Jx3OtR#WIi7Wfvr+C8k_ z(>|U1q;ILbMJ<W26~1~3dA(QDWizfGE0z?#&U~3H^b?JEwIV41isFud3pEjAO1J-_ z-DJI!Dnn<W>bV~6Wce!tJC$|P>o#XZn;mMm)mGII;ynb1yQ0uEj+T$MX}fo^fUH{O z_3o4By&FL%Y7mr}Iy}2}gUL4GWI0dbbkf$~1=8!zRuM)=<}D`x*Z=BvS$)=~hTrT! z4e0x_tZ^18Q+Qz_1WHR!jW9S#frno*ncW6Vj`Nm20^!}UJ%W$~Y=7n<R}-2wo=0vG zn)ho(kL_}Q_n_c=d7uvR+yYpIDqkOjWY1psUzcb{!59bWv{nTvDmU{iB?@eO_KZfd zxL=(PS;9p`6qh&prpwYf6t(UNcxz9eZ-uxYsO8qm)_ziBiuhl2pE!*T{`WE5hxJ`h zf4w@MNQ8rv2++P=GC5Pm`~C%%>GKwT1tTd9Aouz13S!uMtyQ>M&teg$R6?p$XAhPw z#mrc(Ma1ZSM`8;2Y4@fX5KJIw^A;bfX(ve8*FU|tgfY{#AAk=RiYOK#Er&^0_PN?q zDh!`MY1VVly{tE#wQVEUc+b~Y9RNCeR{wP4=Wf;o7ENguN2U%{&USc-d=rw<y<P@@ zqHiBR?jPP?ky@g%DW-e2d~_0S%>$Mq%Q5(jYjt~Zo=lZZy3&#{pHP4otG>L-p&ofL zm@P#5{3>NbYE^!5pi*z>z5Rm{je3YBVN9Grj7On#m4JW%VxBp?DTfQifDi!^Q1-r! zB?$0jKh2v!t1ACqxW(tgFx(YHq<t}_UXM|&f0`YR8as0P2mRq<J!F2?)Iu8uH|ZoT zF1w9c-2IILUZ6YAt6jwPR0w6I17zOS$1VvZW?X}gRCg9JPouHY<owlL4Z2!S^_ajK z3Qu8vAkA0+TXJdF+Om7Sg6ANcu10C-@f>8gcw@2Q|NEwe9BS%vMaGTf!NqVcxJ0A? zF4)TQaW`B<w?vaZ8;?d~#RSSiHF*M)Is5e5joCB(U`n2cw>@^wf+a*o)}261)FQ3@ zFDVAa^9P`o`EH@oS}XUI<r~6RXV^V#O*dRewugqL<r<c``}H)C?$ScWT!RIt2Foa0 zoQD0`gm8M8aT^YGlB7yJk=Rm<y1QL#qAK(u)esTy_Pv<lS64}1egc2|AHDMdKiJnq z6)eYMxQCs<(8Y*zc6<^)kVXUDs~{eft}lYCd;1+A+nn1&rpZ4e{vttb|6@B!Og8*b zn&FVmydlxn?2xtDIVq<lQ1$qId!^;;t4(ZGiD<U%k+N8Sp8aE!%H6ZtLM15cOZtY) zS%<scz|N4(gTq3doq8xueF;|5^O|J?lS)HK5p)u%Re;mDGE8n^*#Ua&cmCY9TmPB% zvcWXPs$fKQtKa)+7q3g=5pKD0RNIt1+@0J(w5lOrh1B!x9+Gv(rq_IB0?c1Bvg5mQ z3fs2Sxd@Acntn>ZI^fds#Jcdko}ElH%`P-(bfHTGc{*YJRwF4itl)zu&f*_`s!L%{ z9<vvhL0FBz3MSQ|Tt@{UUP>R?nS@TANAK28E9-5?4VFBvqPiHw>gv9&<F%~MzZv%} zE#c^kc7%U3{#sb7Z}ga+ubg<UGQtyd2N8X}K4(3zU!hfo{%<+?gBR*4H(SVq)e}=G zn6ZUzFr{{lsWfWm5jUH(Y*773xw|4v3SlE4+8cQYKYlBy*%AWy&PXWmgStPB6%s;U z9J0R)U5jW2ZaDeVuigV$%mKh9ni^ue%8(S8^9zfHfYVNOw0y1&1&=GcXD-rsvDLnj z{;B&*Wdk&3>R6?E-CwZPDGfSd3B%zZA0@+wMg<~Q@5QG(TP@5}mmEGT)Rw;wZ>%sc zUx;4V7T3lgrr%$9lb~Jo->#}&ew4Z0+{WU0edF#|_}#E3dAy$?@pI9tpRqKbE^IDL zcK$YW@M1B%_DS4FO_7NRQmoT=Y;1!5OYkzoU>aoGp+7HP$4)f()O=v@Ad+8CWJRIm zz=6<RCa4rI!&6N!#ar3Z*BEiQto7E0Rk(b#-ixM1gA=BhsQ+36D{?>_fjgwtewmcj zw-%P?ls{a6fpxr%SgF)tt=WU<gTqxiv$u%04TT`&(9}plltAkpV~L=(Y|fJRB)9a| zQN!-UC%3cA)R5?kC6xn5GEx#@BXn@Qk4a|&-&8ooRcZO5day$qg$m<Wkp<q}w-9i; z;!K^e_CTI$xGgX)aK5ie7^&lA`_XrD%;~c$y<inIC<n>hR9eCyDw77KKG!lQIMq`2 z>amzQB#SDewc8600lsSofP5RDKz>Wh<qG^4+jSml{N80vC{+X;d8Qv%o_V%28}kB6 z!$v3J;3~nK<1Cze6DaRbEgOAol6j8Me7?79pSBTg{@E&O+3ZoZZpkR)c)rXETFJ+2 zO{KRXU&ALO1)i<Uw<1xQZ~j;B``J6Q-mLe!be~<%3bo^<+#l7&EKAecp?Hwn!KbsW zDlPn&6W^u3y?#&Y;*+_5Zqd28Jhj<mO-(Fcgoe~MEgbsF@W24j2)|6u5-#~gk)aI; zl2Ni_{K^_<N|VU4WenPgSU}$Mud%ow$v^;`gS?cGtP#D~P!5}&Z9kwQYe`a%VS)LM zg7+syUgZVYSER8a6!pKmAMwRC+hQuT6k<{D*k5Ge`!}++0?WtZ113Q)yT4DXnQ9eW z>*ZZ}8h+!HRNch{2$}N-e<nCmkByb%AAVd3w2fNmas2USMO0|kP&}SSIuD*PG`=3% zyPQp!Fspv!gw_t=^9R5J=Y-={&j+k7^AGY4j&zvYJDpqzw{EljauhGDv95MI05k2r zz-SUKxZB|_|H}t0<pW7}Pk{Z12fN{`@Lg6*tQEmb!3DZUofTwTVuvnMwQ`lwtlE6t zD^Jd0SlyK@DOieAa$#^snO^7QMt{Zj3HZWh6UYZpq<6y-lLB>XNT)Tw0)<Wjx0xJ2 zv=%9FWWR;mMZ(N%oJM*du^$?pcbRsJDLYs9bVLp}ZWFZioNQ_dePSmn7QVG}Cwe)b zE<5#nnfpswsCN_xQY?<<i`N(Voaeca9Tpr^X$I-KJ2N~kEHh=M*tpg22Ao<_8gw9% z+W)?-`-Fs3wB8D;Vn#ddCJL7Ie!|6f28g*dh?*TGXQQV2d@b(3S0Ka3FqOlNGMN|T z`OXZ}OA+0ZE3N(XXdS*6ntV0BaUfp$i4N1fmFZDCxOeG2ReqxZBqv7|i(1d)e-1i1 z0sq=xL!f;h4^e)D%{Ql07S4XhH<m8qNp7a^>oqUD9@|0t#&U=Cw1@X+QWeG0)dRo; zAItG`Kg0dD>dL!|^h8;F@L0Qf$4brI|B8n0Bs}Ssiji|TZ;w>yXdY(MeNiGl!z(A& zevLDAOs>U-1G)3aP3v+NQv@!$vc0P8si3DjB;%_<dh&MfHxgR4ShMlnMSC=zHZ6TY z#Jtd>4SY?s4}Vw?C&@)#^;sXhp_P=u@$xnrr!zp>ts|)SqZ*a7`D-yrKHBtD9mfW5 zK(ujH|GAy?^+gKPw>LZW4W1kBB0BD(LgSYWHs>@Fu$l8|aITQHNT<AWjqZgav-J}8 zYcl(k;(mrP2+Zhmr0z2GOzi{{uxr&(+9h>!<Lw6c0*j2H>OOGS40wIa{{1L>O4A#{ zde36N%8pFi=PW$c%I*zMIu!9UdufZ~?bL#{5Sk&l-yD0-LJ=B~;PwmOHzw4@2;-|q zQw(@hdP?nKcsL3+3H5EO5@X%#ESae<t-ECxEUAN8_12-i{@Ma;#T*tCBrp6WLXYoC z3l7XX6G`XfEIgIj**rE7NLoa~kMANb>l-~ms`Jw1)}j_!-3ZIP5=(GxU{;t)A!NO+ zGKHe@aSj<6Tfmet|0s$Svcb}cH1yQ_107$+4euZ8mB5~KDM7Pbsr!?fT&7yELq%AN zy%|cZ@#sqTdqk2i+#sQ_JV$$Cj(uOokc*BY&&Fw^kg|wDd%k*fR*BNu7mGZ8$0e=} zn=%3Wf!`e;f(ikd8v)(bCWom~1RL;hKFYFq4AqZh8+x_+_C%9>jY}z>b;lRce@80E z{nL42;}7!<?V(gEWEP<vGLWO&6BnCSCFa-~-f3$VZZcyW%+3bmzWjkGR7N8gA>8v@ zw$09fsV@P(oSf#RPl+I8B>dUh%F(#$D+kBBD+xGi=T-#2)*ejmv9?FDb+!guJTeSO zpZVY_z=^e&cyb{^n>+RL19vTQ*uBE}In=Km*>l`Ysw#YfU*c^}oKQ)mj+>(<el`na z=NvRVKbeEIRi0eUrEnLJ!jVml@?pVUL4c{o-j_`7+S}^;qhucZa1>3U(wBFpcmFEJ z0*ArnTRx%4IFT65t&J)!utOG&ybh(dY-HesYxts>ShrzM;%zVWXo}P=-z2P<f_cC9 zkq*yx2YR2(dsKCDrk}sMro-u<U@uRLnH+T#9?jwiY7G1Ei_%e#*P$$t6zP2pQ<7p> zh3BgK@tujGY{qp1`6+u-i1&+&RYLO@O*6Rkl<=q58XyI>MOT9eL23@e=v*<5&T$pK z1*=xh-v>)yop`~2ODsrmHBB271-T1l*w3>F-65O!$~r^E7+1&B+|pzzPKilUU+<d_ zCy+Q7@PAsLn)ejDaVwH%OFOZ>?%hv0?x+@WnwGC%<QjLuIS!NqI)hHK_)KQwwy)Mf zizwT|bO70gv&HZI>rY|4qH#?Eq{7euksdl6hZCiEsf{^!;iAx!yL6wAP4zy1@p$sh zwV0qu&Nojj^|$SnTlQGqhohy|GN<p*?+vwuaRzN;A0>8(k5q|O)?@1>V#^AJ5;zNa z%*`RfARX`~Apr3rTz>ZZiuWOqu7xXJ!EMq*!cfPP@wM&gsj}+o`c8Nrhl_?TpohC5 z1_-ljVt`P_#}C1qrWi=UiGL|cM!<0A;4*Ew{%bffWWW`hXn%aN-boD6a~8$67)U}) z2&|+g-4zxVEd+~#4BMO!#-3*n(MS_ID#LzD_n<M)*4=ob`MU!HjXA9wJRDiGrtSFI zY@uJJhIS*(YuxV5=C`Y#?w7Y&p04I!RomX6NK~if+Qs_|+%*&E<?tN2x`V(pYM_ax zcLSnd0n{|#wxWkCYq%SP1Pt%qZSb~qEgOPSpOC@d>;@Ah%^zJMOvBvVmITk48)zG= z!awm>0x#MDZO*d|822Ldr*@03mJnQvRpO7GL|b_C$uH8h$Ysz?bZ(v;FrFrIL>>nG z7hLmxU2Xb7Ov$bp`{mjDF11PM<Dg1e(Y@BgMmgqZuBfwTNc*l2OnrXUke}pvnPquI zXfYHhP$hk@&S*?xMkS>MOt|7qw#F!>OzRrUL3tcaXZGY8YOKU|B#lsb?4>ByYXgUG zO_pWd(YWg<jXdMIzuv)DtH#;8oB-)t>ETLsPdo-CynIjpJ>e6PG&KICHET}#QG>R1 z^9e>)ib(dX^&sz+;5F<7QJ@<AXswKk(~5Az4e_LQ{qMvEvTf62Lu`c_A#P<Fjg&1M z$I~UY_r`&d!rY_BRTq}qr3ms0jd&xc)NZcH)3W6*-bLfG)6-Ek%}|`<z@L;_KcxGO z&070cSCKMBKYWra1(^)Lno196^zIA6f9tYAYh%9>;JkeK#^L;<12Oe*N&X=T)4a4+ z;>q~L4%78OEaFH7_D7~<-UCa)_vLA5{)z4Uhf(n`838k4*1mp|Er$oe&(>GQT1{7u z<no9nBr`MtaJUf?o=@X`-FP~`A}yF+tu5gI%FR;A&kM)J9~Uc5`t}2#^)mTZ*#E*h zPuo&VID5n2hFRZoF3*?b=naouz%jdc&cKYknicTjhzxUS%#^??##`z!juTYk`f`%Q zYt#)o?3SF)BU%J_1zLDgVLEhGtex{Bnt=)pjsPN_?K*4jl?ZQww5J}`l1bM8UbFT7 z>&rTN*U=5a`)p%f(F*^mvJN;<dVin|_@X#%u$M?kWPn{1_&Vk>^!B|SF5S_vrYo;w zf-+V+(<PIYIkP|Q@wb$ANp1W&R`BI6Rkj(WwLLmMJ?gF?R1%S5B}}K)-r<H?UhKTL zjmf+29ntzXb)a@$pyVUZ*<Oj{#G!huUo9MB@gysceLvazOUREgAF+i|M}sv7)FAY& zl4IS#RD1@7w)`%sd1~;U!$1PD)S;8qZ!%33GPPkCFRXCW=LKUl4uw2qYrj}Z!u}sp z0PZDP6o3(#1&3%ntYUde*A65d!Rb72x61(p-B|{jD0w`e*8zvSn$4IU|9l*R&CmU_ zg6N&%*Ho7H9Ng<Pkpe=kVQDkvvB7O7r?X4b+LInWdAb?(t~nHC?CQRtAN94q7%Qx4 ztiV&=0L?!N`PN1iEc2=tE$E{Yy=QzlR04_;F=0vopv*oyooaV^k&Au&cwXX;*w?f9 zjvlMy03`*!;n{EIPYXBx_YB*+B&iQv3z7h_jcgsDjNLf}D-b}rk|a2P!7vYy$c<Ep zvi`)PamwhAb1Y`6wU%bJIt}#i1_-D$U?9gGyG)~fa6H~iopIVjDn)1b=DLt7g7|W$ zQHq9+ZUg!FTrOe!#SSu@rGWjDC9KkxUkf%dyaF2{L*9(^80k1#X^={38otAr?Hk=_ zLTPRhM(^V))UxxyCnhkA-<akR?Gqn6Ay|w?*e|Vnnc7=QRO4NdATjaQ05|*LG?F)2 z^qH)6eq?BK__FT)EXs4Aom6MJlxeY7O3j3MZtmTa!umr#zY<`wWLN3qrZjn2D@9(P z8fM6aG+f$aK&Ih}@0e^XRab?Y+a?tr%Ma=dxc;_LoIaK#WdV*2rQ6Lt{!^4ZPG#*@ z<wrQUZ2&PL*v$yD3o)rHVlnAORmw2`$tpir?BuvJAlH~1osLxeyX}L!bm}hp)GVv& z2%IlgVvWMb4+ufU6FN{rRL*(7D0-()^>E`G@ldVBcs5|0`qRZ}+1al1hF{6tK-x`V z6tdr3vj6X;YXo)(3EeLo$!8*K6v!unVM$j%lYMz@V=@YE>pj#M)x~S78{eQTO=Gjs z-L}4Ea1uc;8(Hh$)oW4L4UZl?xfm8HwP$I1;t0GNoA2%1eCoU(GG-Kpo2<7A1Q9@U z>ehGOaD-{{fBLz_Yx}3S#)!}H@OWo8xY;ewedV)9hZ!zP0UmNn3r^2J+1!{lGP2;9 z9<NkYu$xMs_XL*9nJD%RCj3a9P*<3TgT+ruI0=l+?naVq!#^xYre}z0kV;ElIzT%F z$LoN{$$JguqDH#sar(ZnWP8C+gsG^S?SjH+!smo#H0@8LOs(1KHK?9p@EI-83vtnK zov=?2Kl~QUAM%MzoiKSYbKNz*h&5mK&3WFlJaHPNf}Jjdl<q}KEZSsOL1v}UttSVu zL7H5vg6nx@&|T>$n}#4qsF>>EB!7NUW!du~0&QmaQz@hQB(w3#Y!&KwFvm^23mI|X zn`W!INEo&<UKGwlM89b~>f>6ZoIyXrM7AR#{1V%UMk9d+UW?8y!&e)sXFh7aWsb;_ z5&7y>gskVlg&3LwwBqNC@wmtDq6s%tNEQ^@P66grnZKjDa~nR&j7VzhtDE3V=OTXw zl0N=!_X<3#$08nVw`5^0QKDLpD-FsIk;#+TYzP$+)$FneSCzUl`weI;QxvR>HUec= z@?Kx#eCG6@(HH1TX*?-lB>*+bIn}Scg!*U|#5*U~29#~N7{9QUn-vh9olA9H&#~Z7 zJhew0Ta_GJ`ddmH>1`hk9Yaq<XN-2Q8J8b3z|ZP}uR-qCJDaJ~I-kRIjT(pX`c|%! z2Zzrsa3}FFN3)yhH4iS9cR<UeJRJTGqey1Z<rWFZI!JX{)TYOEOiT3CyePY)L7K!t z;AEXucAkFOL={MPuoOtcYW$R^q2*N#u=#rtcqe>H=JuVtH#g?DnpaD@?d^V<kF%dA zQ~LLdtpvDlwT2()wAuGehn3rbG`hNQ?RMzneA)vrE|m9}3|SS4+P5vYVm9B;$o-}P zJsTphR9hZY*Tj|+p%(RDZvCA7*s=}I#EwUHB^4c~XrlBQxq6n#Lp|m*i3e+gOb(uj zCFS1NI<8L2g<*bV^+(iZ>w-S!;l6$y3f(kkI<UXl6!W?iyszN&Sf7C|9D*SwmY<Jm z^SFbPGjko7OA1kBM&jw*Gq)%}0`~bq)|d_9a7f<Q1`!6286ZFlp&rJC-q6XjGY@U| zRXuC#Efo<bR(Vs-Ei{qfwW`K;q^{T<;#p#%M@ior?_r{OMXLYFtq}PgPLM*8sTt~u zk6eDb+4#a;!6DmDeu8xZ0oZLeE0^eUnh;LqP8I%$f^L_M$1XyfWrwUW8N+--n|NVr z09{0crnI^-Scy{fmkLwOF&CJy#I@#3R?d_HV)GqPM!MH<ZoS2R+I;gfov0w~_Wa6j zHDKNDSDLk9GwFT4@dlDKwU41;M|EXEEjOaeoz?MwVPi#)n6D<{&xa=uz7z{FXzWN? zuG??SHfg<mbbXE%QIS^j$etTQqNonoHBuqA6c+5lDAjIt<udPEnP?2a(i`b6q)9!$ zmQpBm#h<%sm9&p0O-p^VFf2{w?s*UAaQi^;vmTQ3rtllGL7oR&=h>%aPo4D|>+=sR z?MST!t3n;{_w}};$t{hlJma1(NfrPfTeFK9@>A+e5=_Bc8HG6BNBbFN3}SSwmQy_5 z)Tn4^x*T_}C@CI4;D0c)C9o%qD9oJJRr^dIcA|hjP_C|%epgZsK07<~#0h||z|ZCd zwMhXXJ%k42pU{4k!M%-Kq6u|_$)4nT+B<Z@Vgd6(Se~{4KzAKKS?KmTariageBZlt zOzeQ|qG-9}B4JkVa#Hl9?#Sv-PRaHG^0<hvDf}Y<@4#yY9BZFhERZsQEZecP#-1(| z;YX#e4e%WqRU#F=HOl~&B*NqBAVs;n=4Uq6Xf?%a98ZHDo>67d_VSJnn=)-W(-(7@ zm_II^T@AKzRgn_=ukZSI+#Vr^72+C2NH*AUhb@)X80Utlk%Yi-e!Cr3KmU0)m-)kf z><hCjt*g(oO?aQl#m~>{<w07rAt2_jAsN*=tmi*-C?aa&O%IWOw&%#HJ!vcz1!t=S zsi`HKuocBk<W?tDm>(>IRvEi*pFJ*s`c31B<`=iOpVJ%Dc2mz8w;ah{Tif+g+C>KS zp!w{1{+VI#!gcQ^gsdTgjBbYV^c{`fOX`%lm-YzAFHopI|N7sJFC%8iOd=#eG4zpd zrX#!9^n98K!dz^^eQ|4zYLNi!%%ObC|E_e|X%*>BmHW$Z@)JHYNjavXMUN+6@@%6u z@W$hl!X-5B!n>w@-sqDtf48drx3@RP^jp5W@B0X?QsQ~duP__g`D@;ioN@Z<(nW<o z<sS!?(Qb4E+OAWorS;VdpBL46(Oc;SfbKUH{x%F@MYEhOqy8YX!!_L8L-XurM0Vv( z$!hsV{^8?(oa_d`ssgSw>OykAl-#{0hv|fMapdgD+tK?kPY_bQ<k|YeE6pOGI+KLA zyEcaEfgSG*se*OXr<zdq$C_t%1Xtrj_K?~flxC&(H_;NI?bk%$8B)DKugzqwLVDoH z<ckPlIX5Zwsn({lGU2zvYOfcK>Q4hZ#j--PLqMkb<`2NQSSZ{j|L`r<kb*LWgo6ZZ z@rmJMnfnR%i^0jTn_JoKgi=x0MTL&1u_hPzO*GAVsm^`SB1RWrv^;OlmAZ4l1Yjyc z`6#ZRkm=C=;L!$DrCrk32H>Sqh4X%3SZm|#n?ZNIzqT4krIMN_f!uSBc#UAUl{+uZ zmq2{nDwK<hi$-$K(cXCF!)GT6jJb;y7Nn{bd2gQ?m>2GL28jsv!)oj|FD11`zfMUa z-Nz9QxrbGy+m0T-f;N@OM_#h=()fP};ApG#cY(_kWs&kIPN#2h%9FOYzkfLL4|;s+ zO^7d1U3ME*+dp?}oliXSPI_#Ek0X^2R}X|0O{;<uD=r0qdaqo??XQPu0M6rcD75R7 zR~`094^KZn56_zT;TNq`k!N%8{qio_4?s44ZQ{fuRW>PCSKv!y*wXl;!|XV@W@ys+ znVc0pi`}GsOC5Ep#JNn*NE#wO*0KAcgudsYhcZ?DbzjJ7@p0F1mi*(N%MxGs0L_m# z<*^WE{N0w~6t(9M`)!-Y5zx0y#%tcn3k%@I(Ocxb_~L|`gV8wD<=wm)UA1z!UUNE_ z@Ekn3#!YI->&TVA`FSVcrn>p2BkO5U%(!jMGWa;p0p>?VnnZ3Ax;)Bn^3U|quWe~^ zGyhG>ZP=h1TvclBPt{&e{fJ-Qd?Rs6|3b+>meR-oo3eBFn$~2Hwxza5HS}_Ms@X+Y ze7?T)`CCb_-7C99dE=8Xs$@muaeHZFRI#qZEVbJ?Iko%pgV|h(?|wt+!E<{%xYN<H zZq?HLLWP%oc~pM&&9(h>ENv?AojcjO@tt2ym|(b@;ay96L}9r~bJ%b_L9i>!0FKz_ zFNpuA3Gn%8RJNM9c!pt&T~3dNpMDN_lsTVEuyAsYoVs7VuIk49o@jA`MOfY^Q~hrL zcKh<wTz6t#<Ytr}l_sV{A(fJ2wb^!XeK)e6YLwu|b~E`BN@r2{7A7GLe3neP2SH4v zw^`=PPp}%W{58l|p-KCS^8V|-`m*};)V-)wEt+{UgoCB44~jt&dyg=+w6uth+;uc= z^>r(vXFcW5ngz%1^Y9B%Boisz^3rMP=jOspm5^391lweJhR5alwtD$tt7=;}dy_Al zX!#Cl4VU^sdpES}TkFVt<4)O=e2O#$4DYos-o|r7o8t7?>vXQ6ZV>?X!I-t?GE}Lw z55Lv3;=W#rxXXrj$J}YlxM<1<XE*M!{e(Ni{ZC9j<F>PQS3b8So3~a4sXJj*RfV4& z)>eB?+{9lxw~sPG@EwDqSmYd9Hm=ZxHKNU&;d_JB&B{f^=`SfYIu;9Vn_K&Mnp_|5 z_gDClDHbRAxT)@1ubWFpobJ$58*2td&1st2q|)yBQ7*1QxUR;cXRepvWZ>f;m<5Kz z>7vf-#&@yaPxsS=&b?dX``$V?x5Hz4u9RtS{EBYbiDdfM?b(mT+m2%4QNhpVxn$m} zZU#?Rf9E90Z%i(M3g{63InWe=KZPX**95XVg8Wkc61VtY?7U}Clik}ds)&jrC;}oN zSWv2f0s$!j6agurhYnGc8j5u3_CoI^R4IWZ1f)YCASxX~3q(4Cln_D>EkF+L{l0tl z<HOAPa?b2CbN*lM54k5-U03_9b+5=@P@4Jo8=bZ5NRv&?XU@sR=L?A#jQ}tul>01u zT8H(6Uqv^xzkYrWXvfyY@@KJb#~_Gy8>89fkJ5vJB@=+vDoWyJj^dUfj+K*XV2`(- zKC#umXYt$1aU*y7QZ~N<k<NpYDDdW&V47oznLOgHTm_o@1tm(Id3j5^>Kh{s+a~JU zxOG-cNu2PyV^ix1yvpo)EB?gb2DZ<SCfiB)R$S+t|0+ng)K+vQ`*9{+SS#QaVx8sw z-00E_Ojb~a7V*_mPZ*XHEx5jgYhZ<WS})RnT?>9{6kn@o*Y2FnxtQo_<KcWiL>G3< zVq8?>zI=E2;1y;&CGwTy-}m}>V`NvjXS-)vAZ85)%;u@L^YVuI7@n><mQl7e>eY`g zx5*UmxT!s%$)|?Mwrs{98!Op~;r`#MUJuI`pZ5T0G(ol@)wO1&vj<_K=XCKi?gX#V zJA~xM2QwPZ+-X0}*o3&IBf37(w03#iYI=dT@P18_(!ZQqj;s4(`JEBJv({lWBA>l< z`K$o+7k%eOr7=_L!bbnu?H0dZntbeZp9L;}b<P7fs)c{d@N_a_HBT3-vEy73@Voi@ zsK)-u0mbTDcbfp!8S(Fr{cryM?}xH7-QpD21&&WF|0VZ79t=gt3@zV~G#vl+#|t-K zz4bnGU-*;FYau-}rovZ7{m#kD_c^pd?GKJ1q<l^JIGxw=*D+U)cz5j8<FgmC7~%Z3 z*Z&spf3V7W38l1y&5qArmpwv*!w0>_*96<hYYD1%k9>Vd;ZThe^n6GEy^-yj^8Y(> zA3KgYwwyFl{NHy0G(L(v(g$}=GW47@j4S;&hd(~hdwI<2<>Q;`M~atBM?e1>p<#Bk zT?Cb1iYecT<vUV5?L*BP@wvB;Q0zE8-5;Y|yWDp4vVb3I_Snhb(vkK&{>La6!hatv zlHs8?cK||+N80n)A44#xc^oOyYoSAJl40@hj<n&+LqpL0pK<Yj-1;B4{>QEVPr6l* zrSsc^yh1#9g1AFC7~Fh{)N{8A^0luh4%xk%5G(2F?~lpO&h{9e<vPmD+9yMwy>#u5 z5}`CIIkt@E)y}#w8@v=#l^hSbucEF^5c5SNE9T+yZZ*ba7+7i6-{2@AzqX0!N#$23 z3i8JD3SH$4_o$p7gNhFvYdGv@YTmwM#W(nxi~%;cvhWEHj<SG`&Z`@;uf^gqHoZOa z6t!>n-4do!rNM)-x6GI8%jOd-0Myt_e5FUZ3`qZ8+fS@jEpwt#)7iVnrRH89WMmew zhYqrH7@6cINO~qoFShoXB}~x?&i#yAGRLZUR&uNlO#ckaef#a~q7FX(BsK4%7$owI znMcAWqa6PPaNZ)Ko|;jnP%ls`%|B0tY&z`}sra;q+BYFPZdHJ#zs1Gq{!8Gx!-X<E zbec#4*o`XTxJ$X9^FLUeth&zr$a7emCQ~-F?YWj-v&(D0T<V-Qiwmh*?2N#;&GX+% zu43lwdBCK#d(wOjt&tcEt1!tF0g=U{&-9Q9)t~J!9-4`ATZP4n_DStBzAL;-gdZg% zAYk?=g~7UwbA)vR*NJrsb_4;6*&eM(yzpkA#Ku<Lgl_Ns9!2d?d<F{4G~c)t6_<{) z)dcDKI8MzEaAAATbo#~d!%6*q@|5Sxr<^QKh7>aj{N+Xgqbvs<ci`vT`Xu|jLW1zt zOvovU@9DWh?z@;ZguBzP;L2OK#)6C=D&Dx^1?Slng&Xdx-)GPE%Qs)`xR_CFo7<k? z{W>5&X=7C6;r08EVzIpU1$(R>?nbf&)l9v-wAjXA{aF=#)0dVMCY~qb-$IHQLC&X- zgYgX-8nt;)!lL1peUcNZYD_&?cQ6Et<4N;Gj3n4Q^chA-A(m4X%zIF|;A4koXN zpZ<Fhe!hNzpKm@CwazI9+HFa3@*n5yHUHi4>EXk8*CK9ogYn{kcuFHFdE>X$IOw{V ztDbB?qdu6jQC(H;Y>&ZxRN|wSDHlte7i`i#9xjy9fp2iOP4Pl}0AXIMG0PHffaC&T zj+GLnkY~@9lGvR>KdprLssis8*lfNHHmR9g)tUrG^w?r8<|URXy=iQfq6fsY@>Aj~ zyFVVvlen7WTcMG8AwW9uiMA&RG3(T5M7R+v1Fl&2#2zpEEY-bS^vhaPJWv&Y+CCUf z1LuXp0H&Xpp85z$ih@+&XhH`M3KoB87o<-CQi}tvPfq2UhdC`R2fQ=%ZoxKHxK5rD z)zBI+e`>Vdo8HoQaqY%mAsXGFY)U_m8Sl9tWn_ue5Kkq-&1@;d9cTb%E{W@@TA!EG zgkIHP!l1L}z^#a<-u)j^*EmEL`!~E?bj+7QSTEb`;Y1}+8_~?CN96m%iW?#XV@Z*N z=#1>&&ysAO=F|}xy<<~yt0u;>x}|sEs{p8;@p)g=oHngvPhFgOtl$k(JL2h&V4#Hf zfQ9o2qb}h)8Tz7_9M?(aQsUQN7TC>>@8U`#ycDaLxf)#7R|MHe$~f@Plur4Y<z1bv zRS;5aZWo^gSbg4LS4YjS4;9XPLLhja-jS%VJJ4jxNJtaaT^5-hsQKmS!&$R$4kVc{ z?S0oyAdi@WwYlMS)T;WQ<jcdvu8;B}d!-}vj;AI@O!EWI3VB&<l3FxGC=Ge_Rw42} z9}Ultbl<xXm30v<E5xFJSi||wPaTw;P|~k@kWn{`F0D?(EoxuD0%C3`dpZS?mLZ)d zP}pPjbQ9rO)z4PqRr_A78_#Y<S~w^(#O{v{US{&zDih(?EFLp7u{9PbSk8S$zB}Pd zs)l<qjSc)TM5a7X|6*RO^Yio7P9vMS=LnaMvkN07cALjsoMM}!MzXe811GA~W~tJx zffF9VN~0%vMp_!btN)HdgH19mw?1G3Vc8QL&i!hvStuI=TUv(cknnu(efG#!@pXY5 zM^4tPk+=>%*T1Xx^Vjs>ZYT@z81DuP95XD`HfvfMdVG2=G@+=dr6^nv6_7}u9@3OM zf`_(xxYhKZwk#%&qbzkwaec`r<BXJ$UvjE^<_G330><cDk!fZIJScU?E@aTI-H@yI zM76f$Rj0?+9(p3$Ju{gn<)sLgU|C5`rtI@15+DV(|J@ip>S?;{g_<$q_s-b`R%vu- zU&v1rDkhoTD&LM`6Fu<$ASaLujTP!<eY@k`X9L9Gxnu+Y;o=C%u7G;!``E^1F~ZU~ zlQ)PxNt&N$P%f|iEX6Em#aQ>iYU_6CTJ=T<laBr~4|uvgJ|7y-X<;yiY=YUV^KuHM z3}fe_eJsf3r_xihx`KW6dSGW$OJ}0}qS#I4a?y4V@kHY<s2&&DEY6%HVnT$@wF0v- zL$CG>DG=2^--^W~C2;q~jyP6f`zd(Y;{z8-2D`uGO5u8rT4<S#YrzMh<map8o6>%; z$>eZ?{LAbh%N%F`wXi<ipue<<LiLdR)}cL9=iVw&9Ms&X!e8yDR~$9wOc1{zXCT^L z>VHetLP;h(%3v_@oT#K>KDB;+@uFp=O}v-{_O4sUlc2jo`ef~wxU=1Gfju;CS*{oP z9-xKv|MVSJdBds<v?6l<)`nWk3#yf-j+D1{DaqmFQ}JSUL<Gu^QoB>{Ej>{sbeM2{ zJ9MyhU0$m@2yM^=iV1!$`QBiVlW`tt^`=iJMSVxU@`<gLoMS~jFd4zFA%wIUT<bUh zw&kBUsB)|v8?^~#h-=u7j7@R=D-F}Kl}-0pDcP7ABh88p|0EB&{k<^ul$|)x=*+Nx z`z~3Xx)(~r8;vBR7v%Y(nusSB<69p=jgrNcO`dO7Thd+G`K<}+rDL5I^0DK@j?6g= zJdr29&l9OYYX(+^i%F)h<<&C{6ckE6SYFB<SO9u_kiI=qRO5o{Yhusdcr(=b?JUlF z(a0*O+ZUeiLySg11omBDySMp!w)p_@<*!RCi#-lkIcX+%&cCBBXxa%YNsAsHVq9L9 zfp(_|U)ex&n^gFjdABO$)^<54=w6$v%(J_RzgfmVl8yE|HD3z&@s>fJq6kT^li7mq zMJsL8pQ)B|3dZ<iY@Uq7*1NyqNh=Gq4k%BNjO~g~kNu*#g{?JA?N{JyuM^)$|1oIL zzZL@PI)y<7Mez>H1k}00Y7D05um!_4r-*5oD#_y|I{eoL$F#9^6^ZhKoGkg=u*G<k zEvRD6^-76Ju_Cn!zN{f@BMb*fEai=RM_}cjE%2_)3$q}Sc2j~QE8bQW(7w`(-nI7~ zGcqCIOVy<9U@w1PtnH$L?iljlyX<XeW@WM!EoU|HRo-BE>9;p#sR?aPC5e$`j$;f# z^~=pJC2u?<xJ-IFtVZu!NgAwCbxl(JTLP%~)6deI3Vh1Wa`h~Wb-9jMCBZulXsP+a zwxhlamUE`By=DfM7QJ^jqu!W92iKq$LR5?OdbzB&Wm&SINm=-U>TlN8j@k<u|7zI1 zjzj2g&8vRUc~$h$t1HAaW+}7U{AtoH$AH(851gjqY(y#hASCgOnUg1Z2+1lpfNS8t zl|yFH`yfNs&(v>l8qD?{E|phJfZ_G|Sf8&eA*DX9pXw{5#w0iqR~ZX`Iq<)&{(d{b zP3?J*^ROHGkDQnD7RM1*o4Ob$fKOmz;Se+*Qua7=e+Wmvrf^(|q^6x<zUx+n8Q1sm zxzPYQBvjy8q2llO<Hp$Tw+Fxt+*NaKZnR|QN4f4+g@)hn<o5j*Gx_f&<=L=n5o=IL zc|SVG4skfGt9Ntlh1+u+CKBNTKQm}<zrz#b)bEyUy<}!4*%D<!30MY)*-Ri?RCNV= zwV&cht<R$lI_~5&1hxq6>W=hR%+!JxB%gg=HOuwoARCnp<NUqry>LSSe&tyv+zznN z1}-7rC`+;{<Vu#V&eqjem%nE}7Ir76%j3syK4Ap4Dc@mFzM&wBn54*;=zzPFBvv`H zd_cPH8OHD28OwewaFjc(tX&?QWa(REZsLBL3vD4Axqzmj+PWvQ$Yn~sux)uf*70oy zX-KW?V%oBP<nMP4oxS0&CC&Sbk{sW14mrvy5J<T@an{fKAHDjk$n-JN?{$yH6*ZaV z&!_d5Zjhw~94^|P;>gRt2XzollQm)Fw#?RbRRWI~>2oI*_O{2tU$FxwE1v;nd_E*5 zQ`X-nUxni1Q4igLej`IpGaOPwnH}cV?9h~J<AL@tB)|nPE72AIsBF?gtfgo`XtOAZ zbE%vnEHCdg8!MG$k+S=w(*RgD>`?`;&Oo+~A^e|(vtE-db3CCKdubmokZ3WZx<C#f zQPrNG?77sf73Hioeq36Ycdq|z9~R9#UDQ)eNP@O95}?1PuaYnUsl*Re#m1X=95>U3 zihPO(yj7}(pg+tE^+$|-h%IdvfW{0=s#Y{k+p~+@iq1syXaW1f$qLq2^XWTQ;ccfE z8KI#hNBCmn)7V95lE5S4c!ErCxRe6y@d79L0QF?OL4RVEZ@_hXUAQW@Vb|AByMiO! zDDZQ>mpsKgc)71oDNX4+pq&k_HUjWy<qEQWU1R)w$yU<5^gV0lrg*&PzXp}$uljG* zbWE+HmYRxAV1Cbb*ZC<0_`(8B`czcvO~xejktHD&aNA4Lccw*`-e&wTLgme!9+ar{ zT<S{%)k=9TxdtUBBWMw3D2)@{lv9Q}0BFUGg2BZ-wdZ~fCkM+1<m`Hb1h$``$L#rg zg-hRdEMDX$iggP?cPfp%%k#@-Z_6f;I=lScDkMFKWA>>dVY?OxSBrYfv6iLE#CFE{ zR!#G~5pq_n)`?x|l|*}vi^>)fi<=ry-xOtAcA79-@WQnCRfU{l(1pVNeTtOlJU2h@ zpsAZ;2)MDa=C+$Eg>b%>JZVYlK#^9BaT`-3^2-B1dOHBaSjCJG@@wCEh+#t+U2Wg@ zEh&JZYI^h(pB+=ffgPwWFC)0EQwlnf^6(b3?fK0iS;m8kpf-9+dTj23i5CGQR6Hcl zt+Y3om2(cKp%EsXOqnZGLd7`E7kOG&v<_!vwWz!HUW^;J9b61}GihmUH2N2kaqktK zx|*xbV_O|O%4AVPiTK*H@3<(e;(-MyO|<lxY&sYPU#i}>^o~%Js4jP>Si5Y5wU{v; zoKHz|^)&f(SLH09a6u0C`nT&{GTaa1MY!h<5RVnhI+?3dkfwv2I^I5>bDo<U5knoL z=>;0=te(pcbhBE*GeqW+ZVWo#aYxp0^gQu_2L=Atk=Mhc39_5JenV@gdlF%GH#5Dp zQ)3Iz2k#cgk+*P@inLnwG}_(O`xMT4y)OUJoQsAN_(dLjryuyL&S9^URYKp3mD&@0 zUwhxZo4<|CDMuy&$3qlAEkA>%4TdB#5{`q|H52<%>bF1d1RIsh9JFd`^?%8f-Wj-S z*w96@Xjt~C*9tygmrp&|dyq7?6B`O3!aFKVGdqWo*2N)tOI>T@HH1`I`^U1LNt|ZY zc=@Sf&*Ft~@AW#rJ)Of){k-`-c5%`&VcUS;p{rF^iC5<@0O!G@ue8ix*NsGx2GPp? z4_=?bNs_*GS!6MHb<DqZVzJW?k$jDFcAgYA9M%5q$t<!Mn-Gf}$*|4}11Tf@-wri- zIwFBKsN|t*UnS2L85VnRxkyKD+w_@>T4PkJq(14-Cb9+HqrE)1%lG5`xqDsXZyUjR z?|D&`>f$$ZhirWutTh3aDZ36ahO-%(?wAVmy8&{ARZO=)`!>>~viNhrjn&MBeq{NL zSVO7BexMIf(~ng+K(T>}LkxLSun~6CC+u^lhi{QK`gHA{W$awCPxi^2D5)HVA+YaU zw4BkBAZ5?YyITDbZ-NKGpw6XIs>B9js0lA;xwA)X9j-C@e!6=gAqtCtYSMBongMu5 zR`mkgnY}kogANZ#$<jd;ntQ^k09h>p__;rHn4`nn&i|yOaA9>~_Xzw~2YTMDu~D)1 zYtAm%ybC8*)ZM99bDuB7kQQm{jTxHpZGVe~xdufk7+Q8!5o4KcH`?c|V3I*^4(_Ce zSx(&1L?tctdzFb4l4{vu5?^B6U?o*z78^S&Nk&*QtA8Z{!R4{;Oz~eb1pZvmb_=!C zUCjF2$<IIHMOtw2iDi?dbB&sS^AM5&7pVC4^ILY}LO~P=fAm~fsq2`h@_r{*z>>z8 zoxmgmQ*gPEp;cL#`@4S)G;3$>r)6=i4nH{a5R5|0$lWGPLzW4IhDB*5oyt~;Ta-0m zJz%Kt<-;1-UCe?WavYMFU9;4OO18QUX{gEAvMSQ7pfmxSC{xKUyVu<t4(x*qzaN%4 z-MJUb%!olQYZq5&R_p&579D4?xLFqCVQ7&;2mM?j(+TDR%kVR|{igZyyjy??<xSys zyHA=FfzH8&Ic8%HF6J@tRtH_Zj_@xXiQVDM<(Yo)Q9H+J*9ocLO(JO({fpl^i_Mpg z>HHe8S)e$895>{GDrcgHK!Zb#RZqq)t0r%XQ`piv@<ob1ja%E0W1M*A95v+U3bQ8k z2ZZPQE(TCsG%@v-d;_;r3rC8OXb$mh!zi5YKtY?u;tfl?XVWyW7co_|xp_Zds&C_+ z_rn*iKTYZ(H6U9>34|?qHJ;122toBJ9$a~A1OyJIEScX@)MV<D*vOw?s4Nin22e68 z{1?VtHenx%N1(j01B9u8+a^x*p8WtS+m#2aT!lexZ^l+GmF+3nj2@rWF0;<4hzi@f zLvggL??^OZ3dlEKj=M6!%KC)@G<bU^)NWC>z&m)Wkd2CVEM5E!1HEJX3o~Wqn{1b8 z`Q%4g4InL?pXkeDO~2MtQkQ3#@5AL6@I6P^X6y$Q@4d43Z4LlUiZENLTsU3laB!SF zoZ&>r#?SDi`A$L@g*iZ?wycOCs_SOF+MG{H7aJgtnc1Ec={)N=W0OuyuL1WAH-Y&t z$3Ib%ND#5$ueyoDcJ2=+#5#`qKN6D^m0rFWq-tuLpZrxzJLPQX>bdoGAoH%-VXq%s zrzPb0A$(eBXP7?!_38N7v?sftA4VQXWZ31JydMhxY!kfHh<I3OAfZk5WiQ>2MC|aU zc%SL0$yc-&31|E_`1~l#Au>xoc?)LxYX0W4Z8ffwvE7>7>=r8S?leKg`oQa@OMSaM z6~8&mMIQ3%US!onPB!?Y%+*ii2h8Cvvpy8*)c@%fdT)T<;jCe{cm#N}x1!%f?V9~z z`p|ZkZ8CjBJ4l#jTQ9QQ?OZF=OTJ^jBEso73@M2wix)bsKs7%74eYXkUftl#LU}aN zh<Wjl8EsRA;mEMQlY~LJ;ZC`nu@FGVURuw0?O!8ygHVy+Sh7yQgRU1x0M#qvjBIT} zMYPf<3=OUg(l-~QZKk}8--URNnlr@d0giyBf6z1Zyfgiv$8!{zzH)KJIg`^G4X-#7 ziGTa?*m2ASA_MZ(zu#TEkU>X3|E+Ao5pWdN{*mEA7Gq3g7S~aPfBk{!6{zXPN9{WN zhv|Qq{)g#*nEwBssWQvi9@}{oRUT<Z-E^9$ufZr%D*8O{A3WWQa~dp99|l0-wBUN_ zBsSI6#BR7*oO*>Yu*3D)H+;Txm|gQ!*bjX6&*#H$kDy)mhqeYMXKh}(d>5_T;9I!> zWii}aR_>arhyX6uvbMZKq3uz(=-VVdEtZ;%pQbL|E9F9bO_g87`unlIK;4}U)<?;d zG*|_x(1*WTUi5C)@|pa9>-e?g3>)H@)idTW;)&w^#jb<K_(!UV;szjG?^K=mzRO<s zI<7I!nNEm5w-)-wC*_!ZX#l-V<(%aa)>0SJn-W}4mm1oItfno92dO2THJkq3MXC_K ztKY_H$K~*>a6!r;TeC#WZRt0U22Qd`u*gG5)h{DA-(ejWv<XJECv+Kh$9(2V_5GPM zXfrJ=GML)9KDwi=E6qoXMY9COz(?2Gf7WSs7`s%iCxjNG`BxLlY*+G<N|Q*m`g`m3 z3f9T!^4H>ZWNH3{juzn|yc^iyEle7nD7rrTLn$G7zFbD463GRdQ)Hy&+DT2v+G>^# zJIl(rIPJE&%m;sn8z%6Iq*GkGe*x}nO?U36iHa7817`$-@)P%K+E-<46N)W0D#EL* zGKd5oPU5ihRzw`1WBv~FqM+?$$J|inc&Y6DfA9I8y&$-DT#h}p2&Y>y_&Q%)^rcO{ zokCF6DIHl4D~xq_aPDa_l>J)%Jc?922$g3ZvSr%dJ8i`Z=~JXl$8md+Rw6ccc64=m zT1B8g=ctL1eYU>A4w)Qod*!p(vDJ^tv6MScoFG<8UhmSysvu3Nqj};VCg7S&g7G1{ z)CsDwjPz~tvkuc7`Qkc#?#=|%;{LAtW<*WBc$M$(pzgvaa|BnD0c5**gLOMH`~0k~ z!M-5tSM38W71w%jW}&Zhoo$NLo0bUuS~>o#8O6TA?*4r%Uc5m!6G;-4=8Hjl??ji7 zU592Jy0_rKjF*`WjVez;yK*{^WIx=yc`cG?bI{TqZ}L`*=P#N(s^k<F@QB7ijT0m7 z#L`$Jur#>{fNyDyy;kGNf5)iai&tNgms4cP`q<rlev4aM34;b3W|=xQr{)T^pPnAi z5?G`x+Ta)A>vfp25Y6YAZoQo>Iy-|Aknv2n2Y$E`4;<ZA3cg4yN8ydFzJ7i{|BR1^ z12GkYnMfLs5Z~)p-#yRM5gKh@XjS6WTf^>cv}H3L7O+0lD7%~>tFZ%07q20<PNpR^ zSLjD=Ipqvxc#mjbTmCqimX6cDPEk^TPR%&zzJ+jwoM3J9R1$KAz>**L$<&;lD~z>l zSV-9l+484i2YnZomufpWkH}Ba%Dv}$QhH7I-z(%_3TAtH6{D-wCDoMtXu=EJJsqSq z(H|Bzc08kS9q?k&OVnBck{Q99RW|wwe*Uu4axhm&BRIp^d~fHX{Dq{716@$7hmTqX zFYowD%)#grE4SXXRcP7<T!$w${Z|^t#z-!iGAbCPxGC!Gw!o;tW4>KDYinUBPJ3Ni zNnMB!Y5$t(gW0+Z1XLGK{qDQU3aM0IG|OXy_JOAD_6nMmx_S#*<X<rI-h1($XHhem zYF!!QiC*$kd#XfJ*4^BWl5w#Xc;~2lEvUwC05WdE?k1t9Bx>!vMQu@8s#4!z;`XZ1 zBrIk1s+>XvboAFbiq9Xs%?MbM1$^RrFsJ&9{$H^ZX`bb9YQFQqLGLPu<BA21(wH1$ ziFNbW?muYT81u{&O<j-JvVInYLtagC9Mm5vEI@+rvg1I;pOmu1qT&2`BxRtHKCf_k z<-LZc6!)o{VkwJVZkfqjx)ys;oMx5H+|`~5B>3)3)H!Cm?s>~GrCmv2PkqW1Nvc;R zr$J99Nqhp5s=I<Kvuj@viQ^z5Qj5X)o9M213+TqAu$!d+#(cI1XKj3Px$dfHkv{8I zoQf9Qv0@0|yJ|G?@!P`KM9&usF_ZM|T}<f&l*=2!<0h*faPbkOxw**?;^{yvTNtQq zP)y!VXKtot)@Ledi7p<5>h}+l@p(Z&w_&X!m;6ogNb144aRyblUuplYVL#8X4FTr0 zZ$HX|Sr*F#==57n8;|f<_<Zj+cSvtac}dXeo-aK|9`XA*vdWpMfD}<$wYF0#sZv50 z=m4P$P?R?7hQ;oj1Uq+CtBy&bhDCbSx`n7^h-n#I%$N{M!tSJQ)qkz^fo<9G3dEEg zPz#Om75n0SZyP<yct+!c9GbLeu}qTs!E``vov?Xu1|QH2wXb$QGU%sSX4m??IeYCi zGbk?nc6lVDx&8UprY2)4Uz6eP$R(4<L1qi#yPFIeP^=>9k)?zMUuRTMvhweB)|LX7 zx&X35_c`<RJ7XEaB(r6l2F~r@Gt#8P$<SE_Ig9U~3Zz0-z{?C$%fj~KlWE@*OZ%xm z>RId~3MG^V^XFQIe_X?1`JB>yOaicw<sg)`mVyJscfmbscg*8+kSj<XJK(ndDzXdd zx6bAj>p4B}tlQt2KgX>zsW@J+Y#p`LnleP4oRD8l-cbZ8i=(mwsl{^MLUSfAR2>}Y z3fKp{!g$WS+e7239;7)9r7@w4e_8`71~d{5(jmqMk#f&J{kzc9TV%CHX06``<5l7y zy^A{M1p_YQ;%*pto5LoDZ0vs<Kie_^tX~&soy~3Su`64$m}y^%F`BhQn1i07-Rz^9 z*V&%Zz2K0!r?Q%olq&BD^iA*no`li}^x6#Au@tq4dFJy0?V8^@yn{N$L;*3nJQ<H! zH_c3Qc9rGBREk?gW36RbPgCWPv0@VaFOx8D;<4|85U0)4i2+*vp|KJ-jD)1yM>~2Z z+G?@gYLUr>IJdD$UbEzEcE+`<K;L`Ud#%^Ih1-S^6oCd}sm|wDo3`&0J9YI$B(Xm3 zN@XlA9<djbMDZ)sOwYkKPnTXD$#*re6<X*C7WM?KXFbcZNAx7h*XUGV(5FW=f{72X zO50o$5m)RhEFg2(xYf233&XUhqGpxaTC<&f(c>JXb{&G#XDsoJyqOW$+c^_BX@|Z` z_)%y!i!_>$x9K*VCj#XWv2)oMGUHBL=R=oC#h+C&rJ<Q)zs6qPw;Q(IchbqaGgb>l zY`AAK`|rN#rX2Ltdheu*b4)QcYG2GT23q(rUK!bPV!9%u(vc|Io0c-|ZI2pU@LIjI z^{D(2fYjTSy4lnB1e3cC^pRh74*8UkOw<md@ITLdVV7h_KERhRYk;H-b(ft7t&9Dn zH&;3?Jc2Ay*BL3iE75WQmwXfLbeYtcgcA3=!6(*zwi6cRd4St~K<^1dyMC5#DaQ#( z+!4rt^2ty<gPiU)0hzaw!@xrOSsj`CS>=4Z>L%EBXT3WXLGR_CPF=KXfR8WbwJ!d! z>;F(66_V%YW+iIBk$6VR>d9+=Nu`a%fxX$prI^R;0~mD>=y`E~{jK@IqDUF5C%P9o zI*q4ZFCw6$BM^{Hdaq@P`=Gx|{nPf39Dy9c_9?TYh_Yq7V4Zp+zs#9V2zq@Q6ELdl z{~Z|W+AMMc@LegOM3=JoTa3%kmI>_OmySuGnX>xaBOTbLcpq<ZThUFMRuDF3Cxc|u z9{>E62O;g`$@XnqU8)zCpU-D0mX`(5A|<_fw?ZNJXUku7$QyOY`{QE0B6;A<{hf{} zN=tgIwBFYl^nrh$|2cddXJA9Hc-@VuM|>>Nm;G)KgV}3yALlU@&8faOAy{oE6VYQ| ze12s~Zo%!v{Vn^AndiFCaefA$8&x+?oyhPalp~j9!EZzYbAEVj8(3Mk$N&dZ1vBI9 zfc`%X9roiacYfFIt|YG4RpF|ui!%VJ;AirsID(<dDZi0PIX+{Sp^M3klI${b=Fg2| z`LG^#UXVGMl1^3dL4+D`$s)BobtHFr2cPQSOFx&Elg)duAX28~vU%+3&ZRLg-N=B9 zjq{*D#ncM#h8kj=eZa259tl!iFE#N&UlM=}DduahY_HngBeC$*HFi1iTs7E2HlfwW z`DA773;L)ZS^u3RvwG-?ZhNxHc_-i09xqWL!qJ@k2NyX^tkr+)M!r$`mK(gVFplv4 zI;WHjm=A@vM0%~e8h&cM$Ew`1pGRzyCwuqZ00|0J1{TU>#Rn{eOuN31^<9(<9{gCA z97y_&2aahAMS%Sbx85R}A4iu3PpCX?0B^}1)DGBPjtUx-@Cgl#06SY>lZBc7tk;$y zZQru6puzZrD+4pe+cy0}j3495(b3*t7-u;C-5^DOP>z93!PL1=)bm)3(>u`N*z3*_ zH;d4DpdRF87eltqw9(E(<IRtDsn0F0??)EYvTwDof0W{#Sr3E}-h3l8(aV4)i?jGD zFF2kRelz#)jPtVL4~K<`FLC72Gwre!xaX%l(w#x~W_NeFuXsLTJ7W4vyGa-RXK)Nf z532$Ff20oMjYgae<yCTD(;ff<PZ@yWQ3s4ub#(vgXCB;t37CKInWNyuQRC>(vv-;R z&b1lukDNGPAC9?t^CuUMcz5kW<)1OPlH_>rD7u1w#@u(-S<FX`xlcq6$K3xg{SVXs z?=p>Nc&Dj%n*PGQ8v59{IDq$p5qYe3>o@XVh3cQc5-g>&ZI9Rgz|3QWG(y}MQRDjW z&ze+C{(J<KJ)&TK_)Ck*<Gt-wr{3&$NHEGrAv9n6zYfY@di3Z~&$oAs13BtZFV|y_ z|F3QBUOH`eU@!11mF3=<lZ7#!^m97jB6HgR2*q;g%R%jr)}<SxjZ#eivnJmVQ+`?W z(f3Z5%0EM1{hCVVrYiytO0}c<*|v*oia)$%65gQ3GeParNvT{g1juiFe=sBRuvg%k z#`}xL{DL#p4Sr$POMTXvx5s@(Cw?#<HoEgCP2VidlUx64BQF$u#eJ8<Qp5c72}3@( zkVGB5%=}%!q6J?J;t7#XQ+_}p%B!zh>1^wTZ&5Py!x>{zb_X^CQ64-5|7L>Q=f0BO z777nr<e_=^zcOH+uJg(KW&W3RB?%&^QfmGV`}z4cCzf3=_t!$VRQj(j=Qy50j9;Xs zP++HYtVvk0&NjKYxz(+FQrUfzf{~vM>9^ZH`7e(b;aai$1c$vn@1an0nK_jT@2ExY zJFcbUq>xNIf!q|SlLSY|lqGPmsK&~ttTM`}(M}}Ov+$1hYJ9*DaM@uXQp%QWi41`G zl(CNDOFb(${nt+Ry(eoa8WCFRJEgh0YqlylpP1^nmz<sn-FPTvxG_dOf#th=I()wu zc=oP}<S9yTZbC-Hq`_kS_Oq0^VgGSZabQ(jk<GYEW#3rwc{?1Q6_iS3Mb-Uo*jU3R z)sjaR5;!|_r(&Wqc&AujP5${FqDUa`ucM`G*S<_F`|Zx=!C=vd=G7T;t$fn$fynT4 zZlOV`bMpkAwsF#f^qa*4oh&CPWQ6a0iWV~Uw#CLn5)>c@PvXa=<aDcf^+!`NPMueE zRvafXuOgrgPvnYecR(o;)^kPvT733h1l&3MDVJdHc1>8m7Dl09YAX`oDO)DBICyR> zK=u57N}4U5yAsNT7Ue}a9S5+-8SPhnOX8BHU1hy3lAn57Dc8en#%p3d3Z*&|t1d0_ zQaU~=ihvpFPX0Ri#8*}bwzJK^4!uw;=xM*cI5g~BbxUP}8KZr^K@1D9h1&%y8U$Dq zQQTz5?=k%GTS?Yj)DMPg?M_T-J7Ly5)G+F<I8%D58q<QYaj;9}#bvEs)$dnBENxFQ z^*62NQKowocW;yIK!8odW+fZCknaicxZnil+YKzw=^1)fL4Wls+XVXTsZb$e0yn<g zN<QG>z{&Kbp1$t{VurN+todmZqwtz#&iw>vET5a*;^BBCBen1gWmM}?zPT@J0lDg$ zBMzxHUo9y?2H*D$+I#_wc(EWa87rcq6v2)D7%9F`1EoDx+Z-?^+|QhMH7QY0_uC;j z4t1Is)ip`_FSV~5DN5_0{S|W5QEr2+oX~`fU-Xx@%#Js=YGRywjF@Um-?MQS&yvOU z3U@*{%H4|YiG(JuGh{Jwx{Gc&mk9!i%y8RVqIi@%GqG2MWGfDM8eyFri{yas>w-j* zOm>_^rM#wC%_VK#UIcwDe9}#gm$eOz)h-H|4G~H?Hq~er7w=HCg-*-2f@hi=i^2DX zog40~ekr<2N#FH$%G1>6)ExI~J@-&5li$ItM#rMddiVWQ)OxvfE$`lg$(t7+GhyNi z$_j-45yQ_*8FNzs^P1&B%Ei`DwaQzmEKVf}_%CKwW>2ag^9*j+dbpR2Pf3eY&4eqJ zO_GHQ57bM_(pWs&v?SO=0_rAm9yP&~v)!`M6FJWLLgpopQOu&j-{`qBTQ_szXCA4V zU>@c0E@Ua5r}RBv$Ac^0s6}0V{Q9XKu-eN${_%T2?Cqq-;Kwc>jZoAjgXV~*@f#~U z!_rIM@(wR_oHr}TeHTrfk`OIV(_y3%=L#3+Z}A3R1M361Kf`uC*L`>bp>SSaCH*`I z5m_Trg&L3V2Cvrl!ZX+0%D~R=OO1-+=T62r^@qHj9Urv-%3<v$>efnRD5iw<#onL{ zqre*%mj2Y2eQssyKhDy;3Ngzv@4tk}GV4;9;F_@#7o9BetVuMh@ew7i2*IjXRGU&) zV%QVILf6h&bm$oc-j&3N(Dscyiw(o4pz6pMp9D6(w=(n3&(iM&+G=%meZ<@XX7oh9 z1;h5*c`&4!MDu5POe?JoOmHA&1o;M<+?-l5Q5iW>7%=YU{qWdrj7Q!6AcrDN!$qVv zjpcQ7Bj0r}cx&?(Wo^a8%fX5jYc+Q+eYh!J{#gO?HZZGJsn~8U>2_9^&SY<cpMFB> z{5!LTdE)PMbJ-B2tKXg&0J@nYXWU`yR2-s)V`1Ps4zGT%Z{Kh9&n;&*dV{^e<PNkV zB(UK}c)uoLHld8t6Fn2Usv7N~Wj%>C@D?)|u$fqB>JHHl<%w>`hhKjqMHuhAZqViL zg-?vBa$J}S(GKqlzmQ6awH|fv5r2Mb2Aq!}yAeLW)141%N=?gxG@mMK{876p)mxtH z<~0XojeiFBNh~&obivF?zjk<vo=NU|<^!X9mR*bTcd8oO4fLxNf?}Fs6%+NcqhPYf z2#X9nkyj96dE!(EJU9H2Atb2~bWed>$uv)Dxeq*I-_=*|lMcFLh<x5SAXn#AIhaaB zgGP^69EMCn%>I`_Y%L_yRMGD2^Y6w?pv%!Gj?;Ubz4KZupMmgKkI@3UrYV-ro@(+# z)PQ4ygfO9Q4K(p}#rJs7@|i(=<-ooaq$B!alBnt2qKNxLtEfjD{iav71NHYYqj_Nv z_t;vbb-p_`-9N2&mjyezeib-M)dbq|a=7*CgX;2TA^8Rrw;ucMWh2743DMR!gKI2v zz<X9f4i0y+WyZ6kAs!je((~q8Xf3i)p#!qR=m7Z&6Lbszd|c6xI@_t?Q>dN=wA-D= z;u<;X4iwzx7q&0omwdI7uquKeDbb8HWFYnnzqMr&!1<r5{0)<wdIsZHKZ`B)jn>$o zq#zS|s@E+7Iy#HHjQJ<1X(%T&io~Lnxxkaz+Z3MR8MqVi(&Dg9VwU<JzyiHm1XrG7 z&@O%KyYl~Oqbt7052#+FpZt!~(K2492*aH1G@EBRTjh6=xpNXs1BNh4CoGE-s+Jfu zaPWZa7nJCVG#vJ`e4O5iHw&;gkhGOj-|OW{NQz;J(F#aYI54yUdbcf0Hc0<Y>ZYYw zy?1oR-{qVev!nUS&JFUj5JSVmf#2p@%SZ2D+oQjHpCdR(C+wer+jHp-OVQI%?wNkf z-s>lWk^+^9pLy&g!-8<J9y*RE2iss0Flty%r%ri|Qir_m(k(w^Y)jZ$NBndO`FUp( zy+KIXs+#l5+SS<t$s`6g+v9Xzsx`ij-2ZHSzUnhPTv#hv?f?(fvJ>^=?_c^eOs^c~ zlCy5AntvfOcUTH6^MjMi<Lz$zX<6A)tSmn;al;S0zS-R}_h~gzi%RX~23oy~YgffY zxnrE!)vuhz&cLcQ^UN!UDO!QPk77M-;8A0#zQ^Vpp=W-)*isQ*VP030`_iao<(^A| zn6x+b`Od4Sg1;}9!Q?FGgniz2zgZ43$<l3f^Vyp?;27~8r4~-A#r<>Yyyr+C+R1>C zb{Q_v&ry>OYzW@>nvRh1FV;#Db2&Y4*O~m;!nH<qq|&8-zyyL8Z`d;cBaLJo<-$U5 zJYPHe5V5{t>lAk>Z@yd!UvC`%EDKD>h4~1HV#2c-olV0v^q(W?!rBBHiFWoVy?fSs z2jXL<TSoGNNm5%bRz3R$6%I8J!T@k48Oh;77fp>qyj7OGN>gMkSIhn9Dbfevtk&=> zXiwHF^D0*tn(0sDFE~#tq>+$W_cDeg77#yr*rJmUz9_D90jeB&Zv^}pOOy3152E_G z(aebGfI}-@NLEe>1+!m;=(A5xgVi{YkvrwMX^}+tv%_VYZsQ(^0Qw<Se<*HE0kT3$ z{(#@k{%r1+|A?@aL-kY7*onHQwY^|Fw!3f-OEVRx`mL(TI4y;as<*i$xT%n4AWSBF zTMiBUG7<Q8AntO*=yE=^?*w)O0jW77`JrH9yP=K(aiw#~SR395(k1l=F0b)R2pIEB zO_Pw>wzk3MKDCBcpvmXDNPz)sP)JuX+Rg5&)#%kY$^X6!pei75$aZm5uofM|F_DQz zI}S-Nj>A{amxGH<8U`{bWdqoe$5`6%8=rc^uAOd?;QoNBG<!%DQQp{Mi~_P!(v7Ng zwVCj(5$j8qC5^Ic5eWNk0}ks-{t5;PHwZBwhp3(Xyo!GvD82pa25Xi`fjpteN(B0B zECU#@u{9Ag(uUS0$<3{9^y@<Bdp-|Wxn<UGPce@9P6Ul#8(SPIBYW(<@sVBkj5tPj zl5yMZV_rEEreSo*e_PppKQTHh4`PWLPf9}{pKw#m&Vsaz=JLy&9|*fTjz(${eD|TG zKE)>OdaL2|J0|k3P?XLR@r$El2yy>(fTMR#Kz#H{YKD-sKA~=BpT%}}qIH=123Nlu z%(U&DZs6<I%bK7x*wIhZx86e61<Y#qS~nzHI8Cwb|7Kpe)fHr5Usc~P=C-wzfC+|# zfW>7E0`?&bidAZ>SW445^fp;$-!8bhVWnEpkRu&}&eeGG`tf<Z$%oU@4(~aGl2=G3 z<{n#la_hZr<WU5Fk8zP}08br}@z%{-3n(0F05gt&Rn2^<_3Cc1#`<dTQ2fa@O!cUU z?7mH>Z}}&rq)D{+FM*$3Av@vbcxWNdm>RUkuLVaaCYW@f8J=M3tKo4z8@!*#YJH(Z z0S@A<R?*<qrOC03AC3#2T>!bKi?=JPNF=|^cx-pzmh3;r$qUa9<C%@{&8GkmTcn*L z0aNfRb;VMQ142<WK{+T|j+8>%Fo6cu3K_zG5(6j;c{=HGhzIY^z6-iVJWOB5Uf~nU z0170rTRPP(^kbbYAq@uyj}y7ZXcZZzKDFt!UMXIpv;`K{G-?lh_$JD#?u>b!c>f9U z<d@*SFejtl-3e~7zWEteFU>KI^0h?WymB7ocDoJJQZHU?`qg>szPLGlAs5qeR=fVq zd!NgI{9h9<S%C-&4a$V%Q3NTSB}jJJ;uR|GgNU55++$E1h_F$q;x$5mdXLo%EIzBM z-+9v<sHfiGR%5|2<h?ml3I7~SeXKsPK4##KMa$V*!VAC)v|;|Bgq6?37A_`$F4NT* zM^gXpG*MbkYML_v^CYxcv8NHoGqI%=v0oa?n_h3p=!$Th2=j0O<m`*#$)2u+HT-d; z6Z~>MtgXCB%F+;|h-wbvtv1SB@;8sN9Q<jSj#lp)enlk@HR&(NhP;6lKDyKRoqhn= zknVSob|xH-e1e_oYnQ^7d*$y+i`h3olXlXfnM1lee;wAH6u%(NH^0Z7K2alJD&yF9 z)9jTjNuV)&J_P_xOcxav4xO|NeyN}`DM)`Yg!-VDCJV`@&P2HNT795-O?(t9HUp-@ zVqC;UmSWtz@&bUB_#X+o-)}lX5Y++0c^&kHnB9aMtZz$mv~bw@zM+g6AN^7%i!NGL zCh&E!vqsVl@nBOWHx01$mZ!+~fNuH$yJv9X7&D-b;+asG<Hvu0YKgC^*)-GJ^y$HP z@oh<-fnANU{aSyFKQxO|BN?_`>qx3V8uk)0V!d%P*ELc;l@NEm@orA;HLUbr<5%;V zWguC%x1iaiL_COsM0G%E1vK9%MC2KqAG1j$Wq+?L(D3P&Q<_kN^)z?IN>$2&G1*4G zHvh7SRf_Xq%~r}>`rjD-_Tgl>b9=GOP{;j}P1WF+^*vK=%?)C|fV!p_i}E#7I(CwE z_QqA#vIy0Y(y5j!O%T*pO9MPzd_U9LLpLa*$RVmqGN+wcPy_%*3`X&c?%uXICaiw{ zq@@~S2Bf0>@^+VY%0B2jGNiyK%C!H{I%b)TBf$cpZ;w#@^k_`lF~Tats=-KL+vh2E zR3>PJzOHa8yF&_Z%aJq~B@+9)oZ?x=o3^ZKMlu<0R7^rxj4kCmwiVX~o$oUHmX<eL zCH`HA0L*uH8;3W#i1pS1gFQXUX4>~}KuO{YfI02`jNMvZ>he=qDyEN_dA1}iqc)n4 zdV8y{ChVV>S(Wn7)ANPivwKlo0H>cxr<t#;xJo=3yEm8Sxkw!x_8dHQ@lVxLcvU)A zDLJC1@VT}NembB}`>}JA!dM{1!TTzqk8{Kpj?ADnUmF|679Sk^z78CoJ=dkFoq+Ok z!3MY%`YTG{oG(A|`3UGmzfJj0+1<+MVx%k1sYtYlN^KtImW}`9mU~GwjacG0wpI5l zN0t#Jc-zXtSVuoIH6IZV>_L}{arUY$`|##wvYt=fRZT^dmf>jwi>dN2+P@5DrS6g3 zG_|$MLoNlb#hwWz8*@kk2f@1vwP>EDa_N*i{cc@wuHy00j&OxK!wOI>H)IeZ52^2Q zE-JwlwXD_f;aA_>92*-3J{i=$ALP;#GLX~#2vp}+Yn~MJ1Kaj~j(jq3IOlwl<2(1N zNIWIvXJey+=S;7?AAIikKasL#x+hhq(gz56TJrs)g)#0?in|5omCnTdvqlJmrtxdv zhV`aC31oa(CKQ?(s=Pl}(v7Z|SBt!Y;FPqxGcbT^K10_ccwyjcVZO9k(g4=TcG;(W zVW(ZjKmP;k<*KE7$HfuWRrVCJo6-Ue2}HcTU8Y5P-8Ag!=h>9xHHeHmL+LUN##TMZ z2+ZJa>Rtu0P)5rX(UZvlfAnu6*xOp|ykSOuIAa&g*QIkGR5M<sHfXi>Ee=C2)dKh7 zu`k{P3=~_K?N0}TrpF=kr1Fu0Y?#}R(J%-t;i&<_kQK^=iSn=PGi?Y3t~6I+iu1~f zQU?Y_lVsK_De<KD^Hq2GAKB-*d8Hm4cqHNKbKm>duAis6qSIphadLh*!3II^;B|W- zRbLbkv?1YAH-MKt&x*Q?(xG<cqr6mtWEOlX?sDsTc_u9@_=**Jo!(!v$mgY|1<i&B zbjBoW{rBl^##aE8@ds6T$D4EvX;<g~P{P@iP)w(s`l~L_vnj|qD;6k^tO$e2VQc4h z1DZQJjtwA#t{0{bKB_)!k_&vu!#*&VkxF8DzfN35a~jPPs&a-#mF*~DU1xlChxIbR z3GWWuOfQlOz&$JHbh&id3C0Pw;~5mJczne#A&C%V=pG>9n6d1uRK?{}2<R+hHvax* zJHwKP(aF9jrTPzmx+hQ9vfQ9c)7kf9{O@2ZR*t!H-#+4Xho5Pq9PMR#1tW^4Qz*Os zJ8(%z++H?=dYGn^@6Z=IBGpZFGG3MBh=_G7Lo$|y1XqlE){iZu*z*)hyguZE@~Z3T zrsR!2{72mmtyKP5eBY$JHfivv`(@r@{@~-w*B3q<fsgCuo@D4@Cobi=ABDSr7E^vH zh7b6-dlX$Z$3L?TCcyE^QP6q;<Ap3n3U7AsQFK+!UmmlHS+eFjN~8-5hhxwK?1zG@ zN70SBbWPbLw>GKy|B$LJ>RDdIKFvpu?kT=A{4X#}{rcm5U&LX@q#hG@`+tpipE#b| zrcD1ZdBgSRa+jOYX=#NB!+fXZajbx01ww@Gzp?(7oJbyd<YA&vtxota!2i&v$U{xC zhs(;3x(jDA_rl{)l14Ac=;9G?vkJ~$$Pz&UwQ7&NCg$v+Dgvr9`Wi=l7LYBh{IaNE z^EUaYJC5!N9ahhDwy}q|j=K2g|4!m-%Dx6(tO*Z~AS{TayA|s6-Qll2TIF7j!-zD} z;~L7>&CH5dx&Fthy$lz!<hcNAe|tXsD-Nh3Yy~gG$>ku0f26|=@}7FP3+a3C=os!E zj1BL0tGSGQ(P$U`ykIY5kO%Xg36%qD$Zt8!EDQ|S-o5*5_<`yL<!cIuYvi4ML%-8M zP1?$EMb7Kd2Z{5@YE*J|b~YO)Ct|*pfjm-S!8q4V=u>3`-zG<gvWFS%{<<g({&g-v zj%=iwBGua)Gi>qfrUL`ruiMc@%OA#ahVp?~jX+!*`xN2K2|%C;H`d*RTXhaL^<(U& zvhUQQpX6UgxIpi-G+Jbsqt%{}V5`{GD$82fF&grSD0EuNZPPc@C=n;Oe{LN<HJnlo zruve5&A=$fj>vRjpY7)toK}`E#T>4?pFe+wY~{7ARc^4|vVWFx@dgN+6Pb5&?R~Ve zhlf7{#U4|?G-1vIF?D!54#phdd#>EaKm<07<Cfe~=DHo94oAWEl~EV^;(y+}k&AiL z{!ioo;){mCkRj5peHZ|=!fwEc+K;JRI_(iJ1~%`#mE%46HP{wbXU4Bw71SY39xeqZ zbeI_J%gq%$KzJba<Z#Tx<cZoX+EDHJZDC}2)HIDPR*&wp%qx19hsTLGip~nZE?5lx zcuj0~3EKF22?=e)6j`~uP(zo@^&II?A|IuWGlKlx9z0;gp6Yv4y)5gwJUY6;t$p)) z!>Xs}94^gsHf_1nvNO)!j?D}aE1Vo*#Bipq5`lkPjQ_0i!MQlYw+?yh6XL)l<Aj#C zIyInNs_j&I@JL%36ppcyHs$W`+i0@luqD}l*aU7g=c@AGivf@=))4;Vt0~OSM0d%v zeLjwRWikjALI)mgA+x@Kj0}SGHrx1W5k`M)%`fRI(H2VbT=yREj0D5F?o_MwQ~bJd zTs5Byc9MzX`#%qMM_c+!Y!{%BO*(|Afs#o%_p^CAB@>RRc*0`$GOL!>%YZ0&eQB%G zfsCtb-iPMG)eziSoF7Nf)}*rwrC5|ll73#ZB{+-YpG&9a;=LD>FIm&d8mr^#Z%b2` zPLUUPALqZ1;6|BKxMu4;6TI=yl6Zjr4}Z;i5WYm;89<FFU+4F9o!d+wuJBB<K{gkd zCkV^Mz~I6OB8cpo9{|E{#OEZn5VS@dzvH+0^HSBDTbOlB7{CW?ypreFeGl9QF8R&T z=|5+tdM;4Aix2d8^{d7J&q^IXDD~N{oIam5Ms-3_{$bMSU9oFftmrTpq0cR&%8u^d zmJilgoL2SeJ$HxftiiNnoZ5moQ$ycZt*Zk?Ht<k~KJ7XD9>wfkjNcXJMjybpD~|aR zvQ++OsRsb>pvnb{*}&QJH-;X2Xz0Yumag0Y#mvpWOGVAcRN1p5%-h&q3#-nH4qWZ> zTh@_&B;(wv&~<go1TvdeJF6(F>-PXO8kP4Oh?>jGRq;CUSMKV(^yPl_o72pf?meni z{HZOcYnpsR*w|<w*(vm6Xy2K*`y5s^p)jfci@o=ZYVzy$MU|$Ah)NTYq6kPALhp)* zbfiiL=^YG3dQ%VtQRyXsbOHnfLP_X~h!A>!5CSNY03k$r4IFs)*?Yf#H{*W0cic0^ z`M`(pB<opo&b8+H&9dfvH`=R}<j=i|^rz2}OUtPouQC@9ZYbAJ;^FIhWOqjZ%LoG( zOiog{4&_JwGV>kEXKo*U^C@w2YHlK@L;neaO8;ZC%_zsHbcrd4($b(~@bfWUlvqte zKP%q;A*#QHSF2{ZuqW2_aftEbnSB>7<d<}4z`R|a!0o)tfWgSuLH1_xxvajCv%;_k z^vT@L2RAEp6ugiL#N#SgO>1PI0YXKz-w^shyEt1@lXO0}h$7T?HgTpctFlUTqhS~Q zks6O++eit=@bdiG*#%Ye-$o!9<V(t{l|D!eB(>38q@WVFa|{n!(lzs5ch$Dq2E(Av zWzIma4l`Oamm#?g39rryFj2tMWA#sBtKF=cgwj!&mo}_KF}PhZQ&L;kZ?WuiTYr5a zHDGJf2$ZAfyYe$F={}WY%TM%e$ArRMmXAo?I;C}lGQc#fFlK89x>Lj>V#SSI_v>t9 zTx8T6=r76EEGHQ}-M{*ic7=5Kt1O~p!BhL?_JwlC?R@JtD;M*vDNvG2SCMGgAn%Kn zJfTsw{iH7)^MZF|A8lZDCAZ+xS4gX*`}iAzHn%)H!!%e%t%pC7&d+a?=fq^XdTcIz zazI7-ieN%M!>+tk$Or7WsQy5^(x+l1@;h9zxs?N^7E$;A2`UsRuVe+cQvxW>S6?;n zSj14jE6RCdumCnPs(P&L@apxw5&Ivi*?SE1HGmItAO|uaZPr)t^ZMR=xy(-tz)WZ7 z*K?kTnetfx_}YGzF}lOd>|@Db_A1SO5gzUoyj1O_$)S~1;zEB^{>4i^zmr2KAm-(m zg;?PH(8Sn!XJd|FBaKv8ez;CvDf!Y2&C>v#@W;_HtyLA)hfk7uLh=W)XU1vM+iqSh z>;0&qImHiZd02Im!8`bXpCCR>L0_tCwnRa#pbnP^9n-Pqf^Qi%h6T0%;MC3msLju| zs#nvsKIJkA0+3H61#0cIE2`4912mF(6w8Ia<c)52vue-v>MZU1KNF$1nYOE?;dSof z6>-BTaSW&G9xuAd{SmT^+Zgp5s6ih_Hg!OGjBy~XG|ZQ8B@+kp5>8W(6flmE7^}Qg zQh@KoomPN*#`D}z&Gc?#18{Ro;{k2bvUd_ri_<mAiU2j*QQ8Fo28t|a-JTc3Wo5ba z{pQ^oKU&R__IStBa-36=MOv#?HAN-OB%<?rHoHloTi?dac>27ezP0;)m<e-<e^`L| z?$&8#O8A{i(?*B&o=Pn*Azw8L28JYVZEY+rv)l}*t(ys4vkm;%60A%aRO~kYktJxa z%HyV(ZImMWk(#!|fm0iC#636%v%8Dl$Gqk0_mS3b4GUCD(#EX#%GWxUVcU)(&1Ph# zP}RK5hj}wOc-m<u@ponW1Yd*2+f|BlR7OC#L#$@V1K5Gc_t1B*pkYm8RJcm|^RU@N zXWQt1s_#9fCxFP$HYGNFsQl^P8ok%AUgIa%=GP4`8gbVN4qNa9Pg_Wue>T<zp&_6w zsEeJatjPm)7e0+%=}+XbSC(G|lDX>{yuKMPK}nBDTq7`e905x<tvA<;7+Mbzz~!O* zG}msw;XiS@OX&f#eqw{;y89MC6|9D7qQh|Z&0B%nO0XV_7@WsKh9g~efu_~22Hkdx zGVL$f#p*(}a`i>#eZ{2UOt#4;z1tG#ikN`Dy`xI~iVr#im}>flSFCPgb&`vKh2IPN z%L_{P#^vn`Tqe%nRH`hV33W_cO6tvJZPPPp-?pY*34)BK<9L$9(Xw;2LzzBpwzWG} zxrY#l>$TFRaRu?9{z6&NJ=&^mr%4Cm$ZH|jVCIaDkJ;R~>Dg)w*G#26F!OhYOES{p z0+jz}k?dyhliVRbQ<h*yln|HW(rsX%PbmEuTAE<_+HVj3_;Aa$TjI^=0$n1qK%{!d zvd!F7w5?N;ZTCZ4&~6A}wn^jmXTqklMN=Dkk&2Ie|D}8K5mXw(Vjv|~@@~R;B%^(o z{5fSXWqopw`%vf~WR-`Q1W`N^IV=(+!U8%N2*&DT&5^KA)Z&C4M*gq(2$XqV$i^Gl zuifR^jcC8*=Jw~m!h(w^*_}ZBK9d^9a<-qo%}n;YNF!v!*P#%?<QS@2BqPjyol=g5 zU9G-XoOaaMiM35JEk=sI2<|fH&>Zw)&)QQUH52Hm7JXn4X`U7EH>3_LjtCxX?#iNW zuyA#aas4`G9JEgz$glC?!_%o|r^W_PZN0MQ-_WS$X$ga$8k3o2u3O9H`XIAQv~(t_ zKvVa}uHNam;#IT4;*u|oW3`dZtw)ej9{2k{xtBiUWtT*c_2otfC>q|m%x_}i;R=%I zEa&9UzvZd8LbH$NWy)uz%Cew}wQ*Eqmv$h7X3PEDY?H}$>N6bkI3a_Vc}D{Z>$So~ z5}n;fG}>7MA(n2!e6%?aS+hBHrX&+3LYw6vj^q5gl=Ly1R+loeYRoPu5c)%BrZ=Vd zz<aN;idJ@YKMrs$EY<+#9=wRhR2JLFqc1bzvj_Q?09g3yLI3v*K9|H*yv(ycSBtXq z3U=bY{o-{sAf*y#5tgc-r7|U{cGr=c+t{P3-%@oi`lI*rCU6z_j!3Zl;b7K>_vHg^ zeNV{oMLeD_zKz}eBc>mWSr4l=i?oWQT@dAP=a>dx80D{+_fzp(C!|XRT2Zz_rL_kY zM%9f*c$!o%ZGGhZ!ya-izKW%U0S*u8K?w=DIzSok<D}K5LLGJ30jiI)-~uHtx!|1% zc0XetE&Y<!!HoQ|J35H=TeI7K_Cpb|YapQT)T_>_3FflRSp54$Kj_zTEmHmS=&_=B zsG>rmi@E3A-(Ydy;Pud@OEP@Oa!Xyc?bT5cR>^xpUtaa}8(0DWy8JL>q1Snv_XI1W zel>alI;)ex0mfW7o)@=y`tI!*j&j^xhX7cfaI`oJix9koMI=IN)z#bheoP-AbVPJB zD%fcswp8>><apk||1n~ON_1L{;1R|zF2R-VEQ8;ojyfZ@?Ylx}iGzAL_r4a!I|UVR z2@>(PsZ<v*jSaI~49tU>Kd%3i?&EY*T&XAF(?=fRm)-W{C32yOo7P@I$_iT64XaX- zS<+tlkGCH%wDHwC((~D8`e!3Qw{-^kdx+7Aei!I4RmEL#FTr@VR}@PfX%Z0Jg+6R@ z`~xl(4b;n_tNnzW<JV~pSB7&~0;D^?9_-g6yUD*bW%sXHsUi{`y7-fIuziO=o_6f4 zMU-5z&No-gb%=^a_SYUD+h)15GIHU0s~PW5lPT~oWH*H-1@dhmsJVkV<E^67?3M4D zo6e=YTm3^$3{$&<u<y6rT&O*%%bl&x?|j{0b8_o%Bj8ujm5xA!=@lZwwDeSF|L}+y zYR+Qfb{?f~DRjy?)p$RxW%9t?MPupm2<46k^L=s0zwPK<2{O|MpQ6l9wrvxy#m`Jz z*-Zb37j{;W4ZAN1m^w8UUY*6FW+ls}-n6%(x`DI+VlZMKDPZC{4})q*(IsA#p!@J$ zB2#(nqtTj%IKlmyyrr%+(o%OS7I293r2L&8SYafi7GBO+!fSP_+Hwi|iJqqn3f#{Q zvKznRL~6$D^M|e|+;n08_TGNgveEfhVNf^4+#S$W8|^Jv^=rj;{B7LNi!Lr$TY8>( zx5!>Yc-d<uzy8@)sw!bol%@KNrU^nnm{=n;nto4F)M{;wRotyVd0FvKAdqFz09I(Q znot535|&6G3@bI^5gZZaee<$Qe)FekC~>;9vIIu!KDX(hbEpW+Zlwqn^{t`qKzaw= z)ZYkk%GptJ=6L=ATNzGjv%Tc;B6)!N;_qgV2jGwD))iBToG{*P)z0agXD%fBM*CO! zH*-AU*~1cU-|1_6FZaUfu4|{|2J%OtA3=72!83*Qv(xxzC7I{u(`3AsA*D{(d(19o z_anbOn)UmHy?s^l*G5}{Opzl1CpHAP-hBw~cbITFkXk0dtqh*zNCj8gRNu-*Y>VzH z+E+Lh!Dl5qOnos!tIfIBEexwG8xTI*dNiR6asxTBk(b+h!V?@*`(#WerAJb2YUu~# z5aD?X?w@}vmhuI74=7%J{@S<*(!V`-k+mrJmpM^kTLYq`>XmsJR*?OaJo1Hz&9M(i zKCt%PtzP`&iiO+@=l;tnVR-TD*RN#(#2K*bYPa!J$xUpow_IZ|`7_EbL>i4Fn1RXR zA*=1wXFjX!iAs}St01txg4q@;$YIrm3EZD>xwyFGUOxpM{K!~L#+ujf*UQ?GBz6Nz zAhr8;FKbTV8ibYfHhcU2`G(jF<wjL24z1i3i)qw69YFJNOEf{-i%r+AReVi%AOv}Z z&UtM1o$LF+8(+|l>Z5KK%3ABbVfl;<v(YmXG#5N4LP;<=O@}Dp7v8o{*g%R_`zVLp z8k72<W5V+D<g|W=?92@-qjr3Ykwb&rX7QjzjZ@zWwXJ7Va$v+)UV7_c6{+c}zL`Jc z)Gi~|g~aueB)>4{daEb<)(T_Q>2>Q<ktIKy<yv;~0Y3}Oc``~9W=?Fp-ES;YM?AO( z^nrKtWYVEWp)+^=f_7vS*lk!wiW(I&4qpX?RPEzu212!i*+R){yqIOrKagX#CG+4V z<@M9Mm}e4N>-*$=zqq;dT@EGD9AHzxzkG}0gIWQG#{qePVtD!ieq0Z+U}M=qTjBna zrAO<wm8IOgQR%cQb7n_LFdX)<rPgd`z+tQL`L%tU<egeEMmOut3w~?vLvwFg9VLk9 za3h+v+Md{*jD8eHIYJqj!+j)i;4?mf_BL+E1c~9|Kq8YPK%4S!nZV@*uqkP$!TV-d zi6>Gi<|P2oYEBno=H`Z5f`Dgq@-q9H2%FD|;fp$hay;2}n_9Qo0jasGL-Z6^@6nLi zeM@+nE^NubjMLT^p$RQX`Y)6jNdHC(Wlh5*IHU~ZfQ(49iPL#Yznrsav#hYKt#BO^ zlvkE|{`I0!BKXt3-?H;;!^<kGwnuSsXrpp7ZV5$rd6!m6Mxf5Cf-ZrKbD)$QUo96b zHCV!RVq69Xs)k{6eU*f*DsQXA{6?qSm`Kw>@B1`<@348_8~;|xdqjS$gZUnmPU}9M z(=KMw6b60WN--*jT4~<&1r9cLz*aSm4@5&}HeMj$0SQOdNzH~t6RlNpX|g(o(U1O_ zH17EFuzIPvk6C|Gg;(YDxp2p7Rb*r_E?BzlB_0MtZ)<W{r`pkv{oFZX>GO}XNgsee zDnw-Z?2mIi#nwl(fWtg?q6b-(y4dSh*_lrA8$utACVT$~l(iP@3`<(oD^mEDcAyOK zZ>!a3+uq!#qo)4WZ7x9canF=CB+bH~0iCYgduUF1g<w*pg_2dVd|oY<UPncRBg>Mn z)sF^oV!E^Fl@RhQlL34I${$8$G^sF4V@~LcDNoO5%cyxn5?1A5iU0dVUwGVcbUan> zGO9s%>G7xPd9j9U({Y4*N2lV|t{LC}Rf0P<Cp1E(#vnfMh1(lmgQwSQ!B>}`I!^hp zP5XVHP8U`|_LFdTxC&B!QX|*w)MY)RG`Hj5kEPgyW?`wxg^VlymjrMW@E4C1^aDuw zVN&wNQwmgN;Z^hdxD53HQn%HWivuWsLgL;Aon*5)q(D*R%81hH4Txpvk?t0zyYvtH zjSOG~@$g6$v)eDfb?ard>s?Z%Xfkv8h6>SvW&l<DLG{w=<fRXRRM=?(7Rel7IYX3` zzL6o2X2J(-_L&3Fuk&B85u8dW&o5sLt*>INqNDUs^2U^Jbx%CJeQ?KH&U7O%(XPTO z$S0R7^f09SWIk=i?jtHRbli(i4DFDKKe#Fe<uO~MzaNnlpjla8?FVBJH}Ol^T*?9a zD=4vl;v)#9`&G!N=F3|XIv<{1`>~m$XZAysn{BGP-Y(Yf4nXAqpnH!?2x)Jon&D7> z>g1C3!{4jdNO{h0B5oQ0_4{r=min845pBM~19Dn*X*8qeNnXY1QdNZFOG<Bzl}-H& z-#YrUg<S%7D@n9&vuVqQ#~D}6l##oH4}C{l8C5im1jPBSCFL-^71lG@X;;!ffG+qj zwEC+f-^9BVkg0e*^+OhQkZ~jHy3pLpCQaA4|AO%vpOu}R-vn|#iV1vJuExm4)jw+C zCLk|p$j1W^!Px&`n`*aC?J8vO%+(LNBVk&Oy*`o53vkHGTI`j6`itwWxNZ=^)w;X3 zn16Xv;ZLqd_efd$2Pz*nduy$W41#*9RdTuJ-q*&N)K9}PP4^Q13Ybh$yenZt4lAe? zU$O<yF8s<DA>}kUyST7kB0V@4`QkKIkhA(SCh;FX%b_OgUh|FxbViDvXcrVy4NI%m zSpk=eoZeZd@dTcil5fv=7!kq9sodjp*6$)ZTo^c&18%ON#Lswmj*Mban(D03$5rXX zlV>_yirJ6Pc&Hq4j;-gcx1A#^eHw8N<MP#M^h`Rg=Fi_a>ut(&;+Jwn&%+4l#tN0# zD@PN+L50#JrK4vD+k^u|V5wGSfea8!0kuT8cPKIyd+M>~UnO&R!0A`GANz{`?%lg+ zfr72})S#?`c29dLzd)~EmsQH_zw09=Qx2S{U3fBk=;l*e4n+%GZZITG#2RAN8svfm z8?7$S{tg{3P@SrE(9}cUR0yhH=>x^<PgH%8BXf%H5U87Qo`6tv_w>kBdnnBml#MDj z@t0gEZD%e8MPB)f(3Ff07Uq2TV!_)}FZUL4*1EcFA52BZUde3r@_||s`xckyRK5Cq zPf|L<xNajdnHIayC|n)XV3{rCG=bW7m$aB|3q_V2@Rpipqi~Q$mQYU?_=s=-`8EF; zok%|duD)KpG^fg~Z*p+eUI~td;yq?DTdV$<+7>RoDa!5dg_Dy&qiQSq4R(CXa`&U9 zq4+`M>d4QjtYx2=Ihoog(JI2Do39u)_TD%qg*;?_^%6i74xi%+Z{BsO#_NiN7KI<~ zY48dVvFS&JTlnyyxuN^GjcB{Hpt=qH#--x(jZ4X&y_UqR<><oX1@ih^#Svl0x5Lw{ zj}|oGlBB<~rS55yIax#qUzHLQ)0dhJsiXgD2J<bi`$6@c>hg{JuU{Xb+$H3Qj+3Yz zv?p9!U0q!V)ZypZ3U!;<$D`&ZKX9pS4yn+|5GJ=*#NEaPaSk{subGv~@bz9^5a-YD zAGjoZ7xkRNy5kvn%$?IWYB&5ZRk}roH_ilA%mfn^N?Sr3S)x3z3VXxR4IaS#HlO*& zr63l7qcobfC1l*Rla4~8T-oyV;+9CMYin-^6jeQA(gL>j2CZfs7s<*4`ZndYiGFa4 zWMcTE^l!$7KVsBjhYf}MHkJkc-6DoP0Yv@dofcfs@=xUc%gJN@$_Y0!sqmcf%kT$6 z=8EO4X^`=eYAd9Y=TV)c?1OegA=aJp)t5grtSp(Up>=A@9O1BsjY+1-D*W1Y>|PLo zm{+cWhY#4|kF5@l8)G5!>l3$hLjDQ|-UBPYd@7IvT|eQHKg?Z3#$&dvH8*IP4|n}p zwu4h?pD?_?w}w^DztVji#hq?Z5JuWBcSVAAB+WsxemQf`27*kiL!mdNJS$s+cVr2Z zbEdcf5NNL@EM$MFwD$a$6C5IK8cNTjHAGG)KPPfinkbwj>j#!+Pnw2FPCARANW}1C zy#2+g7vaYTvq*S=S7ZEmm3isOpW9IW1K27I|NGsnbp*>Pb5nY)%s1yGTv>+NziS>9 ze^Hu-z;|>f4n)(Jqg;NPL4OU#Tl**O6pS)8W+<ETa<9ykDQuZJ&n-R(+Sqf@AZcFU z^J`yj{rqfa$JNP9UN@<s0!+@KgCwGjKTgHq^|jZ%T$0ROdJAk_=^5{USSy6A5e9F0 zarjyC!JYJ{Q;$gt3m#c8Jfo%F;E~6?ervmD4nOFiR`PI=+0_;=_CM;?Um|nzr2=hv z*CDbbJ-`aV+tQDe4*x{Y1mT5FmY)Yt4nn*xQYd?Pyfrw0v^N;;Upworho}nJMmZhC zdE6g>0896`@bJ38Hn;;JcmiSx5^R;Hp%Sd`lr$f&a*OuZ{%DC-3jiDTQm}>?XlW&c zgQ`@#2U35M>S>Cq)~yv?IVjeaV81Oar<P^PKe#2yJ#b;oXs9-%Otrz!W3`xYkl zOu)o`am_TTJg(Y5zWERuG~K*E8Vr<JK$wq(bv#jRs9f}ds~e8D&g*LjA0@T*IgltB zlO^1+%g|PRUgPlPc8hU{milCVDz?=rl*nD{e=BvMbr|ye@0j+S33bjIi|+<*Fd%{~ z+HL#%bxFVgNVs)VpZB68xtXLn!ivW=+HU*0em0BAvp)!r(xzFD4k4WH?jPF)sJxSm zB9|VR;!ZZcJ@(2ToPjZ!@!7VBIAD+a6Y5}qwwYk?+Tv<Sx^TE@K#&zM%6CJF1#90c z1Z4r<EK#b58+%x9%v1>1U~I5;T?C#zVcX(|NNa7a*k7Tkh0B3oqK*@Fjq`$T&jgQU zzOgpGct4{`kLvGu{q%_nq5>g=(Vy*NlNp^ja%`gAcV>dCZ%VlSrdY^2VTyfbGhMRt zWX&hn@yaEOk^PN9rM?-O0ml(ktk&kzs2Vjj^-)lRLiPtIYf19zdpiL%ErTFhGAr*+ zO4Rn_ITgWa#)bqTH^AYFJ$iQ^U+uTIkPcT}4{Z#so40+K?|bo)Y@`FLMMHH<l-V}B zueFHzY7P)TQ7uL1`^*dLp+|fJoNbm!>L2S}=-Ki_UvmvO)^d6#x^*X|MQ~<EIaa(X zyYA5^<XgpGuzmIL!yX1U9cbnYC4A(nNZI&XLhTly$P5@dDQPC9BxYvL=u*3;^~ZBc zE-2XFTi0DUsJiU0(p-906a!6{VQ^xb9J-BFF{H`;{(#PQ?I12M+-f_LR`Sn+j-=)Q zhzyUmnNir8o*xS)ZB1<b`9dd`o-<YJ4{GJLs7c1GinJg8VrYz1YSfjKBc_^I`RoIN zw^!T|D6#F2#s@W*0%|)SvnmU^XNkLfJUZDaKW2K~X<E{ZJ`Z)dTC<aXu!4On!JiLc zG$UyW<XKl9q|rS+3}MZ<GK>K_W*!XtjmsSal^f}HpD5VD%YQkUngWNT>sBdEBsi}- zqm|f){0C4!SYs-Jy4^tCsa}VT<A=o+?Qa@EuKS~h-LfHmyxqnvn8wxX+Li%t+iwB> z#w0oM%5Rzn4aU71N=F{@mD|-#O<$0l6jsgD99*Z-Iysnj+FtnK$Ng$?)3y|lI=V=2 z;<4id4myB=wAzmg;T^|OguzTePw%g~PARxHS|l5R(`jgHEowNy6*}SMc$mY=7lD=H zD$mT0g%g;uv7=N2AykBRxz9CB2eokhaie^kaO0=^pWhP=1{PZe2HMNny#X7uc946t zrJiFBJagM3gLJN*Q$A+=MYoCDEwcbs6obQm`okh;&GPF>;b<>~u!hrAo)pGN08jJ) zRZkS{V-#=wl!=wW(}@KrriCne59)@$;P`dHXyTnf_2&f(re{*^garx5wA*^)l<so} zDW&hlN%<V9t{k^)r>IMct)Z<3tM?fH^1KZgp1eTW#4O-_Ydfe_E0y{LdzVK9Ms&mc z*5VOFYR2MvwC`VuEpz?XIF(Jh4n`b%C>_72{=qu4pQnfyyjl(%OcZ({#Q#6?k1WVO zbtA75&cwnI%EOf3^95im5`X9GJmBQxQ%~mA^=EeuxP&Z^I!#BaP(IPEK|8A;BJfhY zpWSQm#}SaLoPSr7V@Qgi9q?NkQT6fh=^o{*I{jz+Lrz6StJ#o^M5-&db_LA%a={kA z%;ewINBuR~HytMc<>CP2^RKQHS9b{%D;zW{JNhme7l%?~T9rA@!q-2l&Yg$7fa6)t zyld@p^@LkDx5+}!!pip=PmuW!0>o+VEQnqF;KV+0nWWh~|381JoIib<?$ij+jXdje zcnZ~dGT&lbk)aD`r8~V4I5A<SSA(d|YQ3g+lj8pvVja{u4K{d_CYY^5K5<C#GEc9i z&}P~EsFGdot(%_8oR<jOkC&fd?CJX24cP2X2h_u*Zx+&?OojP$D&3xr@BcY}6w{wu zR#l+hnF#c1qT3~Qtw$NAdB@f8YXh)9QRrPGH-R#J!xVRsj8iV!P-v{P@?{VV{>Sn3 zkW#W*Ye?Pb>FA`Mhx(*z?Yu154|&zP^{!CvUUb7Pc~8Yy{u2KLzHAA$MC(c!&4znO z;RG;b>Ju;H&4qCUe|pOvueN!h1=MaN^(Ci<$rk=ohDy8he$IkyNSE;yBgA9_tN;i= z2{s4D*}`fE7vk3>ep)hp>N7JL>kZ8;X`ES_`$oC%vL{(A%TdTMu_WdfPlMD=Za4Ub zN(Y<w-E>6QlKyPDgWeFp0#joWdC8k!elKZ2P&%!`uHeKCC+EFw6&;#Sj+Y5=%kmQc zL%y|r|7Ct72wN2<E*4ok!9iw`^Xu@0R58x?$9W7tlyOUU{#pxxS0@X#;iC-32kw3= z)A~<&4%2GHW|aOw>)L@)KnXkZas#w<F;UKW{B?PhkdJS4o4I`y&=!e=8SqLZ>P#pm z$1$g=1)<~mwLsE7kK$s#Fb0HacH4U*f3s-%Nms_m`r}I)J|q1&ZOa`i<@05ojF7!! zB(plemx-h=X7Gjg5BZVCkCuIkdDzk|lRq@+0kpk^i~IqWBZTYS<I?53s(|`sJyq4^ zSKFR5zsGh~&;^)sUaf=dRF|}uSF#6tGvhs{pUGi$eWHMV11{B`>Gc4TY*DvCsau`_ zz_OfIA2eq{m}H9Ix*!Bf{TDOtob0QFm3y#%mJ~=aiR8kMXM~9Hofs?|b#Yn9iv}9M zc&sB_^ZZvdO}eR=Gy5Ah7$#bxAq2l%KBp)TEUptljaAS9RTDp@`S>hPl5RrdsYN53 z<X3f>pR3pzjgj^%kmU=evQ3W3A3ZFSxhLv%*d&M{uZ7FlAS$dT_ljpI!6vsK#R-^X z$?{xHuQ8Jpyn!w$X7H|>%0i-xE^Q&<!NJIC18Y$A3fBIQhgF*?Vi3Z|O?+BV-Uy5) zxs;44Og*2uLV8ZLF;PXZvXAZ)dKiZD3t>>V64|Z6;nY^)`^_P0^(f|B^{tBV9*!|g zg3?q!;P%NbqQAI1buSoH+Vj^QcY-OGjJwO)P?@S<i>0sMt6|V@u8nJ98_r5p8>^aO z2l|v5mg*n{-&|tUI@c#hQ1l+N$TTzHVZi2fJw!}(xY>~0R<tPTKW^y2ch~`drG1pV z_b;beF&x50UZZLN0>R)L`5zGc>@mUyP{=?9eZeM|=g%*)FQ+NUbXP_mjXs`ZaID<| zcS{<-HqvC|$SX_0^ny{aLjFqYf>(ZVvMmQ?51$Vh5DMjT=6=V0?Z%#Gc}t!>v{s1y zXcg>N$x;PGx4OIS{Y&+n=quAH^G(KoDmf>z?VnfU$|cc4rg$cyACmj6tP=utfp)xZ zf?G|kU(6+l`w`AYT1Kq>az8C3v#MTP<#7FGDDJ0%T!Xod{r>91Ce;c5k;<ioxKAYK zoXV-zz=w~)^1?>q?k0ir&>AH%)Jx3<3E+%i48efSGL%GQ@Fa8P)%sKO;+4yn=5LY) zeuZf+J^b`9<xC$C%p{E#$lbO^_q%1EiygW)CM1J-WX^wiA4J%S)f^ldE?ffZeX4EI z&cOQ`yfm(?K**6fn0Al~ADXh0hyLwzQK6I+c`McH$v9T4X1&$^lL}*FO**IuRiMA5 zIRk;lE|(kozIo?qR<<BV$G@=XNfHmuET3<^U`hJsm(YI=k=gu2oyW~%0+v_*%ckU^ z3Q+0p9bQ|I<Cd1E8Q6Hh5?u7d$OzgcipV>vV)D@3W~{0Px~kpd6CF+g7i^#@uuFk& zb1*fq-h6an9<!IxBP1C7zTRjybOY3YJ~10P20iV?j`g*@MZu7)Ebc9H@%sw~+Q*26 zs?VwYA7QRn=}R^-74>%&O^vi!)zQq$=%u%*&$DeFo{I!LjJON~JeLx?_)n~(#V}ba zggtt3d)UX-5_5pBIB<`3#M)l1D1jgwB-UUh=1y!`Fg;e>z}Vw2S8p!Jvv-}RE}wYH zW`|H=yxu>m!#j0B)A0T=qxb6ygT4c<yI3;IneC=FYxe3T9m_iT`uM4@lY+9uu@)n{ zsw~pmJ9vq7>Z*k-*ZO9C=35{zqdAjXK_H4x9M-1QkH}ok#pr#?epjYZSl4PA2+amR zUKEivY|g#8`@_N;$*8gK|4vdQ%f)IY$cWWq&K@7AgnBA^vLj8IF0N&i3(`fjaYb}^ ziQIqw^&%~c*zd;K`{w`ciMaPs+2!E4;p6Jyuu5zS3sdp35#e=-OiBM;HrcFCWy{Dq z%7zyyKX7&>&Glo`M8vC3Fc#^r2(1+w&_WK+V}F?d16`5vo*AO%aSxU3OYSZ;HE%+r zda-idJeM$3lvnS0k#Un+87g^Md^<IsUis^YH>5F?=xhurt#M|omz@n7h`)~;8Hws+ zs2!)cQeo`Jq4e|#D#SR}C_%EbHN?2~#t9awKev-FFbYo^I1>W-oj@RmP`Z)uvmlU| z(21(nA}Y!zodto$DNi8Kmco<cvogL<UV9!U)_Slge-;EXWj=vG<2#(BvwG9s8$HDx zo2!KzXF(tb%Ttvy8@<VK76j6wx%&SfV)gtfz(y4%ySux!qqafuC#t<Zf}|K97stnF zcUgq7HJ|=()!)(qov^CtP3Co*s&{cZe8$3gGV8GO2Wru7kmeFY-;{Hf<&(6&e_gfS zpe!gXl<=PG0EFi!Ts`Gr!MXG%rfUhm&h$w$l%CA?*I1Fz8C*CqQtq9W6S84Avukj^ z^yxK;QXY>pdll<FI=u-&QFs>WJxA8fcQUZFgv;3teD9oM*E=`5&uklfPv>Od?s9eW zv*~$yvLdc^-aETRvd`(jI@(ibHfGL$bF$RpFFy7;n-!-mhkaZ}&hA#M%5buVAKi~X zvq!RC&gsAg$qi@58cyVM9(E_{>Dm3Df1M7TlU09qyW(r768Qg4w8hGE5cn!TWotgo zzdm=K)+92HfAP;rv0Sa`Y~Gm-Z@;{mBK)swl}#t~TTsvZvwnh@u(CHKfv5~S*<uUE zC(LceY+e2b69(>{j{-W4%-9Q_@NnkT#%fd;c=_+6%q7r&XUVC{%lwa>_wIz?+PdmR zzJKuIy(VY%+^wDbzV5GN|DiTd76B3-JMd59_Gqr=^v%Xd{7WTWKjC`XHdCl-e#%9| z3S;fHwYB0RssB#+zSmAB16UwaLLXbdJ=wzT(g~+Czo$ZW8cY9lG-7n}fs#yJT|Mhx z85uJAmx5H7|C_S)>owtqt=KF#L#QjV#klVBznIQIeKIjsxoF5)(o9i0FYF@}evotR zOl@}O)OvMx8e%+a5v}u{$oh}~e4KFB>Wn|-Yys$j$-lne&G{$$KWhQ}t=aNU_`BXX z$Rc{yTI4(BS-d}$<r(G2uigtkRpYaYPG8ToWS^XfpKprAm-4K&czDW||Mv<1Ka1EO zG0O36q=}2I$9W6qF_@~)T#ucnqu7oda!CT>U4q%QKg+^1!+Go)d9ox+DyIpSDJ>?f zk}HNW?Hyinz>s;v(TQGJV~cE|UoWQ#yv!5ZG%mb$gO@_ZpBEVuPJn|taap0=eQ5hG zafZ(olP{^a@>-vv{U`GtOmISKkd(dgOmMsHx2HELg>Lg`q9TVea-&%@Es|SRe!Q>a z&EmhCwxz14K~Y<$!iy;mk@4|vdJl42v!N4G3G{GDd`+fOi_8p%J-W`W&h+{x$Han- zTkZ>sH;m#h1IIy=&?j|HBF2un+~Lu$b)+5|eaetD8e4nxh+#D5?U0tQZ~Yyv=<@dv zRe+P5`g7y^BD=88dTTNVF@NW&mCUK!r8P;b??<%qOq%&p&Don7R|30Q`^a&?bipmn z_@K)4{qw^Q{*C`S$q_`USEKcQr-5b%{rutP#9~4=V>|BE@>o^=S6XzA&&!Vuu4>=7 z<7o%=4);TO6eqN_`Cs3Y_!*pdbX1dtRDeLy70YRIL1h|~>VbFoU3O}{wvb%}9a557 z!qcQqa^HsXI+xYEp^dJkb@GDyCl=1p&F-v)=8^<*v-=(;X<kZ(&L{=ewuvzmKIK<R zW!VONXN+5Dc`r-83^kiz5LFF|!C8L73oG=%2i)fms!LrkR$h`eNUEx_(m|qOH$)o^ zUMmdKuX2Re+Y)pvhakDef_)0?vyWT6deK{m^wAJg7bF9#8@aksUHn~-;fdqS;;#(Z zP^OY^9@Tn8VQtVBWuon|h?2`xKT_j`hVfH)Zm6%Vg^@?5!qbgpaE0SK58+LlVdG9^ zc};>f!!_Gu>L<fHc0F!hzS_lJv#VoU!D=hRzn>nbCNs+f7d`H=hGbV?u5<%4+stE# z2grQmm_Z3GT65Nkx2<+QFqS`DcE^vk_pld^n^+rG9e)JvM6!KJisdgi-uLuS%5iix zGRzjJHkoid@7W;7Bj-Jqz5y~0-`$;^3R^(zgMgF2>%zad?Ix)jnB$#vM{;O`TUx=- ztkZXv%dviiEqNp*n)`J<&QnZ@B;QZ6C_9-EPkBqFM7D}~HZQ$F$5c`kgZw<^+Xq-; zN{ekY*uUMh)jZ=flehbm3!BL@IwrhR^Ws{xX5#w#hfn=jd<&P<z>bMGE9jZGcXn*? zbo3HZ%}~!(<n)rp5zb;p*ofW<7r4qKFFgM5B?XkN$n1v}io3*4)Pr9Bi)1X1{2lJE zL@A|FsQ>6Sq-*d8*X*~Cq&#&c`nKKhwn_ZmAffD{)XYrCW{Ra*_KkA?^aem=RkCcz zT-m!KCw}>oxB)l&Xh9?2qt_k`^w$bN8*ScEKp)F${dRnCS=cunZPKP2eb{#ewprMB z3Y<<^U+P4;?x1kIju^_oz~r}Z8D@Wm0{8H_$Vh&t)N+6jzbj%|qV^LzYybPDgYhCT ztTsRw>Uy;t<i^b3*$f6)&L(BsL;=fnl&f*vLVof-(8q}&TpyE`iGI*W`kc3JXrsjC zuh^SOb=1d6cKiM-4D>k_`I0=!FBe`*q`tQy<F{>~a}+~a+o@@rJb$UOwLGC~Qtwgb z(O2p=lEvldaAfxcbCk@JF=r73N?S(tBz)2Vry+9i2_gU?b@ez_s6fGIVGpOMicG$# z>{{L4wv_JQzZuvjbIZ(_{S5|JJq&wq=&(s3De(OFAc(+PnfIwTp<|RnU|gAbO=3Vh z5oiIIgM6B5cFk?T`3cog`@TCN=wl|-&xJVScswTN(7s_U>CyAPHlX5Nw?%%gf`~CK z{WA-wce#??=!lHLGYP27V8XB#?I6C=Kha&eGM|*aq{O5UoG#nh+@uK^&kt)i+4znz zs~Kax>woj|?uWe09Wk>}N9?uYJ%fh`+?QV24@=fphxCu?{8{68q?xY;N3z7CXeilP zN0zJGU!2I#QE9uaHj#RTJHu`xL*}>z{X|EjZ#*`I>q37JkwtGvCOuEn3g>xLXiNJK ztan%W<Sde{R5=&fLaFs<ab@vpRh({$Y>9I$^*LV`V4IGob(tzY;D>=<9<bLfn~64b z%i~pkgXiHWEqF<A4O@dknfc(B3f_D0)CsGA&>%0epdRtSg$G8m)#*VEaef-sa&tvT zTWbMRHo|o)uEN!{IsADT&578f0)^OsMP)56Xnf*`F14JNfJZBfr{~WEabDo6eF?QO zw~1lJDhbgC7yHuO)X;V$J?Cm9_BIQtGrs&`BPGXE3_T*{X8BPKx7}u%F5Zx7=mTqh z7_XQOeaxCHG7`wMZKpQjFmzm2CHmO_<38`h<Uo>6%daZIY#dCluxjQkn;d<s$0Zir z!ZdYF8VyTCLyWo1D~!FCzQ^u+<}T^J-B@S)vh3idt&eKnx0~&=Z=amspMePTT*Zd; z=JgvsNfh4CYx8I&-51Tg&+EKEx;L5^lz!Q8a08U13^L+V;Rv%^l}n$|#5Kb8&`gl0 zj&BEKl?Glpj9zg<Y70-6s9%|2l8|-T!qI5!eQ$~ht_o2Y8b(NNRL2L=9<}y%h-<P+ z8QaIR?5r<ntiDLI@6kJWjv1?f8WdxT&Bga)?P`D8cvZIwy`G3Sf<t(rllFjy#h}RL zjD~l(MYRSJ{#+owq!=~cFRYYPP~Q{-3+b?&VGJbo_qdza_Q>$m?qQ9TG8`OPq3~^^ zSxLW~5w!`X5ckUaIJK>Yc9TK>Ezo)*tMTwf;4K^@o!_NbS<zBo$Zn0+k_|L(XYRr6 zl>$J<d;bWJmU3SGQ_;&eR&wbCbr?i?OSl=URHS>1XVDJx96mMoN$v7m&oRqtcP<<^ zhBBLu>(#k;)<5CJ3ya)OeuC2)$ZkFyok0tSRt0)T$H`FY#A;K$e=*Isx;W*vwLoXC z?G27`jj0|ve_$W+=Kg{P-4(BbRc6WIl-CtoTieJI(EV=9Ni+punzKM88sT|gyo;kv zw(U#3$7=CJnddkynqSHTQe%qtP@iRRlv>KGP3&nOlLN~8#Ae3nVY1F!x9e=@NF{u{ z;U!EfX<O>mPcB)j-9QTI(bJ}m<3%h}%|zr>KX3A)AE=tV)bumQkB&}hY1ZPktWzdC zL?XSIeIih(E9Xy|7(rptea3#Ap)#@k@$2|7lVh=2t>-O)Hcy_B^X6kAZuaCY=oaCD z8`I}A$!rH+ioGB@nWNIh(mn`Xy-^cQwp|SuI$%eZCCf@peabUI3{z};?EQv+f!K0I zbK<xmGx_dqj-MN#)=DVSb(Tyhfh>u377HG~)bv{_&j-6~dK+h9`1a89lI%FpBbM?X zR!y~Xhu53EG+WAlnK=2YC~TWi9~R%kLC4?H**zmz;>hC-o#Q1n{h$b0_WdA5<TXJ? zF&l!5T}!^MF)4^Q!JChbU&J);k5cq&g>cJrD$h&SzCcOx)-6L=TQZIC?R$E_h6DC1 zb4=^4Ql0_On0i3t+EjAB15NnQ)N25AucZ^5UT87bqaiBM-$Ox=678uA6@}5m{a;2K zM^Z-TByB>|b3FNXr)Vy+l{>1?+o0GXR>uHkCzNKi_7j1wxTDu{osEazhVo0ALpEz@ z6LNnsq@`vq%J_G<o4Ag3Sg|i7a>btZS<o_<Y9nH>>nMUcPkNt)4jw&{OOSkKim|vF z8gIbquBUBic;Mz~91Pf3SZjCwNvGu6nLz0p?AF-ghI7LTv9HdyN#zYtE8{TwdYUxy zl46b0=>Vr9%HMr^jd{qBj9@;fDFc>Al*(s-v6tHo*#GaQq4ImO=J5GTwRgHt@OcQ$ zt1($kr@f0e>z#jrDy~=Tx8*BGGx>Cq%Y1k%PQbKV_p(5dUG_8FUc2gjjm2R7VhxR{ zHf8!YtKV>Ii*3h3gaTf^XInOsEx6q3R~UW%{SUDg57>amkTs4(2@iH7U(7S8yD=bG zWiRAXIWQM6;9wnINRix`-V$Edmg}m2&^7Sm;1gp5$bG(d#``5mI@$c5&~6a8fj4`5 z+kI>Ta9u0ds%c8{yURDxV5~-QMy#{pCApGjYu&NII37LYjvHB^*(bSNZ^d0AsmC(< z0vr2D8XSovzT-Yta+rfus~z^P$4t0|3s1J|^6z3t4-e#)Wv$!W685PI(m^u0t9q$@ za@Fffx)~piF)8c8iO70!!m&eJNwpH>`($06WmlF_VT4SN(kR9Aovgl0ax!B|!_O5f zp@)h$_p0LPgAAo0%~{5S$6n7Uv-TR=J1LR?V*2${@-MrvwntOp-Y4?8!&>2xaKiMY z<oX}-ckc)VraNW^?>l4_@_94JO+XAk$|zn(kQ-p#<v!haa_GcaL<&>h!oT*eyZP_t z6d48Cal3+zXx*t0ZOJ5%l}}Ur-RVS$SgP#-!)~}>ryxL=PRP0T=e;Bm`)kI-Gpd3Q z40yHlrc=Yk>13MJFB}1^Xi5^s$*j4c{RT#%)J~`@4<B1|q0Cytyrjt#=(I&#rofHs z?1lTHe5k3)nO`q(eAzvqtY+6;GFEJxb2MZq-L4%#r?Wc=Pkb}AESjILG}<S8`A`fY zk?XFzT3MyoigwFc+K|c%LRUN+E)qkfNXQwv6lX)^-Pw2l)IBC0I1y`WZo*n%*92@X z%Mx8JKOYMK2OF05Up6<IeHr)22}5b|d2xP&Pm@?Com6j)CQ#??85<eG6(@GZIKMF1 zkttPZ!|9DBhUYpFIbt&~N;JdD@^;tGYQjOpH-yEfHI8a;rpMzh#jL?lU+f0E%4#T< z;a%CH{N!^~iU<_kyKr++zDPX4G~jUc^9{yPWzkH)W+FUK+Z#W<N(g1^pBGZ9({L&; zZhjTGweGd$1sCb3f5DZrJfleQj@w%i$21+bm(J|#o}m!>G|x)o)>aku;=6GR1HL=o za?@SfI6YKB0ahM_`#Yamx4iJ?-SY3d<-bgLe$}eFB#XP`&A0n(rvah+4+GnR^Q&D+ z*W0J3zR!EMk@fZ)hQs%hMbjB$`tJ9wC_uWjcub2}wR`JWS+M%gHs<1LoGA?l;YBWh zZt<JO!zn^Fh-qYU^2eNnqDAMOJN?rRhnnj*lEOiN<WEIK41k8iefJ*wLVuLDyAl2) z@rKqnWBvGMLFrk4P~wHdC&Rz5aWVQYRKaA&EsorlA3svVU5p7j&>srB_fflJ95|R& z`YTJTyQU@{`|RGYE0^5+?c=z!Nw;jp?!TSVFnjS)X0^+3cm>yjr?PW=XxG3-pY>LF zCI9kDfZoO)2Wvx6EeaBM39SE>iG-h>UHaA8h;Py0(QxA-ezqIO0xvWB4lLmH7eBAM zXL0<)qY<Gz(;m#A7io05;^Qtp%IcE=ir?}~quk+U^o)}6WU_wu_(e#)$784NbHGZW zT{~|2rb|IT?Br4Sm~2k<2LzPpg2Fyo&sERbo=dKh!Mr)T+x*=L;`Em<SEuP>4iA1w zn%re=)XydI<TDZwQhh+b8k#R$Z*N8TWxo^e(YK9#^3xH^6#bxn-m}h`NJ*qSZnhEr zG~j#G=i1s~*TW#Nn9~;^|C$|digx-(IAfiOGg{b-IqlSDT6n~%f|hhQHgu;!@(J=A z={&l`;m9J|CtX6z>JNVKmMMNfZrprVkMAFlr9JN4dD!f$%*3<2XPoaFl~>`8ILmj% zXZlJx^~lI57B$YL@|@{&zIf`NtkF+VIpdjfKE<gY=^VfI8Es%La$c=GnU+oQy|W4p zMJQ8WyqYg?-Z1N|VmHd1&(4#b5%>AuzOC!0nImLn;%D@9IvKd;gq*0<g0m_vog?Gs zRE~g9=((I#6zE)}4dullN&!`wGu_4-$|szl&L6pZ=D=q<g#XKX6>-9e>&nGv)e|~T z5yi-<%v{N^aJG;9{0S$xBQ%oF9GF5tIYRgu-;cB75dT-O|5vd8kAh_oexH_7R8-&9 z_mnJhoxejy-)bkMH!<4|{M+4y<v&<wE#Uo)a<Rc{7ScEqq{$}h>uu#fBV3mp+SrE~ zY-b|+PRurX<*f*`pI)W7dEX`ifTdI1?FbyK7VNtw%^0bjExFW;%LTp@3ihPT_1c3v zCG{mK9Z9z%QEAM@?hWz9zf}f~(8SzAwWOnxR!!~QAMN4O#O^DEVCR)zY;9ph_>EkU z#EUN<X6vorDzX$oFtBp-i7QzjGWN4Q<UGQoe$it>^=j>`m9RmU8^i0r*vzNSdra2U zy+q3|jE`)ow$u0xyU~!FO;(l4`i=pCnEAd+*#<3z{+%zA@=2dDL4=rG?8|9<{fE%w z3{`H)nH4ncjSerV><0Bvxy_+vaot?Byd~~QE~wYZcAI2$No!-t$@H1UpB>e?0A#t` z@xC3uB`|ij5UxhDs4N<2H^9yo7pt4%x&~whD^%bn^#V4UN_51+cP3$A@l0YaT=>V9 z7n(JhDbugHbS%-j%nq&VC%D7!q~5u`XZT$7KUcK(W6H%9kuTx9UpVR=`j}`r6sH4G zf$)Ba+-S*gp;}+tdUkI3QJ|$C(rEv8vaVsHC+0Bz^Q}mO>$`inJkYtCp82&ruUI+` z;mwe`2jFspQYt8-AcYp(IoqUn%JYI^&Ge&ht@pDx#)dQt+sBL4ll$EYa+m1KCssp@ zSwkZuFTOtf7CHq^pE0dY=S3ht$^d;`qRVF859D}`)uocwkA}Ztob4aIk~6O)UIV*N z3CuJoz}t}d*(JaCG@U>DE0%q`Glq=;rYHuzyR!Qu*uQF=A#f8>v~|R^?Xmmdf&yVo zu>l-zI;Z7cAq>7oP@sCTn)mUR*PK83!A3ShEz9l;J!lZCGb{5^H+J132N(|WAC(U_ zHD)q4eqx^*BFDO`5b8S64b)N<cPRn7VgshJXcC#pBMD~+&+Q9ar2R@I+3GycBc<D$ zG*vqCOBKP&z;AcKC`&d*m-JiG<uG!qH4<D>o$JW|?PCSGM|LLIwH}@W2@8RTj3Gh` zVFE|Q<!Q7H^?%6ZHBFA_dD-mL^)4EbGTl7Ipe>{c65;5Wk&ajl+#FUz7OB&>e}h=U z#lsF?;v4`GWW223ffFce2&PxKQG_+6#$#%yLo1`cUL0|nI()enKfUfr>ey<?A+6~6 z%Ndkt`82rUsdOY&gsc4;5_fk`M!^Af{81w9hXr?m)R`c#QAJwa8vs>yuYDgZ^W`=s z%)iHRc4ObYZ{e05gtlfbfw88io7Jo3Q)l!Ae5O<G$r4CX*v<f6nF0<gd?T#c4FV24 zlQPGv%<-#m;x?KhmsMsE)KR-F?}M)GsZtP`o*$ph@cO3UN$@A{L#+pbbR!oq8%nqU z6&ocFrRg=4Hf#&C(QAp@p0)JqgFO4(<x{iaUu)-&r+mlj-O`}DI@t<sQNj@KHoDKj zRyMT9T2xgeoQFDEp8H`ece0S?+E=0iG^Ea_RxV|fv>m-t0{o0iYU@k$dw;WCISDg_ zGM&YL9^BgM(Ovd3kP5Egtr~XQu_RQv)!v@TfC&e1@_AI`wt@3du+1qCDYtJ&m!@P$ z+O!9|=856kW*BkTs%n9~9WDvmlGT=Zqr{-ljJhfv$1wFn*TkDs=)I76yZL$nyui3p zy=vZ}DQQ-wVDodd-@M%nr^zGVH&{fTJ6W1#4ve%)(xX0adP|MIZNkpP@5Q*^%32wg z`8^@MK>&{UNE>U^y{A2betkG)w%OYnwC<Mosk$*x2;FF(1A+bISbvo`)UA+f7$wpH za~LSqiOE8|Zy8>p4`}w_?_H@b)sD$ZRzMvEC1y5uH@^1O4&4r;l?wmu)8ka9J3h$1 z<k6P`YHIqU)jIihU#9($*A!79=DG=Ku|7}K19m;ceCobSRF_t;_8pbqD{^-79$f~@ zz9c8?Bp8x4%yKF2jotvMuC8oeqG#MKK(T~6`P<?ZJKLU|jomH3-WKE^FB7bmx1iR! z1DDy)gj*N(>>C`Qw>?CAR);2(Cft&C0ve=#L%p<P=67Hdn4{f1@_|TSp_}u4(vs|X zT3Mw<?zr6Q1^Iz%!8h12(keT!p69b_61<86^kdt{$u6TgE8Q((jF_;n-*_iAgYd8r z8?5UQE<5g(^YWhyEj{m9CiDQ`$gzh%n%hTeGxy!C4jvZfviuq&OwQ*<C~8uMrBmFI z+o0U6esX{jPpenwzyuTq$onhx56JGUtOceM;hkv8<SKvM=nU{jBgkcx2ds90-uNEU zAFAUZ$3X~d{aGHd0kE9SByDSl#MhNy>~@|7Q{I&54;J)WIWTM>W>*rII_xIUeL|yZ zS?*dyQKCCwPOhKt15VUW3y4^At~1}*UzK(hoF-D?;Da(VcgFJ5NXXk=F5|(9?O^pn z@^|=ix|xLi9=kRrUTxO$PrA6Z3o&mTVNknQZ5i}Lw)cC?&-cZNYkQ<0kDM}b9U?cK zjyQLF-ubkhSp6GbS)_ofNLkARW(78r2iAiA=s(OGNNcb<c2-~qeqZ3Ne6Y*`-!TwT zdD&m9IoshsRnWgKOjemU%07t5_G&Zz@Zo&>HI}F&(m{nQva)>|J*WKqc|q9z5-%_L z_oH?9QjxaZhm!byOQ$-^Y3mUuL{{<XUAw}^i7$RkNlpuL9`x-BRJRoD%mfeasbbPT zJ9x0kp|-tRw~Ryg7Sab=gq-@&LH;1jK!NJp9Gfh}VI8R^8RK7V)tckipzEK#&Fm+K zvR?PdA8uO-8R)fi1Y9JD5M@f+NdzyQVE=;#Yn9k5em_j%vFt%l@Dssx94o<dPIz}E z^o#KyZ5coEA{2yI)=-UJv+mK2J+Bom5MUnY1{wUy+H(<TLr*41(raermWqE{4Uo5{ zQttTVq?5%VzJK5X<+ph7;(UL9zvjg158s}yHF$tCunF8bZ1g)Jp&3^b{0<$!x*I_5 zqpPr$0#MA>cJA5x&Xx4P==#d2Hn(l<-9k%gp?Gm<fkJUB79c<=P>L4`F2xBB!KD=U z7I!UH+}$O(yF>5*!2<;O+PlxW_w4)Kj<J3uV<hi<)|}5=YtCnlv0nc3Mc{(HYijgW zYG6%;*33ocg*jrmxnjYNVSxc9T<Lx9HI%^FNou42WrTIRDUfBt+l2k(@f7jM41DB9 zE>rGtVGCx0QTq7#L7A@G=QFBkJ3cW2psNP_?kcFn<66q5{H&U69-%t~+<q0#*&fz< z&!+3`j?^lyZY@sU&07<HyX=rmpZwR>56;Mhnq^L(ini5sMnVncTPp8f#ua!bbZXgT z<h9jwm2>)}b1Y(XrIC*Z{&Y7G6V9RmkiS3I&cY-BjuL4>;lp0F79-W{<{c>Z-J>uN zk8tDwBN%d-O|`F~uqJ$$C5550YGm+!8f$8CMnrKyP)ZOcT)%pMwxw-@J5UM7fV8fO z`7a?A<dV5{Y;GBKkUD~jg${QoU@1d3P!nR_ou_bFv2|!5+NnU&Z>BDzhOEjg!zSHT zuaSaC@TQvVV)$XTh0=h|dXv-?|H}S$VNNt?r#s&I6Km!DzOg<Z@GOqXWd+?%Zgmw0 zdSBp0e78WX!V@7*HTwO5xAV2gdi{mlZA;@#{C7&7X2onh>e7M0$cZ3>=G6UYE#2AT zcm~<gXP)vqInW9W(@IDW@)c7}YD2=+F8M`b`mW|p`&(=`Q$Opc$vHXls|K~Xavzmu zysRi}9GVN`NMH<k67Yj~b`Vi?bD~+qO4r%j%|#Ja1%oE?_`%Tu8><Oi?tsX^dnM(e z<77R>sihLi{xO}<x7Uf0lUK(Isj!TOU0ACrF;zwt^stHZUQxZ4;qBcmLzU}(bc5?^ z^7SnP?EF}!)@)CP-8>pWp)PVPhV6RW>UNo`l=Svk+RAksn^I+HQ6SDWg|?v4<R_{P z8Z!qIAo!A!vCYnV{{jgwL3qwd)Z8Pm$a51+SH_LY>+fG~U!2;`v?e*2{J0xG!dP<d z^lW*l+`hfgaz%UAl}~W3KW;gc`1Vt{39$H4Fk}5i{H;i-sIqCYq23rf<^4uV-mN(C z?ikX$VsV&Lchot!_8Y2l^==NvwsUL!l{wOhJRi?om}lH0(DUXb$8CG<P9xqZk9sny z0JVgjoQq@8a5a3UOSZc-Tn25OLPG$H9PB;4uOnz3<ZlnVN8TEoky`*@a!dUBDXn)N z1ROX`gZ48USM%wIDCOX*lHP=4oLl>`PI_j`usJF2A?JS2JK60bd1L2gfm_nwx5Aku z)5<n~-#Z@=bQ`?Q4%T8UHDodfIrKhH5Ll5jslK8To;f>Dt8MnCbBd@Xr<yWYIlizc zEpE7PN2KUGjF%vIILA;>J;are{C#ap_|<Z9#>`=9zB83$>p;YAsMzg!Pi?u|jHTg? zO#I$~fepBwiLY$mX}Coy{~TNAcCIeX&-j|{l&$&xkecVf6JcD40u4E~poSw0cS>Cr zMNC`162x2B-(XgU4&62HvVMLTlDV?mc^NT$b$X#^cs{SwI^%sKc32ef6gU&Ym0QG{ z_;;`M((J+MvrSUYp)}!zi55?H1q%y{78vIPw7kLoSmso&nxf)L+qHMwl{&3<Fv&<v zGl6tD{gKllz7_sco0hBG?K#tQ$kqW)<Bbmnl`U}Lx`t9~MZRVUg=k$dgwL8U*4a@l z#4YfltVMpU$nHK6xr{bLFFfbHM>Ph-b+^tl3l~dP{6zLQWe1wXg7rYB<p>emWNYuG z<5@ee%eBCod~Or1X>|OQ5vTft_*6^1gV2H-Omr#*0V$ivkv7AT;YMgQE4g~@-zzO5 zP3o{ddWLf+jrp+Ns#a_CY9p@Jsv%mq*1BPre%o-^VU{vm#~MYzuZx<yWwS-?*O020 zl%0+i!_yGf)Jq6<=Vr>*rChDyr8ra?{(a7bNaI1<Om}+eF_HAChm$J92m>6)UC10P z1WK}>aL%op5@satah<P4`I@TkNsoN*wsD)U_3Vh=(SsisU0x#7mZ|4!#)Xs*8+#{q zFBF8yonBlte_O3@SvpU{ZgJv`q}td$+51|g_H0+`;|;$;;4|P+-O9!C^?=9ugb=J` zZ=X^@E%Z)6>mq4{&zKq26Jm6KT|Mm5WHna~X@H_^zSN3FnJ!|d3X8Yc!cm1+mUl@* zJqvL&^{X}bLP!!MpBFExO;#{h*eXTuVt>S9S;Tpq6!l?cHd-hhva{p5s)cA3md~6F zPlL;8IXIcP!G9bgEj8+Axt$N6jtsLpq!{XlEzOvCYvdJ`+i;ziI9^m1CwK}vN#9Kj zLfJ30FDE^e+x9_~2d}r(H7>7n(vpjm$8m;vm+odgO`&lcHf*bx+yfPe^px8-Moq)B zl|A~rhpsu|7$XeKO(l170B)a!A@eo6>lKtZGNE6W`$$<AsvB2;<geY1I2dRhYH?fF zLfq@QH0lrYt<)3E<~jpW0#T?-PETIwI?u4{KD-ri*|!uoQ$0}V13RX2h>&}=y%1rJ zlZ5!vC|o&%I7)Xo<gGxIicTyp2vzK{IxI&xUU;^zytan7Am3eYGj@21RO~4`+}utP zP?uo}20RD3j4&dcL*2a+-_=;1>TK?duQ<g~RHL{{8Ig95C--xLIG0Qz2a)$|-yYIc zefc&jnEyrPwGi$zefEqm>y^wj8Nji?CrnJUf4Rd-XVVCkSTeroKTuH&G0O^|@l%ZY z>s1W;2U?`}@Zpj>lD?LX<mDzGwLRi+crcNBC2`JpM3_6eY0~rlEXvpjXK-Lw*6yx0 zbjtg{`~V8<@nfF~1221iWItGHn5s7!QW&n*au)EuH~P^o1~pl`GkL-R#P^GL9dQOc zTMkVnZFSpYhHjm9LD-`frTkmF=V`};xYYY@4P%d%PJ)31KUz%+n-;<@uEh?yg?rc_ z#sf}XUfTj&+{Jn#Bb9Q8tQXtSs*<mSU%yKSsR{2xn6#Z2)R|3Ei%zcO9@2^a9ult= zb9&>NxS|xBKkiKx5-TofR$GuB?;T|SzVV=^)-78@8KGHgjUCvzc9AiLt_Bn?Q7b0% zx@<pVQo?zG9Zt^2+oEb6`eN_V=Kw!Hbn)q5b)vZr*YN!%3<ryx7wi6drWK1F!0IrX zA=X1Ec3!81BQhnHH#zSsZ-uQU<$nDY8Yh*ivr<^vGJn)IRz<AmQQp3GGQbYKxjMyG zcy)f+h-g6_&4WwV`WVvRzMpT#e-_t%8X_htT=Voog7XDwY-C7?y?9w922w)c39r+> zd9fjQF(5D*tQPFkKOjE+F>hsTY^=w;?AR!$(#RrLJ{7R$iv#31fs;gpheO=AEm9$F zrOVtZ>ECIk8lWTjO4+t^#_^<A4?WSz1J!gxOCvzdpnTI3`BYT}Vb&S4Ks5k!`b=#l zrb+2Fp_Mijwfp@g7V*-V4U4c1_I0<*Clf1Fr#f>HBnJ9SplN8%EJQ#uYeQ~8v0x52 zv3Cm-ufZgWQ=FM_JJOwKz=kRU&gMP#!M0o6W;GM+UMG|%<oeCZEo>v-^!v^aQ-~#) z?9oJL%*NQ*ppAU}IRA(W2Y1e`@&rI<6AqEnVvsFO(j_&J^i)x!=PjBKHw06EXH=pZ zkr<ljKXDl&03CJr#N=Rp?X&P-%O;089kX34ARWpt*Zg;G&nS+InJAh}4!10!_NG8D zN^hcu2&8=SXUj-;Ss`_{_DU`AY6BcYe{X+Ik|s0;v{cP%3D0zmg|Rk_YCs3rB@dSd z@Vu?K={9kAuQj|@d}g^AsqD`02utJJ`MGnW1k-7m<`J5Tj~1XZk^1MV`Za)jkbGr+ zKmXn?lQrd2Dwpzay$zfvLLwI5nG)t54hs?WsOaK!F~@XTE1s<4V%5}FL1(ph*)t>p zVRdtTW_Ir63hke2tt;+UP+R*SDyiM+pU#da20l8EX{5a#aBTb44i1WUphcnrwt-(z z><yHLC9NH}(^)It$0soHE;JA{66sPwtX(!Z8uS=H)ws&@bDMjxPRPa+dp)jC#N|uT zu+}*D*_Q>)3|(h2Zo*(-tq|yzLRx@}e8J|;Y$OFlGdt8!@NPEFpF8<#$mBiYM$SZ; zVKS&)>$uTY8LHO8Ez^3fay^A@<>?wu)Vn^FN5Ovvl_Ig7aL9Kb#?@AbNepUKNaSWA z<1YHn##Wy8o&c(`%f3Bv)lJat)aXmr86il{s~NshI31eD^Q33{-o!l9lRdUSL?TpE zkG0lM@@bc^D0-8#hNZ6~haKV=pTY_rE#NzQHq(1wd+tR{8XmDU9}FsK)t^v~s-hev zayRLEg_@qQBK4SB;+_uCVo27fiuw!l+pi(|{YeZt+7hX0ih+uHUZswG-)r4ir1ATs zkE;MBSW3&$vKzd(XI@PrwWXk^K~xOey+PWy<w#2`a_UPaJJRCIM1kXV-o%CD691H# z`03VA^T{ru`aptyAJbtiyC*Acj%uzK{B4U`u_mdq-}X@Q_OffGJMyrbHEMT&^Z~f( z_G&x5=i1?7uUNCXpWkX!RIleDhMp&<Z3HZ|I?N3!n6}^JDucF!+u2Y8Q^lU|7soc$ z8_-mA*h-LOW%g{h(Sy`Rc7EMG*T%kfOW&KT%rj^M8S0OH9eVSUbT4)8k<Nyo04rM1 zu`Kb^P>ZL%j<YJR%9dMh@pieEl2PE)qI_P@@2#wu^-(h@Rp=xQOYXBYjf%&SroHmn z%&lFlIFX{Y)*|bl7GmhQjaNtX-Oz_`M?Rmwp2Na3o2Dm>Efo4nts89`a$}a&z9(Zs zHe#w$X>Chya%n)Itrqwo+jieL@na(wdFeJ^2dYO!FVZ7jD)W3y)2pihxJ%pQqGYI~ zlt&O49ARRSCmX5)ThuCy%LpYimC_6LDHq4i4pDH0x|Zt($|&ZIA8>7IhQ()_Cb0Kf zp)!sy7VHK{GB(dk-O0%(A}TXpo>#M8Y_W-A(?bb_ZdYCGQN0A37`H!)qsHG?@K8BM z2hsRHsoK>eT3COySWP89B&nlN<}k(safyxh312v|HK+~Xf@>e5J?Ihc$l}~DDCO8M zm!-3gVm#p!@nbM-Tsvphd?D?w7yNZeX5Tep+iSIS$#C8=-hGyyQ_S_y0L6PtW11RP z4!+4#=OwVkpycbuYDmix+{j%A&HXU-v!bQYDoW6x+(M9-U@cq47*>rvvLb8fCIWop zw2L?^6v@%UuDVvueBZ)elz9I1U0}c4H=HzMy1FJ9cAY^$1o6u4P%Ys-sMBz8Te`tf z3GTWsQr+{mZF8o!CkVqDuh7P{X-b}T_<0K7Pu9cn<j|YZGc_p$^=h)SFh=>3km0)= zLY^O1VdAl~<WGeLJZ6^2z}=<FO4SAc{Fe`Y4-QNhuW>fm`$_lr;ot_z=;}93ZWF9p zHG}F<xmL7CU{=O~{0v>jy=JwT(Xz~|bOu(?X1-~d@sH6Pi!fyyez}=i8$H;jre4=V zmAN6wLx@g2y<8GWfP_xrux8;$VMmn+SsCsV4N1I#)1h%WxJJroMb1^a#T3YwjAKgq z!_4G(2FsN4b|`xbhtTy|lG}wjS+lk4p1Pz&xM{vRdeLz%d|-EW9Qea~K5ug2Q!`7k z7k-dzSvkQQ8#`DCSDNF*Bg#%q;&YcNAu<*l09Xznm$#g=o$lT8U6;>Qu`@ivh9}9q zK@|20_BC8w?_61U(yT-hKpDCRDHJ<rt!obhdAVLiMDp>)O3N+=T}||mv4>k3o;~U% zpinYh6@f4hXo^>ieQ}{PGPR868K8<g-wPmtvrZ9Y%TUg#BHEq3VkFip%fU-|bxsx! zX~MB@2Oo_<)(*;g-#G41DG4z~u%l1FE`PY$=O7lgmqnot)kjK=4{BkvBNZ(f)6&Jd z>%}L-b)+8{QwSjo+Gdu^9A3HgjH2^BIgiP~(LwqZ6l0!8W=ItwAvdmfrH$04*W6gW z10@sRzY<=(V$d4YCGH!5<KQTC0_K|DK?YxBFLp7Ckkl{*R-qZ0b`j3FDFtE~7UFFB z>O@JLucQJdz^7QHEO^Cs(P!k?Af$!0WM8$<`fawss>Hz{SmNf)BK`AZZP5C?0oPKI z{?DR%P}6n^8TGX;h?06)Kx2OI+ajMM%wOpPK09M$dr!LkytjQTSunEuO*||8bn$?0 z7dq$G-NO0-dp6w7%*^VCEV<9?;087QTuU|1K6TsHyhXIH;e1P75-3QnOFS=Plt5U= z%8F=rN_V>Z<%$pD^>U)`?sh8RNCUe*kSErC7QH^uxK~(~&ze-&nzSJjVNDiS-J0X= zr<W6M#34;C_r{*wyzl$>*rO9l_GF|&pNR9K_xn|UGp6J*lJ@U@s&GfEPKqv8SL~78 z&3f$jCgj3z$j$5K&6X=o$a#=03dvuK6zVa;%tJ>4BfrauR4MfL;7lC$oUR;H;a}cH z5F*A67oxBYbGBq+S~kDA*Wdj$VcoXmf4y)dWsF_7?iZv+LUSM40{2>SVL&6TkX%d< z8|fHZ^p3RQYrFAj{xtDytf#xks+KwI6EhFxPK!yw_ubCqxscPl=dq|$8JB}b)}G5T z)0rTR#5&$-NNdIG=ls(V+48(&LUjL?r7wLl&<F2@G33;E@$;R7$!7PT6%=k+xQr8< zf<Gpf&hLbV=T0<%XG(a&l&@(Pn_Sldo!f7&qbxV8`=^`KMk~%G^oZSSzaH`yvd;o2 zj|emduM<tv%CnA^-4UeF+C}?kj?saq!-6A}d6FMu^TdRACrPpbxHTgCg{Ovsu#Pex z19>v?OX6C7Mp}O`@PB~zm_)LBI8~55zR0H8`jJkNo^Mg7vCg{lBbp4DoG;n#z8Gry z5wW&@>jsj4cJ?^=n4jirI0I1uRnc_9C}$D5u9;$F^;bi6XqG&Ws$p^w&Nh$yxtG42 zFb{ei&~cEtbh+7Ge7f!#;Q4{;xjI7Gf@Q|e=6DAF%&6QU)vJVjhLATbiCtU)yHzbZ zNlXYp<#Mi*qCDeauEHMS(J8A)#OJ|9z{rQwnbETKcIu-}z$y$Bn85xWFO}2gBAUc; zsd?u<Y1S)A_iLt(c$u261q5Jl+QNFIr{UrrQkd`}9vJKpx;m9frWwG(4Sp{w9ESOc zmp%S#sr#emPuhDVdf$}}zHy%e&r+8(a&KEqT*?w4e9Ci>0=unNV}n!Ax@on%IB^Dp zGMx<gEFOe+tJRIYgoNi|`N)98@m~T`PJ&e_-CqZucDp(+hcisK1TmCguI5l^NWBpB zR+~3v>+wFJeY`A08I2SU5@bgTF$Bn^!7WO;k4|=$>!f%ITqbiJjPj)iCk|^qpfbVJ z+S4r}$9wzRN)Dr<Z$r;qwB4d4GZuz~jkK0M9L-Hg2{z^-pCbG0i^Cy9vDs~wLXA|* z2d6KR2=iJ3Tx@*fb!w#aPJ5|LMW)r=MUMIzB;#GVR4*0JUhk}2oW0vsi2zR*fOv&> zIW3+`T9fTq7jE6U_p7c<+&(pNLZ*++tQ&(iIObkK%(RwpY4Q|B*b-KRY(n@->z}~1 zzawSuJ0LhugqCR*9DCC2Xl+X_z?c#9zMKP_Yr9Lj%dkEMaq!~fruc+S7a$tkG?)2v zqf9*_cn!WKhRiBm?0oA;ea(`qy|B#x+{TSJU^4luQpqu)`;xK!l6xht!x>56Gf$&X zXl{1*3)1v*lay1-rt7KZTnuw{<uH7la*Xb1)rB(M*31Bg%DDyYEF+WdfpN)c<?}R9 z5%0LlwC6mk4hFHu`QU|{ZInVTb|^gY_yvg(+wn!I{ESGbd`0<CeGTJH><A`b?#sYb zM&xatvTbp3Yj_%9rdKy#r<k`IlaEwlt+j&LaVsO)A4=XMeB1zcUybjs@q6?fT(xV# zQDE=MfK-_xvjWtWKpgZYEDbucrGE_Q)P12y&pTOMIGI=M0w&nJN0MCOOI`qm_-keu zkJQD>;Ty`ty8l`Q9*Ce*G^nSh*KxUP=p{gOn0UMjOp{tBEfhycG(J$~r8*^{lE@Bz zU$f<vsHPAzIjPb)YWiT5Shu;P-R-KnzpQDl$c0sTb63WzRJS>7H#3fcbs*`5>E;B# z40||uzN$bg{;QpZM^%6Ax{;E*I0yv^pU^MW67%F){#htLQ3=nsi<7^AGmQ)n|Ew&n zP<<@k{W8N7j67VDG=?xai*?2{Q(I(x^&H!iYUzm(F1}UYRQH@*W;kzn>}@v<p#)zX z{{ZY+_XAi}XEK>x5F9y4hClU}MeQCzrX7|r=YYev;hkSyi|r?6lo0I9pc2Ow=uJ-b z3B`zWjf>C@*!#!KGsWjo1QWOuLOrj!FdRyE!*NQyi1nTeE_t$wHzD4M(@M0$80Q2d zZG@X92$8ZVA5SK;qZ@(oyfdZUMBtu?LWIk<^lf+XsPlO!?SKMfR;v=4p#BVxziz&E zI03Ci0!ZunyUtTKVvF?k=~}|cSKppWroW&y|IvK=(6|hW8H#mGcCymCA1n+dH(B|D zal-JciZ^zNye3cg=}8u8epVfyH~W{AM14HrFx7|Fjsi3tyKrR@BqOWTOX5?iIA0u$ zn`f%a+7X#U%&2A@BU97<X4PrxvxPe!$f;H#Y@hsRq&)b%c-U@l{S%k?w5-!xn?v3r zt5j#S$E{=3BAyP0Yp9r&kXTE<xky@nZ`^t>m$)9lqXNuq=`ZLXzM%Kx`q-Oi2+rM{ zZ>l#hmNcFGe!D0%A?v5ERl4_`>#NS0zUlDI@1o}PikdwU#u>~*hHBWZfK>GvUlp5{ zuVAaR7^h+R4$5-0@|IzL5?2||q7+``-2Q$|v4NF$#Nekh(n@~*zj`UcK+z8OZP;}4 zh+!<axqN*?_?7v<W-}cIcf)x{rgKZXH{hqKp#+Y=<$4m(<ujPBgxXX1c}Y@4>GbA$ z`)(*lRq}4V+QpMtC?K|3Eu-hRJfoO~IVuWzS6m2|-z_O=XczzCB7X*-iR`Jz|186~ znJj8fB4}}w!~>4w%&D$&^J8K-Pn$4r&+Fnhg@`Av*E;D4@mk4>FV&d#KhL8ySU8*d z*lqJ`|NQj+C9Ny@MIT%I(ANg+)b}|9Yt3}7FiAfi@PK<(BYEGvQw1}eIvM{vZ89z- zc1Yr*Dz)RUYSs5dJ#T$7-TZIY%F{g{+mWZ!>8Jl!LjHfl=OsGRqhQmw|J7^$pQ8<v zP84kk(@$pXZ#nA!7`S17VLP@z;Y|B&^Zy+3FMk7hsU7lXAo}QL8P6nxj{j)I_TevA zJ3n0e^k=Z>w4!J_9Ph#y{%D2Z!<WYm1W)3#r2l~Q!%LE1P`~1R7W$)=6w!xoM^i=X z2<85ORP<r{lTlIPFkILlt*oNsXZReVcjTD;0qFz$Cz8LQ>idx>{Lu=-H_=#vH_5-} z($DC#gi*nH*xXviePAX~{HjpmVK?pQ8zu^cC3^tb<Wroa?=XfpH1zxr&_gDq6hw~+ zrT;U6eqTBnUwt5xjQ%ylFT_4tdY44b+KX7i3sc7p!vy&G`RHm^AD~*H(MQ9cslGI; zmzW_znDT%5te=e$C<;kL{bvwfwK0~6{l%Gt{vm_IClys;mckt74`SkYz@tVyl^p}i zd*~datbYFMugdxKq5s1OpQkdvX8d&Ftcd>)z85ur`76NYW{>v%L=r`V-}z{eoJRB~ z4!ptsMKosYVo}OJk(G(%7Xz3qCo0$f<oFz)Uxd%eB+5to6Hx!xzkvE%xv8c6fdCnA zaWi~M-c~(?{3-tVWxs$HmdTBTME`+^F^_){F*ZOg<N2R}62<)jN>sC}VTYfuk8VG4 z?7W`#RBcyTTZc=e8@p}&fAO>b>93jhf0R*Dz<&cn=fYnf^S&wN*Y0xTM_RYD5_q*I z-Ofo2;_=U=r(5;x*dS3K97#&$wEg1=#yz`Yn`H`;3Cd|{^FD-_9xes@QND<#y*#|t zvqedfhsM;t31-=9pZB_5)U)jlOb(@~c$g;;)=Cf+BIG6iVj^bBu5Lf^d{)OtD?s%h zvGa-g9dv2MA6UOWucH6_E8^S7CzxsDsaeLpOizl}ZPTgm#Q-f~1JG17vTNKm(fr6l z<I{1xL3a@%>Vr2)O5EmsY>W2?KxfrLsemjizqcyE=;WsvR;5<j_y^iFA@QGHnb)~* zv03&(UMRIjcUR#9c%Lvz8RiGMB!>O%nd4w~oPXa1@GoC|Oc0fB4vsC;B$WC^J1R{6 z(~9HvKrn~1c!|o0PhqK97@ja0sp?Xbt#EE$V1|_meM_MZab@89mvr#IXgcIhHB8n` zWYZD@AQ~1K-<smP^xs=53jo6&P26_`JYM?{Ir4TLJo7UoPcqFvPE{^DlG_-kg=k`R zD4aH|B1)}it=&J+?k{=Aeca%0LNDio#v-+EYBt!z^z76lzRY9){Jbt_n$b*BI`}Q3 z)YQ7Y3O)Q00FoabEIyy@cKAHZ-HFedVu9#DylRnFUFcSULa3EBpsK`jhXllozKbb^ zm%iOqzXV?&chewg<xuXo)9-EDsw<X36Q}2@f%)(DsXM;Z8$N(MsvzLg?`rDYnL&5q zlgGAuuI*-rb$FnPT`G4=uJ<98gPE$ak*_U=S*wk@mfEDGJsJ~AcTa`o%JU2n1|YyD z<Np?IApGK?-5dJTA<>K)KIVffS%nX6b&=0sD)9?+6zUIto8DPzs9|mw^AK?+NQ>Y` zjpmf&%~HktE<hde4qeq-k8otwT_?>N6?ZYBZ7jm&&j+25F^V-2lgVc#@q@c_I6`;a z*3ozTKOoq<GCurs@Ptskt-A;YUV)=6zY;SRC2vwgQB>L-G`(SnN7vqYt<Ss>*VFBd zm!>CSqhnZAp+D4ypK|JeMh6PX68}yRZ`yO9&{fI(>G<HmM9^%hv*)5<Mh*#LylnOM zeN)981vjhKR9lyUX;zCmoR9s6=ssR+V5g9Y%N_c75hX#DEA2gb!o_RT(Uph_<AmjZ zB86ECQhJh0HGJGA{%3|$KRnA|7P0C}`X<WAkWrg#cuB*J#g1(gW=C1LT6wi_JZ$0+ zVl1!5w$4k@F|sywq?msFnPH$O1Z|F=MUsrCW5`Pc8)JT^9m7!5@KYp*M~yA<v`Iq1 zm&sdK^#*!^)aw~2+!vfZ@59nm|2aMxswYD6&LvP2x1jgKC4qC063b5=xh7!KtA<07 zFvw@WvOybZ884`JH~&m6(%c1AGchV*w1l!u0Y6>A8}zn{CfPo*9a)uhaaSjdTE|(< z9twPK4_vRX|Hj+{<mN9omZEanP9*+>+%j;zQA*(}dqs7CAF>G^=WvpKPQN^j+et3S z;p|lbzW)4^<l1Qsymr)+P~&nOwI`{gcej-CH96WDOVEFSh0{bHFT!vh)By_pRE`!q zR;VE7i0i8}@SMj^97>iI;B7tjS-q)3?6nF$+J>;F1$oc6v(&juyHWvRUJi^5{z0EM zD;vBC8=g_D)Ou>yA)4ds-X4;v+28^MgT8slE>WG=p=2k&^ZD!Z;|sa-Zw&x~<3xJr z?PV(x=AL>V-{f`WU548CCWhDjZyR0ip`?tLtk%qT^C>Dj3Z)2ME1A2~^fnTySdN=U z1)fgS+4!>3&O(u-qP!EtE3uI(G6?VVFnOM&r#>bYZkHbBLyp1Qk>XCCsi5{kQdSek zfo{tHyv6Bp1E#WWEx=1_{E-wkfTkW7Wlp>c9PS&G)czbta&3RKw77KneCnuucH+3b zY+n6BJZbGXzQR86R~R^5jkE?yNy8JYNY!g5V&W4ML&Hfe-tdY?q}a%DqB6LR2_E;= zl}-xulOS<Ybuks>?$KHsdzxeOvOG)=KXlk|4b|IH%f-MKavqWVW0&B1Frb>nGUL<m zYh#MRe7KIig#}G%1d#P)T!fPcWzPbdZU=yiKbMt0Lw_!^Jmt2w22V@!lH{}X&~vLm zDGjv-LU$j~(NVlZJzvMG20Q~hA4=6;7>K?Yy`SgisEQ`b`O-Lj6V~S*nWT}a%o@2C zx0dTXzf#EE^+xrXO_0>L05#_+i9J95nSlc_k9r#7VmIC%U$n`QCnSQr=x{299@7fR zC7q$?25ujLl30kK0qtcM2Zn-8No^l{<iZ(G#ls81qDcivlPtC=WorI8n2SEBR!8di z1U{{|(PE|fg=_sHsJ#r|By7)&L>ZUdpZF69cK1loRx1xcGn;If$86uNUq_CLobJ&O z?kG1|L-5bnV*+^in!|4F8Ve1X`T2tQGAilaAeK9yW?%6rZHe&{M!SloKC5mnbiBO= zcZ=~`NPHCGpQxMP%LRN$B@6_q?Tfa)f|SY5pA>~^1tEXTr71)ff0bd#BQbZVkQG-j zF?nI%0XG;ua^UC<V(gHLHB^83IG1`7tz0yJGUKs{GmGu9QQEY%pZB?Q)^!Lizl|t) z=V%k~Wu97q(^Mg#JKMJS7b`f{bD!5u9tjBsDG-}vsv>$w#=G}nv<S%O`m^Ke&*%pr z&`?7gA!y}2e6LP_P116Xc8fYPxghW25SSJ?h*h5wAG!2-6+YP_+>&HOF9Xo88SvtC z3aqw?kfP^BZtz_v^9*lRXi*(4IHST_I5zuvC9fa*iXS6$TaWsq-Zu&7`^!m62n_bP z9MfDFGapVi19PiN-%zM4{6~$Jj&6BR#FkEERQ!9VW%j|XvQfsIvr7yR6KxiG*TIZZ z;-$2aTL_CZb_1uYt+^Ox?#dY#o94NSi!YUcgMtVniz!ZXR+5(8@(dIOgJOf_Cl7HC zRU_CMO%hHc4x#qJS0LI2qn2+CJD}HdK_j>$)Tt5kB|fanN8l6u?b9w9=tG;?M5?J{ z<l}PQbrS33vT>P+PM)b5cvjkzO3lMi`H4}NL8g}+e4T-epuDjcPsI4mEK09?>%F%g z8Ik8LTOp)h9nhw!K>)K?YEqWui8MuzsD%A&y1wx4R9U34R7hsV0*dSmg~mAv6xbHS zOE(k}h269S&q7}KT9+wS<54B5U{~f@cQuwUCMD(A338IHta6cIMBCB8ik$#VkGp;b zK6JnrewU+wKtb4h`t5Qgt8F3RnJPu|g=%}N863e;y}NybP|Mz|#{dLw0002&>Q>=H zk-Swdwk4xT0Nhcy$XZR=j+MEo13hu5Jgl<6XK8IWB=F~BCtZMpm}}_`_GGWbqh!fT zBjN*{xpM2sFg-o^yFWBJNdZ$npTqU^S>6ZZmC*zQ^;jKECE$i7#)Y^fzq%S9&{|!t zl=Fp1Y;*wrr*;)}ef6u3b2XQq_C@c1@?ao8cQ5yFh!`fOTI<uTM>N@++f$#{gM81Y z13EOrf2<&Xu`8X$H5q64$iWRvnZTT&DvmP4Xc;WSQcvoCyFt2JD49`6Vbma09tQ4h z)8x!Zef5quIp5$7ntNBp)Uqc2knF~l<BICg5Ce+{P~mHvlw4BqYr5fJJ}P)voU1@D z;VsS2exCSOqg;{bG3#$*->~u34!)#V+_l8GOLWJ7WP?iDc{AZjykA|bz*b{P>?@1L zBP+2=vGzU5n#>Hl&na^}+70J0;I(h$OCC<5%I$+50&arib2Lh!kLW@_ec@F6lz0;a zM<FDE07yw7qpv2$pxroacrJEFUvUf?sL%0e1Vr7YERwUnru(@IFW`W##bSh{$!piV zS15_Sr%BO|3{L-4_86U&q^Ks`atfV#5uB>}4vjSQ;*NxD34emVCI*5vaWwN&hf7rm zI~@|-{%vcFMBw9{Jx;%TRbK)Z@=H;39kz|$+#t(G-pKN=7mnD^C*L=^J?H=Vesuz4 zo@T@BxqTN2Io>+yGn4+O7aENMx#6WW6RXajQ)Ta|x$1bV;p(Md#q=Tn(<x+l;2+(T z)_F`vR@3}SRUY&WCs=RCfXM3*=pvrw{W*?MVnXC{vGASVoeIP+SuKH85QjvX%PEOm z=u!qzf0(p94^8RMlPtMN?X=rRc)A##%WrH@#W8*%KPqq9Neb|3*jZ`eietSbAHbiW z)6M<TlJ55&Z?-mEeZyj=JN7f3i^a9gEDd<(l_7(!%a*AIwH%8R8+#oBgov7Ca?X}3 zk;>MWQaS(!NofPq?o{}LIbUaetYImm4$Kk6@~+jN3%?w^MSXA4lXaI^%?01*Ao%Lt z{4my5rFUTYFCFAQoz;jGy7O!x76aqGKH`hR4dw<{6`GimjkU*lK5hi*7E?;1Sfm$y z2X6(Brzef(_B*i}yq1cUy`j%FvWvt{dv?eVMrbEu+qXe-+Q25Xv}nlw$5^}Jsn&62 zWQY<ghL3=BH=U<Tqgx#+gv}*W>P;N$d`M{+(5U8MrO*k+Fn7TB?pl4Trr71OxwRQ< z0XXJ2`QF#<T-$q|>LMdKtBA8l)yzm|jQ!npx%rK}W(5_FR~261YwyB{^H&23ZvOjz zXtQ=_99&5H_4>qdo5G}fo-qIb$7t1e${m-<Ex_ck`&sGTD>$p#kzzGx8r1@pvNc!% zru_)<v<Ud$8GA*exZ2vcS!iE`{p;H<ZP^t{MZ39Io4d%aao!~Z<S8!A^G%iSz}7#u zWa%%QY6U2Fg+?2emgND{7OU(jm4j=zdDUxXLC)^k=JR1Qjl5x^EcdE*@#On1?g}w~ z>rZRnu8IR*wa2!emZ^~l8*-;5mG{MV`d}C({U{;AINl=_$bH47H}8)(;l;O3iKl8O z!J25qcwEb?(0v+OGmwkDfH(gV3wug*ElNvKD&7_u-}%$s=-FT$BL=c5J)#f>N;2+M z8QQieK<DPSq>`HE0byx|1g@TjIvHFcQOCP}(+}#W3RE9m*`YWc=O4&=?o;sb#S$g> z_SNMNvQmbQUwo$&T=!3fA5#}}f===>@4K<>;w^Er)-30C^e@kb5&$q8Sd$jB`2t!l z2&7(YVU}D=T`LT(3BNW7Cz<a30BVZd<1ftSv8!<rP*C6dX<)|Kk)CwNmj&Q!+ZXc@ zD4?2l0l-2g?7Tlxq!Ev_MMO8qEYx)GAo*791Zq3#o3nK!E#M*Bjb@&;WSWpC?WZMn zIrZ?jKYa$0q<W18_dX<-k4&U@8zSmYlgS=c9qOX-<lrpxYAg);0EfEx<1OB|?>s9Q zC*J2W_6-vp+6lSU;L)5;ESi0y?*1QJt_?bcJmzNcry?B8Z*9S^Gr;dy6A9fH{f$h5 zMwDYMN(z#@acQY+61k>$Xeyq7LkecIcRvh0mGGVSpV+1tB8+^M3fx=3jdnPDX@A0m zVjal$Ei%(nB&JQ*Mbg&pR1Xm;FsAnJ>Pf9s40;4WzsJ7(i_h1WM0T*iSMBkLGsp9^ zn3C+j26-gDFD#F0sNIAXZSp(<n0klo=WAhvgOep^usCa;yWM{)r%Ez^AImr_Hed2> z__bqZJ}fJL_h})dD<SHquFc_UV6-4`)MrZ-p>!_)ET%-=F3T{0MD|&@&2BvDIz;nz z7j%~6)bFDfYPz$C@8Q|R=K^&f0&4G-!nRR$$p1KmUmAT!%sEQ5lH}Jn9G@qycp@dZ zpLDRKyL&aNBZ{Io1wA>k-<wS(d4)a774n8Wi5scqZ7KQrDw{vH+UT;E_{)OGrhe?+ z-Sal>iA&hlunpzqn1D1dFG)QBk1|=c+q^<@g-<XtQ#$ZXd|-BB{l<LTr`#%!LZ!wp zY+n3CA2v~E=^N*)N+lr?-)rQA7I%N>T~i|OPSg`UCl^B2`Tp4`68x5eq63V0{%eV* z!8P-gF!dM(VuJCx%4zu?DnFi#FYxlOp(=jzMqTQEiK6!JzdUZRpG+uv`d^Roe)!64 zw1J4tM&}OPPZsr0%}Isg;g*^?QC>?C;~xdm7^dG~er{!O{ZW?+|E)_EcWdbVNvQoK z@e9+ZDGHT<KM81Aco{w=S=Ib-nLlZPKc9?>f_^6X_Wuc}%G+N+RjXc@dj3hM{YdnH zZ0Dn@gCgmlfQI~*X+x&hi`f691s2f!s(T77o->I*H1-wEZcr_^5O<qXjMI#2lYW^2 z%T!Wv`TlYJk`bStp2^^0_ipxU?YG_E|KkyaK3_T+GoS1x`2B{oi0*_K>8V5Bbq#xJ z9D;>@L68*<w^mr1q{6nq;2XEQQQ1hd-`mqo0lMu~8TI{#L+pNwqjn2vJbw#p{EyI` zs1?zWdb5d6XM{1sG}3L!U);Qakbzw@MdmuYIYEYze>fxRSJYlhM_2q?Du42yLNR7k z)EJ%ZI_A#gOzjJXwNw-!{jx*-;eUAIi{3+R-(hw#$$xvMk6^T5?d@=^5a^>2@Zmi1 z?vSg;enRM<E&d-gNcb)1(sR)NS@Vyg`>h|2|6uu})c%J4SCm6A!}|WH*JsfEc3sq4 z#?U|f;0t<)^e-ZOerRa_XEV~j^MX#UpXQHPKjY_r8a$Jg|L;SOEX)ndwqC6lFjM~K zk3ScFJjhk3dolF$egf)D)AJnlPzyu*OQg;Is%lTLuz>1j+N`D$;2-?EQGR%qfyzTq zO#k;;%wIm1-!&K;o=fUZ%HEN|#&chNSV#-OyGI?Q$2;+pquzf^^=2z@!IxL9@1BS% z_=itce-K>eiL|FX`fI%WcM=gk)Ipu~6oaZb3X{nLOReu-?3$x8dm1^e7Lt!x>09t4 z({TWJs@(X7l6qes92jc5*dL+R*^e$$bUyS$vNWR2WShKk0h7-jY@`P`o<8G0Vn|EA z5%#i63jpO^wBtmJbY3@LkL|6pHQl+t*sHPe;k#dYLfv{z3;Z}NHRB);J<Y~=`R)WE zryc-W4u*pITxn{#N~qn~By}dG&jvb^1gO{V?@A(k<SLKW_0Bo&k4+?lTLvh@_GsV* zAg|6(1(CEr$f(GciQ|!$;K`}pUYvi%E$`P>0Foz<oBBI&Z&2vd#hSrap{-p|2Ou;C zszyRYw%8bJPzI<nz++1yWaz2K)pi!c`bj<5)fo-!i1#)n+vUAM=qz5hrq1dXzmU8r z@V8n}wmtPk=r0(IRLuciS!^x%NJ+90b!xE%g!-^wA3b2XVkVbSvut0yow7BTef{IL zWj7B_Y1>wV(hg|C2O@IsZ!E1j{9HEmjQoWFcr`P#c&t<tXmX1X9D60cZvXAFQ|u<G zjDX-pUZ#22HlJAfW=Ihu4V?VF!O4+4$rylKq4nAq8e}#ZLjBKm6Nu?@SE~(#LpA@k z3W+AtW#m@g9Jn7}-e0)wt{j|6+Iyj|jLg!lWV*ob4<+OGo`;cEQK2DpBN$9>g1jPY zJD5Ww`w8dhFTM6&c1|25S*OFAwh4}>Ls~hn9xDGh{Xhfsa6x;~uj!1VKoW2#*Ui8N z4J({EW?`XnPa`A>ycBE^k6pg+&~k?OIt<XTcsinSMFc@9$P8~_&34^uij&yIKBqm? z9SwmqFBy;tU8<7mJXZik^3yv6y$0XNs|r4n4$nAuI!x~mMcF1KdpuUYr^CDc?e(#E z<{PUR|J<-_ekUg4!ua5CntR~(4)==6o6*rsJyrYYD{p9J=f$#og-jG>`&NEy8kRyB z$r;JorBI6G&aGDqvG(JhJbK-(RLN=`q2a@TL-m4OD-CZY2fiC%Cl3QVngtHe2FSTr zZm@J6b)c>qTg&8!nfT0o2IkXq`xY|`EI%0dF=eh#(3^MJ=8B!$2d2Dl61c+fh=CpV zPt++oKb$J$&C&tv8ON?yE?QU}A4!P7O1c|uw>zoH@js6s0t#x+w+KPLJ<@l*!|x^K zpU}vhz7**DpuQ+V*9JVtdB7$3uMV7{jj?32*<V8hpZ@{6)BdbaiB4m~eVWTUW)teL zakg=0VPe}QR81hRXn)^Q{9<b;ITDm2n7-$^Gx`eFM7P=S?2QD*@$vCvKAG3<OT}P@ zYeDeB_91ZnkX`56V0b>YB+KDw?F*HQH>{nYI3)gt2Z1eaxze&jzCa`sJ*5tbdUpY| zT&ycp_n#_IBmbT`g{RRB_≦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 diff --git a/docs/images/pr-screen.png b/docs/images/pr-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..66b96110b878d162e3fe9814d553ba5f77901db4 GIT binary patch literal 191858 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%0AH4ZBhOby=#Ugk`Y~^WUbMv4@Vm@N@;ZE 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 H&;S1cgBg~s diff --git a/docs/images/pr-workflow.png b/docs/images/pr-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..d22ac16d4e91cb9843e7cd632430ac66bb8d8cf5 GIT binary patch literal 34308 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�OZ*$RO7FlsRN+K! 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 G@c#kYRScp4 diff --git a/docs/images/pre-strip.png b/docs/images/pre-strip.png new file mode 100644 index 0000000000000000000000000000000000000000..ce7c2df0d4c127e2d18218e95de7abdf302116c4 GIT binary patch literal 218111 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%0D(2rZOK6NKVc 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�@yRJ6pc`_tMYPBXQZ7q@4qdM)rTog8 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�T0qj+Eb*hV7=HUTqr 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%0A%Ced``ZZgu_7&W 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 H^?v>@g`K6u diff --git a/docs/images/private-gists.png b/docs/images/private-gists.png new file mode 100644 index 0000000000000000000000000000000000000000..e404dceb20fc5fbed788e79b1706391b1632c4a4 GIT binary patch literal 177910 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�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 diff --git a/docs/images/prs-for-my-review.png b/docs/images/prs-for-my-review.png new file mode 100644 index 0000000000000000000000000000000000000000..f1297fb0ead1f002e8749a370d6818d74ff1c750 GIT binary patch literal 103578 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 XV||IF&3zL-u=^P3n%qI%a*Fydn|&j= diff --git a/docs/images/pull-request-flow.png b/docs/images/pull-request-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..95652bc4b36d6b7ffec7b4bd522d75299473f884 GIT binary patch literal 48675 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 diff --git a/docs/images/repo-overview.png b/docs/images/repo-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..cb23d820160a09ec44dadc07b063337ab304b0d1 GIT binary patch literal 222041 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�W!fT3qy7Q)3 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�oN{X2Lr zR#8cKbp;*j{uPhmt#Dzy!Tqu(8O^6Is#M^dz~A1FZlmPaD2Hp=GVOUevjqqqEzh;b zvZK>kjXx~Z>Tg6&wRKOe!6<Lenv>-@LSC#|{hcj%8Z+R<0s1#b4*G_%$U|=wHSP32 zu@*Y{L21M((DdTZW$|7b85pAz(0*OX?C1%hSVm_ot|l;_wR8bp_y+^7FHeX*1g@TM zJZ-VxVxgmthBqk%zKe0k25+c3)Ec|MOdifj2wg}`s}7IxkEioa>s!NIQa9dG@H;sB zA+uV{!80ip&WIZxZWBf88X1odGx&AyVK#l{=l-UOXHC+X@V)K<>t;HuGb^p+&>F&j zG#)Uv9jaYp7w2}mty>}mAXSai1_or%n!uNbO%!C!R1p#=x@^rCmfSM3Ssp0=DDL)V zmL)tFtK)ok+;@|De;|6-;MCJ0@OXDpM?EatAEfa-{jKF_{Q|)n>D-Hnkw#e8rP@>Y zXT6gX$_y{fB#6p@j_~`VTDK)}`gC7~%$j#0%PhpODt?JLin$i;^LLx6FX#`iv!0bs z=;Es%CCgYA`n2)*hTGxap)OBDsH6lJ!&xZ}T>27(_>L$m#H;lvC!Aq5QvM5SfFtJ5 zt<TN76^w<omS}%DGQjBT7*tJNsl+m`W$&r}QcYDN0UvveFD_4_CLh8d#=sji3=!^@ z#@{pa0<^g<`Fec!87FNEi@&b;S4>4xjVy?|KB0H!C;ZKRv~wr9Tyu)pYV>?l9ZKzK zAgF^goiGmapB4|7V&NkSxziN}egE-|n6;f@j;o$1I?%G6H3Ut;Q-c!>$Z%-cvezF% zu=Tn%>d2T|91Y-UF>gKH&Tic7U)0{@oHOOiPqrditON;iW-RL!sA9z#ZD`>%M%4S) zr-)Q$GiE=@BxConB27_slQrxRZoS894Fp{J`mi?zc?I>~mn<&wNT|DmGSR0WD)D!> zpL3?|4`V<#oujQW5t~33CRDczE%Y@Sbi~$wdk<VSiofeLY8swQwo-CqMGN(9kS24+ z3!`jZiGUoQrwguzP3}IyeyLqOp}bJJaot!j<Nj4%*@=!xX5+z*ouorxxJ%m+RTJAX zK=N3y_Miri_zA*EWLa;cnId`nqgR2fODPJ#Iu5{3HXyuoJ{P<LM+t42QO8DE?DP|R zIC}NY%3_K+s=-v-{=E_am6+c>EtyQ`q!8xCznj*?k7wtyA__$~@ztnLWHwt&;9blS z=nj#mICWa^)Bxh@N!q#G#5^`;tIaesOkMR4G$#+?yyungRFh3uO5k%c2;$=Ylosd7 zlL)bfoK{^D7Iuf2F=;}>c|}czE(^5aGxFnCK8l%tl*X=FsAS0;r4VpWML8BSY*!7f z)q?$W&h_$tV>x}Pq8Pfyv0)70?cXG!k5)gIWixQBRh-SXHz1^OCw4C8upc&x9t7fU zh>4tkGhnDO?f_fnTGkm|0~oBQcqxH8W(!`Xrm{cO>b_qXn<DxIvF?^mPKM=iwnxYy zvUBy#bb_N>WrUYYrdVWs$|VWBv7v>`!O9h7&d1EfoZC^epE8rg=18xV0cd~nd`qZi zM<2n}&<k!x<Jof68W9pN3Gb4jA1Jgg#5IT)O)sCz+$Nm(?r9OR=f_%7bJtTRxW>TT z!c}#p5j`dHD1x&^4#mswZ_mXBfV(D3fOEbki_%jl+>a*VgHjUk<yDjd9k2W&!Pc!A z`y1a5s9OO1wkcQn6r@J><#M!7|IDGoQo@=X{R(#K^Me!SFq)+29}k%rW|_Wlf^|Z) z4$!Fc^tES+qsE5cw@u8{<kuN39|MC_VS$aarl$3HhRDb9_p(qFM7rdoyujluYZ^j3 zxF8Kp!v}WR{kVy>80V6Fb!N7PWLNz{EidZ)g#sVF0|Ny5M!lq<*opy6FGiS;W+6pg z$jFASkfap*8s-~(=t$+&rc<$dIrJp;E-4;r_T7vN;&{H7h&U&?W<oeWOD2Z55$)B% zC9~l&0}R<}XpkgFuATFRS@G&*`^QSKALMI|jUz$=dfE>PlF~hLt~}E5Nh=(wb-{tk z@eXpoYPOh?7%CC;j}Js%4)*{nnAr_Sbej(j!qRok?P^SljFZ)Mv8O)x;>XO)%Kn6K zTt7SX$4)UZ<fNglI0ryjap()CRYb9g1OKM;44}eRDx9vL1c_<ovA4c-?Rk6Q1?!C# zS+nuU-wbs75cP+@&Wj$BeG&1za8VdAOD-}Bbos!+ga_hXNcba@;%%W!ti4$JAYf_@ zSTTYW-B((0zc65A84_R>!4=AU8qIo5|3G`j@+DvgAu1PAFYeVN<-iPMdA&V_O!&vt z@`jB!#|HZinOB<708c3EFq1RlL#1Xb?3|{<$G|pDTGI<>75}vIeyewNB&z?mI$6;s zky>(b79K|`g)g(3oC5$xbrQAD*gu-^mtWqts`ZtYz>642s0MnnAqnzkhSI@~imGRA zrsS8n%miiTxgJRGj!oCQOfPFUI$H+CjCb`|%qD7V(&6RVxuxD=tqdz_4eOU-loWRa zkSjKf32XTHyT`cQxaZ+W|5$p}Ve&u#BySA76l$p@!bplNKR?|~e|nD}24`QX2LAe} z=DZMsXM=R$p8cbdBsL&F7xD+V;u=qlTUNU2&iz*p;`UxSq2w=J=Y$UGKBBR5s&SG* zpDRr|b}A3fzhhU1xUmgBYOUFNEXwW5776D9K7_^1mX4Y5W@Ko^_rAU%*IUFT>;16y zSwYzncN$RpMJ=(Vr>!97)W=7Vli{dy{QXx0DbHf|#P67OEdcE2Co*9T{U>EtmH>sm z70`~H2;`GC-Eb!GhBMO#50|E+9(Fidx5anF%|TzB)$)toC!6(Avuv+e%upGv5n=mW z@MBermFLgQWqlDlw<GDR%ZEtl4Dhx&b-g`pTC@H}<7edAu4^S%3}Jf>($7-Hb;XD} z+|6IV5b4IzmOBEXl+$^VH@77-YRV@!_;t^y`&JE^%(G+`^Lq}7(l?bU_}pvrX^~kM z>(vG@KK|~cvA!;HcJ0*?t$KArTgO#-G$Fdvl#~!5Bu)Yj@15qgguYdxFnF!d#cqil zN;5p6B}C=!#CcZ3Pdpf(bqbSnqj5-T?>m5JhKxl8aWtzr^_&`Y;ef9$6)3f~`J!Zd zq_k#uLqSI>tz)6(q{NUwez$oiBqv}L$nEtIqtIY>{5kWOe2FoIQl}GQ_qu+aZ@*e6 z%l82H=ANvA?(Gz2wh;y*4hKyDj4Q@OdHsZ~1FDhMz~i;<4O=_n`Z|7PTW16tHFKU{ zm51$v%lY$5N203RbLSf!wi4?^0Ug@s5YjeOBI;jhO#4$|ic_c8aD=8pPF0fKf+2!f zSKOM`DLcN~zk%Cn{htXBa^H@CxIDJnAgiHh8?h^ewnboh-(WNtQ&*B)QiH%(hg(cw zBeq{rX9&tG+K9gL1svWjgRm~%8nTR&WuEDV=YCw8Z<J4=WS<6>)u;#!PO#7uqNz<> zG4Oj*elxPqh9Zm!_PbW9?Gn0|6?4s@2s$B@rF4<%OcAv9>DIDf!j$<$IE>7(oWr_$ zTMrEmoL8Bix2cOX@yV#IEA}B>TZCcbc@6n8932|0o!$gl=$sB37EZ^>AOznb%}uw6 zv7h17O)Q*0;>C)JoR=ti&^2OaycaGw7Jsf=X5}NHI{F0!0DbTJs~Q!Q359LLjNYS8 zK{i1|oPs^Y!JpTBm9%88EU4iN%+z4lhk^&WL|pM<`V(nB-<NUY6SCVINk9RT&4%)~ zSM5jqE)$(*i`yT4Yeuwg+OtAd54|E?C*fSv^BfcTA*(?A!5$~b>oANo^Pd0YJ1U|u zT~y$!8rB@s0qQ?>?1G(;xjfwE5~w49qDOsEtLT~oSbLrPJ(#F;<PHd=-?Tqlu=~~) z5sx`MSO@nC!T4e8&61Tz;Ws`LyyB9w14+2LdlL~%^TpqpW>w->8wcWgU5kd6(DC{? zch;~nY-_gZN2sC$5X{&8t77kS-SwFbVY^O_1<<K5lZ~ciCu$(P!pJ&#nSgLt?^2oh zh8YE+T@FolG!YSh9^yk9>z_ZE!tmHwY+m=uJf#~^l(`?rz<v}tt0*7WrE6ne3$t32 z4v<(K8+jg_MIFovvtYZ+s@Oy=^|!mP);o_a?N8=N#PFHFM#L*rpI*e=+*7a*3XhXY ze?9hRNv3Osn-<cIQlI@sN&gg5E^gNVilwECX#~m2JxPwT#C)D3sdXAcW>Rqwdw;k) zUK7>xAR)Qdi@??CS_a>#Rzt7WXICu*Z6!EjsbA;%`8Uz-k^1gha(Njli+}<(^79ym z);QUQGQEaxj8!121}+BPhzhnZKDapBB}?wbwtsJ}^wkSuk!DFkx-Th+wj#S^?N_GP z3O84)Y)dGBd`{I<J-p>ZImyf;J#&o>B+vrbe+PdH*n>33G__c;v@}Iva<WA!&!;z( zziPAKS?<39)*pjOIy|@3W?8Tn%v}9hcoL;pA?5_4Ms%|l>D_bk#vz!p5&6mE|9*zh z)`74#T8>?;rR=CHP{h6p@r*Xk>P{GFfKa^kUBdR0IKH{mT&~-5F)AY64)+bJB!qH` zTRacmaSPNHm!tNWBk-%V*zH|#9r#N6{?vpwZM(#p>9rqLg@=>C{zyQ&<sOQ@0g>ld zPxiU~@M{+#TOfg`Va8Afs2dk7aj}&b(L`(Kxdi{-MuHvf_bZPUM9u_vm>hY2(R>R9 zXrbJfHOGZiPXdD$j1Xwf1DE0(@{cz~!ANrA!#{?%iKcKtz|G4yC8z`A0a`X2?J?sG zKWKZ4Qnj7YU$!Ple8@gb2orXHXZ|k;L`R^RblPVYcjNJ!iOj)HQJuNs5Ck0MzPmy? z1II{<V-DS&LVj^40HoegWQ&Rk_mdXQN4}%o^a}b>;f%99Fk)Z)(s3V+X)ZQg-(hMm z{V{VG)ob@B`8#S8fn@$zE&lFhQTcLexzL3~yj&Q-{6j;X<Vg#AclI{c=_fRA+={PX zm-1kwI7Xu+7e|`8tM8uq3c!1Pz?-vVbwImF-Gr)BDA;=v*Of4xkCGTwHkykB%3`7{ zNl=b?)@a!Uo7tx=PsWT}t2fbmM|lte4G3%Zpai3`o~y}Ca4`3TOi{7YY^}FdduCLg z?1^7wc+>@%*oTX@!bY_h>LRAmWHZcy+j_%RceNohkgk+3zV(V9aTF+X$%MO>5a<<# zD)Vq)u<q8YHMlF8W`Y0GU+&kl;S@5WqlJGvORsk`@)Fx>i7o+OXXM%8TCI0SLw$f+ z9JK;J2BJf1<;0iqIr*$_#Gri{7u-=nDg*&n9Msl%+T+4#dyadamq<pe%>;}UNLNR6 z6gknMn|hR+m4Eq(69WxP>5QauRU>%{J9G;6Lv&~6_cFie3m89zxmV?f6`Vql)-oBJ z{_=1%NAe$a`Abq;nK%_5qqm3sC}JF0h~rUQ3uw^|(TT{!8cE9FEGqNX)yi#&Vz@(* zxECmW{Z!d^84?_i*OcJ#!-FH~D`HYJ@-*~krOH;tXa;+h2%%$*bg8-Y1Z}8C{TR1E zek$$kM~*Zs*Ka1yJxiLZ0jh(L^;wpb*>;{Rs0}%(qrrzy#EhR2{jOJI(f;4Ey{4iK zE%usY!3Sikt}AaxhPE4Cy2D@%fuIoC7whA-?5>R3prTIkU89TYhGt6<e`GX7iw0-; z&>OzUy}Ns4SBxFh8`wF5wzD0aPQ7OuhE~OAT4Zm%L+A($A9ynWe>QNQdqSeWTego! z{@`Sl!U=9D^oe)3#O0!}m|}hQ3w*D@KbZ0Nx$<WeS*vHYd0$}wwGv`o(VaGyk~ex{ z;XlQJQ$!KO&(s3DdUUYM?n0Z(%vf@Qia#-P<mJp$<TS0I!@AlthJUz*UYM!PnFaT+ zsGP+_WF-ePsq)&9H%cgV<i1({0tZb)z$bi>fnoZ55k>4{y}s_@%7G}DJ7&DTy%)NJ zc$fjM54(CuA)dCh?hvI3jkJ6rT$&n_P=^4oEHjsvN{7n0^($ar&k@sQ%q8}~>PI=z zGybYT@~DpYjt06Z6muh^VmVz37!?+!K?+utgDdPPTjc3Oq{_39E+iS}AGZz|#3Ki2 zacz434D|X<2QfAo5wwNS=l$bU%kEH4&VMQ@#mEx)Rg`4ayDg9H6`VFzl((<U@>-8) zn~?gttfID#ehjF!NyTSjkCL>{cwj{S7k0Adi?aDuho)_hC2$z!UJy{DFU7(0GX}YS z>B%Qj$H?8n>s&qEvbL5MB*R3ygmFG#9A7Mhmg&}X4>}<AHQPxar$|!O=|~~vWOm}A zHf5gSIz$x*<nPYK=o?s|9Qa!l?H&qOO(1H4$(DS_a&quvxy1{E4oyYWR~JrAjiV<n zO}wEp@{jX)hk#p4+wwLlw7F{KM({p2GRVxULMk){m7aVNi^igTzVnH1bK5i0vbosQ z%*K1W`#b1MN{BIMrEUyv@0MHgy^M2aHEQ?w-Gxt$4o6%+9|VwuH<mAa>S{@u|KLaB zuj5<g@5gbuZh3S$ZznlNs*iLAZDwU|E0UxrsRfr4(c}3RkqSbJ_EeeRrilOnedCNi z@sF2vB*89{y|KqX969iYNBWCogdJ^(p!2qAW^Mw?*m<5<A>yRf4lP)1`OYNDK7hTF zE!&Y+<a{E-iWllW70$)Sng#yCJYC`BMC2cgrdKK;bMprzaRST;U|BpN<`FV5J8&5) zBBs4H#n<6fU5$v2m&nC5oYbx(REfR!CNc(uA8biFk*UEWl0inGy|tmxfg$X-<*p_X ze-G%9gQOO4eh2mz_m%H{-|D`GhHm$mCU|3&E*rJIJ^gjBWrybReM?A31HCU_ybsq) zb$11qh-9m<fOdRkyVGvL*0LAq*?L&EP120^Bn^Mj8blXWo`1j~3sxyEq}GBtNz6jp z9@c-KYJmuK?L$unYRw}k|H}%w?b%y0;pO!BE1S($sF~6@VJUW^Uaohp<7W8T+{$66 zRsEWLd>mUO#lsPGv;F=`!rVr34g9>OAkwjg#ed8G;Z4u69{+eH_*Sm{P~b<Jpo0)S zUWm1!NUsYKczl>2x?@;0sfh4D&<#r6|3o)d|AB5Gc#!*Tvd)6K%N3z;&U-7uEWD#0 z1lSG8bj<lUY9R+67``6kuJ}Y)%c*dQ!hKQk&J2U>86*>@(FvakVCXR(?FstFbCs#> zRwJgMJD-{NVy-)&YSh=oCA2>F7RPD4gl^9IaIAViBNgX7L(F-wECenupdA0W;D84v zhiy)X&=cRZ;HA&Y^oMA#mF+oaps7ohCnqiGaT`7(E5n(b(ukQH`{nUF**eNAXGN%V z1Xm4=M?!PH{~*k3Dr*q#4nY@wC<xeNDWmAx<ud<CyTK9-mbfqBUsRC(;{p`((;EdL zn56wk?oY_VhltWs#!gJ9hIu2tbTi6^G|UB)g<;7@1v&kV+0hD=k593(D3t<UTtnFf z?kOMABjc(NKmZKSm_@}V;vlcDAIy1T$ZF^~5dZY*aI-f=ZN57%_b`h$m5<MfKjY?; z_`k6yawZSDbmp0wtxcj^w^xQ@OJYRmXR>`yvO;J-rE58R-jyHt!bv_cuf9h;-8B6t z8zhJGDne+w*ivolmtR(SW;Cd)V+NL*r9oY$d!CZUp~q@Iaq@DrH{8eUVXDzIE*qB< zqtYL;ry@bM-#3a&c6lDPkSKd<*)UvI{BdZ|RTy--SqwpL5p}@A=@Ycr2aN|_HqHL( zBu5~ml;gYQazD)+6MG2iD1Kz{a~R}~WG3dktvoB>JNjG)soE`O`#wdwECWATd3{4K zX9Gf;m{anEhl$M_UzU;&7m-7C_F-sbr&NjUz>6$g9Y@20H**>-@txqTD@{6K_#z{} zkr|C1)}k46DA+>C&EdJuY112k8wSws88N8tz{tAqMI)aifhkxL;T8+rc5ew`)c(HB z=mxvU*6CY>1S{WViqJCJc%;y1>%3r3L;Y8(`L><jXbQ)Fb(KLShOB3<hPP%4<&(L< zwZjQUWk9og-GENwNA{+nJTN%&NupYeY9#sO^zbnGZKGY|r?;l=JYUj^5hZwAJ^V(i z1WTg|bP9IUC#r)1&b<3f$X78DI7xiNjp_TxH=ss<pOo4-Uint8`A7bIpS&aEbiP30 z1^+@bIs|dc6z6r|*sQTen?}9CxTn0~l7HXDeUM^>r-Y4q6Q%yi2AJ1u*~ED9U~y0* z|Le-ru>dK`&I)OybD0`HJwov;wb=hf+B=3>)+OuOm9}kXR+^Qz%}Tq{wr$(CZ96M% z+qSV%=dIqmzkQw4yWjrt{fuipbBu^sF$d-x_gW3g)h!q9qe)W<V<|F%E}F)Yf;Hnr zRjXqCxyC0rMtoz%iS{eW`r}+Y(T4&W!*@*0{=K4duvd?BB)xQik$_CPp1HKE1G4;( zX;K>QCOm7mLY@M`j7ANA>0*g^35^xy!ianO1n)rI7~8;M8&!*dvjFm#M%T1?8|dC| z^yY$wqPZ)x?oK->yofTzv!X`xls-^pP#A)vP#wsmtU6D~#^SSg;s&AuZsuO_ecZz6 zs{raJyoh+Rcer7X;1?z<t7JAHC1BHVd$W3Oxd@}BD4f`~j`=%n$K@6{;T#*TossDP zxEqUdYjpblgqP5571?bSj30HK?c`+Hja%3QQ}Um3is;$J?7;4C5uJvSH<x}c`6~*x zi%_|HW)T3)w`h@lY@g+Ah~&l?j5F9t#KvKW{ny(W47mRvm<nmx^a2+zHayB%Q<>es z3Hy*5qjXLXv|H?2N75AGnBYUlMxZ#;x+COzcp8RcR9f&63*a<qu%(gvY{u|~0fEZk z)|v9I(g(g+D5$5C7_w5W4%pAnuUIO<2?~b|zqnn<Imsig4Ok3Mh7#lyjlJplTP02t z5l+LBtL+tqC2>)VpWmh(*AW-)R8@??W_s_%HQ!199?p%A4}&>V)l;kZU?y!upPzPa zXEVn3^%soyraKfl^3?UF|8@e+jGL=Z>vuZ+%V5w4B6pQCvD%{&hf)j%NZL&a>)3=y zT{-HRv1y@@7UUFF3N)WxNL$cwV)+^!o}|aQe1Z3mBL3cb?u*CG<s#!P@TVkLNc|x8 z<izfH&gLzM0Dleibx<!U=o(WRpLmjl+|^Wr-SXd^-LA!Rd~5==2Ek(`1}e>%0Y+t> z!JwPJ3^kGav7N~88Pd}sx=|r(MVj&TyJ!eT4Z(>L0t>7iSvpSAkEV9jPd-F&fdMhW zUQ3L^7u?atecRY*3ry^h^oX!G`9pDd+CO`^3n22#6wQ5r!<|VF=*pONp5hhtVJ3+E zostuMDXDhmrDjb#O+stRemCnJHF8JYnU&+4&Cb4+_WD76Fn+Y-ZNa!Bd=1tNRwuls z*4pO*3DA=KDz`qHEM3TU@1a$o)N#q~+(IuY(w~?AOvijbHA9?P*8TnmY6<=WwcP4m za3x2JeK?gBdU4k<7YV(IM1C+t7gB3j@68aMwa`^*l;x}rtb2Q>vRPL~=X_!qcopx~ zA}?B?><5&6YK#=1IzU<c6I+=pN;izr-p}4mEhD1hPD&QbI)EiO%4><7jxoW*e;Jnw z>HTYpB`qy_?RI0`i`EhexLPYQhC>^UG!}av8M<(PrxGb!>#V4Cb}qYwKlE!@silhx zY~<Nd-$j0^(G2^bQf!PP;hepgzdgAw8t^(QUGA<i4M}Fj1<h!FFi`)EVDoj2|1{_w z1EV<hWpXY3t(>Zx@6+pos`Xp(FRIpzaHv-O^e4GlEkGDfxE0^zL=&<D8}oCKy$rJq z?Qb|*29${(Ek74}g$2OK_>Js<knqRfa@wA&Zd_^f`DU2OuD7_}j;FG?9F8X1lCrqw z@U<?FZ5LEuL!cP^=7@XKn~Fr@=k<Z5eW4PmfB-YIO~UN6dgCXqId|bP@FFjV;-n@j z0Tmq-8ju~f7peShg#4Fpp6qmDqCye`kq#v>ZXCzjao;f>cLbUIO2mBMUP^|OmFRRq zneypleM^bFdi;ku4$r6T%p%Io0N<HF*Wu?O-bNNLSwL-A=z|$S=Z<74=0T5C(DbWJ z4w$&OP#lx0M=_Y^%}g+<daLtw2rp@=_Tb4SnYAUhQyFSP!$rxzi&WLHYVzs<OZR>U zTB`gJ9z@RsMBWQJ2K-k53MljG%d&J=h+iv=es^NNYb|0Br@F7yTq&tg?_8j*F<&n1 z4s=F2zEKf4u8m4h*C;8q2cT4JSJBTG*K-ghm+}L%4^tDKZLzE^b(rYrOW^CJRn*w4 zSj94xdQl!$h<5yD*h!DrpnE8PbtxI(TW6FsC!R8|_a}u6f80p@hVp+I-vfP{4B!^N zlfrs11CignBgXOxe7!HESd9IP^#8st0aQ&*liUUdBmCb8YCvgdY2#8;)pR0sEA1oP z!vXaMz|y&nkhNHWbGsvD|LawM8T`aE1!4%G;NZm6)aPjw#Gp<2-4}lv!~=##Ynzh@ zSJMBtUj3Kh7msMV)yc5}D=0Byhx>13|1kI|QS|h!C_xSn{x)1aU^1fK{<V1defIy* zw<7spIz{lYQO18S`eR56`UW+T<qg^WhklEs|I!t~CMFpCebkA8z9JIDc9}k+JMM-H zd{Vv!%zxu$iFmI5zNj3dlWaR7Fij<G=!8<|RMZD$|6yU;-z1BJtk)QE>@;fs*WWb$ zR~cC%>FHlKIPtZy{=LsifBG(Ai;kH5yYJ`^bz`-}tNEN@G4L-Q5#`E%KZp+}KqF)^ zn>f`?c2vHk;D)xPQttBx6W$&FA0-yWU*n0<JGkBL|J#)-E0igPfq9w*ow5@8LO38i zLQt;)X)WC1;(romlI82{c~hyHcs~5ErEUQ_7&wv2uA+53s-fPYsfGW~5ae>cWeB(e zA~_)bHJ7}=f(a_@M2Sg>7C{Ti@Km!gN=akl6BC04k<zC9vqsK;5`+S5XJ^N5yYsES z-VtzjSa|ZAuDGa(%>CiSZ>`A!gNsh=uO<okfY6tYO!`&-HHTl=KvfJXw3Su+YG~P2 z8pJm**YUY3kPc1ypG}H(qJL@MQGf;I*IR6Kf7a-H<d7=S?U9p{6EiR%4ul}kV;mm- zHFDO=`noJ7K5`8n{<8*e=n=(bWJHd7V&&Q<iJ9SMXT!eiZ<9h}qL;TY6l)Dsg@Mx? zdlZ#&z!}Jjq^2ePBruM22cd0ik3;x%-XKWhtmFrP9y4*{5-~%TJDP=3SZVd**fyAj zzu)`3e<Hm`90ST6vA#}t!#)dpr;Z4UCgQ&EfCUSl+z=O_)AO^Z1Hf;4=Iz-r$a{@r z$82#%1SR{eKtr^CYZr8o*V}$rf-YS^4$Ovnh@Qm-tz%U0cHpJd@{l4w-v^3^MGqC# z;;i`~)k(Msq8=uW*%ARq^uYXHXv$mhezF-5FKa=nJx1<+OFPp$Dd3Tc==S@OK_~xy zuZD~mHf)~5Qr=PR$yT(#@>XxtzuHsy9!*wgHqYp8t2^Z*)2kaQqwLc}WYb$onhDt^ zjZ3dTy}It^RpekKh<c>>arEiRA;*KiFT3D$!R3S^S-=R>CMJix=oUgmIsuv2{~mQT ziZPDnH({vNf&M%lp`~$(NiAWF+PT@WYj6B%BA(<4blnj(6y%>xZ*Y3s^aTV&mR}=M z(2LK^3>49|mMfJ)cVo!|0`(Puoa~&OCczjQ?elZbum<ofR1=i~ySKe^j~;y0ZDw0_ zKq2{lvWT8h!^4s$EIJ`~vi|`x$i>C`39MqpBLHlG@;ql~J{@9W+>a%Fx&@w{U89)s z6xgB32AavnDyw+UFguKeEHxnUm1gU5O~^-`eRaZdNYQotyU|DVK-RUhvuNjdhJl&a zBOCI-r>nn70>tt9)dv%>O@zs1j`;*;Ihd-@&4eal`gSdD9rYMg<YRHAr;<{=g7X2I zKkeY+!uE2!+Xb0-izPDF+<G`!=<THP)qGR<oZ|}NoOkTL5U(4jRk(2nPNmV4&6Zr| z&{rUJO#cADQp#J6`LA0bn+(_zJWqOS((ytEK+)|*C~5;ub6F?|Cp93js_W;ox8ESS zP-7mP(_gcHMhGU_cGj$_wc&=8Fi^icy8sR~oKScB;`Yw44DzE8z#IH^#P!0V$;SC} zrC5I&Rcw@3MInwfvpsV5EhpEn;fFa1MBZ%7?z{>f7d1KoO}J2G6tFT=ww~$>m}Smx zu(^9!1v2q&7ZH?-a@A~GIj|~9ws=CSBx(I-C*4%8Cvm!v1=#!Ba!3*!BEW^*oJW3d zQNtbTj9{zBPhk9NH!lb)^A?m(n>&CkVZ9(JE84)=5_L->B@hC&rlA21)t&nxp}xK@ zknGUu#D)yOo9Ch6H#gEAB#<+#q=klx&U$hNrFJToZ!rJ-9ZBg}TkLy~Lrqz(hbst# z0dsAkDvuLY(ChJNq}(_ekaB;`4c<E_1$`I7xsQCnoMcHaap?v0gZafF@H(*9YJnwU zYZQ<Wgu#8;y{UfHImizqC9?Nuyywo^>j|wDDkX)R&85NbZ#_QOZ}h=r)q|%JlTvDG z`m~BYs&YcT^=cDPmdgDPkzx(abJHX~skOcYv(|m)Kixg?wIL>wfG;95!-Qb8?;wt- zh55rk8u*5g*!V8+w^5><W9;bk=*XiogOf{^3+m#Y5G>ju$N}tdOOdJjm_3es#Z?<Y zS67R1*bYEBa37!q9c)8Se)Ms%qm4ZanYdMYWfHMIX};;csgXwKv#w>)DB!MN5Y|?j z#MEqAL#wi__*eoxP5M@5!4ow4umWts%Mk!ncxnOt56A60JEH9!`6-ChQ$?UqB;|%- z;4c|dqM?h%)YipoA<vs;kmyg=e8~N%PA``}ai(8S1qNSfwI@%E@2XGyJP<gfV%bBT zE+x4pk<dLg-UY%24gG*ef2qXn;i1<rh80gn6$1RAwwkU~zHhpe$Dnhzu5T*BbD2HA zvYs&4&W+UMZERnA=`us}ert8OW1g&|z#n!dYkB@zOo;YY8qTt-oFb11uAxN9mWj6! zyTjT<@}QWbGL-fNM42?mw?v^V0h)#rIgM9vFl!bi!Q#c0m?5k@SbN{~tzW#`#l^z9 z6gX)~7<n!(*HMWac#3@blr+$!<f$doo?Or;a8!obNH!P^ernQSZ3t^6YxT!@ga%_R zO_;{uq2T6@jWCSpLMO@yDJ8)<zqIWuNg52SsF>^515aYB8vrm>onFuSf&!NYxQz@B z;j8H|zd!k>VQ?S5o{KX<Dbm&%IdfHJY(jpCVbQ^cCBsmB$n;?&qw+P@k`g&XOys`v zJuE;<KKh3Zm`}Yt;CV4JYd2IzH=(5KH@FCZtn^<gh;$x)06!^i!3;GI=NlhEa-~$d zAi&&DD~a;bx_}}Jx#W6$)#NhiMnrEK6N*-~x!<3lJ1SWu!DikSJhhkZEXLL}dGic; zhKv-#VoFh*t_egEO)}+W?af-T2v(CxdhSJg!^JFPU@gyxf51o$Jta1&i#K+%m;dv( z08lQ+L6Fv}mI1awte1&bo41F%J$bgaz={%uWTP2@v4-5qR_o+uO<|q)$+~=acAm_J z%x0Hk*er@_Rl(NS@HAP~i<N2Jx3P_}BxZNc8DZi)w7Qc`g0Dtf{qb>1h`6}E*48A3 zGP?_ymLHahbOdu63(LG+Zsr}$p7SkWzxEgG*fFc-uNa+b9?sK|?r}t;SABOjnP-c) z5ze?xeLp{713G`;;2qvX)M@TtFCl!Ez`D?B!EIGq!319%ywy^&V=`~@?0gMhWA5{+ zQB85-b>705(VcR|sXl*3m}=i3bTS)~$5#pG7-#mNPGgFFfRgF2x|-f?S1;ju3BN*G ziM7ed4xO5AzLmCK@*9@uqc&PaPsCzcaoP(}jkd`U=+BIW$XokltnGN44+l%L7zvuA zvPR>j(sv6uEl^O+Ep5axBU;Nsn;#d{id7(G1nZVW^*`B01y_z()INBImd5;w##+*p z<C+KuMcOTS)=y3!@1^95%{2p6>~^U&(FEVRdLfSA`|_89a5+7Th+B>=e1;Xrc#TQ- zMcdMH!S<oSg~cctt8J(VS`Lo(>)Ioxvsk6Jo6@b>1kK8~uC(n-iMq#ugo6|DnFiE0 zGzTapsNRmYa<<l8rZ1?XAJId92UH+hWn2c!Kpe1Ud_6(YZgK=qw{G!Fhmv3F&w-;( zD<Qbcfhy|Ww&`fZ5I=4KZ6(<KymlMU!O(rxMH!hz<tL&qe)JxIX)&<b-78{fG`)vr z;t$8DYf)(OhohS5>CZfU($BZTI^C|4M+@6EsdZW-Z2Nl34x3*y2@C$VfNt{mJoi-a z*|;vf9~q_2;@!T@mH0&OYNU_ABTz}3DZzhvApE7ZvD;$F`je8&aX;_Z!{)I#&Q=7A z!~Hd8TL2n}abNv1@fm$^9%EW&EqPv}(zvx6p1X#eye31<`?WI~^!f7d);+Js*5QC` znGcsdJ019&tS>6>tk$N$wQkNi&!6B>g~O8m8W0c`g~OjR)9tocp+o{!K^Wq~8SXH* zYjt*5G<+Cge>NJDe{Emn&}wc63!ZYsp0P?8-aE!y@sa$VjWa`@JNaghJE&QT60@v+ zK&+@VF;MYOMtb?$rmID|%b?Radrn3N=AE_*Xynw72RH7<G)j`0=*ymdhjk1bd~8ho zSxCAyko5-GgW?E3An*XuO$hUcE3rPMlN1Y6lPg9@7Cj<lBL{N`!U|N*W5=$Lpujus zuh*Mjz=!+ZneT1|OA5Chpr39PdivsZ4EA!FJK9c+a$opjayuyz#gI>|bMHh_rLK;c z?oJd3+LL@!Sv1R2=pK(PIQScrM#Ejyxa~<!xX}D0?q*~N78(bpiQERQv8;e!a*)JS zcrUH)`G(qTE}CE~5p;0qLYkDw^qk`%|82p8D9!Xmof&C4w-oa2Oj%zl!73^4Bxt)p z(si`T@9GnJ(yU#MQ#G}Rj+7ut4w&_6lF{y$96)2_OaIfq&z3Z*rnSI<(RR;XTCD{} zOrrE9XSjkfchkjO;E>=Z3jo5qff`yM_Pkqg#;5;S#(p3(+y|gz1;_^deygy1SWvLc zJP5>+ni}(0HPA3J_oPUU>Ze=mSaEsy?*Gn52DBiFjB5r!ZHm@k6N$X|<c)6rLNy2s z7Bi+2lnpWk%Zx#u(qEs`b~XA$Sn0ZyTHt&60S>sB0i17_wZ={}*q%W{cc2RhWX$dZ zB&Fj5;Uvd8Ac}1|BEZ(24W5gGLe)Mfb#fj%NO7yv?x>q_XVan~5z+%9%8!EXP_SL% z@*o(k&T3L?#}J}Ie@}Wb*K(Ip1N+DPdT!@nzc~c0<fGs_k1-v;>$Q`bxkxzt+5N3C z;vKz0NR~*QQfgj$llsGbY}gEvrvaSV|FZVit_2Gbnasy34}%%ljg>qDl%486(BVh3 z^LiI#4+u`en%?@=rW(^Imeg=p85$zAbN9ST?(usR<k|=AnrIdO*HlDPf`T1^ifl%3 zc|*$nBDmAdl_%dyLh)QH*!;{^7)#1SW|WYF^kac@sOU|>XlsE}-}|BIE5{ib1s?Xn zwH6o_R8OA8*Qo1^6}&UV<<K5}3&UrEkYWan1Xt{R0#;Sq8MKe2!{`gN+UqE1m|wx0 z=F4D3aUt!G)t00}tfUrc!o0x)I-y$Dd6<j<|C^8gDYa8JNQcI2q5%yNg3Uk;Z!htV z-`GztFcB@mWf4ds&yTp>`OiTIbD#b7x#y;<3sB{O`#-Pc^mv_r_{Rk6z4|0!u6sbz zRZ!?G!5cSzuY<EXzK+dK!GNb5$}sSW&rz0?HZ}iLx$H5OxlRLYn&>^(pQ_c~nK03_ zU`>%{8?_O>s|pcbo!}RiY9!=pquXo4y?_=Zf5P@8X(FLAfUv20hoQDN%%vxgE5><W z>#dLV%<7qr12<mZ0hHj4LkQO@UEz}>Z6cGDmL<Xi-5OA^efBX*^mnfaPqAzyy-rWi zOb+$Ns4>~}V53>m#jW@tbvu!xrd2<}sYmU%NqKC9iV4L&Iwvn(VNf6(f7iL@MU7U| zAkTE0Ekdk2e+5SIUGWbT(~jz#qHxQO2Uf|Dt)!~=(sabWsj0m&EH+1WQs@`)KlRnv zb_Ec0!F=4>U2c~W;8f_a6g~egg>pT)4_X+m%GwVuGT@7qCMk=Lic!D2EwLNKQvPA4 zK$Vl@C=hlp=98Bcy=05{p~DEca`-ejRo_PFQAUxcw%Jqcrt$>n40rN6S{Hd0%kW09 zv@?3PQ0vv}QY27&vs9nt;qOn{^Mu)b95BXH>d0ONn07l3=}8+G&Ult_BbT0pVw_@0 z6@RYp1!*+WkYvK0&AgqB@-PkQD@$$7s{6MW4R7~G5vK;Y<GOv@1`EWQCgK6cS-xiG zjAq04t6>5nmrwumfG(XSB2}de{*hsM9=wh*hQa;ZtMhIMCiN{CPp8I6xp35<Nk|+* z;)Uu-2Fj#>{s0BT{8wTL*%WwO)gl4C{$8gmcVn4vUlbLL+$dDt(X8(NPQyFrmJT|2 zj*M!fzqAvgFrMt-=Q-9&9Us2F`dS{TTSmd66q>wlr-EhG4HKTnj0Bu!RB;8g87X8{ z;g8K+{vXh9si<Z~CSe*=XtN6niR-Y{PF6eWJ;++RvAPQB@^?0z(YRBDD3DL!<fv2% zn>K+Z#2pICo|kXHnF(`@`m-X!rC>|V%99elSz&xAW_Nc7@bKg(DFm%}bTG*&H83Rl z*Bq|2u)lLO^lhM3rlb1DLbW_kv{4+mG<REin%ohBe^c*N-guCTO+-eK>VKGx8jAGv z(Q)opac=g%!;ECpr+@%E)6wo6o<awegXuh)N&t7V;NHGrWgUG4Zs8ZU9iG5$7ir2b zd(y6&kBg97$zfb6Ab-s5R1IHvscp3Y-4z>%<!5VBp(Ud7%9w$vBHv|xRHv}qmTu|; zPkpg+d=&<fo0g3(3?=Oep;OIao(BhDES*3FUgSxC!X)T=5$tw#_ttULSWqxI12T>b z>=`ZRS*d)KT4R@1`@LY|Jf!4sL_Ks%tLLAjoIV0Ai#R!&dT%y;W>ofqe+HkwFug$i z)(*Oo(b^Hzpj&^ZAhFm^DTLDmx%S$^f+&73$7hchg@=;z#DD}UHS;DuH$-lz;%mn5 z;>nOatl={x@xHT&E*!D_o~db29{~n0GUmTiA;1@3YlC$3+AVnKAiBNk!Jr|qE?2~f znw^3w{TAZBu_3@-|Ec6?s;F7M-%nV+PhYqxw#FSzcUecHM_yf{QM81sC>X~K?LpBM zMovfPYBi$zFjYGgoRDt`xX_T$5KCyb65(mcVlSS3LVec1)R(@PN0MELUUPMu)2<Jo zs3Sjw6B0`g(dLrpYP_at5juoJc|Y`Kp%)tfJ(Z^SsT)Ga>V!VJ?CD*T;E`C5J7c!v zn!3Ccd*<(<`)vl1kIPh$bMzj<lK*`YDB+|DGssXw&(`cT8lJWy&wc#q##Ev+Xk4jS zOo0?~(hH7jIffr*Zp;4ilhOJ0htQ5mNK?NeNB&EOsQ+9=>P%C&<EYaKyJ1``jo;Ls z?1!)*sE1+5MO>hDOf{Yu^yWFdtT80Qr(*eYXSbCZS2qYJ{3~$6`LIEg1_+bVTjxSb zc8c;FIuV5<bN)gEX+LN`wKrZ-GnJ90Ho_*4SzMrY92DeaOSjT<{_bGi*=J<q0s6aN z_PzHI;u%EX(pIKdMwy9tF}gA?1xqP}UQanZ?<G-k(LJZZXFDr34}_4IxD~66je>MS zc+@>1==EzXi=9Df)?$CJ*`*!*3wD#RJ47JCV9-YPOITwFj?%i-ya#zV1)OgDu>{@q z{gS~RdYO%;{Xsdo+b3-Ts9}|cLSs+D_5O7Sf_z;)&!tuwC`|k`)%@J8)QmT`^mHzk z@6;(lL`6^&f|8Zg;Pi42_4UA*2?+1`eDYRM)NY48y^g9@|Ea|<mq0Xdu&ZG)nMoup z{E)RtE~N}v0aB<?XzYei?gwqrF<R_~mGINRDN5`4`%{4qUcf*{2Zd-AcK{nkWXceo z$Z5yrMZGD-91Ze9b}?8?!b!1C>8uf9bfsw+xUF;IF+NtDhtZ{8(~^apnJTzUoiumE z9*^OTb;*PD)A>@=4nZeEl$qQ2On}cb5K11?I(^r(%&p?eS^++zL_&yP{>?=;7VzTk zVpZBt9EbC8L5#3WF!kfO<EO_C_g%2p`~#&-KD)e-n{_icX$wyLs4rS+L&Z+Y+SAIF zl)u)yzmOPi4biFb;I&|ZRTj$&l$qz4c#?w1P}cL6f4G$vF+OWV78d4e<W=bmHnP;+ z$pUM~=SY4U+7kvDb|#%@!O8>PmV~#{n-qqpphuB>^hcH;Ac-bdyqz4^0q1TiLdO&c z`r5<z)f#;jp*Ati*`(ZE4(JpO<*_?L*}c#N`_;tep`41J^$o%U%`&sO?(EJYhco<@ z97(0$QrscV@eh7Au7UcKCnCPHUhD*(c4Zbx(NC88A{cKB^^LrlE{)+gnF_ugm7S+{ zYpDe#W%)OH{E$r}vLJsrQ^FX~9s7M|WS3e`g548s>OWyxf1Hum@7T^(Q+_SuYlR88 z_N)xkxzIIu7AO6s-Gt5SNrJ;Ai2v()n$dN9dXZmGGu5XKrXOhx73gt8gD&BYHM-2+ zP9Na2!@F6V3iUvymqDI2dNGQFd3YR=bWm0L48BxFtOUdY#V8K($Z)wXcY8G=H~S_9 zU0N=6TrsmPMBB(Dt>I-Hv|L=>U+2Qt8_TOJwG5Db1y=%ZP68EyZwz|L;=LAM?jhxh zbvyJ*Crv86wUJ9t^R4VEtF-}TOV`ti9_5c9cgN29xy<u(SziYCheA^i7Gnw-ZL6re zqDaQjWvR+~5yN9gXOQ_3i7C#Jt)t{>*!E8=q?seIbY^YFQMvS_IBiKUlsx^<oE@I@ z2{(8wf5~y){yt150wHX8L3Ru*dk8v`%%($R2<Jj5N-U)B2RdeFH3aIr@)1uEBXlH3 z*fNX0lwNCk;ogLeODLFFiq?CF(H*)WMDrNP9c*S1ElY8T)5EiZbU50HR{_~<lj%jd zl0>LX`Eis@IiwuY`tL=7ceV@3LSA~QKG^;5`wBk7`<;EIxnwpF_P^XCX{^ekP9ASj z`HQMsAT89$33<6Oji)}~(CIQcAHdL0C$vV~<T=ezAPW{zyffS{cZ{1un-?jF-`4e{ z?-2Nt=po{3xsfKt4eF0to#yuX7Ux~!9CSQm&5Ow?Pg{s+!y!!oZf@Vx_-{DI`qiOS zpgti5ti<L{SZ(-Fa6EOBm2z2IvH;l#8IX)oYh^TMltRnSEGaObWXwbjUJP02T1TLk z!5Os`W;@ca=S}L!@~188AEfx&TR=4~=mT{hdYwA276ADRxYQ1(ctGsQNWp?L#Jsrl zv1O2qLYV{8Q>S`gfe(o#Yol*|#DtiUudk`l-LKSQh9s)>{=Qix<F+=}`1I&-v`bqu zs^D(Kyf@CqP<_k@0Bgc!KwumBT5_UG_NVrP$`d@Gz|q5XuK&m#d8&KgJUXk}MsId< z43lXAM(X3Eh*a1#Ljx>Ey^uehFKy2%b$Avyb-Vtx)OlBI%?Ksnw(;dfHiJqrw;y0l zU11)Y{-rxpp~z%6Gx<A}7}AXjU&<J)e^fX$!vbw(!6L@#d?_yE2j%tEV4zKWp_x=M zl#YMbXGfN-%=5V{8{^Wsl~$t-1VK$X<}raZqlT12Zog|7{y8>O-#XVAuCUHUHXLxW zQ@VnWHyCBza4i`Fkdtl5Ra2^iia-M=Sfg%NIbSqy#AYAHf&o7@%jE;O`7nN89y{YQ zPw=%f*?yJZC6db#BD{8ZG5|4kJ-<nnud#yKk~@Qh>lOORk~i8z@N{$oKkMyjK<Woe zfr_?qOm$B0);3+meYt=12O!TVs(-vx$}i^6OE7pK^d<BV6|>+XD`{vL3l=395E=5U zW4bT|9SK=4?X)<P(eqJS8p4bwZNQJdlB-|r1QbwAE?N?P1W-(7FaGIKS_dpAH9`&L z4}P^`p)z?y>Uft%D{SRZIhJeC55!P{k?cmS+KIgOvCB$8n)Q?wC|10pYBXkR%`86; zlJ`hdv0+aUKpvGkoH&Ets~)5YPdu$E&U$bwVae(Eog!~5qFof{zdwP{XrM-DPL^Xr z3I@%rm25_^l!1G0T<y#d#1t_dm%Bk<YDfJwoT_@LKT(!$1Z|PX^gAy~+-PS_uxR-$ zw?o8J!l>Q?F-K8P=%PgXjPn6iV4Dg*ol#A0`qg+W2ox7u8Og9NI4WBRrMu-Bs<KdW zBKzrf#~>U#^{NBDiR!4XdojQV!;6|L!pdH~Vb6<A1-zXux~JE>8O%Hkjz(Q@<_sK{ zjkY?Q6KrKX5pi?N=B6azE)5(TG<I}h=QwIcdSOJF9gppz0_J8axmx)XsuAwZo8-0E zm9)Qzf$~}+vJq3_Yn@BQ8ge39g*M|F+ONt3zi-S*OIT?dgsXzltYb$)JiFwQTQRzz zt78mJ%je4=#oOtvV!^(BGVm6MVKd-cgK!e@Qx@wsn{IRgTmPOxXJIMyansUwJA|Uk zB0r^DW9N{fs2_?EL~ovtTG}v|&`K4H#`F0^rs)b+@`zn6!d##L8;-A^UD`>f>)FFa z8|z^Ylh8LxX50nkH<dl_@R@^un5XQkQ`%=8i3&?(LHn_hK=PHFsByZ4ws<;5j#w;l z4SgDq7_Ee(CAfa<VBN0om9SR2(1Ww3)(-1LS7`8Hed}HI?RZFqp(T}amA4Q=Bf8ux zHwZE?y}j=~KHp1+>6bq#3S`bP3aI4liyRRsve0w>@JO4hpEK|~i`X@ZfXdT}sMj=Y z9eduX#~{Q|_{EjpF}n>7r#ci2h`0fL4q++7SH6*>^}3`)2BT{{jp5ZkC+q-gXm{9< zWmJd!dKX!flFa&Ik@>q@2l+*4bMks79SuPe9`Ie)BE6i31~%~Xl>prESU)ll{-#9l zq}u9dXQg#6frg7^yVtkkwPZT90g|9T=KR5?RLghW{k1v4WW<GPK0IKyIz;g!_f8%! zaXrdRv~X5qq=K8yDRjK{W<Q5z<4_nkxC*wcKslUO4m!nc8FCbI?@#39$?Qn_F7F`< z!)LCXhH|NW1Q?nx8pMz1ZZOSr4VI%aGB70$(V1gDro!KGDCF59l(kzO+6iI;AMP8c zS*_w7#?knmy6!oVmv2m*fR~Dbv?DT664~h299Nm_cg<|5pCK+is<j5!P=!Ncd+9&X zG$jx<#BAuyJA>tHGeMieQ`+@^9)r6&ez3@H%Y;ZRUzt8iee2I=5zWE3CXMzA)vSw| z?Y`DDJv9vD^LYg-iP7?X<H{0emvYcDA};UwBzPz{2y^JU_<h^uXN$W?06_kx%#_AS zB49PY{8j+t)j)o=#|wJ78C6aaoOff7P0yoi1T5Xl0wi>rc3OL(DG8cbScRRD3W8?V zF|_5w?`-hMM?+>3pDek2Z5V$eFVZtAo@a|~qCKnt&|8Yci*uv|^8m*0t29P44e~^z z$|HN-h?GbKmmWnz7&)qdhPzlqiKl>Kx2FoflMP@xXQT_-AhD~??%^zm;HrsB3kHSN zb;M$;XK9Pj1rTbOBVQFC#h3Zf6vo;f!!HUPQ{@|&;1~u{?4hO+iARO@O&g*M-1{;7 zwW*O~@Fh;MJPLmabMM!dkwmDAX^go~=jUG{G4uC2T{gXd>X5Pf5}i59fGpy46{ikN ze<8K6bM^O~^x1b|YGJ73g7RCqDuNfhln(RKcR5Yr9dRau2sclj>z%09R}Mu;pWMO? z4jqJO6>9b{u|Zq!`q}!%PvTDw?kMNzl=~*)uOCHyfnO9~wb#a{lRT%&E79ML7}w2F zUIx|_^lEXpyKOJ)Ys^9=0*tJvB%ycgi*Jyz^K3Rgav=Z?btv8uVCglbbI0`>_aVuN z&k@YaFKi5rtF6&Hpe<LhNtng;KvbokI7Bj<=wA}jfgb;IGEskh7~^C{FA32feCBG& z_r+Fe*3oPsraJdB$5BUXzu~I;?sDqfY26I-Vf;a!B!MBwTi?Ju5dN%67|i0wd<rwg zRpKp;=85-s2bEb`jgqlbf<Ru*S1q8KkP@Zh(^$#DOO8Uh&zBcd5$339Fao~ClDddP zvzms+;e^Wp=h8CW+rI-laj`C`4Lkq7;P>EN8O9D}wYSJjOJ!r)XuVruhG7HXUo^EO zClaGtZRWyYz={wjG?zh<M@~uYRCQ0o<ZHAdU9<zdYl{;qp)IkDMis;ihs89HPC=Ky zjTc?s?d_}CJutRI37lds{0{3p?DYBBFg{U;kQAqKgO#4?Y?@yqn?YeALY3AoUfh1r zmVNwFfYlOaKZimxuSBLxl;k{x5m`zhC*vWn1ECa7!s!*_GPgETN!aUjmFb8op}3s^ zkI{fcCR#j}iWijC`b?oQZA+9QF^Sk*nvms(c(KfvpExX3U%}PZ+%EyA=`X_Pet`{Q z6i91xB0Z%Vq!A8g6p!ByWPy!^i*0si;H0HW^$x7V;bHB^M$7MYYsX|XdQEvypaC1N zgQ$KLL=I#ERkaYj&s`~h{$9-#K+*D%e!^6U>|F>(Gb?6n94?Yk*N7>+K3OC@$}(*2 zgPYXsdOS+@Bb*m}86rZ~C>|@_&D7dUOp+~qE>27T(=DFa$^2L^Iy2SPtdfM~qo9mH zab*-Iv0Q1rsic`JY|WafX|r{P2eXyMpSPI2<olZT*0B|M(rZ=pFC;&0bu#{ZSr7_V zU+pe?ER5+K0mFqKxV+xDX6g^oOw3)a^8a|S2Me9ci<DjtHBLS&b{3e+9<>z|Q5zsl z>ttIdZ598(GkPH)*ts#y8;`DX7)m}&<BqkuU@olrZpNGMB7-Z*B~Z%tq|K&#CWcYA z9TW7lY1o{1v?9mQI8Cwg=tgge_eBnW=7lJe5=9GMnHjRNuKU-(<V%xyMzMu4do08d z&)Z&R8%I#OcgM6?v(B+HpGprcVcv0g+n6BU2@%9RN=+RlEwUiO(}gFdNcwp{fmmBQ z3*1eLTSayXzUcp4sxPvjR>glLK@;bFNZ5S!3Wmhtw7XcxOH+xr^L>JJZHXU_OJ64s z`fRZ*5Qel+yNB^x3zGz>@ExQC2cZ~Lghoxi(m*<kid`>t7Z>ufFliAE9kDjwGlq5z z@OU8(yW1V<l@atIWBqz1W8dS%23$2H%6BeMXzdzGE)g#k$ve!96zx8`HDmgX5JwuV z3R$PRL8*qjjL;f%Z3>_QT;tDnap=6>xzo!<V0E!btn9#jocPhLa>V#_gV6(HVyq^I z!O-qoR|*EKF8b{F>P0gRxXmBr@Fxa_nokr&);*nq^uP~i>M1Jou&OP;A*OsSzgwOL zPyx7z>h~C}6*@_Gz^(>NX1yq55JEcgb0RW>h1NweT^Mm27L6e_n#%li)(`@Dg1_z{ zdBE?me+|IL)QMUx@spNHwo*g6Q5-P(-Kfgbcq`v)cHG-kCfTd%^>a<`sLSX$$+C;A zH$RVie4?_d7+U9(rJtHrQknnweKv)`XnYKJu|kPV7>t55p73LwQ;qeVamcDQ25S89 zO-VUbo=|452&a0$VQ9QG6%*w8kkfmQm&%gr7s9J@{Fng%Umax~N0mUYUzx+p&W8fl zCSTc-ZbEm=|0~f4*tzgjcD?M)Wi{-yL$3F2(<wED8;a!3adBzVWlL6lf3BGb+h~&i znl8eK54)BA#z%ygRs8tdMg}Q%;jGK2tVG3=u_2)s;xQBefefcc5JvR8a%ZlHm-k~w zhDJfRLJr%k20AYR@v7`>bUN6H$5YnXl<SGS&nP8_Q7ZCy#H=_vZNY@{Y&#d=I)-2F ztoAq#`uJ10yYTg#Gw=+X56a+lfGwUxf1k-FPu4s@zoUhCS6f%|*kW{i!ivGU3cGTV zyUFe<a+Y-FqxsRY(RpEUU=fv%1H(!^=*coBX}{K(#%tHTeJ#OTr!L_wcI*nJ_VHfq z29FJq`o#TXi`O>6KaA1{43&(Yvh^sYG<|7R5zj>t4`TKs@%;OQG7aQQ4Qn8KsM<Bi z^l3f3@-XAJUL(UZzwDGpAW?@e{j8doTvaLG=wbz>#LjFc;H=K8bH;QGewDR0F@B4{ z>Q#7E`W~Z><yng!>{5U0ow_CWt%cB!cZIwG6=;|?iBl)B5pQH|_*E*e?bq=P>R1s$ zUWAXuOM;5q7Ly-KBU{|e?&c@Tj8T);11oPttzqsv9op$k1;Q`tkLXN4Oc_?wM{T3} zA}s{XnKB=o*LuX>gyf}WXYIyfG^!TYh_kFnKlf>6keoKm!j#y6g1X~F^kPe?fe=ez zfta5P2&1sQEdus>4MLb4JF%>Lg;o?hLPu(A(VNkXaa(J=b44By&?HUY0Ww3)U{ZEQ z(#)BbclE5*>?7i>p}O&h$G5%51be<~%avE8nJec)2I%vjind}hFv?=ZIq#~b((H~% z8jtt^s*lp9sVyyW=!qiha5rDTA0g8GF6JHmq|q@QWK$JI+H1}w&z-Mys}fGfm-C!w zMwcUzTiNb_dT4B)ih8@RPcK8>F~N%}HO@(*d1L66#Znm<8>kW2cpw-lse>czCz+ro zgaj+8C^Fp)N88?TARY#VOTKJg#}ys-=f9>AyDWz6t^J0F*tOYcARHwF^sZXN%mly$ zYG9_Ea76SSmn=yyYM*7M?(nlW-c9zlXD6*QB-)%y1bhB9dbRg8mYU}$Fz@9L3|hLW z#iz;o8ivIiPFb+3;qcXhvYOa!3B^twW+ZX)GGV4-SBVCe%MPUks-!K`9@$S?aD8b_ z8|-!06X1fZ1&GwWB+TxdH6ao;tjP6;_?-chKz=l}wE5Jfjd0<75tk|eyx7NjT&wFL zeIOoGf6@KqZM6->!O5tG^79l)pfq8tJDkWmr!jkr55%5CoWujZdtZ2LnWBao<MgP2 zc{J@>*9Lr&MJYim@!%1mv@aBDjIW?bwW|WVV;WKHBO;~QYHgLujA|r7!jd&-lm=CQ zcB2(s)=acaP&|uHl_g&82WzT6q2hk-OETKM4(**Aw%H^Vt)-q#3foscX&l%g3R&e{ zk~W_;=iEqlv{g65S^Ip*;>9Iw&<vpNmK4loZe+^X$pDtpY7W1-zAnk~3wx0IENs-H zumfV~T3`QDgcdY}dLC4qS#m^(Y?4bxU~%~*UxmNyo)`|5Y*p<i4BC(7->en^jwjqn zmIfMe?aH$u3VR?1X@<*5d#F6|?U0i1Cy&rHOZWjX5p9{W3U{muQ_{0yvn=Gg+D%Dx zJH4Pi?~I9sT~ajyduH-Rb81oKeUTAEtd_>8TP2rSHI^jnZUDiUUx!J2&(h)aqTNgG z&&(wD6gpU05eYr7zWjm`&qC9h8KE=fKi1G2i5?J2vkf%{a<fi7a5(4~eMrnkQ=}Vf zN@n0mn;lhUT8vPPkb}sFpdLCGnVdnOD@}9|(s(wF_KikWUC8z%P$neipYF(qkBbEP z&9_N^)-#(DO1^XFGQV$sBCWr%(j<9)N)Yd1VZca%ixk3>@N$OnMjsW*YJ_DO_8Up{ zT-QxMlW9A@t|d)H#EhW>1qp_VJvP^t1vTMm{s?Bi%<OPrLu%43jo$w1^czN3*3V9W zKiq#4FX82(SjJ8JRaxyMVnHypp3I6w0znRtG`Hv%ZvFI-PT*JAQd0d0*}WV9xp{L} z=PwVl04xi;NsF<ZQKuvv34=xYginqS-c$5s+(o`E6pc+wT_rR>u7~0Qrdwt;ZhqH` z>s_ujVg4}xxho<S)w@(R94ooM6%8_?<yX*M{8L~ysnvFe!BWG82&aM774?(3ISVv6 z${ocA!Yjf6i}prE*CloH4J5-mOtj^BOB4hdFr2j(mRlR{>haU2)Ec)J0pdE}U>hht zEN~pcc}F-B%smRzpK}b-asxR`ATisiU&8W*19!4(OOOI1eYs@2|29I>@oHrx*H)yu zMu3J_A6S}@-tTBKBSD3`<4&r#9{Qppjmn!0SrDC+v?;J^W{7&?14N)oTmzCw>WW4} zUUMa)oEXYH>QJxz%6*r5rJ#8Bg&4M|YD=XQqrf$U{8~Z(IhWyU4=qS2MFE%vh7A!p z{1<jdF<ti$FYzJUz3N8>=@4KnXrhH(=}*W$Q{F7>1jYv*<^*MNX|ywK<?!t2FnbLQ zk(CPFZ<BRU-syzxx=ccP2OQJl?9o6UCi(7c1hDp=k&B-K3>9xk=w~qIBE-MPq*5x5 z#F4X)EWWvna7uxhompG>3;0<HB((O`Ftq5|=FKD^-_tV~p<JF*HU{KF70V<_ECgh; zT^7dzpDU+|5nbFbZia(4k@>*GP{X~AgGRPo|6F;Q7<Mt@m#3Db%)a%EmTvZB?akm- zeBd1FR0SzXwj$FUuBz*<sYI)W%c;>e^LojRM3OHX^k_)bLRt@*Z8oZh{6{rC^eCt% zKL4EOMTu*01dSek=5Og_y^1QPqD%iS=Vu4~^u03k_mR=wEAylEm}YcjpirvAJl)s5 zwyp9?NhWfu`vEGHxs|?2cCZpfO~GM?8^E#Pk*R=Umv=RFGjQMhYwZ#sPxXM6PEIF} z2S1Q}T_7%g9yO#)Vte!E#9k^9f=+Ho;gfQxwSz#&LC@j9;^S3o8KUAS(_c)>F|L6( zdw=-$^5X^KolF~uipvERM@~Jr@TiYZI=2z3*4WAn<?!Jj$I+)L{a!4V^)5F+r^D5o zCSEWDgLOqCXKJlhfvsuJai9ltmb_$TdYcL*O$AwjR{w!e+#wPAZM@Fd3hPMu8zi9H zy0~~512#RK4q<*%$iuITJ-p7#H(J`<36=haxP=`=d}d<8z^Ap~14(k@t&smIGcOiL zwBr0y3|eMgLgZTD#u!NyOYXv%M$XVu4r#%o+<9>!J)_)Ct~()(!L{_?SdW#0MMZ`@ za;(2%`l)1nj+G7)S`^J3YE$=`<?Ejl@CBfO#<VaNQTe+O|CW%!^4o)?XHK}<1G<nO zs5>Bslu{X+i%`x4B<oaXBBQuI{UKpYuCwi<{tcvIFWkFU2X3BNaA&WO_6^0g9rVsq z@Zr>WsO)d)i@ywCJ7Aj1A5%d!O#eohEBsG7C%^TOHoml^l%DI)Inoec#`C$N1g4Vy ze@BiS$MVPE^B`hkhE`Tqnsh%2%2S_>NB`lqh<XVysqvySq5qa=k<J|i9fTNKffWq9 zwG;jiaLy@`p1##--9h4if^+^rH^>G1q5lESnIrj2H)k+P`JdpNKhO=C=rGdXz%c)S zbHx6@Im7Wvzy1T9lj<uHW?(;vjM9parM%aQ8}~P2ZYy9o95(kgbz6WaWNqydWMYX| z7|z=~`NZkpAw73uzLSKBJsv}3#((F`4i@QOIWV~?wom$dz{}^)`H{~ntd!KhO{q!j zxAjUda2qPsu>bd?db!+q6S1;b_0?6^zHV&MhkMasm1_AiUp^8NeSQ6C<Eg0!3%`bx zul_=pEm2Wp@^p8P{l0>q+`L}p7pn16BmZAps1e^_EFyv;K>jrWk|F$ul1YVuOi7aL zDiz={#*++&XDr-q@qW50HU8Sap-(vXykalV*D>gP$)KzV_}qZMqZTQBlMVWxP#yk+ zdSnfS5&AFH?#I7Uoi#E!DIzNiPo<_w@;(GtXky5pmIVgmz?_<qM#M}lHP`rqjV&ei zK>kJA2tAOMj_ZGtz51u%{?~i_I|OLCYL&VC7>p`$t--D!@<RGPZW<4wF`_fQHnG`) zPP;Rl&LvlGp1sjRnL5ZbjT@E8w-~upek>A142%#E2zbH>bggVB6Em|gd>;2)=gYNe zcjY#3=^b67T=}>+Rr@{Z|BbGb(pyE~>upjnNKHVu`VM8zcZWv>Wi0ZIQ3mB}LcBwT zJ<qGd{aCj1XAiI05|!QEG#{hSh1zJ$*I$juKS5fq)B<_EJ&8P?EspE#O124yg@r-F z!Vcc-4oGnr$wotQ`+%mi*}&^WdwpJUE&ro-<jEloi;D%Js8?3iF?zTk?2>+_mujf5 z`Z-6{|AQ#v<^fLs9Et|ukhG0>Vd*LR_QZYn41+R-YBb-#1flQ>r&ySBrjPq!O5xRo zyUMZpV!kKLBva9QfJS{%@Jo^==O6?f4k!OQFox9c3gQ09eBP}XfoVP#S`!l<BT-yt zGO=8{Ih#kOO_IIat=Q(^UX>$H;f)*8{C5`GqbEK~XiksH#E(y1q}UX*FV!}O?!O!+ zBHLy47pmT?p4CQCZ}nycwr~#IH67$3IW^pU3bJ^y9wxIy2pjYwAsQr8{>9P^A-Z#w z5KpC6vj3cg!Eo6je*wj;0>6({qOeI9v?>49LHRMX<ztD-{>Tdaq}A`jhXNv$lb>Tm zwktehwC4!rF}1}SnF3(*2N@Wl$E7GpxO*WxOOm5I&Z%?j#~hl;G9uICxlP4Dl<+V0 z-w@J*N;s#r3(egRZROrAyLcNYy32~7J%LA0<kh7|0JR2>4Cv_S=;MpAPO#(T-6uff z`)l>ht+NH}27MnBPbFyh2OA=(%8gBHsV(%;Y&>nz#t`+IY>>imJlzXpy`~qHF5ZCH zgiSN;6&f(PS)x9}O=LgjL%GV%Ms0!N=GnYG^uqx=oLc@fF<n7^w{uNH*w_@^sc+XE zjmRDGB7IcWEP0%JWLwac+jde}Z!sRy?XA4BB78PlAc*U!=2P4gt7%^G{A<I0@tO&R ziHPWI+EDKhE27cR|KMl4>X<3B%#z+DSil+)*wU{qx!VvY+pj$uTjlte^Cb};Ei7m* zaSYO{{N;VpbgLK!t+>MMHd4bCe9>Jk^JY9^j7{wrI|MYR)?0=1F1NV=2oPOpKaOFE zO^F%`(VRYe<;xn#AksZg8czV^%|f;%mrhm2-p<WaBA5I(_<ET5&0;Be6emTtx$JYW z1!2%v!mlXnXQ{r~%kSkL;IF}9lcZAJMOeNd-Qh(6=t%oTtD4r<dt&ksqk)1lIOJ#w zgZ<n47yW7obIb)cJfMtgJ(5F*nk}zL8zY+?%|;Zd6=mfePc?A5b?(5Ha~P4(C(MlH z-@C__13-EIMFOSloBZAj5U~rbQ^=JZLb-tM@x5f;kgtL)v+y?@65XwGl5pk6;N;R2 z$ji|^lY!N6#6Ym3nQbtJ=iNpOyYjN%S(YVtWV|6K7dtSGkM~AnHCtgGK)Pe|fa`>n z8_|ie5=D0oDcLRfEHpDXq0TB2-53(%Qo4WnUi;2W!IE(0^pE3n)1(a+62%kV8W?_k z0qMV5EhMfKvMpa4rIF-+;sjc0ZV`JS*{4CRoIMi_#h68*cz8vc+oF}-3}I`>5hs(* zSixd)VrIx?iNRP5cte*ls%<!ZbDlw$bzlRdDLP1caqC2I=DvuT6d=gQuQssDiNj<m z=J5Wi#xQre8Mw*~Yi}?43~~vU6(9*2Q@qG{E7n_>Gq}-ggX!9=Ah~@2m*%yFOXI;l z*-I?M#{EN%oA~l$!%sZ*J>-IxOK}xk>ncc`6F<eVA<+F!>0uo%=Q*G4ABDFodFo98 zoFwB@?Ck%F9)KCz(|S9F#QgHHt(6s8>Hdw$XNAhm6`b3Z6*<3F9-21V_j>IhzVmBP z`9iZz5Rke;u$wabdmw<toR5*P?qNTs$bro4^aBek2*hHkH~eA|AEC>4D~k&!kajf; z83G(Yd^^1V(rOkIPbNTO7}Ug)PU-E55)($X%jW4`kGwQ(Ls*1!#D{)O%LBLlYH{0K zLVaOM$$qhd9f{3`Xu`W5cIb6z%W^l2;v`Xd_CuIN^HE6seGZK>nCcY)HWL5>nEC|I zaWn%fB;N`BVxLg6N3WTC8NwzXk`fv71L5)bCs3r-`QJd%+EZrKUz@&NVOZLS)x`n+ z?QC1uC#tC*e=TNmAweg?5rYG`oq*NFJ@RXmHIR6M*@m*Aek}Ayb%GHBov+d?SnUTk zd0#RXMPogI4+*6RA`AB0&orBWOb{FeUzbEUCa&N-ju7T8gyN7Qf@_&FDBZOMlIdJ+ zVUt)%h$o2U(l9AuFGwYH{gV(1oOmqsc`Rgty<fm0kz=<<m}MA9$GWUD@CW(%puEv} zm@+r*9@$7^0H~l;YaoI`prw%z-vnY7ZQU1|c25T;{K1(N*owZwGyp;nWf~$fIbnCB z=bx-ElLCFR*wEeXNiX$iF>@63?ynK&)6L1*Uy_3Nvk-|ErlfJz9HFveE!Sb*{Op0J zZYv=;QJJ~|tcj&NLXuFR3VNQRahRzGKK1lh@c&`#9iub(+I8PfI!?#7la6gC9ox2T z+qP}n>R6qQpXkXGcWhhx-|t>)?Q_Q3XT9fZjT%)oJ?oy=ef{!+nm{*JXn#VS<+laU z-Q(tg6R`4s3SxM}`&JOEEh*UG?l~3g#$T<^b&wnY-Eqr4@lx2`PG>?|XiIelgmtKv z3zFY9;2i)gyyCb$IL!S<dzqua_xEqTo&k7{KXHHJY%F>q=H8GQvt@ILkh$-nLqJ0p z=FDl6)ipC;gp_q&x?YVj&SzUC<?8AlB>*?P!4DAZAk>n7a-}3W;=9byHrY;+qx!3c z=cV8soasd7#<V!*{<g5wfM>uZysPQHhgMcSXDX(>M@sz+o{cX$OfFy^X%VoCXcc{D zATnAR;?z{MafE&jh2<-NP=&=};%{U)m?aYbayJHLOkxWnuA03);`sVH6Y(`ZjJ0~p zheCvrK^z*3s;b`#<OU<)&Nkk3>x8}v$FGq;)Zp^*)k1=o<xm-(;I$vgM-0w*v4^bo z44uo(o9I60yzD1*>}uhu!mVimt{+s(i_h`>q_=i(a(F}eTMEh#zq?MY*EZZfHcKW? zEL)zT9)z21`h^N}b2!z)piYE$v~e~%&SP{^zB(?;;X?$wYW_L!qvR(3rSn=mt6&L5 z-tLgP-H(t4)vl-cM~o>L^z(?&j+Su~6-OrXZXd%QZP7QSJ>ggqJLjfTu~@12lQ^l` ze<j_x&SpPO@$rU9GL_-@D83!*C>((tH+hco3f4KG4+sRp@%R;Ja7879K^Xmi&>A=# z$$May-4QJpd?>-O?uMgQOB{vy&6Pw-(2XIfB$)TxM2wFxzvbSf*jFIwr8QXPR|HRf zPblCZ_I#8D(cgs#;}&;jO>~SPbt5wxZBEQg;P_EN?a;wm*Cop(WRym}9X^vK64Jt2 z6X4e-5x#Qn`MLeSGH$Y&pKc{0Y^EUceg66LdnaNGs(e43_Zy@B_IbflFY#l$7w2$? z|5D-Z`6Alg+DK;_tX+-%1|GWVXI2vuvi#RXrG|;2@%V-$Lnbl;&erm8%_KPFjfz|P zFVS>$Zin+sQbXBwR#y*oG4`!6^_*q%s8TV#K@FUG1K}z++oGq!&>ofRXovafCp!{G z?f^ndzc>}MAp}{9&rMZErIk+xK7@ucBWoiQv7ZO0;Tkp*HJ4Rbs8UQeu(R5@GLFYw zSm}^C<qya<yU{0Y%!zEaNGDlZl1ZIPF9n~lm$S3O5t=7>aKB=EBMhWc+~2OsOXX@& ze2%RP7gw4wGHzkAZRVxlL*v=^VX8c??6Tp8`IZj<SgVu1t$YMskOox62h0VkX#}^P z>C$*&W;t~R3bRHooUuL~sJ7-3zPD8`!LWw2s}xiizE;t>o>o_+(fwKA_X%pX4zmGH z@yzn4H{5RB$QR-|JJ<=sz#<MEZ#}ELGQGB_Sh7}CX)kcV`R}F|j(6*ENrMBl>ZzFP zw-E0kb}%VDZ~`4z*0$F+gn=*nHJUu`eapFl#AKN8gkcv#2}v&3H-J^orHSzRQj)tV zL|a+w5W5}^lL>MQI)X>ahe|4ACz66e4-nj4Za<1}Pruk&CC1T~7jtNS_7OFyD3UQ~ z(SX?~jR<#jb$8?0zfoh=WIfo*^3t?2PNiq^Tdv+GCN8f=gmj5yem3|XA}Ltg#eK<N z*`qYSzMYT!Z|N5oXq$?U&~P+~AuRw%jTGnMNcXwjRC^F;s)UvCSJ&ma3G?0BP5dZ~ z-LowUUX5Q%@15-o|58qbT7qt^9j^z|bs!q@)v9PJl*RyTJGAhqrWD`xws4e;A1i=9 z_2m+I3ipPAu>BLgH|LjMQCkR(Ji|NYw7C87g&cg6k2yl0KowQ!QhCuxLkZ<}(JU5> z0B&%b%X+2Yrx3ks@y#nDDT0ATZE>IfO7M)Pu-{#l<NXi;tTUAdPH<b6eya`%%ogKW zY?^-v(_!fjX)Xt?z(2op*_@V<D-v-c5gwajB|L5vBxk7@v^$SWE846u3+fGHRFi#w zAt-DvPQojXTM`wYh!QFm7Q-*-077{>yfD3LkEY8bC5Y#MXoHHnA0p-yoqe|``V~$V z<59QU3(A{SkKcFj|1%><?U3ddF~Ul{XgP7k8a@cD1<!?db7%xi&x%AdR%=3wI??Zn zR=0wHMOgUbsq?`Bd(DTAl){Bv8b5pEYl`}pEhxy80T*^cUv4l5ENc$osHa5PZ(bcG zsbZ9I6Ghet4oDmJA`>AWi~ep*C-cTqo%vt1b~Caazkyv>Ig;yhBKZr8n7U<I$)fYw zVN7ZBEEGE!nW67iuxFy!Mqt1jq>Ni-e>++!SGQ@c*iv|D9fWS-m;+u=vJK;gr5#@< z>$CVi@uB=H<)lkWekODjzKvM?crjTqV(e7mVxD)Z8q-=;F*Q=s`wd||az*9pJ8{~0 z67-ec7kWcnmtz!Qr@uj87_5o#Gw$Dzh{E46gusG`O6^J!;Q=Wot33bE5w_tK9{U{X zF_+&KO@h#pr?NE2m=VHDJ-f$(Y^?(jRv)F5A7CP@h<+eGy7O^Q)w<CS4#k<=ffC~g zOCHE?s{}SUtv~QW&|$S*A|;z4y}0w^tY1DP>-5@kp`1Z?34D67k?E%#U=@nK#;{2T zG8eutf(eyyWr<uE<Ug#wH7p7s)cbQ9Dovi7)sdp=N#E=iWs?AK+H-`$*X}R0_#+g? zhFY!;fK$Y%6nAJC_nv2!3TjY0t$tce`NQ8Cv7>WoGM*-ZeV?p5zGfOM)VY5;)R^m! z(Y~z7S5Bc_MP-3FU7f_?z_+Q79i1QF1tdyAxC}x-fS6GRzdKyMq*er~mUd=m?2FbK zxDxb8p|_h3$ylnf!&3#@8_$HpXv#T8Sh$h6Vg^^@+jbkrSM{+QqTD09JWvtyDTT2+ zEU%E$zgJ5(`bNg5ck@^`tnoyzxY5KX@&7Te=inmxxYQ(C!VE<Epa3VAS6d%jMA~Hk z<&Z3a_PpMW@)q()!a|9-!~Eb##Dr2kKu?}X5Y(+Seyww11MK)vSwt<;6CfoC!>12X zH$Z1lmyG{F@Dpbc-}2&RK5fG?Q^=0}?ksL}S;|Raw@ArgV01yPP|Je@eMx!1#bPJO zGyNLHrhX#1LuI!Xy^t@!<!*=Wn;Z5tOn915m%*m{BalNM4k)()sQ_>!AqWJ|wI>mE zb%u-3PL0klu}g_V&pwp#(1Xc-tf@BgGXTkd=ccW;fxE_yC~DC#%xS>^*YJ;xdMB%r z^=UN&lnqGyjTbyZ0E!#)Tc5Embix<_q)G6wRTsNy^JD2%a&x34z}ig}L-j{8*NP2J z?F^i-+3@(#?pLvjNB&lk+^J06Z)@n0oAso=ep7fIxc=l!zb|W<zB>wnevA>b@FC7j z^QuTZqmfz_pR2!8E=yRL>@dR53#S&e`i5{+Y^Npc-3Ti8!-Fp;1hz;5k4?^`5l0JW z5lwC!9B%7F-Wn&@G4KG%ZLN($lv!MJz*-C<JT!OP(ecqx9}(WE{5j~cP&6Y9wi(sA zfb6Se=y&D~Lf^#fT+!3|KVLOz*z5ra(2TArCEl(<yjF1*uAUh5r4MpmQ4c*2Oak^Q zVsL1f|CQ!a=8_Smb9LlOMaS)o(eTpu<9IV7Z5GOR`Os`)%VS?ZwCi!~*d}4F(+VFG zioeL65BdV&A{j#k#yUUmgJJBuBC0?j!jSOb03J_aR-$5d|0fz-bk9B9M88Fb)K?wX zem>zkAzq!d*8ntnFh}UZU(0NB%I%u-gEtFxMiQRs^p&IJMgm<~+*l-LTEcSOY!Miu zM^-C<8~9aNr_pv5SN7d3PBrHG)PIbZa7GNDQA+7))<v|C=Vv$jaJWJJz<PJ_%j6}d zX|+WD+REig7#7>@sWD3wJb&o$Z+Xi(1I|y*e29D4#R~MJUpWMS{cP~SDf6d3<%04f zbnB|sBx=k{U!_5*GL-FNHP$ymwRW(y4H%%4Q3V+^+A;Du3a!Mwg1k8N<ZE@*YIjp4 z_XmFp?|U0bsy{Yo0~^2}e3Zf!eeSmWv(`s%dnC1|KpV(5;v(m(k8vgs_W{ljvmn4^ z9DZT0A0*Y{(4tO7Se_=U?UhX&Pb!CGhnrp7cRKF$ye+yfb%_l=iRu7^od5I!h?)1M zL@xaf6+lxQZb)vrXkAg5?!$QkMyX3qk{C9X5DT#WSu~ZXG39e#6|=**Z+zd(CA*3e zXCP4-W{9(@+)HoOYGy_TQ6nU+&GXKVOcGTC6n&g%Q;{RcSv19;B4%t}^0~M|z%O#v zGXLe!e0!a+G^Cx>&z<FTmDn00Y%*|<d3gOX0qyx#UW9p5wu?l827_zFC6?M6)$iyR znZ@g1I4kcY*7;M!>zU@0eiq_FSji4G{^Ov8@QD@$lL_+jnQpKK>#!KpP6Pk+o`V6@ z5t5*x7JG|S{<}RL)9uf2h|$5ipg~NU<(&HO^)-XS*)Kek=TS+fvrBVPkdS#c|CPW1 z6kQ|UBEN;uw$MWoh{x3KaZp^v$(B=6AWRc+83XP~<s`lY^5Coeb^`2q$<)!ytgxy$ zhM$1|B}In-WG*{eIv>Ubv>_S_1cUd9-O@Bc$syAssoet_h41&MJEDJmUR=O&u9Zxs z%h*r2E63r2BO2dR$@TZdT*)i*j#r6Zt%9ZkUYSIN5$LPykPy;PQFTUo5OG37TH%ZF zU`t0hY<+B)f1?g*ll&+a9!G1Nlj<&hCTq3W8Ys?5V>YeCN`HBkAtWs=e~Y`DRDhq$ zzOmVa1Qh4-a91Gu1&NJT7L;SZy$X^bJ7>Ea$WbAv>*(l4$NuPeIB)b#E)dr0%jQzz z!6L%veOxgBc6p-EO_-k(WiXa#RLFxG%hy6M^mDr5#y8);h`#vJj~?^x<H_Ox)lpAk z9;!)&>&ttk&oy}QiF+D9t}6wLn>ZM~6SwF4Q8;SoiK8+f5MR#M2=f^*H5K5IL+tA3 zBXKiDv@2BZl#xwvQ5p;_<Ysd`-Iw-@iPBc}wOjpZ`}2I$FjfaENW=!Ck`gd@;$M+} zcW{ygg|<Dm*Cj&CO-qrGku_hjM30&?r_s!<a+i$HX#x5dpC(ITKLyldbK?;I8n1Mh zixDznWWxIJ$w1JZvXwNwVU&yO-5Wb<wfvS%xRtIgHM*V@=r_a&6f8hczp-g9lh z$?^6Eftn;7zspaFCG7O*O?cWE`i$gphl*wtOQl8TcF}A5+>7>f8y`5tpY72CTb{Wt zqV&2CT0`m_1b?cM1;_-rzC%2GxNGHUV7Q*GAko{P>x(B*{EfIrD+GqMjasPlFk9yI z3=QE<F9vI;L>+X=sNX5kO;k0|E(MF&;VS&9CtIyO2Q<J6xM2;AbNMpua#-b;4<rbX zrsLj5P9atz_j1C$K2)2$`(u$XE(!JXbhjD5inH&e*g>9R8O%}2iIRI&7BM#wKWm<} z`X1|2PsmPF1SL}zyAd><8@QCe_PX(enKr8bGXaDafVYzeVl+^%^8fEdh19U>>XGk& zv)+V@(xjigZgRLI{6ocF%;NtPaC_lG%u0EG*Bv_I!;`LzT3-eWi4qM%=8WK!0oJJJ zoI8g3^)l%=1j|iC3$8+%*ac4YaMjLcQVeA!^3kOG;KDehylqO#m%cqmLxfhNP~R_$ zNQ<DP#vBTbr>0s2D9tGR)dN~ke6LtX&~J=XNURlaFUZeNQnXV95iw=?LL(~G0JdWY z+jN4;EIM#Vo<oBe>o*+zhCzkIHZ6I|73<@jye>ICumpN50|Wr}F_x4h@I`r8uS0b) zCjpkpMdxeky+teJN2ej-nS7(L9uxp_2R9(=Siu0;bp2teM8&V?QZZDchUF=wR&A~9 zo#m4yof6B4Y-!56BL=1m^ICOz=}A{u_DR%X>E0s7MtJhJocdhVaSZUyN^82=t;ZPQ zY{_uTM@wS+WPb;}0(iCnmE13HxDz_LLZzg-3F-|AfP6S14A*U#eNxmPQ@|hkU;5>g ztH0xPq}K{}Qz{dFn_!BYDkUmPTRy@HpT8`SIHJYqn`V#YxU)rGamYItWQkDCWXJw6 zwzfFaOT>SMer``*?u`2}|6_lPMP$3D*GH+Pn@rvT6na7MOBNdT)S%j+;A|y(=jI+S z`N4MA+pTO%@dbNzq$Avl-M;tx&pz5(eqeImQy9tN6?fZ)jj8u>uNBcyh(P8_j6fz8 zH>xMD$G>tcjE7RbfTGHsR^&Ixy=v;sXpi!0U8HqO@@zg=Iyu@*o_l*8J2ZbO{sLE1 z4q9rR1<$~g9Oe>pIJ4bdjFcr<AA1?7(G*BzBe`4e3Vdcuw~RoX5gDqj*eSvi$5*$X zM{xL_zA#f}xW0jzz`W&=I=Qn)7sjR~UhN;mz=|_JktX@9hpE5H-A3Hk(%8My0V(hb zSw2cQixPBlb@2%2e#RfP_#~;DVr@?gD{{J*1hyA(12Hb8SmRlRC+=n+D6yijd$-}* z>3SZo-VZ^1CS`JWyd(Yx7}1IGihcgtCuU+N^Y#o+&4b_d<<Y~^-cWwFj|FAP;1kJv zscEFk;Nj2HrVv;B3DWy&70ok#ds1Qh@#*_~nUULw-g-n~Z;z7O2ot*g%p1ia?cW1I zd7*TF48nNPR8lYstC}&&10gX`ebXZmF$J@h0u!}G>c3R~(jtSYy#J~CNBNYXVs-xk zFaW%L^Mq*0R@<&d*;A|hVU7`)!yE<JCg%PVM4oGB$cR*UhRZ(QcU%u-?WJz_RYc2^ ze40-b$S-58#PHHv_d+P?pfr3cp6o0lxJ^{Np^(|rRTv3xVV0DU8;auBXp9jEPfO3H z*k7p>Rg110X(ejdwztLwpgN@Zt*{;myo=;}3ycT=wB0Q28Z5wt_jFMRc-M%@_)scP zS(9*4LJB76f)Bo$;_kSHoTy0#-a}->uMb|bCCc;!81Q0ySA}3#Qa3T4F}wqySL)}~ zo2}D9OIO)5!D5K@<jG8_`i2^4Ql9#Qx~B?Q6duP{WUCOt`HFf<y)<%T=rH{aA|=cB z^BXM;*=icwd)KdAjFgsp$`|m4TA4!at`6jsf7~@8%FinjsNMyA4#BWSuRlI#l@L`M zzhE+b#}<x@R%#Mfo!Z*GY3sn2v&Gi=hHFzSbyhrv8>bfnDTbz4k_q&WZo+E}h8z1r zBSt34{rkOOm3DoQfOzo79gcx>5AS<#PYdfT-)*c64!@Bj>go<cN#gld6WaU@7x%_O zO%RGEZdROvH}@&*z%9f9JVjz)qm~cc3Mm;1^+(Evs6oLh`GNzy4{oE*8c2vbM(C%v zOHgK|jjBYNWpk~Kjw<K%_>|mYSIPK=)}mDGS(b^8dOACpiO*xXS@_nU`TE(b>8Acg z-#tYEt@x#gOMszNkR=N{6Ulc-zh3;(R^Ir!Fd~U(NxZDGiUn~z83D4om2gWXnV%}+ zxpYzK>XeptEjX|gdg-eiBlt+#!9W*GhI!O2a!~11#YzX@fJCH4Y#*Jg&lE)#&o4^- zL^$EZ8v_*8%aP`Q9_%2oz%rwWug?ORAvLEXBQaMa9~$sC%rXoMgOWVePWduVzG%q; zjV2RZaQEa`i`|Ajq#C<t$y(lPI?1s<K*=DY((d<)@|5<1ZP4%uag+JIsxCh5o07nY zhCacZ^+|$hJ+Z!Z!VE<1*kx+vS38C~Qh9N3gT%UN&9<meizXC+vpqEet=e<1AXZL_ zk`8TK7JS=2qfSlQOb4;v3ubJNJGh)V+k6g_f6|R3Fd#$dPm4t-5kW|3zf~Cqf6cv~ z?p6P+-<;Q!W@lG-vDUlyk-!eCD=sf$TVC!}t}H1z-#eZ{RYG1WsVbDS?#FCM;{*?3 z55otA-S7Q_V@j*ygAqy<i74hfx|)~f?v+uebHw2!C&zE?$${#3L>GBa@v_}zCXE#> z=&B42fk28@?e8q{Gbv6ah9vGOl#cKgCxV(?k~z22nH|tgaLN!x0`jg`9-7tXIg(O) z?<PhG?ycQa>MG<l;aBh7?DC9H$h(~HP}dCQGJZkxSNdM?L{mA48q7OM4K=|D{q|yb zMRFBVnF5v#T4^eaEY-K&9(SyF7Y9-~&0)&@azAT!fXtV8CktHz>ME2QAE<5oIezbp zIf#_IjSY<VcB&lWqv8!Z@#|9^m}k!~$V@f5NFkD3(mX<YXY&iM!y?wT>BR`q(@D;| z-`^exMy6}6kG8eGnq#&%qM4)C(Udf|F*PV6E)h&_v%p%dIKU0OyP|?6@rh)UPbd#e z^|5O&*NR-0(QlrfNSQ^7`bPH!&*#Cf9D8$Tj&F@-v07Yl>3vT~BCxp6$8sI|tHUv- zRNVHJV?G?8Na}PxMNM;58NiksA7Z!ELWtr0NkI?;<&3lX0|Q)g=b#QvL<`5)f=vV7 z^qk3DlTY4Gws5*fvL@tU5>sJ5Pp^IW>Vg>?H8ZeYL*xglW33+8xm&CGepxN?Y-fVg zDPdAL^}Y)UV$u2549b%-e$yaMBK4|I+q@R6Qb!NGZ~ppF@&NW3Vrg;`4%ki};XOnS zc~292lZ_&j?_0j{Rh{AuiqT%Cz`B-#VpXgkIjj*CHdBz{+9Kp`eW=mHjg0aelpIY- zjQ3X-cnP0aXW!_{j__Tdr1mr%T%8HzHyO4pgT_Jxq-r5^1H2j?y+LdivPK;iGND*s z-L@flA3*B4%L$@6okp4hQ!e{~U0r`F^#=53j+QC-pnSu+kl0l2)whKShRf|PEH&Zd z2A%0<Y|St>o2b(}p{4A`9{^**Ufrc@XYx-wQ5&mac%zG~PnmhF)*8RGrk$fkZB{>p zkSXE%qaqU*O)3-tx(Nunqv@nDLvmO(c6sv!%o;>_#VFI$`_asD{`tvCy<NHfY1P>( zH$B^;pt(7HwCy(S{SDVC=YOXAMQ30Y1WLMmo>j!&<dHmwwGKpH(F9IfPgkEHpLyj} zm}mSmVF4gC&e2|U#mIih5%sQJ36fm+JUOtedN9Geu@uv(@{Pi7g$jGE?yGM3#TWxY z9G=>j>ke?cgAx?|ImDAbUMD+U!Pv9%-@~o*mTx~>ThxcevmC{6zsPR_#C_ya)X%|e zm^sb4$`Q`$yGv`s8#*q8TzZ0`EV9v`{#qMwh6L8V<k-ugDc3mmpJKc6cS}}#$6zjQ ziq(8CrTAg^k^GFU0CKO#EsDccoGL3QD_i^Hx?Cx6Qqy{Tc(~S-W9#aVcK6jh?zWs_ zf3nqo*Y|xsUVSqX)}%Qx$~G@Q%#t?@GK6oYnn69*ChB_e!oO_SihhcHZu==_S0`!R z=DQz!<%+1?O<<6m(?uf>F>Hf#0DShHLF8yxE23NS{;)=DU?Z=M@T2w{94qt?WgRtv zg@uL8_#a)%)o2^IW}7wZCr7@>s4!iCu^Q>iRZ=c4#uXoz&(Z)^iNJudTP&_#pO{Ts zoVJfQV|v_aOx_aZ?%hYeSN>M>J=8+;2gDuD3N-EFH8lN$#HTh7Wu&cLQ?ZA{Q|0@3 z!<*K-U;9vmkJXT=rGe}Hi~PRK*5xx;L8T}l!KfEfvnPA#^B29Ws|{sX-Mkz11MqC9 z(y2A8p!@Tyw9N}r&{0{-bHT-H#_LAS4tplV64mw0+a^uVr}A$x#*#?=lG8`cq*mnJ zih$TOW$(KPHb0G|JbfRh{F?sOvI)0ZP#5~X_kCyzA0}9-()&~&D`=%UYVO{qk!KS8 zE6?J@0uq3Hy1xN0$T=}b*<e{!zRrI~FXUoaad*~Hx66s3XgtL6-dOJ&!6K>_PqX^| zZVU`18jL*wRB=@aECW6$4qF?HruD%!7=u&=(r>jgQcFwnce6-~M^2HgnJ7`42>Gb+ zUr|$HU@Q+L<3l`VCOP!e3XJKSoVz-!k(w|o@kHLO3jkDx<52@>B(Yl~?fMq&pbs)s z6|-hx2bwkySb}gQ<uL#RCPtEIoM}+3;=2pJ8z~Uqr|67K@;cr`M6(XSZzl?x<>f|( zO`CBv=9x-NL2t6Q=H@1$MWpv$efzYsIOsUDRm7$=L;vi@%8aFbF-ABWkeYmMVh?EL zl*)qVRLvhL(Ilztn0DyCU1kewQ<(Z_+auKRu@Pxn?R>O0$#cvk=IJUIFyks%F43SL zG&0B*-%*yQtU{UWv#R4$BYAVy#w|{2@*Q{2C89y|On$#bn9cuZJNok)BDr!pMMbA- zWiOE*ghI%F-QR0W?O8?23}~JI?Bqv1$Bhf6cW&#EYP}ITIICSs?ZvtxdGX)M2RUsZ zjEs~k9ebT>l;S#-2BZk#AStBMt3VZf^cbns<EPuMA+DS(NqNecBVTNi1=Ueo|GdYf zlPdIi`$J(X==de7G^}P-_w0EU`RnNPr5Do$75^lppT;q_9O+uSvyFGgw>>&anj0U? zGQMwohfpcSF~wVdRzD%YXX=+(MM-Z^{E&9^TR%y}ejm=pq$@E}4@&43@*JFtV$}7Q zW(X9deh0T%sSoSu@EA0c?}ioZPq{lw)Z5=Qtsjt=Q2A|X3&}tv05ut|Z)&oPIy>Y) z7SB2mu}QSem@UhfrH&NR!x=uY>jHFULOmDwfN_AYdq56=2umN6*wicf>4UwNAP{Wv zxS1RkY7^nH>zazw{f+301jyB4q22MW?2gWO)^K;$sB+DSNt<V(lW$)@UQekots+MM z7*5ZiSJQV0B2&m7-0gH(&4DL#En-#%3hdUI+;pm;(o9k^OXF9TK`fuYI7Az1ZfRZ) zRqzF*3u@`XV-X3MdEW=Q1tm!}GZmv4YvLFm`-;qJp|pSrBdrbI`L+a_*dwQ)a5IcX zCd;qs+b(D*$Tm_lV+l7Zem!^D!U5sPuz9c)5>KQF7D?)f>>M?L>k)A-Z*T-rDXWGk zia1b;2$7^0I*)68AS42%3*@27zl6E$ZC+h@$?3@+1&0Qv!gZ1jKnSs7y~%}i8b{lk zFTO6bxL?N+Mz$<gcDBpD$?A8oWfaQF2N!|+h;`M>9yWXlIwT?2n|Ct!Mo`Ru3aU<f z(8PDWxf>~l-Mz2J5t#Vf{2G-OS%iQ$Dy_H*#@{siNr&8=y6{d*fHu~bEV`lM-2fvw z35mQwu~VNTa>KhTvB}De#BDML?AqN)+7^ABr_vFWPB*?#h&J^`4mt5(S-h2>K^N6p zCQHmkO;>2m%sr45i^A0$r<8F-1UB5FUUcYd91@9%?NqvxTO;$+r;e&A=yJN%xu!l~ zSl}I^OQ>1J_G|t$ysgQ&b-%aPH_`Go{elhRZO7f*rkdsRTcI)@UepV2k<bjmM`Z%p zZDKO0D#rfh%iac?XxFiJZKfy#Of>lq-*t*WAr?}`@EvVWa`aXy6B8s4u6;lsJy_Z{ zDN7J3nq<sRS@7cQ)-J|Jz36XAWFJ%za5YvhbbQ#n@f#_>HS6}jxYoadk0DFu@P^5v zW&V~K7Ljny&dQSKZB5L=U@0Tj^@gjf6s6Y8ScWBkjuf<xd-6r+E-g$ok0y<=B}o;x z`ih1c_Fs$#;=hcC$p2tG=$n8qKU9`w$p*yLOsM@!+W1odqIUaiQ{?6IWiiTT2m(%F z0MLbkizUDnVG2$WFQm2d@B}<SIqx@)`|Tbshm2c?Zsmd(ZDej<RB>;u1j;-{O>+Lg zy$1cHmJ4atxBK$<t%aR1*xBmT^{w0l|KGw~Ul>iGn)tr&+iJ|;#XBYt2$4weKTER% zVc*6fG&Ns|w!X~d|KIQO?1jn9$suE4xVW!QO#(&!C)UC9ubBPM|BQ8LGLiU;bs!_# zZTo*<9SFf$D7yaq|G_#GBUkElFaW=aDE)h^1M^?31M|PfI*9$nIu!qVtb_4ig}L#+ z$2vs+#X5-nd#uCgUxoSTzsEYDhXraW{co&;yywWj!#ZS07M9mc%E;!WaESl&{IOp@ zM^4`w`+s!ivi(m|?;?nQDiyZZN!Rv&ESo+fI9;t@?*-LL`2Sc}sDC|QDelIcn*K-m z{6Af(aT>I8>hEm#-@b?h;<u-#G{y9<sUH+MaM+tARD5`y!c`C-Fh~(uS=1+7-17}M zGX_2J6QTkl+TJ|Yk7rR8v&mO)wvw<_)L1G1=Sg&bZE4ccBmR3mqmu<SoBfuoDx*bj ztWgBJa62&^Xg!vclN%mfsxj2-MhAT(0!!X7UI~6?qAEJST~rmKq#aXsRQ^9;ikct) zl(Ye`vEBUN5Ex^~FdMrGXJ@viW@bgHVUR-?n_|-1xae6pOswodRZ*}2Ru*zO9TgRo zC>hK!1r1Xn%iZSx^O5?3f9v}Ff_mk@Y0^=J3XPv{yvu(2?ozrlY6=BwtLPH9Ko5Nz z(%%|Q7C&EF>zFU{f(NG4!;jOXT?2C?oV~A}LScUzLll>kI6Yk%na+hyo?c8%PtX4| zBvtFQ@7)?`RuW*}Xdz6coj;}Jb7B84&1MNpx7tTw&rr`qK@XB4uY9+i6Ov-01&=h! zesT~2wGF|ZuPuFicvgrb0BY5?r-%X!H-SybM4$hR>+L17MyFkI*UL=;3|e*HdpM0L zis+aaQA0!Ga0EQ{DQXvI+3jgE#SVMDE7!9ekFBn;e-%|DSjbx$6+Lkn1p1Tq9SJM= zpKB`-Lf+mi=y10gbA8_vQ&SPU)^S^n^9azM#vyP!yNhS{7!##)!q4?;0fl*Q8_uTY zX2w|wNLl4+M!%ymTB|a_C#e)fdb8Q*{e~=(g*;x@xj(r+QIo#(&Pp`~`+ErAGeqA^ z)*bu#n$Z+fV?8?PXX)G!Vg9gO?1K%~4$@q_m762}Kq8`=c|jm6%r5sErqN@m&IuX; z3ObQLVG`o#vL^-c9y%CLUnu5wJ_Ci)SgsED*MN<$H13cQyHfecvrfBj^b-LFzx4QK zcMG<{zVXFIjx5dfRDW`gI-%!d(^>GvLxk@nKudX{$;yo&(3m(@7Twqc<Ha!kc7*1A z)Ef;K?YJUdN(}ZSl_!ED6JNQO&~2t19Qveu7c)aDdotoe!zrNBXW1wq-XRh?9>=XD z`m^*Lu`?9%(}P$cxQmf|^pERRo9~6w1&psg0A?K?J7O#j@ATcnffLfg1n{Ax1{iwZ z`MBUH{VY+1!_x}-wU)&65?;17{zqSKzI41km+8cYP+$M*=0+$5B?dXI-aFzF^7ZI? z?&|o^L$qHg8V{Qc$c`ItbJF<&_7wYf0ZJ0`KD*2W^}+J-Y0I3;?24ZwJ2Dsei+e+O zbJ%M{x|8Erxcf_;tH4XI!~h&(<y8ViYN4Eq7Uq9!8&DRK5}(bPo0^k^w3>$<f8Aj@ z=1QrzVzUVow}XOp2xH9{vLFo$?MWulIX)5mL?gn92a=1v9}kuJ*;pXCuDZ542DyaM zRBqj@l|EoMKE`t__iopLJe0hNj`_E6oE1)yvf)0OL{)5i-#PWj5cVhvj9a(72tG4h zJQ<&O^PIgDiS|_>w&GPR)P(|$_tB$N%>HYxW4AGwz{?P6ulg83QV@%fg4#-#R^?dP zy1w_`Cd%~G55nD-yHWuXte?<^bm+|7MALp~Fj26fU9{1o_|Smm$m@+fa9>o?Epb8y z^%-g2v*Fo0WRb9)q4;;^Mh`UIOODqeGqB?hw~vu_*tUNn<N5wkR%Z-~6jjm`*>ClI zKn^0(ws{AT)t9WP&j*3i+2j=W>QK}bTm&^eJ%)S^M5@63R1-toAEvrO;!e1<U>{yP z$Og_v?bsQ^aOnhNhZ$X`9#|UI%_^bs%sK%0@ARHv0(7!VRMO~tdztaid(4cKSuuq7 zLv)V17*JSfSr<hy{ku`a=Z8;9B3jDhqcr)czy(vL>IAY#U#&Le?oM^^hSzOxOwEph zSs1|eGR9F%aMr7TU8QUh;M-LVtRp($z|E{kGl6M^^#Pmgn2uu-WfH=+O6Rc!%Sq%f zFAZGjlSF!djY6I)+z|qibVM17^Tp~PX{q62KzC#I+Cx?#NvNgMs)5<vSChxB-bQvy zw(4C(OgFr!K9iF_pB%2jOPDE*oWH0lE~HkNO}AA$fhX<saBnO=<o+4e#EiN<YPw7N zu7B5{Fxc;oo)16p9e$kudXjH!@sEcGb7At@b6phdA*}CO`>uorZ_SjJ?a*;uT_%<{ z<hdo9+2@P|;;fG>t(?qczjBeaJ&V@!+f))Ob=?cUValg_WdhUf@`8s}uTSJa<Hd4E z(7(7SReJ3r#Mz2MD|3OgI(|nX3>vms7LtFkR?zE?t*_HQ4x<Ob_VW5ckz9<cWNP-P z&L<1u{Guz}oQfHrt=KA#eaA4!r4G5j-Ao4{Y;a=|z2=V=df8kjMc~z1(Qw`E;d&;V zhHP0pn|OJsadF=lsVq?>X*9rM)dX+dVljHke={56zRPMS*suslnC->=QtImDd&o7V z>q}Ty6<`wN`y#_VaW#)8MvOD={!EfP_EtuaV`7-$VYTW)Sx>MTvY^B!-(DXt5W+L~ z5NAA;_D}a068)#^vy*=;Y<(lII5}xg7aupO2XYoQYj-B~I3hJ2`$AQ-I}L!OrkR)K zAzr_lxVD<?O6jn}%klQcc@c389pI1>Kt4$DsZgon%JrxYJ*uqloNl0l`PC)9Gr@Lz zv#vOp$(fPSD&Ej3lYBZ2GJFXzO+^;UE|y^srdKXuA|wBLUuXI~MFwcQbA#zF=LNmB ztYn3Z{R{GWw4=cQHYQ?eu)OI4$S1bQ2oLQ*Zk?huCXg7qF&xf5(w)UVpX{p+C1L&E z28~1ggR(&;T6Rd~Mb|#(IDR&qb6AAtaK5BTd#stJJ#(RhCtlVrnnGnun2HsLqrj_D z?mIPUIz*fFROTGM3}xFu#th{Zl5b&L141Nv_oJ5^YRc|{q@qpq<zZ{!CGa4%ABQ2| z&z9I<UfNd`6_zh(3WQOQi0Fv?nTKbxJw9C+t7=IldJ%Ru1k?6V=c54Vj$8aWu4;f9 zZjZYrQ5FTNlwkO)9FOd2CE}O*dQWb3Rxb7)on(S(ba{})bNvAb@i_gZ-l}rAYH^Yf z39tmg!~v63oc1KYfMDa6Gbc+oKnl^krD6*Bv5VhgR42p?UQm4S<OkM+7!=29THOG~ z3OhM5aCEC2IQRI!hd@OrecX*-v^4sLsA&qq+W2$X`HnQaKJii0rkQ@q&6q<vS@e%j z4clMoac8jrPTG!_f)xG^Cp6e!*Mr?HTpfi(ZDfmmias|V1I&#{dPNV?Eylt@@Vx!= z?EyN$B9>lmgP_oK`8=m%0L9%+rLas>-Hu`ny8zK)WDl>sjRrID_XQcbWkvfmVaL-- zE(T<my@bD=k2bj#^g=X5Q*$9%+hEY5et_RoJx7?ujs$bLAKHY0FP8j~KUQneQ(-AG z6LV5gsxG3;3uC<0SY|^?)D_!AAwmJKt8%FRmf_@et_3t3ShuGw)&1=jq72ej>ER>E z+t@qOWa{dZ)0|Hx&iA31sDx{v^Bzo}?OD8DayU)mRtuGc*GSkqV*jz<((FM-mpWXM zq4dIIp@mQQmeqMrN)KH3p@qBe*9A<p`ABqz)WwKIh&EdP!9#-VxzJe1dpz6u($fr> z+^w$_7CyVp-Lu7WeJjpfz$lUie5Z`|A|$Jk(}$mGD~MH-#y?}LKNiICS6?aWFhTVh z;olv+hy1F5`Xe%#9?kBKA|3_Axm3b+d?cSA$>>R+KfNH72_=KIb#&lM`JUjb8&q+N zB^7n5QKKwVF37|epaX7?9OJSE@c!x~J_pH=osLLBv)=|A5mp=z59ECLZb`jo-oI{e ztk1zA*3kfms(<24D;>HWBjuCE@(^!cYGm;7Z*_#T&_jB(4K2$`!hcLHc4W9Gm37(k zpSRGsS#R6fyjz{E<Nc--?2Nf=*Bu)}Ry!oCAXmG}@(^uHXK?%gs$?$HHSn*5zV;I! zC8=*A7W_1cKI~d@R6^uf-Zx5<iL8mD^}mf_>}Uvwn!#8clq-GFN}Ewa|74}ZVPTbV z#jtLxlnka(;p=>+lK^I+MBLlV7QL@%%%@$5^+WbA@N-Ax;8cU<kg~1}(0g!C(-v3h z#9v7!(y2>*oTX_!|2&~6)Asx?VEC8QuVB-j_crP+8@eBqCI=X8;!*IamCJy5}- z+4!<8)hwB?aVk*=-hAmGdNs-vI{z6%0?p*34wEfgU$@*EH&E&nGw-xPm`e<HtYL4# zR6lNi|7Ay@-1C0y@mTI^c$4^v-cBy~-AmgAJUDI6)X&|DlP5km#KX^`q%FjgDB0=w zaRZ3H1;P7pG5Tjh{)*rc?4b(Ucz&>j$?^rxHM;{=*e5_}Arj+g$vR1!yjtj~tRz$5 z97|S{9hPC41DnSI)i#v_n=^nXoA=0OSM@$S>h=_Rc&Ums6<3BtimfVnBLiZQyMQPw z4jxx&!uS_rX`fGI+k(G{TtSi}z_NzIV6d`j?P{m{`O2B0f+%<PUwi#7m>&f|2{ZwO zc}eTfKpn7x;k8E#S?%M9!oaM~4rgjqDF>;3iBwvYkP4(GlYIkEAH(<Dv@huPOVOuS z<?U`Qm!6?#EXK>>vXt0%YZD`rotq|(>!Z-TA;DMYK1omBON^aKh1Nt1l9P?ofmOe( z9}((AfHB<pk2?!J2y$aif`i+3G+<b#eR^niy}k3szZ5&U)KfwmRWxcxO3k*crio<@ zdT|RFwWL9<2bH^Lu^eRLh5J;)ifa>6{o!m?Jfk*WmdiZ~muQ87KMOI`<xgT9W-2Mo z6d13^2=^87xtzd-dHV+#7c@vYdcUoQ`-ZnKI^5r7#eCeW(cb5e>JR)rUQqIXaBg*{ zi2yI)@A{S{k+FkVmk3)d6%(ZvFbb?UL1D<EQQq!YC1Cb~yb_&5LG`R3TPQ=jQVKFh zLyv@&9}g_bSLR<xkz@|uJj}n~u7PF$Qr&(Lank%F6eshiWHf(NU?w>brNKv{pMs?M zz)xx{>A1#Fc`IsjH~9DW7X=%p+emhGI!}Wog#}aj{`3cg`CNa&%Vmg?K9HnekI$T| zjp@zXs|?S?)lSZj!d8OK;z!CLkVlL319Gpcck;I6R?Xr#EL*=}!tXLuG16pI7c37G zS9HGE(i^@vCJu;DoCmqCD7jOly{t?o{LFtb1J)s&#V1GeSSl=1h3+wzn8$}vk&5$o zRQjnr8(b)+j&0-GAHsBIY9!H;6;S)EO;gf&L`0}pXs#ZZ#-9serk<~9d=JLvoIjM0 zGIVa)$#A!3xMTD`CK_uEaNL|>$;skJcjofg&IHgy6x)zl9m<NEs70a#@*lkQe*<-% zIFzHr-gSvrzPB8ODdu4VtT6<_VhVx_<H)acu|q1P-(M(FqM(TnuiKkTO{4;8l&R1l z;V%u5?sdi={ovQa)kuVskY~(OrkQq-fXh{1EVRRK=7VLP?1v#IN`EBSFWtb*UP2p? z2%oyW$qsE;ZRDvX9XF)qJ+0F?DK}HSaWaJOV~Ut55yQ)#Na2nNu<z`W4uduV_F+<} zD`+qlWhV01N0Xsf9cv9Z6h1)To(n@!iJhv?6lC$((M69xE1g;#v#bH2-t=k#Oa`FW z-WT2DEQFZf;=7vyirM(d5Y4moc|#4Wmt>CbSe9pJfgt^Y9l$;UO%Y|UCW{3(DyfyC zpfgJM?ESdLrH!oRcjC#Lv5yI&LQI6GO`^tF5E;BJADWyO<?hp+s3rF!6+qL9*y=@o zb0^}2@`I}i^MG;y>Qtd#LL&iGI{hb<l7P<=wwRqyayShAYb+N*&NMkn(ke)Wh9^E< zu6quOrYjGbjYwI2AoZd(SJBy2WbjaB<lz$$Ehn*19e7GMJ{eE(?d@+$r7lD$rS7BE ztJRQ2t@lvG+02Y!guF|@*ca>J5$kXVMBB25@4~!V`LwWP6(XmNoNWs6PsJtX+8C+P z2<`Y!=^#^!&bH$)1v5%0%A)TRZ=i?9lFr->SivOsMol*oHYm;%D2L{5JQROZ4B4E3 zn6?z&q=!aUo)_C;bPHBG0sl!!t>>E>`GMqC)9LA{(zp>e4x3SP6Kbnt0DIG*rnPqV zZ*h7xaX1-2U7YuY(3Qn&t<Y+R?S6l*I(?@=o!2NJYZW561p(Q#66lF0=%oOz2`oLi zb$D&(XrKMgUbCdH2Mc#CYp7SuX3<4GhoIPhJi;bnup)=*?D$oGyQRVt-0L$gbE%HH z4%2zGFzt0--5tZiA!R_)2^v0FxoMl&s*M*oIFqHG59u4lTcds~$6|Ambc+|0a-G%4 zSd%Z0;um?Q-nbyUeE?Cq|6`(4;Sdw*mDEh~GUFQ=kYgO*1KxMvLpZvM9B*avPfKNi zQU$VE=?sP(2T_H;MvOK$93F^Nv&Zm0>dVyq^Or}&`l3EPBF`kd(>g4x0i~mlWDa%# zPcj(Q9}(_%XGyGW-|IG?H)3mVE5{z#L9Rj+EyY2ReRp{N{Io9*klfa2mG8_a{~@YI z2=d*W`Yac65UIa`!<a8bJnl=53LF)Xn=cHOmYi>mOk07obNfRjlb!h=n(C~mAIaD0 zMJ{!$9U>hw9F1^Z!3INrkfn#jIrCO~P6#pPXzm>}xj+N-8N?bX;>wobq*cRQDhkN5 zBC7orrZLM<ZB`@?7{4`=a>en=sDC}wcej*D4Qx9Y?dFt3MbL|D2@H1UP;(()he80X z?bdV^+H<GSEpu5OnoNrghcZ3p#qI<q<g&DJm+=UTgDG{j%h?>sek8&RGj@&ap}*8n z87GH!FR;jM<K5ufAc+}IL$jAQHb<*n*R5?m0X`WXo@FwQ65<u}GJj3CH2Q8CfXYr- zmRzeT8&5P~7Bl$7%hhn`F4a`F5@z+kf+vvFFyT=7pEoSeDH5|8(g<AiW7joI1@Y5s z;IHkF={8w~e-QjOS)U<OJq%BV(v$_FWOCjAzW-63G^hOgOt4?9W7AbW<Rgh^2tp0! zJxR6>G4A@PN3j$M{9&Hu7n0?3<Fb~jL;x>q-3F)8T2k_?Q!8(qBU}-;iRD!)nzGxE z!L+Cf$rKC6_;y=wQh%zRcA}#&Iq_{*!AuW5QhGmheJiC1ax^%0>&@|`!iva#zu0<8 zlgR@ECTl|~E2gRph=P9wB~g)swP*EJBpaV8I1s%xMuo4b+?DV+yVK(#h03_)IQQ>R z;GoiFgFzpe!od{|;O*9HRMh$T=Q<$R&1Le6^F=wX{&xO1h_>_hJCHlA5wvPEi)cHy z$5`Q*qekB1p5x_yaNUc#rR&@Cl^PYY?}LZ0U<jLLU9BTKAO3kZ=kU!$%3XBt)VKr> z7GAtwr$50*4CYX7`bb`nJA$5e`(pUg9l}|g#+L}pji4|Q7m@hKin^hRq7tUUH4o*; z3zh!yMFBaAb4Mc%A*o>9W)I5eC>K0CkHT#Wg^|{#rE_B7KnNx3a)ek(!M<I#J5+h{ z^06wl+jK!Vq-?6D;-}=#f)nQ`fzSzm)GNdp8!7{8D&8lygc>Q(b_0I?uDIy+y!wc| zefT)9x?~EG+r)^7w&$Q3ddhUSXceDUqGJ2*Ktt)L6!S`>#Rp6+Ha8x9=(Mey9Q=mC z?-VWrPXgFX-sPf)4=7Zk+>!PHO|E3E<Td6YK4b1hCpI>&#fmGw8@>m^uG){~UrIe@ z7OH-Z`2Aw=qh%?;Mk=t7S2l^e%l@5?nj}-M#M~+jT=%0O^Q947eHBy6^?|;+iYv`p z0DGHo%?1CJ{QggcmlocNrq30dlb^o_TO^Pc8+09U#M1vBt9Uwrcm2?2%>Od}ofHgk zlbWSf7_Y6E<3Q7Ok(|rXo1FX7O-jF#s&V2sMU~U0&u_gGGbYlB9jC<lIbz>@%u^Lq z-`Iq|X-EDcL6-Wa5Gojy6W<>vgK;;TI{b%zI41x$CUZPQ<rjnq<V)jGXDk($WH?|U zpE7Zontms7oplN(elVOt{={V|!9GL&RO#sHpi;Sl(tBw_=p{GiiWjQ^V_7=8wUoNX zDQaTmmuy;&NZqlGSyhe?hA+?0XiBbnd^uw41E64gQ|UCwe#<MC`wkn8Zws(s-{$Np zf>-SuH+75cbU~e;(kf-vUCfq!?=~J}Z;DZ)iWzVBGs?^<y^<bwnAOpCL9aHNeYlvp zO>w*r-B@&pnT4z3XEE^v(h#$~9=LIhrU{YVhxsq^@b&>;MPt}smi;lg7m4`ycpVgN zNoJD7I~EUG0lFmgKr{&n$)WY8jjb??&pc&40^J;9UK(BP>{3SWX<=qZ5Zii=Aki?U z$3W2py$j!&GvcVy)MyRUB~xsx5={xW)fM?koGU6tU3$6q%H3}NudFb7gtA}$dv47{ z$9uK7$mOH@<9;k<iUtyrbP)6+Yi2<nXm&R&@OZ5b^WdGIyulYS??BS;bwBX0;78|z z2&mU%V02q2ZovMT!W(eFj4E_81F9DHb>8me4)IwbThY4++MFJDrT&!I2b3a=!RdWQ zToJ9H!CSSIK!RD!&2WDTTgOk!zJDvewOX^&>#elwXO!DJuv@F!2KAvA5B&)eU~h}s zMC_8d^%Th*ttUqXHU<b*tF{iW((9ButVieZUdzYfn)WY4tX!<8wOZ)aXr%Zv&YPPG zgb1dx*^BA%MmiM7vo3N<!U#%`;7ZP>Vys3PAp3$DP*H4iWa+<nzF2nl6o_M4w26Sh z@*(sL@%yke85Jy3JMz+?ea^Pg&=IKSMMC-<_c|q3K~$H5*LaOB>ABd+o`YFoQzg%7 z?$QzH{#qO?&?NGNpM0%kLuL2J0zXhPD8|v|f`w(Z62o>fJ8cuSSasI!a)n56A2FOV zS5V`|&n?A%PEXS3FJZ_-*F^oDIM!3G_t!Dsw}0q_K@godkt3Vb=O+rpFI|I#$3~w| zEAr9M-F8(AS}Ej{O2SjT@x*8q^2)T{1;ov|&9N3<3#SJqxZJf?iI5O57&$kwj`%o9 z{8!EkLC^Su4QLgEHT(el_4t-?#*%AfT)a#`PeY{WX#1xqmV}EgS0_=$1N6{L50)#% zm*1iAK;d8z$j)c5#$4=&0e4{GyN{CpQ^fbq+%cO00og!UY^p+K9JY&D0mh)f;8r!F z5i?;aP(4yUpO~?3@XU>eTKI&N>$?$;o(8}H9F;nEOp6P&^Ep2;wXt)@iSi1bKUgZ= zg<l6$Hd8F{y$~Cf$_ok2QIL97i|VjjB&aO?t_=!+v>+uEO}fU{2q8)_R310To5%QE zGc6~<9LCfi))V#1U$lIa6j@!TL^jmNI5l4!@56CxvWrC<<6cm%yHVGyr>gXe|8eqN zK>9bOPCX95$+_CQP|5J^2ZUX3tlwctqU?Tv=Plx!C2NB=hFUO@(%T6=4e}P7E!U$Y zDAa0npRSX=DFq@Qb0)ap+wHR6=yYd=q<r-7wI2=dP?2>{zgjLt4c&SqnGvnuw*6?5 zW1cO*I@DSN@jYlCdbsLsHVGdq%r3Pr%A|@9T#Xynq5(?W(8`oU;CP?T>PIx9Da-0* zYEo6GwL7L{Z0umWi3kNH9uhVG4tmqhQ3pf*MGOw6zalKG>6#}1WaE{OM$Pm|JqQsx z4N~dE#EFu;{(PW#dYPhZOKLBrpdqWH!~1TA5~<<9fQ;rAcTx?2p*;nuvnVjRpt)UG ze!HVPAs2s`YNDr|%noeo^;uvUcDS}&v3NQF8d%Fae=ndLw+7XU(?!Kns(eKYR-Rj# z6qfGU1!_Mzr6#l{X?gS5wKnas0=(@cWj<O@*iT$t{Y|A>TUmr{a^%LTW{alUi%i{j zYVungqin4x<|)ktdi&BikWjMeX(|S;DPjykM>4I-NZuoE@UQBb3Nn<VpK5oX5fmj+ zYV2q4Zqo7T^*oRtf6wWr$sK7u<H;+<9zKV26Sl-+yZzKw<7>eiz|5|8e|0IprpOPa z4a<xH09JVSk6E&VXB$yy#;fl35;+`xOMQ5l;iV<JXI+&x*NRK_SVNSC7o|5gYqZPO zka#TotXZH32vk)u15kuOAE(tYsTxfi?>C9DL1v&dxb}Sb7VkBIxpEei56|ID_^b>} z(1^vXqaY6yY``ZytkG#t=XOBBYvFC?|03j`<11Uzet~z;Np@`8PC9lvw(WFm+fH|E z+qP}nwr%5{J~MM??mPEA=l}ZDUiGZ1rTwj6wT-=_Q0>e8lxL6e5tCDzLGA;4vY@ET z3u^``2@!=**~^Hn;qfy<L8zjqzeBM#z10eUDS0}8)H6_O;d)7E^rpW+(<;L%hSW^j zf?+=zU4Rr((NAgpbf+oHSmxj8n4fHyzl;BjRB8*gr_3)NiZmuU5aad%Uzslie{S#> z><6qwy=UxNbMYk2*>r^RW1m@w!90A2PUFDwS3JG9f=ze{Ln)b%{6`n2HkFMY@Y{mk z_?d}KrS3tU#+>k}f>`!q9+OL9qxb+SGYqBbVblxbBPmj%25dmS7uJ2K=v9OM2J4)R zEdit43B&P2Vv*GH*=gZMUp&);rzb+0m3!Zx@>sEOjJJ{#sCML@{%1h$!%W&QZZ|h? zRnhQyc>}vXYzo$h9_vlMwXu>Q*bHV}qaRS5KS-xb7$`NMZXx$&*Q=pvW22nj3%;z$ zkRiYi6Xl7;P=6ge)5tX(r@Yf%*=euH2;hXhreKdH_WS%zkFEcM9*2btN7SxJra<)m zrpG%Zzv=O{(O|J}pQT3PS{E)NEhKA7M4<Up4JNAd)KXknFGEf7i}y+Lp6h9VtTNap z#`rw28fO>=YNP@db4qD}DwmM6(=u#t>!7ZvE^v!BAbQ66w>!ou&(l}cn3*^;eR4a+ znP-2uT&$rSFDQPWSLp{cHaJ3Is3|wgjg~jl|5B}jcoip!UpLF>n*}R762cKUS#3Y; z>8KT3{XW3x(wU3+)E6YEJ47G_ehYY^^YAl+q59!(RP5bxO(VBK4YCO~piA?PHZf4l zWn}(59SCWy?^tS#j^uy_?my&a8D9f2^|JaSM1}#mRR7zL=8(><)m(d}@~+hmQ>8n0 zM{vf3VDaNn62jVnwsPDtAf=H}n=4r^*bF79>QPaN$5y`j`5(nP!aWPHrAl6e=hOb0 z(*mQ#Oe-F;xTg)IIh%_mck5|mKTz|#jsjV$Y^9O7IA0~pk)nKuPZb}<gbU!8+KoV| zkNRW&P8w(bmozp#E}LsvDke4VgFW!QrOV}9F0w>$0K<G=Nj-h-)ejO+U9}&3e5w;8 zp+IQNKBZ^<!3J<!EkY#u4`?i|wl77*GuMw4cD?{atKh7k7}1c(0s5}!6XqnW%+Aj7 ze9>2L`%YhzN(nbBoO^vcgMH3w*n=YWMDHqrRlXo4t<Ek|vJ-XHQbmexmve*g`|*VY zNWJ78#PcqY@i}~DVN-GN&iN){_DH7`IVEB}@Y^<b{duJQE9ze9^r=Kw#B)c}w*uIS zIr&s+*}^DP_pjhcik1i4l_I-UFD+vA!))!Hoh{`v5S~gI1_ZGMKkn5fhjT5wEI9$W zz)oJF+90G^e{@)Ll0My8%}!f#SUb9aB`HygG-a%bS0<bIV@l7vBvpMYuVa9hB=}EK z{1DhzNpFvDF_SW5>*UnnKs^zdP~KE9H1xf6yZ0KOG~uj1)L7!zQLl&{rNpGnMF(H( z2UN9cdEm*J5{ORN%a_pkZ)Q;suI6H+nn16p@l_U@I%jbi#~F8fC%m13ZV&&W#Ityv zH^xkjNPgl}9!-mQ)dH_MrHLb;{z(?;cvoW5%jb5mj*(?rQrq5psH82-v9yavEy(T` zPSNR~bW=*}p9rQ>p9JvjYo%tnCkZ-HIon|i^H-RXekZXm#$MJ-=9Q@JVT8XhwK@kw z@&eI$-}TGp^2Aa)N{6H?<3uVxW)esjtIZDO<4)(1q;FK+E}eIhJ&o%sm5{Pe7j+#I zzJfUv#ai=<#=?Adz=DqOS&3hU6sHO11UkdCzzKx&_S)_bI0oRt^~{GleshqOFgPAk zkB_7yOp?TJazy`G5JB2xW5TLu0!{ZXOf2;*i%?q=6=xV|bjc#HJi<YzOd!AYXR3C_ zzc4Y6CG2wz;5Q~#Wc;Djy+k{Z*N!OyEcXveye4h(L>g<U+#F9+1`VN~e}#d(+2(Lj zbaIP)!juwyKHmm{K!gzT$Y4588bhO*q}DUQVf`*>1i9kMlWZ}vqDXE{Z!JU#upAx? z3Fr;dtU=DSaKbQ1^V=gUM$QaaP8sj2`xW(Y7HiD3X(Emlh%tec^&|#4RNkKee)c<R z_4p*b?w_DoOm@gLwUYlXai-_}dZTceO~A=c%yYnmD_f~lHi~AjhgjU2j{_hX9zUr% zp2sDsv%VtQ9@f8m`X?sv7XLnP6{Drr{t(Ra?Q9*AllKLowPo?GPz@P<(`K~--*U@k z<!y`)M+fM0gQmKC&<Gp-PFgzUPD_;VHOEfAnMQCn6DcxMn;qDYi%YIS5+mT{GDxb~ zPPN98Q?pcsY?~&TugN_Uw4tErdO@R#*!SW(G_mTv3y3%dwZh20`p{SadQQxOFhQE- z;P`py)(8DDHbX2ViY&wm_A8J3z%1IZsH^PZYL4tXREl`ESE%tP5(HZ-$08-B(xyP( zbIv;)0vYdPj^Uhy#1#TsQH1NOtk5alasDJ3Nl4d9z4`X}xt2|GtX0qCB{4Urfl4!L zGF25L3)`ZUxbJ9iWOq$A+Hz8TUu{)p^)B>P_9OTc)e(4_WNC2sI#%!AHM<2n`Y$Iu z?|{ZYW%r-Fe*6-<M3)t^8{A>%B6!`k?$*PCJ@vh<wj3kST0w9=xjUpRmQW%(;**3A z&@3O=K`l67x%rIYtqK>rb0}ZcU0aS&Ap$EZwf_-g&Fb6Ycp9V3)fyww)rJiK+){aA zEGaTk_aRsB<&%3w?0@M6V4%!}Y~|;}j6sXMp;e?Pyi=lAW|I4^tq9LBF)3rR159s` z;?(6}R0IwGl?C9@tEU;QXNnkyg=CN_!SAqZJAZ9z3du<-3-9X(Mu1Akr0NaPml(s; zSbp=%m=9}Z4`&O5s#tZ#WNh-ukpgaa<E-~jFJ}r0-Iyv?b;b*a_3@RjyeO%=ftwq( z*6lGboMcsRY%m_7rVlRBG_cpLTBE%pS6D@7s_b-lkmOg_EqqMHQ4?Jd>~w~s<-E8% zH7tj#o8EN5wc8?e=9FMSeKl@{EwBHi!38v=$3s{lT};f4i!YCVzPa%oqgsH_;Ac-t zL<C1Zh5Dud8BlI8ow{&)04Sbqw=Ry3cJlp57a2)JSNSdhaZ$Zry(t6##2Vi_oL&7h zn7IM}?h=`Sz7v#m@q6iSGpzN$nPFI|y`uj%!~D6wm|g-I8y^J=olO;Ph*k-p2_aM# zhGQ4DVm9I&27d3IBew!BQ`1-zWas_|%9Hf5XkCw>^H=W)!v1F#tIIt^RM*2!K7GJu zM6g!5o5|WzxP^9yTmK&7H(&42@9KMoi171*`WLNl8bj=vdW5p7QnSX}-AlG-8FA+I z2_RF=7f|Q|_?8#Q3{tw3bTCjj!=^??9Oqs9M#@8RAvVVpbvdy4x?1XFQF}xmMa(<5 za(lniqbWkD5qA=VO+hyEdlpnuY4GTQNOhyWm@i=V^`QO9BP+iFnY+);NEUPs%<q-_ z$xFqlfmRfU*9G3_s+qU^7=86fbdT2{!b6#bq{9Gh>YyVn4TFO$ktV$8=86sO-SLTe z<Cf$>$;p8k3#CHGZ(|30l?avjLZ+B;_hukhzrPRk3w2G^iQDFnAOG)gb5EeFr-Fg< zaCcJsH(XW&?IZO$`y0k8xyAb%#(qA5**yIJTXmfZb*-&o+uGVzs^o{w3C}6aCI0^C z+%MoWj*ko{@*g?8|D$h2-v}H|LV9|53=E7)ZUllNlzYQL(4_Cz@KF@QC^GVY7c~7F z&wgKTaqKpN58;p4{R^@BC)`c`9WjhSPB!>guK1712KgJ524W8W4Od2H{N0XGRyyLZ ztSk_zEHW^484V<JMDO4HuF>yyMp<dte-p1w4muWs_-pr#5!kth=tB({JM}LPpiK~% zSxZY>?<B46+waJ5;R6!w!{B$4p8dSPu)E&@Bwa@E;z!}TdViTje&vRs`{Vr7k++%U zuj8?0e~&GjH6nEUuZr-;RPwQ0=+J(QHUFQ*`VJtF9q3h{G!-@?rCe6*y29n&UhaYs zC%F=FVH+Ehlp7rW<uz{evEnF+dxJ1DGb`6>EW_oQ5b(zxPh3>0IqBa${Qy)|HB{xX z{db+S&;fBY3c}(vTG>8Yfsi(p3g93GQX*z%n6MSvUr%T9r;MH;qRvoTQOAPW0hXDC z1;7ky-xB;{|D6u5P4b)d#$SLX{?BRe%Nq3k2-n-d*qDfl3M!wP8s6!VR(@tCYiP_T zxfmcRB^i|wO<=l`l9D2>Swrs8LI}c-mH2PafA#Wbt(|3>h5xI(Uw~0Y6BnuW_pw;3 z-MfJi=Tdfn|BRY`c%e;TGOOI^2!|cl=xVS~V^b~;8$95OoAn<gliWffg2%xL?+u0{ z@+Z~Y5Hz;3iuhwm=9tZwSnJ(4Pe^XzA^fov-*b`K82*2Ai{6)HwXt`+AEh8q$o&^+ zeI^VhIlxGWUoVODBQ?sY+=l<vslJnUqgc+L$sC34b`UR#)v0W6(EA@3Y>Txfg!NWu zk^T@Ao%Wu0sQ(bd4|ID2YJXDT-|Ks}x^nV;FXjKPl&C+^upN7uX|ts-EjNZ3BuQC$ zITZ8=P*Rt<gb$0oIAM2E+6IWfwG`h+B@KFosx7?9)=3CYZ0C1MZV`91QYI5J??&uo zwPe+UU4a5q!=xI$ua=YrT{pwAvXw?s4w+ZU#8c}$&eFEX+w(F49-+EIn>6b=lu>bU zv|98pRwrPeixJHGIhSQ#zMu7oHo}##K-qGy1(0U_TJVnE3iTm6>4i}e^74S90#gaI zW1UkwWBhLqGT4BQKoKw%DTA$v=Ty~NPGmAG9+vNfAl}*?;V`Y0dMY+-8GC?h){2Zy zg6B)9=HNruH>j2?Y}ScQ`N2+&fF}$WblZOm;rb+$HpU%W=DUiCPjas5{iMiF!Ux)e zvX-CWho6)X{Mm0v)*AyAQE%wneJ?PH^v1m?ZwQ4a4ycqrVEaJB;6)=N`3=Sxi8{XO zNJBjazqYQ*PR$kp5;bjNDwQA%dkn)&?kH%<Q0!ZU;&zC75j5r;W-s+^D+^3!^wFT# zV~=WErz>prU0htdM|(jo&W(2DJyN3GW5aqSgmbG!%w6Q32Ev1O1@o$_gk!cw|G1eD zWOY@OyyqJ~sJCo8E6zHh%nkT%P;?$^9dTbpZGgbJc^jRvXU?*qZh8L$_TKYmcO@ra z1NXpM3LBv^h?*-W@xar@Mlc?y2-hl`%o#;pDYMyAc#z7AHc?^J#8-UW@_rt@3M_xd z9=2yW-!zJyf789hu_U?tYAv)oK$G_<?~%)eS>G#-Il0I7)$42uS;P8MDp3@~b+{1y z+?i+al>}!U>O;Cv6L${QGh}Pk_GAtDXB&>`)$3bKNbfMiKd(omT`BdId*c!WtBT%R z!G(HJ1pd|%B$TPAmrrioS8$SCmEXf}NS`RqV6E=syH{z9UHef!sge*=0FNsPKe^+5 zqzY;EUa_4O6HcXn08YM~0+6;r-f52V$?jwUnl!LowyU40;(wDiVz_5nkVLtra zDeU;}vE_Azhi)tG+gLJ`?ePTqL2!8eUS{O7+9vyzoL+V&UDabdGY_repN_aCA+vLB z22=*uXv@O|Gl+R!A_szOI_V(sr|3%WV|oztma_OKPYEKE0Lrb!*)LI%<)=dvSveWY zEC^S-IM(zo9dMrRU|T9%C%g5WY;sM3FU8$evAIdwt2y!aydnE5-N_CfA*&QNO_TV2 z?=Fx?=810AeX%)JMN-yh1^YDx;Rddk06@G^q*g$|Y=XW;Fj$p%NPk9UaF@FvciP4# zZ)C$(yN_wowlnx`BUny-EFgj!11M8FlW6PAj7<&QY*4$b2|ESQh7HU#OyA0D1lliu zGamL}N)5R@u+DiBn%_CsU*dTxH`$FjP4G%@GGj95%p3kOkuMv?D+|UDx?@eD4a+Hg z-$`h*e?Wt++RVQqd8WC<?9$vCD|~+F)_<MOCdZ)?m9T-gjlkAs1hZ#Q`7oD1dbCm! zuf3F${^oxf$<ph6)pmF*O{wqQk7hig``*@=pT_ST(LdN>{LN%T-D7VX%pB1>C_@wE z($@3pmD-#7vI3H<@S9>ui^a_e^S0i-oyt#gq>1dwy7MERS9gz#`7c?QXV>Yw^!C@T zbsJNG9kt#$k6m6%n05&FPn;#5W*cYz2H30n!8Vw;iB1*~zFHgkhLg!nPA+iLBGZEY zj*fR2bASeG7UBwSBo}=^mC-qs?I~kaT1n}uIwnqVv)*RFh%5M-yeppG>@&2Y`HoM0 zY>IwKF5m%t;K-zLfQXIhe@fjV=5um7f+8I55g7CKRKl!Elo~wJZRPBG4T)USMDZuD z5Ka%MpOsUkDzFx>FY#3_syG&yrxD`{g3mQJSHgPIU+$x;pHh56<_z=-r_v7ILQEm@ zNggJzzgN9<3d>S`9hvO(V{F5UHu85R(2fj4CNy8ux{ef%i>H{U<J}IzX@Rj7RDz6c ztW5FS3wyJp&tQFxg9hg3%p)^3XD;~kEcp0IUam|6!0|8^T@2g|lj__z(T9K;iB_m) zH6ar&+BJKlvv`K~RQZ7EuZSdX7l;8%nz~Esct$%*UPpO<vnuK$7Mglp6p8oB#a*&{ ztKid}ChPEbUk!xMffJB6Nd~jbD3&r_?8gqjbMLmNXQU@vXTr1zS4gCwIZ+A2u7>dH zn9XmJI(m}dV}1%hrA~iLZo#THt7nz_u<hX0o2~1J$#kEjU^AB;ja?at_OzjwS1DDs zmtr<(b=FJG(<<37pKr_cJvsZgJLShBJLW)*JkP7p;H2jEP}rfUb;Re5Q8L$2-F*}< zIZP6QSh)`8z|k+mlVAS~HXN~dV>@ccwhC;QN%ZR52tuNF&Vq`&2CD<ml<2?bOC+tn zaxcxwTbYBaK;L2bpS^Y>9<FU)>aVxe9__VaoS&)$2G(=K@UUjpo^i2YN3z_ZUon$j ziNnhdXb*&SnI*Aa3Q$H)G%|80Fd59BgPX?THKBtop=j=5YN_nZ#0!~hpM4*#ESGB? z{~}q(*gqUv@|cD1%|1dzd**C*C@PV@V)p2iXIQw%a~$VOs`+N*TDk(5K6p)^FukQ% zYLC)dvF;DU@twns=#@)%x>|@Xf3Zw`(8!4e$Lojzm6S9f7s5mS&3bRo8RTIM2)V|8 zhd);+d2Pb@Z!!yP;(=@mjvT5z$%UD23f^<gHa-PR+?IK6Fkh-q(%G^II}3pU3Ygx% z-ZN@vIdSg026bc>(2(Xt*F%piDNypAhv;0n29s71F@m5jG?>iXOMp&X`p(w2*OzJ| z=aFaI{pPwn?Z3IM+~yHkyR(F&)VvPxGdfl7iF*fv$b**{m1@IjKEaKcOcR~qp^zuU zkB_dEZos;ypG^j6z1;~_xapeA4c<%+*}Vdjp20EVr>g=Wk1GnazM%nC)b$EY(OTj^ z?d}0d<35EL1u?GC;P2O4(Jc6xB9-bTl2%ECVA`DbF?i@z8yIJ+jlMxfx}3u`-YLso znDeQg5<i-<k<@5uVeQ0^EsCBZkezog$KlyqPjm8Fc^effi}3&h^lnK{cT+UAl+y_W z(1el@EhMw-;9T)lf#|e&R-~4gw=LR^RXYqU0mXE<_3uh2b6u+o>SBR=`K<)y^d$6_ z6KW3mZogW*YPP63o`TH2j@Z4LnQUqDrRV)p<SCtD583$IKY0yD;)F(VPQ`JrLPj+z zyb}w`<#DB&T4{w771`<6p?(baG4MizmUrW<WrILQ=ny7m(D&ng#opxeUdbW<<zC~8 zGmtYl6(c2rVE=B9)|A!w$8=OkQC#6+x?gFY)|&HyT8J}hs8^V9U4sIJc(R}UD{bti z(%oCi3G1P=L$-&LIp~EO%64pwI6j99s_BoiF84efMC3XYoXfJlxnBOJ;x4*bPQ8H$ zk)%$2x(6#YpVZRM@2iy`GFnPsd+2cb{r0_k+%L5)v>DKYhjpMs&M@H$fFx0p>QjGG z_+u6^k;Y!^43#85m5)JqtQLTAuRVVIhe7RH$ilbKo`R$zyYFW;wgW9!FL*Zdmc`P& z!D10^iQRIcQ<ik<*^$H3&2+me5N!&ex+b2VYsw2|b7#}`ObC-mblx>KlsH>|1^L)~ z=SE+4hro4Ak8D3Z*gc*Ws&j|}E$ESZ7I32NRfrr$cA_Fx<_@fGA0WI$JfyU7bop87 zDO0*Ly=lA{p?BXespwoKc=wC_Xtx#{Y2m#47ZK3Y=I#8^x`n?}*FE(Eu(EV!#7%8t zEQ=|7n)XgO_eeII%?_xalNaBkLB4oZaz?;bl&)i&-v!G2?c=(t{U{9Quj!rZ{HmK< zN3eiRWgDy;j1_r}?PEr?_tRPNUuaD-O6^8FZ!g_8jwKNJuy!;MAmGLgWr1S%v{jRy zk;Allp!Fi>YYxsA^}emO7!_|Ix0qldU5QEGs}ZA?8*`itVbmAx3LKE;Ov!q^J!DcW zs(TU5WFE(?eNk@V_!3It6q5WP_@--~sO#((Jz4Ga4z3eNqg)*@F6LfT&02*MTLY5k zcrXxU*E#8tMt4{7w}t>_Af4UY`AAhCekCv-!Ud);VH#l^nRJELLSIq>KYixA2}EU! z<PkSx_-0kIX4|A7avthT`ylVk>W98_#wsZDxH&@1dA5?SxVh){M`hdCmXQK}6jrGI z5*zK9P2o%GaAW4tsfnvI9hVzi#;_C)`#vfYl-&>;>m>yFWQG1w5kLI;o~>x_jnp4t zo(iN8J%539oXR_R%j4nJ*gc$Np@hLS=^iR}mv)h7eP4;b>PX#_58(UimAZ})tMY{x z6o<g~(2OhJ_$?QBJb)Y?DJ=p>fIFXSrWg;%P~gsCQcbD|NVeXQS22-<P*TLF>{{YK zwQ>GOOv~6E2`_^uisT8WoOf{+L&)Vb<`|b=I11FpWNpj9Ob0=VLQtl&xu2YlrQlV+ zyKL%Qprn<5_AP0*u&KZ8ZDDS6FH}Xwv|@m_4jpj*`4wtAD*$jzUupm+QS6jplgDFz zqW=;!d@i@VRU)~IK7)(hzfuog=c%zvfOHkQ$zgH38U%CdogHnApgAICp<X#b#faf- zwaJGl;T8HNCYK(l7gSZ%JZV&-UA<k%aqPOP&%em{Y3>rRajFTh=g`P4Z|4%pN|6B| zn_}!q^r(be%*NDxzt==@aZlRykOe(>b3x&;*S~5sq_|T^{emAax1^Z2%rV@ruVI5} zu=nXy5y{tA&4%3)8?+v*2VX)JFt-<v5N<7ozdFi`k#J9y8!?~=VjAqx^zw~XLp|o< zY*lr(5jbubnS$N<H2vQsIsFC&IrB|K?j>@QGWeVkbE_-P>`2N!I`>e!he&EUuM8Qz zVULAJ-5H!)6dx12n5dh4C=+yjq_8;8*MhHSff8Nu8`N#Xh9Z;%QnlMQ&KW`T!c&L! zkJTzl6JmgR?eIZT!50j+HX`YrnXZknfPUh>`87I7yZ%qi4z_#j3>wSoqDmOtb$Qb- zrU|i7pLBGE*%G7TODqEj`Z$L0&hKIcEFe<CZyI_4;(w`OG0wj3Y}}x8?qDrXvzW36 z*aTd$em{`Xsf+;FiTl+bgA)`(Y*mU>S&}|54cKqM;igju2h7;-CLl3MPY#f)=zl!x zeD8l5-<DR7j#1$9ZTrM5OMe3bFw$I8?;v}Pd*OYY2G7oDgE!S@{^X85!M9nc=Hd@1 zp&{McsZ`Llj;aN&p|*az8~@xo+k&118ZEM{?Hbs<vlEq;WIdKV*(=JKaa3A6kLB!M zZvH0hr5QTX6s^kSQ`?Fryfh7!TMa=NpZR9;W$#QA&R_Y0-+mcIv!%S0uXJSE^N7hH zU8`WejJ@{4eaO^CZE}Y_LgqznXMMgMtn56Ee#jZCB)OuWWIT(85(}?_8!Xc*gSaaX zh9A*{Fq8#FoUj}$SpD24F5o*R(wDr{l98$|_xRqSc=Yy7cLwH71ks_~aWf%_(qR^A z)AQy=lW?~QL!Bd@Vo0Ko6G_T_%`to8x{S^&V~exJOY?7spfR&CttWZDsrEu^BCn_^ zSUK+Lk;z?D()jGar*xEg4|5WAg%?^TH->~#W=AF)s0EP3psyvTib;yE(C5RT{J6$L zI_pm3Cku*ZtuJG^0cVWYGml)(Z<rt~+l69|2za<)$qE9J*~8JBJxZ8ujecHvfTqAC z3H3)<*t~L9cRZf><f2vcb!#yYHd%KL*I>Mo)TiA%qaG?}BaaVpgeqbhHG4)zQ=)I- z<LcGRs^aP`4pJ8M2`LE$HF6Rpi9J05!oUpW;TlqbH=i9?uN7*C&mW@4$DT;OS45?{ zD{mSn5>w8p9mY7G4PukWJG+gF%coqIuyt<wQzP#tRIMSkI~r1(BVYOED%nL#C9%(R z57)3IfIIrql}h2`58aE3!=J+Yho2;u5|tiFjzkjHA)T7ZFodSU3?S|iq5LyT81fFK zgAgoI^&?upcHFe$>qQk@T+V=w#a%c;$_bk>*1YaKz0ghNB(!*w<mY_opZm>|0n;xY zf~;{ifz1lv6TDu9S1XmV)j09T!s5=^R|SEag2ob(aFTuprOXlFbbA;|R*zGLLmAg4 zPzgUbuRHb;pTqG&FfLi>rj#9uP5#*#Gd6v(yZzMUZ64<pE$Pr}=GdWkeR{2PjV~c$ zE5?eA#|T7v)dQ-1b??1>$L<FN{4YiwWT0Cuqrg;zAIs0o4BtSXSjVrC-Zea|H;@F{ zLi`^4CN`8PI@7^`X_|%nzz%EO=C8vbRfG+5V{)zhSmdKz?A_Zl4Q7SOS0;^1|Nl_y zmGl5%;;VLV7F?NPq-I-r0XFe%Dt*g92x^{WF+Dvk;|NmR26V$`&{L~|tuLk(5B9~f zx^JK}v?%ID*2V=y`1rt(3@TYE{R*O3@xL%c%?l}2nTilM$`z6sB>SW{SLZ0g{1)?G zVvdUNy-&jVgd578U@GZQp0pAv>2<Ea8`9kaI+WF(*rk2}^f!di+?A}&N9Ja#Hm=}N z#uOhJ((7Up2PjR&7#t5WWXZzU){EGhniX><_CU&HQ;U<fC`Q2BP7wn;?DgkCn%J=M zKf!29fA9x45`S6=SjY`rqSll-fa=7+eNt3|B75uM(YStAC1_<(<_T#D5Sm6b9o-$! zXr)F!S*S>>=2s9)!IEhx<dtxK@`Gj*pNobgiLf-VZ|nC&boCV{W_(%57IN0jzOWOL zI`i|o7s0OQU>evB&ldgMOZOv;@s`$9!m!V{Oxq9TFQXdC+y$p}bvL$u`z{e3+!Q}M zIyh5|!o!>#2$M(BcJS^p1}!$|XKKJHZ3{>C>v13BQ(zavP0mDsE<4>w{F(emE`zz$ zp<NrVC5kjGP9V^FM=YU3<_mYhgK3F^S(fahI4f9v>U^;!%Yh(995Ftac(%)>f^-DG z?5gpKmqW_EKCYKM`Lg|tSX<<4-Z4SID`nyLIW;#Pj?kKFePEK{@9L5Pa~aBw^RAbD zebLk7_t10Upw&8VcRd6tdn?VS0!0fX#{rBxnXTtB8cNxsrp+(>B@X<~UbHlq59st? z3==$pa^(yrLYON0YR;~<f^Bdw@*s;o%q`7xY6gox5<IrDEZd4q%OgIRw)>&V@1xpl z$hwWa2Ok+tl!D_?DuRM@wQh}6d0b<(T@#<5L=W|PtDzPvd%dUmlV)QY>=!Gh`@AG9 zm)<(Dp1l_xI(Z5C-mM9j1J^P9F?+S@U4LEXxznLpDDj#!XF9*w_4<?I{8Mb7go7xU z&N!AxLw*-H#;SA{yX^DZV7<mI>ImHtF|El2ZS%if@l+Z)eiaXuzuP(FiSD&uGa=_$ z30WE*zj7Ib6#Jr;C`p|ch^8r=T;AUOsFDf=Fyw@N6MxA>whw1|7SZh=S~jtD;?|sJ zR)W~BBluCvg23Yv3-Q}+v+n=PZDVrs_MImk24rEMu$jH+J|l?r@B6>ne)!7j(g!+H z!~i8J&kFx!yGQbBy_V%*CBbUaa(B+rzT<wf{0I+&2Nr33_kNfFtti<E-R&eRg&+;3 zND65^P`=PhrXi<QyMSs)Qcu#zFK&)Eq-~Bff0<l^L|6n?VVad>LSb6t`zpkzKMm^p z2*3F`*8XUDwE+@`d>4l2;hfCQc-#IsF~<EkmOOriwS;w1EmCDELu@5BqJpL9TEWdx zpF<{&;}4^;Gu?bi6~oU;WyR{nVFKdq?WzN@P-5t+_Zk^L8a;DN)25n_Z-_?0_WKXX zUtg%qX`-JiBR5G5v&unEC_>arm-k!5A0k3V6xb_<W7L)We~yhN@r`sit)J*xD6n#P z!Qe@@`03sNI18$m3Zq<6HYdUdBd9gTl9$HLdQ`0Pvd-KWabYK;{H85jASam-ycgkx zZXSg;1&LzlG$DRY^r+VF$Tp*r!VJ;$!J?eb3r4yv%gS&Db#=y&7+QKAGppUq<r__M zWOGokh=Rko*VwrxuW`@Ks(~lc%7mzEc`>PaEPzqL8I9WZZ@*0_Afr5|FoTjQ%2vb+ zPaCsyVlGw@@?cYI_w3nh7ah^pC$X{eJ40+%MhNAa%EZPzXY3_pr(JM_poheusoTmi z&nO~;8|%+EAZcG)=Op%HMFIi6LK@(d^c)+&v>evV*x3|zBdA4a7bYTF3uP8dg%R9i zz+BOQUdt;@Z7H>~U-Sz}DC9Yu%)}jalDq03V+_ylAuE<4(>;42TX=#U&BvDbRqVye z&=%Ou*zjD?YBO@8EMs`tb8NqwnqR-JW63s0@SBTms{+;kbWS$yewwIcn2RBSdv2Kp zlGV-$3*FwD2W9My&@)qqoCvn=?*a%+hoPdLoEiRf<Xs$zTIoS;w+V^bbeut3_d~Z2 zj*KBu=(;;UdbxM=xKQcUL^hLM&vUnjqUiOE4^$732wJc1Yx}``Yx+cvL|y>uFlo{< zb-y+!K=fu8Y5mDFE_~Hn(5rJ?e(E?se%VHwaleUtmgbHQqI}UmI0If3Z8CE!WHIy8 zX&s|}HF03S33;U=StV>HF)ziWNS?&J50!NAhIF5(-@ogIMnkr`4IH*yJ@BD?SV}|| zKBHVa{cSO!rx*&2<aBvOsZ_KRp$>ids1ZyQwK3-ohrGjfsB+V$VXjh1VW3U?Q=eL4 zBjK{QDR$T=2`De%b~{mYlM<JfJ?UW{v$)c$-id_GZJ2d;EF66MG(QHVWDe*QSIp3) z97+F)1Zr0?_c}aRg~ra&<|}VNTJM|oi*E<==TX6NQ<>$jg^iuwKo?GWyb+cw61=lp z1VNq?>oTdXs(8yiI~P|8Kv_a`iS@T41^86?pt1-<l6a``Buus+kf_cdnaK!2LKGf5 zzldaU*IV0twrIQwX$UY6^Ite~r5de@G<|@c_dz<Na#*m+Iqtt(E>fRuw&9qDIG)~j zvP9=7gXnzn?RCh84n<{Nowj(QKTSX#O=SZ$oQZc)Y3Tq-0Slcyo7-3}BXDCW3E9ml zzae^kxgIacv769ZYl#;&lC&F|-op<L!*+PxDH_R!95xRNZ~YKnUo<)Y1zA?4WOEIN z<bn_UtUkmW<sfa5;1g7)v>R)eMPk1Al-d}T5*IUAXy%5A(^-*FFj=TAL$F!ecvpi> z>At13l8THi^;xKQTd+#5bWP#kQ}2Mml*gDj6r%v0DL=8nPYvT>)^r>fx_CXm$S)`1 zW$o_1eY~eSmV)%-#5#TkN5?y3jfq%qs!XBDgzJES6?Bt^H^Tqh=l598V2{cVB8?Wx z8}oWvkz(egt6PjU(cG_HF%|eG6weOn=*4r4DA}b%)z6~XG#QTIi<8>l@#FKQpJ(D= zhv+=})oaK$PgyOedkSe+SRaWqtLl7KHd32%n#`LJF~a?gE5&YRV|S_!L}A6FQvvBO zvoFukc{6o~?u*vjr<T)A8F7M+ToIK!m)SJUF*Ze{Po?yp%YZbgmcY9@;<pa92LbH- zCzy)OcUOyyC5Tj!#U49v6^c#1k9z!KVR82@DPw$#Q6cQGckp8aSFAgILNy}uV-6@1 zYaxe{f}Us`TL_|oV~5T(0I$%8d2jVrS(U`rl?%L0Aw_`W)hKwbX*IR&`mC+ZMQ~E% zBc;@ADIJX-;|)^vRuZO}+ra^J=JyYw*DPhA@^A7A@+L1G(Wh`kCWfbV@dZQD>U<yq zZU`+njd(;ntHB3IsfX3*NTI*R@+&Wog^yuUAEs8u26x)gj{7D2%@I<+IaqSIJ)<ML zEvj4)@m4AZ@6D=Sbz2mb9Ip`g$GtV2oohw2Ig>Xth~*R=vtcs9bQ@^Rtt`ciiHhbg zfK1&SxP?7?@V?00E1U?n1uu5{0_=y+`A{iLak5B1-F3!zbh{x%o+_{a)w(IFZFzF3 z!ZH03ax61Oa+;-U3<~l{M=Qm0NvCldL3J{rV`XVbMbzpdp;^<w_WW|@r<@qptd!wP zOR6stQK#03jf8H}-T-f@^KhxWDy7+w1z-IQ;k|a1>GI}clG<gDXM7}bQqVqh(S2<N zJ0!+99@!yFxjIt~!N(8b8$&EhBLuYRk9uofQ1>G5jF(>bDw&_L8Cc7hI@%V)E6;xV zHu#G~OpFwK)1cFSCJ5C*aMzBjj)g)*ym?A{fpB9?*y~KNwI*gw{&#AcR;ymhFNpOi zsG@|UYrRaIxsEv5bvv?afV_>4@X<xYsGG~q7{rDj<?1fCvC~IP7HpXF72ydmSXrk< zkyEx$5Oenr12}fSqU=s})^ff%sS5{*-IqOLJwKYad<+T})hIOf>Ka&Mk*){lOm+%F zMTIO=S=UFudNfyl#G&FSyqrkY?scTBy>vAvFjXY8d4eD^8$j^uC!5!~6rta$!oX%+ zkx*R=sx3;`Welbj(``>CgV4vIYNJf%9OXLApcCkBv$uWo1U5V5lrH({tFStg<BxPi zBuQ7dI6l?9$v}zHRQF1BN6ac->Lf&vJfOpW-Qe_+XwWJbx`tb{r%K5|J7Ao{L;7B! zTI2xxe1f*i_njKO$!t;0H1*T{4X~t)kER2}v@7*uwDao%2xO}2JLIHf8v7&N2#ZDJ zVM$zYtb}3PgS;a!sbX<5n->R0iCx{){xJkL7djvuDtwz^a$7G5hKsVfcVGaJfx?v+ zi4uRJ*mJ)7W3SWcYtL>#vj^!+9$Zil=qNckXMs4ehD($?64uM1(lV5EOC`PVuuCj} z-nR#dyz4Qg2WlUA0b;HDq}jO2H!hYCI^PnZFYa-9B+eNhuo)vW2XbeJ-*ackPf<z; zwWJ)vzW~w;MzR};ry%M}MonWu@1AzOXb1;=k>cabFF&>K(gg22;;1#PttLxNLn=h) ze*7}3O4(n<C-MWKbk=C5Ky?ecjwf$q8OTa_aC=9zG~D>d$qAIa_;u!GX#A8~G~8l} z>S1R1v~T0pLNhr<L`az|8FWQKle&!{`>KTpN{mnb9hqOMGrLE2skhhh=xki+g&FjQ z2gobjdejUQPe=K>oRIBel*=}1f$*=yjL{j_czaXo&n(}KmBp3kx+GN(6rxVzbKW>f z*C9HY4mvkI$x+CdHrw3UY_+tXa<}`ZWH*-!#W8$8r18@wR{1>d8Nk3tpaRO490E~^ z?1{h(r@ZGFe`dO)C=9~{LOe{^B{o`%aJ4WM2cUt^5B$W_ryu-jtA8WFQIwI2ocZa_ z1;KRE2(3fr5wczPJsA0D-_6PyZpER`C)`)mV-b&gWmw@#g8A4VCiLZ~T(<9yU%#Hr zRWCO?*`u$&otDX-hrc!J5J6DkvQN$}48~X6NqJggu9aIjdtL9@=C-4jesxJ)2-%<C z&H-Y9c1$qxqb@1v!cc&R<WnZpP*ZaajVE(tb4dd_HS&k0fw{-!!e!1#n(fifEq8mF zB46jnxR1Z^FK%dNdW+#hA<sV9Y4{R7QyE^50&Mi=GnKj<S#2-q=slWXbr)wrE$j@P zVFQF1;Y-BJIGO8@Q%LKOa~Vi%98CQnJvZZer}=LQsFJDWLzNrPRBgm%S@DU&&0`bF zmGK5N28uFTa`uZV&TF;zvrkTf)}Tty$lg}Rsh^HBBy*oFGd*H<;WhHo`f^iTT=Th{ zZRbeU6ijj<j)|x$$ITjI-xo=ari>K7MV!iG&aX~(oyF!}9fNCq(-I^x&llP=pVAN; z;FZjJLb6d&7jzDT)Cw5Y3d)9}(In?Lcbhn(szt7m*Q3|JfDR)zZ(ZTY5BGosAau@< z*|K{`e~>w5ACU19EPXC}Ookq=<(;Dd$2BOCNqppE06~f94qt7MTB&QxX6)BUi4fSF zSUyD_1%8doa!c&kqtXG*j-Z8Uw#2enNwi2&`H~+`9PsJh2O5y64sJJ2;1!q(vK_k+ z)Nr}pN@f}A`NNPZ!nCG#+UZKSkBqoSJEb|NzdpScnt7<uyK$*<y4_&q)1mNikiG&Q zBhK;)Rq9kGyZ>VERTld;vmMv-6y3AW-gyxCq|~qwrmmrvUrUGPMf^qg#>(13Zh%=& zlU{$;oj(kFj0bD)qP_uU;gUl{`H&{xWxjQ+7p&3oNw-h+kB0R83jv>jS;5m`Si3ie zUZ|yw?x8$g7lXBoZkWvhEuRb_eoB`&+^BiuJwpJHYT1hDj>|jbS6JF28L$1|&JCdY z0dRe#TTM?UHO0+`GeL8dIl(zNi7K{1pm&bB*+@AD!ska@k}KphOA}3VeHmDINVFo; zDexNid24@a3&Tbe2d3bNRbKxD8uMH~n`)vKI1b{-jo2!E72>+QJDjB�s3%@G4OM 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°{ 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 Z)X(4j@AssRsBQ)z@O1TaS?83{1OUqz7DNC5 diff --git a/docs/images/scaling-diagrm.png b/docs/images/scaling-diagrm.png new file mode 100644 index 0000000000000000000000000000000000000000..99350f806f07837cb2e2f83ac4d43311a4abd032 GIT binary patch literal 39934 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 PLcAVp=&M&hw2A%?D0daz diff --git a/docs/images/server-wide-announcement.png b/docs/images/server-wide-announcement.png new file mode 100644 index 0000000000000000000000000000000000000000..ad99d3fb6670ca587481a95db8f0f586181ce412 GIT binary patch literal 9499 zc%0ptWm{ZJx2_xa5Q4iUxVuAef@>f+jk~)`a0?zBg1ZC>H0~PQ3GUXov*BH2?IZgK zoa@XFebrqxYK(eD^_Tg~Pz5;&6hu5k004j@B`K-|06=0qj}75rpMRHoi%<Xn#3C~h z5d|p`5fTM^8)Gv|BLF}$G$9dAMcE9ixAkfqpPm#_N!Z5!oCfrDIW;l{8va9%kST{~ z7aESDsHhO`@9YqNAcP@Z2+RVBUb_HEfG^7%tjervRP~OdjPx3lV_wc<m!rnx%)6E= zukCvX5<x=*XsJpJK>xjpeoQbcIT=fs-yNY40P3U-3#V$98nVC_Kzvfqd;!=MUn_4f zo&Iz6FcY(7t2_%3f`IR}RhsRG&lEp})FhFC0R+8QkeA0Cvd8UUBV{4!=r!iH&fqoX zHqJO6z6gYFB;i8@WDFS~tOH2Ag!UrXoC$J7@<}bbwok6%o5(CjqfG4Hj)=Kx*q{E= z5b&#%8*1I@dPp^nP><^lLqEH38iH9)NFtLoFnY`!1h<lNOVyqbn@fIM56bx1mmXEB z;kCwN!+Zw3zsFAQP1(;}ca1gKfvi#1%E3zRw7<~NQ#2@?fUF4&A3aq{Aw{Co!hS!! zo!<Zxe$gmH3`UmnHi+76WX0y96?pIIH{q)9jg<Bc=KwUjPF9X2_Hiu*7<9DeA|t1f z7CHPSjg(!W%fYS=9*j&-UXt1{f{J;Cq?F$M-Tw!`PLQ)-L`z-@2}>|F%(4<jPR|X7 zZVx(S2967gVI@GQO{fnp8NjL+p+%CA%G^}oH^}obKL#5+bHG+u4kf95qXs33StcT4 z7$TWJ;4Jg{p|i0DW(*w8o(%(-o|CN7ud2gKS!Ju9dtXmKT^suy`Hin!8y3REmc`B- zF)|6Hln~UZ5N;t9p`NddiC>zN#0qS)uOK``tR9M9fNKnLAPJ!*wB|=5DnL`afWn*N zHhl%usDQXE%rvN^Hg;R2bKkoa1ROx;3VSj@Sr5;jgh14<Foy33q?zz-41yudoQQP{ zDh9Ne@R$NYSFq@BaZ`L10H(;M0{bN30Wv*^;Uj03&JG$IeB{UDEJh|oicU6lglYez zPPIz(1C-#ll2tBO{xq2Fj;0ls23P^u`nIGM%@Z$IfH#VK4j?QrCs#!gmWnnWX@D3r zC`=4NF;(%VP)P-)7-1@EPk2cTC96j<b4;BLb65yJ%W5oRM}Z9=L<GXs4q=d($<_S* z`M1khzz)K>3o=Y@$XM^JUUD+L3;_jUTrhR_q``<@xxo?eE3>jXU1HQ!&ldy!s@PfR z16WJaOOiU=1;4}YH~N%zTxooA#3sRKy;ZhF4Sb6bi_D8+TEx~kR|xVQB`dNgN7qz* z#F+t%-NfCxZC9%jClk=r{uJ$BSL9dTvLJ{Bk_S3>5Oy%>f2We2q?kt&2|?&8>tZoL z2h)J5!Th13O5_@GkWzd~97Pe1{*LKvlD9I6r2DbjeI<QlrwsOljRE%|_Zh<3riujA zit#D~44<GjSvI*h<DgYL6#S{%V`s?}Nyo^>D8b_2NQ$U;-#3c0NLQ<z#%~bz+fn<+ zC&q_kNSoKF1Wjrbc^65U71vhPwmMcjW}hqW;*aODaN*M9a^gnGln?2r46=x*V5p|= z2^%TbD@H3+C<U9Tf9HsllFq{X9X0XG485AA+PGT38n+s=dfNzYhw2wrx|Dnl_L%%Q z@$XhT#V>2MflY?n-||0rNec|nCpg5f4{Q#y4=yF$k&VW<#L371A^$`3Bm+^FRq(bj zrrcI?wYcM2X<lg|?;!6+TAsnH6rOgE8kX8xfv?n6(@sfBqhCZS%TZ{zdc1)}drp!2 zW25Me|7kL!YPU{Mfl`jW;wGj@;%b+qK|FIg6NL(<D!-~&@l^3r@r3!jdA2#X`LOxu zWaysSUe(@*z4SeFJQ}<fJbZRMb|Q;+Y-Mcg>{k}fX5N$I(}*+k*;B>r#q<TklOyBS zlitN5V|KqaDwJ~_<grUE@=^;u6zU~Vr&(vhXG(rI<)ZFu?wp;Y?p-l-($(nn=&IF} z{_(Y3F^n<(ZOUXS$$8E^#B9m#S)&DXn>^(oY)bUuWa0e8!eemWrQS0;$kp4hbe$fW zfw1tSV<Y4F-?-!$ZkD>M$?C;gK1W&;yrtrxdq%jGzV(NWjy@1e77Lh&mpGP~kocg+ zRstvyF4>>Pu`t=EpWZGNTu`6=F`rg@GdSJGF?LyaxPy3zxriyDhCEj^S9MT)2z!8g zId&;HhsssRQ%PV>pu<(nYfoT7D3Ruv{w^(w8)U~}kHwQ|_qb!QUfrM9iMhGA`u%wR zkYXKcPwnV(QG1ww1T^N=(YXi=kO-#inOJa$HW5?~?KkFNqHLxEaky!NDLmjjk~~^Z z#?H`gYwtQ*bXq*TGH=ap!4F>^`~)X_DxPWphrSmOt*{1AP>{5cy0Ex#R>*sZ`LGoz z0(g9wYXnLdr|(rLRWRmpDRAp(N=XlZ4Hm9;*Fs&VA+l)oWSC@bu~v!=g_VW#h5ZTE zv{z*WIz}xtHd6sp^Chfmf7Ej;Da?j%etxsiu#gu6=5*#pi~AVe)R?QsF%KmVBqP)z zc?jOI_r@xB;I7Zxg*TE{IahU8<=Q#hd93%W5w1zE_qs7O+b=Ibj|LV8Mu$FzI)$=I ztx65|UvKPe)Og~0lRXXaY&zlYyTjc2^R>6Rr(WDm%fo|$eo`w8?8Voq;2AhuhdYWc zhy|Eknqit{j(3jB8%dg+uv(k!866D~^xKc#x<R=^d5CO_Pep2SzOlBSR{`P96Vx<1 zgx@AE(s#}g&0T1QYNFRaCIaJ?)6VoYuj?+g@)i#kvk!?D@Xy|#2D&})TDqt__&)kw ziCoD|q{BITk8W@Lp<|+<qQCyq$IyI}3ywAt961PEn$k8@bTs93=JdG=;D6(>7oHbh z6Bc}Vdt^neAHR|0Ia}}iCsL_qy!fH(A?E?gNWjPnj_u8Xz{yX(mV56Y2Qh~{gUykF zXgF@TyEoiK=EX|IG=;aP=*I=YQ$$nr>|faPf~$fj-n8<)bN;b!Qj&>pj%ki$-Z}-| zhusU<t6)>-U?WiF`!Wg78HU#zRmL;zuz2CB8TV1yi51ki0?kFr1Kvy8(IrYd7npM! z*i)G>8=gooDKt6N%t{<e44uB7_N(iwTdvVD;a#v=7`->Ywpikxa=_d+8pYNo(dh#* zIWX_983tzo@0AwwvPXWV%QHx5wYYpZ`E;dvTryM9sN1x-Iq3xcwRGXYX=$AXGIOfA zNbD|4T-d4~y*GYbNU;t-O5{y+nRhSsnD_X6uCwE?)8sgFarDz;$fN$~Zt2+T?d^*G zQ}Lr;a9VI~^fw}qSK6iPt<<IR(8Rro(&(p5T7ili?W?OTh;YBNfbxKPUFcR<mM$Xq z2Z;e<-Cze@C7r~m!U(pA?-3dJ4#fLzKToGlEZX;X!OensPo<u@XItmGQ9er<A;~!2 zw4S_Y<tL!~yI-ir#5|Nx6q)iL<Yj$^p58wdJ=RQZmou*Fisw(XuC*k3O*~9LF5TTt zq-><%LP+<0uYsg`zdEZ9Se}9q3WfHahXN=XER&DIupRGj!`~B*-t9CBc}k^|18UTU z>!Ez{Hp+vpF{s}|#khx%`^w68-;7Fzva_emko_c^{^4l6#lMDP_Y2^;pP7<kot|=| z7LI&};~Q1vW+Q+fr~|0ZLzAuN-MO?pAqJx^!$A%ssjGbe03g!MRMZ{SWo3APHdYM! zhBgL946atTfR~5QmFIbAW#p(&;%a4S?ZD&8PxhY(p6Bt)G$R?we?lBB_{r2|6-Y#E z?2Sm+8Q2(@$OI5cNJ#kX4UKt}M8#jXKNCNhsiUJU4<n<CiwlDbD}#-_2_rK%H#Z{_ z3nL2){c{ApgPXOZzAL@81NlEm{^k)iasb+!**copSd+Z4zJZOCBR?70Ys^2-KZT53 z&HlTRwZp5dXMv0_D~!wxOpO2Leo6l_%cEfCYGkP{YG!3*?eJVffSr|vkMVz8`5$*` z{P#LD6Vv~?Q{(^I$;bGA2>Pd6jIZqyK;&cmxAg*uv1)0T002&)l;}qlSBS$!Bv&n? z6u6ToEtW=^qk0Nb*>MUhGwL86w3q~GdKILG_;73m(bDK!s<ra{fF`=~)3#sQ+L+p6 zv^jacK{VBQn3hEgV)S2Ply-vHtm3x3_ur?ycM!bG=$ElKW^thCPs2LDA3dve;NEV2 zeqk7KX*tUn?8@nbmcz&bz)%T6AS#fcKv>}I+p8if_(J|?@-3F0aC_9t(#wR<JfsZO zIE5kL?|QOACF<YMm^uJ@SS<qXD+)nSU>rdG&HRJDEs)Gg81`==Uj&%Dze7kfB&KZ1 z)EJ0Y#CR?#@c(1US(~|QJa;%RGdP2Pa}Uw#x#hY^a#v8yG(%c)|97xDM#^|p2jFk& z<S)LX3d!zgHQ?77Aat?<&Uzo!D=I$=V!GHeS*QLdK@a>h_rxl`=F5M+NBzCw(H`Z0 z%0{3)a|C(r>nUWO58g4Eni*N}Pc<C!XU35b&;GYKLQoN>Ain%REn*UXX6C2};aB_# zKu1)z@#e_*rzv_7&kQ8M4SGfM=O*PZ-&^wiqpl6-nR~cc5MOcfx!p3Ln>p8idg9Cc z%n^2m7_V3abHHi?@=p}xSWSiVf~O`ucaG{%+7b;Ft;LF8Aub>8NYuTx-3}g9NF=dR zT=Z%<#@1N`SJ6z$R$+<Ir(YkPflLv;=qdZA4Ja+zUC_}DWVq3eTz-$6KO}4mkQYn4 z|9%BFp5I*C#+`<T0oiZ>*S!T#5gqKrBC$tX7>*r;xj57#B8eGAcKgojQ@t;g&T}tn z6j-|-vvs2$7guw8Pkalou5@D{!XI;rwr^p<Z9Ta=&0CP39*t1*!<ajVZC`_bRh}wK zpX|~crcLU{F)&BAFwai<Gu{tGHwg&BxiNCC@&-S^i$T$TtaZ|`>(vggEZ3{{U%OiA z-j+Aew2++tk(KpGu;^t(`pL>10HZB2e-e-c`y2h66DBQQ;>?QjphFBRw@QQPgX=rt z`exI-f=iw$_4an1#XAMoQcm5FyX_!+jv`-`Dy88}422e)-GlB?XQ%ZQCOz~)J#mim zU&XM*g+Dtf9(LQ0i6oRWpyu!fbAo<e7lNQrKi~&Y9`epV@S<{REBnEugqk~SwWhMY z*~7%e>0Xz=)Z3+JS5MBaC)oxaLWZF!_Z1x6@1kwqkjgSeOS|bg)Q=NRdSYKqAES1A z#oYr<C-eBOAH<D5`#7e@kU=G%o<Kye$+yh&+RMo_{gj)(0<+JgVz(a12o5?gUa04u zj)y@1Zi%Ml&3|O2ryX+-y;aQF9BFeoB99#StaC;^ww$1bwhXa}|Hn(a@lfLMle7>% zbs>S*D$3@i4Y3N5^~4-=ZHdgL*W#sA-GHQK)9Gk5k@C^Qs@*30@kZYL(&4~Tsz-cA zpehoLgpRB7%|HuUcP?2F<UlGTky^`r@Yu;CHl8zes<R_)FF(*u<WbS+4roL5<VB;; zq#-G&vv(7>pLw6EVk9<=d>ap1h@!%;2Nii9mL;PUAf(f%72kYUh^;@`QXbegO1-b6 zWm<l^hho?)(EJ{+4dqY&V75+fHGlx}v!=O=a?Z@qimZ7Yj_*Z#3aK`7sIl*JnJ(#r zETFbE9(@q@zTdo}tZE$&Zh;UCOPpCBq^*7{$Ff;!4m=;?+h|AP{ZiR$C6*}W2P(zL zY|eq-{Ei+N(;F~yAgra1BRfV<rK=ExVn?lEYYIqpan6=1Hy{DTXA0uuGYkpmyJOWm zL6;b#t_PLVvAK#Xx`;q6r(%a<pRe?1)@NS^T&QD8z7wIB#xI~G&TPsim@?;209^7f z1&&Oef&IurslgfZlYuL@V%K^_o^Sf+9uw8#wKT&(3vs%Qp%!un65#uZ42pw&__lQf z(x=6_hP!dCjpFVP7A}_1&{_pmW**p4q0wTV#fj4^tkN~HMUn@9GTP9GJ8k)vLjHUa zF|{J{11?A*_i5~0|5&o#L#W#WhwIa2t|QrO>m(6>pxpz@#~$)cxkvU!`{edSU!woy zE80Gy{1Q{IQx}(}{UMV0_p$Qw5fNW42#(O1*S@+MT#m;r|GC1kf2uAH?n~884ED0# z+ao=!a!?D_XUyxWb+9p4d1mmGTkNL+j>n+$l)3uJ^>1mjVVVv|l_R?yHouHl<Hl&w zbT~6C?A9J?_;)^I%c~{M`@B1^LA)~Ks|KOlz?4?fVh!o2g`-Hb^j=beyy&&qVTg1o z1nfm1E(Mn`HRnzWNTQlO@l>%Hg`{$jD3z{E<hE9U_0qbrdqvx0;SA-XV?chcDtnHt zO^g+E3(Af!2O15ARfHZM{tCrqt0e;2eng8kZaDQ;g`EZ;#G3WOZYFRWm8SULSyUFG zjAEt*$Q#$MfkX3GBBptn{0qEUBTB3@qNnzpqh&7dAr~K4{j20#cIwTVi-8i3Pij}Y z7UoqwN1ynxuGxTj&Jp2Q6_>-5!O!n|(KEb!ri8;i64RL37n?)`duLgcE?7rRRmiF= zU*9h#kv({L-p}AmBz~zhkzjS^@TfedUg>eF0lT<`S!;p7l2*dw%;eqbSU8d`Pah(2 z*;)Jd9i0cw;;!YInBATDj~a(y!)<T`=f{KU84A1I?2^jFzb}AWG3^^QqTcRpw)jQq zyKW?Yb*|pTG_Z0efAlheC)U!4KpHqmR&m2!@wt%U44WD0JX{TEAolS*;>w^(8vWo~ z;Q}B`Vqa+=JjCI0MSgPY3a0&BYy|n3A#lJ*)9Lgk6zup7Cl)GzW8`|)qH29Hh~vQY z&B|>KGL?u3S9}75MGb2ExQx2QqHDKK2%{l{$4`{h9*@?+$hPn9o`*Exc!;&DR_m_L zUhI`{r^k)MD59ZB`;GC{X<g@B&m~XKVlCL4EbOK_c75f3NY6SBsFLX+zmj8&u$j?r z#9(4ZzU-EYPDJDtUpanYeGNXU&93-547<AF)Ev>g`)=2CdR`64hG=S6`BDG=02do; zsp0LDI$eNkTR4BK0HQo7o&wG-&k(ESJX=P}+DOfY@@R=QBz#lIbL`!UrbOOoDNa-5 z>M`Ly>rBrFbf8lmu%Cv~`^1D(ynHnHSKkVlsCKxdZ4;`X2R+QtsA#bFob{r*!m=sn zCsJjVa9z6PQ$R4EZ7_@C4~A5G-I}bzavZUDCQs@xz{k&D;VR2&0QK7BUbMy|vv5zl zA8WBUbH6kl8*k}}iNi&`p-sm22^Y1_Oyfcm9X<_poxXqPc~eKW!E5NVKN<a*vslna z$qiwT;K7{6=`)|m?5PC4fPFanT!rWifd_xw#hde{lcYs^Pp^AX>N?9#0gaz`^#>Ci zyYhnaELbXC7a-__lSXlUA0Ph5O&Z!;RDy2pCjRT&VU%lI@wYyYs^mHcwB2QS{a1OS zO){3m88{Nt%@tUn0Q<r9{66~VnD<3emt!a1=rxQoT^c_wwbPl&JtHLR%8e`!WE!5R zO<dEYSDxe^%<o-YDQI@6s5?Fw#X@}O^t&AbeC@TFm5VnWb=IpbBCcrq0X1N&rjQb@ z0iN@xNB{h%`E90!!pXpK)M_~~Q9D$tL$>lrb#7cm3HDtWO{KUj#iW#TP69Ue%C#Sw z>t=3lDfH(-6t|yaK`42Bf|JpgS-<oo6LC8hHybMpLb4gkB6Gc?<ZjsQ#m9EOYJSU} zpckQP`T?m*Z=IIN(WI%Zu(eI<y%<@}n=lh$0FEEzSe=$yU~qRK<<Y_KX~Wnn?YVNk zGVn3OoG$JUybVfj+2)5aoo9sOzc@oKm_1Aj{VLN+uw$t3-2h~)UTS@xC6{^Xe6cF2 z`k`DU4#BC~#9(SI%@z`(1O?{N+tX&B`M$S?es)@4B&s)BaW21m+@yN>KtkfjC>yb3 zuC<0Wmj(_J#+{Fv5w6;~^ExAqbziVo1+4AOw?0fBC&l#Y$+>y&E#-P`Da`4jeo@yY z<g`{URIyloE@%Are`Y3CDdiF8b@#uTm}!h}r}*p4joDkSZg_Zlg=4y<kfy1*lsEKG zEQj_k<~4jw<r+Bch5=GS7OmxdC;psv)H_+_&vmQB3z?*5V3%WpIHCuFA|j5zkLXj) z+!%&GcUo`HB<j&l&3TH_Ter};AUlZ2R{{Ff9e<!{Q&b93?FM==*HhvD{CSg1A4=9$ ztkrXmmU+NLee2@6I4i)%9M#2`L{qMlrUF!|cDlH1Rbi%_da}6=zwW$T7*~;);%>Ma z*RfpiLY7B{oRTiK+pdO2b&!H9OA$oE-yrt)ZU!r%A1#=5`e>(O6HP*O=I)qYtlYI8 zrMkYAvlhE%O@k+fVk@gL++O{jBiB5u>=%tWXcZHsRhnSQYiqE_%(mKLQ`UH+eq_<h zY(w-lwY0&s4E+*F&&Bs8<i1|G;bh6a8!{JMGJIXb|Jiyo;+pv&<4bx#r@-tdLSRxK zd7klx5%~hYbDNCgG}HP(f7rwv5i7L>V~cEoJd8wlHWzsh=@)O?EbKpv=pAMC9D4fs zd|l2zaGUrWSLYHBJhjpnLO>5SC)pin2j&h2!<#(Zjr2&z+5}x9_NqW5D?#VE0o!Q9 zc&peBVICu~eRMCB_p{DpZf30mQ=KM%99NEQ!o7S|@MjXKMY?U7oCUv?a6{?PhONEn zSY9Ub+z$d+Hy0r$d|ybM2sJ^H1@T=3X6-&jtxL#4xS6z<esH?(s2&2-CKv4;9UgRS z={M4_&oEf@YU53*eOWFDV+XlQGth=s82v`Az~FVJr7myllkkw@K5DeuL#?EYVgZ*u zs%L?a*{kHnU1FR0cm!|lcpi9v9jWL{gqCm`cM+4<I*lzn8RIGAKiO<P@RDW6)MAOT z8#O3DlJ0aan?$eo7vD7GD%n(yw5_?Q=D44c{DO2#Ca16Btx>R(BNd=U_`0YOlD_e% zeqh+yIG8qTuZQD>0x~VBK+a4LIydNoO}_8nYa9O#a8ASPD$IME*;m^>uh$+e|7+E8 z+aS{2%^<%3BTibR?a+^M0iobMmefL-#^{kFiR&z!AO)=E({CzqhqImxq8Vao_SpPO zH5U&VdQsP+9ROzQr{ZgFsoQv2Sg=s5E=Tw5A%m5cZY%!dO+qrZfaDhio&tCW-HT{? zgDQP+HJzoG7sj#0j>urzscq{-Iq{v&8|&?aj>~v0?tMbh-7q(W3QGxe#0njaD!(5# zgLQG5j`LR7^?eb7zoMMh`W9(Cg|}yvaP6Dc36hWs?qSs5axYUYqcyL&tch=TVc}Wt zw{d!}CzOQ#Y!LNopzM#Q(Gj1X9Kc7i5d$p_-1iuTB26$#f7~yzr>$KIy7L|<g}`vt z?lg5E=x%kITFr3T7UBm-$=z1bCF_8UhG=NIl&+}nM^r=h*+vya2YHn%Zh?NxQ0<Pl zSB~>3a#~Bwz;R}S95wg5OzWZ0xB0FG4qXBshs1{hk%Ctx^}L4FbBYvD@q!H6=gzh3 zC8L*X8`qnvF#M4q(}YaUs0T|~2DGFk163b5XGbvusfO$*2!d}O&7t{2VeiuZjD?ml z-fcouR|On60=s&CX62B=$uc?t8`=>r+~iGEA@~?wva0xqRi#Fz4S?^THj?hjeD=a? zWxe|Lt{7Bwc0}7T7Ru_Zg6=KtOk6fv;=VT@5(+&anv4%#_FKfc%eg1UUfZkE=)TcP zj|KjcKiWJ-hjJPZub3%d84PD`1wk=pM4cnKeO*fs$z9!cK5)}enBU+~3Y3&>_{EOe zy{VF9VC{ficYLMay;cgYS&_7&1gSq?t+6#{ixU<8zBy$Er2_Vlq+%jR^89o{tQB_o zPs=ALIJnOGiP}NgI}jgT^S1oQQk_^rhm|x8N>*&*LWlLS&*GgX6EP<5-#ld#7L0~3 zQ^aOQ4#-Ef(tLKA_9?_l5+`<^hW$p1$6o*i<aR1{E!whJ&v&oDm;M$@i?tRj&)DH| zq=oZ%RgtuzpTJjQugjLg6?aj$-8agaJ_}MU4=h5h6rX>GL(rBRP279bzQb9B#|^qM z0n#PQJx!N^B68Klyg%V*OH!6ECue_#13lQ}GhYncS)^Y@H3+Zv)vf&=5$8jX_o(#) z_#4%nh#i7Hj}4b52WggQf&(OYm`#5U{K<|9PYvq6K5)8Og>rF)nysnQ@ph`ZX%t^X zkJpWm{AI{U-QHUfLxjsM)MZJf@i+jBD&SBHDHtlSn1xMlyxB!ekOxypM9{_Orbh1R zow(k`a&2qs9R|T`*N|+(ifEtJ?EOwRA$Pw|@~zwU^vaPtwFD8o?7X!VwAsQiXZ%|4 z!k><$N!@nIaW$t^0?&MkVHpX{ua{om6IT`NoA!Po@qpXNgB8^`;B`Y&KI8NUIIZyt z^LP!!hA&jmwz+t_;WV)v*czJvRWD{ml5y?L+(gRm>7yvMsA&6y^jk3B+<fS}j*kss zp9;7(kjCVY-TcTi$05x?)8j@tz{Gg;soEV^v%VB8yct=0k&i!c()UD=U{!GG6V7)+ z)p{y<7T>lo7Rf)N(I7bg^wX%Px!&M$)1m72Ca&RbwW?JlmeD78O}eD#8;y+x(vf>L zexakm1aPdx4{K6KE4pdaB`^~Nk8-KMo~ZBX7;rz(nN2MJhV<8Fw+j7c@VP<yt~;+q zF?i(y<a&OS>pD-L`o()U|B*0ks>H%ptmUBK+wa>=+^{>JwXi#045#a)L4%5{A3s7E zvN*9!-|g(IvAU(JJx$ZLZMA(1L-RbY5~l+hyg4dO?eRt@{%kTN=^7DIUQz#~;S|L? zb|HIeuIOWI{;jS$1%pXQs5}BRA9B2~z0&dl_8yH6%Dn6Ci#@fB0BM%-ry2cw8;`;Y z9b(^~`dP2vU)fP)C`NL4!gByHkBHE0Gxkr2=7Tg!D^?gMb@hXPKH9baGGv&>e~3%2 zuhORb{^C=iK{jvd2a*B*T51e!nnV=G084>an+qO-0z;gN1@;v;UR<wbh*{59n+xs5 z^-?fIe#L&6WQF8rsLGpHe~<jd?#u4OdBwOFyUz_y@9fp?6MwP$gkzas?LG=@Jz@RR zH*H&g?Y_6q{J)(ouw#SJclfW}NBYe0Vm*JoMlD~2pnhIJ>R-E0_?gkdB0j!iqwhuJ z7HJ&%zlTHoL95s5V}b4t>$Tgndi$?usos{;XSjA*v-@`jhosGf3R%by{#E7Ni%Jk& z<-=<L)Qd{rzPGPf^P<uNRqyUqCG3kzKrHF2O5+!mmqcxsuPTvWR07CE{#vUqDi8R5 z4-5V+9@qg8{rdNG+Rv)yJOB%SRSG>bL<sU<l}!M2#F{HWUFNHc>HEx3Z*l!!(fRp0 zjgKKL1z+zI@XW9zEYPob@O+&^%TTl4uSy}F`TtqrD^Cy&pIB>k9b<`KJ`YKW$%&Q= H>-ql|Z6=Pu diff --git a/docs/images/set-ci-status.png b/docs/images/set-ci-status.png new file mode 100644 index 0000000000000000000000000000000000000000..c5a66dfd59690fe3031ee676e798ac538008fff7 GIT binary patch literal 131884 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 V9`^WD$>G|ed$-O0s4#GO_Fp<C<5mCw diff --git a/docs/images/side-by-side-diff.png b/docs/images/side-by-side-diff.png new file mode 100644 index 0000000000000000000000000000000000000000..703084e5cc9168b40db6a22acd5250321bb247b8 GIT binary patch literal 253452 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 T}MylCeucq{kHzuLRji}78{ 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%0A5SedQ;} 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 diff --git a/docs/images/tokens.png b/docs/images/tokens.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb6d7b2c057b726f698b05e4d5df2ecc99bcbfe GIT binary patch literal 106011 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 vhRgoH+`^>=+knQMPg3C`bq|x9BLVwkG-&w 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 diff --git a/docs/images/update-pr-button.png b/docs/images/update-pr-button.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb1146bc76a41cd08b0806cb65165cd69e5fe9a GIT binary patch literal 85217 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%0DKW@^? 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\xRDCXfV~xC; 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 diff --git a/docs/images/update-prs-ui.png b/docs/images/update-prs-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..ae95cda3687bcb7fa9db4e465920f0a5de7be24e GIT binary patch literal 47277 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 aA{CqAu6&ovLHg(Kl9yJIs+IT>_WuBIL<Fk< diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,84 @@ +|RCM| +===== + +|RCM| is a high-performance source code management and collaboration system. +It enables you to develop projects securely behind the firewall while +providing collaboration tools that work with |git|, |hg|, +and |svn| |repos|. The user interface allows you to create, edit, +and commit files and |repos| while managing their security permissions. + +|RCM| provides the following features: + +* Source code management. +* Extended permissions management. +* Integrated code collaboration tools. +* Integrated code review and notifications. +* Scalability provided by multi-node setup. +* Fully programmable automation API. +* Web-based hook management. +* Native |svn| support. +* Migration from existing databases. +* |RCM| SDK. +* Built-in analytics +* Pluggable authentication system. +* Support for |LDAP|, Crowd, CAS, PAM. +* Debug modes of operation. +* Private and public gists. +* Gists with limited lifetimes and within instance only sharing. +* Fully integrated code search function. +* Always on SSL connectivity. + +.. only:: html + + Table of Contents + ----------------- + +.. toctree:: + :maxdepth: 1 + :caption: Admin Documentation + + install/quick-start + install/install-database + install/install-steps + admin/system-overview + nix/default-env + admin/system-admin + admin/user-admin + admin/setting-repo-perms + admin/security-tips + auth/auth + issue-trackers/issue-trackers + admin/lab-settings + +.. toctree:: + :maxdepth: 1 + :caption: Feature Documentation + + collaboration/collaboration + collaboration/review-notifications + collaboration/pull-requests + code-review/code-review + +.. toctree:: + :maxdepth: 1 + :caption: Developer Documentation + + api/api + tools/rhodecode-tools + integrations/integrations + contributing/contributing + +.. toctree:: + :maxdepth: 1 + :caption: User Documentation + + usage/basic-usage + tutorials/tutorials + +.. toctree:: + :maxdepth: 1 + :caption: About + + known-issues/known-issues + release-notes/release-notes + admin/glossary diff --git a/docs/install/database-string.rst b/docs/install/database-string.rst new file mode 100644 --- /dev/null +++ b/docs/install/database-string.rst @@ -0,0 +1,38 @@ +.. _config-database: + +Make Database Changes +--------------------- + +.. important:: + + If you do change the |repo| database that |RCM| uses, then you will need to + upgrade the database, and also remap and rescan the |repos|. More detailed + information is available in the + :ref:`Alternative upgrade documentation <control:install-port>`. + +If you need to change database connection details for a |RCM| instance, +use the following steps: + +1. Open the :file:`rhodecode.ini` file for the instance you wish to edit. The + default location is + :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` +2. When you open the file, find the database configuration section, + and use the below example to change the + connection details: + +.. code-block:: ini + + ######################################################### + ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### + ######################################################### + + # Default SQLite config + sqlalchemy.db1.url = sqlite:////home/brian/.rccontrol/enterprise-1/rhodecode.db + + # Use this example for a PostgreSQL + sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode + + # see sqlalchemy docs for other advanced settings + sqlalchemy.db1.echo = false + sqlalchemy.db1.pool_recycle = 3600 + sqlalchemy.db1.convert_unicode = true diff --git a/docs/install/install-celery.rst b/docs/install/install-celery.rst new file mode 100644 --- /dev/null +++ b/docs/install/install-celery.rst @@ -0,0 +1,71 @@ + +.. _config-celery: + +Install Celery +-------------- + +To improve |RCM| performance you should install Celery_ as it makes +asynchronous tasks work efficiently. If you +install Celery you also need multi-broker support. The recommended message +broker is rabbitmq_. |RCM| works in sync +mode, but running Celery_ will give you a large speed improvement when +managing many big repositories. + +If you want to run |RCM| with Celery you need to run ``celeryd`` using the +``paster`` command and the message broker. +The ``paster`` command is already installed during |RCM| installation. + +To install and configure Celery, use the following steps: + +1. Install Celery and RabbitMQ, see the documentation on the Celery website for + `Celery installation`_ and `rabbitmq installation`_. +2. Enable Celery in the + :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. +3. Run the Celery daemon with the ``paster`` command, + using the following example + ``.rccontrol/enterprise-1/profile/bin/paster celeryd .rccontrol/enterprise-1/rhodecode.ini`` + +.. code-block:: ini + + # Set this section of the ini file to match your Celery installation + #################################### + ### CELERY CONFIG #### + #################################### + ## Set to true + use_celery = false + broker.host = localhost + broker.vhost = rabbitmqhost + broker.port = 5672 + broker.user = rabbitmq + broker.password = qweqwe + + celery.imports = rhodecode.lib.celerylib.tasks + + celery.result.backend = amqp + celery.result.dburi = amqp:// + celery.result.serialier = json + + #celery.send.task.error.emails = true + #celery.amqp.task.result.expires = 18000 + + celeryd.concurrency = 2 + #celeryd.log.file = celeryd.log + celeryd.log.level = debug + celeryd.max.tasks.per.child = 1 + + ## tasks will never be sent to the queue, but executed locally instead. + celery.always.eager = false + +.. code-block:: bash + + # Once the above is configured and saved + # Run celery with the paster command and specify the ini file + .rccontrol/enterprise-1/profile/bin/paster celeryd .rccontrol/enterprise-1/rhodecode.ini + +.. _python: http://www.python.org/ +.. _mercurial: http://mercurial.selenic.com/ +.. _celery: http://celeryproject.org/ +.. _rabbitmq: http://www.rabbitmq.com/ +.. _rabbitmq installation: http://docs.celeryproject.org/en/latest/getting-started/brokers/rabbitmq.html +.. _Celery installation: http://docs.celeryproject.org/en/latest/getting-started/introduction.html#bundles +.. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ diff --git a/docs/install/install-database.rst b/docs/install/install-database.rst new file mode 100644 --- /dev/null +++ b/docs/install/install-database.rst @@ -0,0 +1,68 @@ +.. _rhodecode-database-ref: + +Supported Databases +=================== + +.. important:: + + We do not recommend using SQLite in a production environment. It is + supported by |RCE| for evaluation purposes. + +Database Overview +----------------- + +Prior to installing |RCE| you should install and set up your database. +This means carrying out the following tasks: + +1. Install the database software of your choice. +2. Using the relevant instructions, create a user on that database to use + with |RCE|. +3. Create a database, granting that user read/write access. +4. During |RCE| installation you will be prompted for these user credentials, + enter them where appropriate. These credentials will be what |RCE| uses + to read/write from the database tables. + +Version Differences +------------------- + +|RCE| releases 2(Major).x(Minor).x(Bug Fix) and 3.x.x use different database +schemas. Therefore, if you wish to run multiple instances using one database, +you can only do so using the same Minor Release numbered versions. +Though Bug Fix updates rarely have a database change, it is recommended to use +identical |RCE| version numbers for multi-instance setups. + +You can use the same database server to run multiple databases for differing +version numbers, but you will need separate databases for each |RCE| version on +that server. You can specify the database during installation, use the +following example to configure the correct one. + +.. code-block:: bash + + Database type - [s]qlite, [m]ysql, [p]ostresql: + PostgreSQL selected + Database host [127.0.0.1]: + Database port [5432]: + Database username: rhodecode + Database password: somepassword + # Specify the database you with to use on that server + # for the RCE instance you are installing + Database name: example-db-name-for-2xx # The 2xx version database + Database name: example-db-name-for-3xx # The 3xx version database + +Supported Databases +------------------- + +|RCM| supports the following databases. The recommended encoding is Unicode +UTF-8. + +.. only:: latex + + * :ref:`install-sqlite-database` + * :ref:`install-mysql-database` + * :ref:`install-postgresql-database` + +.. toctree:: + + using-mysql + using-postgresql + using-sqllite diff --git a/docs/install/install-steps.rst b/docs/install/install-steps.rst new file mode 100644 --- /dev/null +++ b/docs/install/install-steps.rst @@ -0,0 +1,14 @@ +.. _rhodecode-post-instal-ref: + +Post Installation Tasks +======================= + +The following tasks are the most common post installation requirements. Use +the information in these sections to configure your instance of |RCM|. + +.. toctree:: + + setup-email + database-string + install-celery + migrate-repos diff --git a/docs/install/migrate-repos.rst b/docs/install/migrate-repos.rst new file mode 100644 --- /dev/null +++ b/docs/install/migrate-repos.rst @@ -0,0 +1,23 @@ +.. _mig-repos: + +Migrating |repos| +----------------- + +If you have installed |RCM| and have |repos| that you wish to migrate into +the system, use the following instructions. + +1. On the |RCM| interface, check your |repo| storage location under + :menuselection:`Admin --> Settings --> System Info`. For example, + Storage location: /home/{username}/repos. + +2. Copy the |repos| that you want |RCM| to manage to this location. +3. Remap and rescan the |repos|, see :ref:`remap-rescan` + +.. important:: + + Directories create |repo| groups inside |RCM|. + + Importing adds |RCM| git hooks to your |repos|. + + You should verify if custom ``.hg`` or ``.hgrc`` files inside + repositories should be adjusted since |RCM| reads the content of them. diff --git a/docs/install/quick-start.rst b/docs/install/quick-start.rst new file mode 100644 --- /dev/null +++ b/docs/install/quick-start.rst @@ -0,0 +1,102 @@ +.. _quick-start: + +Quick Start Guide +================= + +.. important:: + + These are quick start instructions. To optimize your |RCE|, + |RCC|, and |RCT| usage, read the more detailed instructions in our guides. + For detailed installation instructions, see + :ref:`RhodeCode Control Documentation <control:rcc>` + +.. tip:: + + If using a non-SQLite database, install and configure the database, create + a new user, and grant permissions. You will be prompted for this user's + credentials during |RCE| installation. See the relevant database + documentation for more details. + +To get |RCM| up and running, run through the below steps: + +1. Download the latest |RCC| installer from your `rhodecode.com`_ profile + page. If you don't have an account, sign up at `rhodecode.com/register`_. +2. Run the |RCC| installer and accept the End User Licence using the + following example: + +.. code-block:: bash + + $ chmod 755 RhodeCode-installer-linux-* + $ ./RhodeCode-installer-linux-* + +3. Install a VCS Server, and configure it to start at boot. + +.. code-block:: bash + + $ rccontrol install VCSServer + + Agree to the licence agreement? [y/N]: y + IP to start the server on [127.0.0.1]: + Port for the server to start [10005]: + Creating new instance: vcsserver-1 + Installing RhodeCode VCSServer + Configuring RhodeCode VCS Server ... + Supervisord state is: RUNNING + Added process group vcsserver-1 + + +4. Install |RCE|. If using MySQL or PostgreSQL, during installation you'll be + asked for your database credentials, so have them at hand. You don't need + any for SQLite. + +.. code-block:: bash + :emphasize-lines: 11-16 + + $ rccontrol install Enterprise + + Username [admin]: username + Password (min 6 chars): + Repeat for confirmation: + Email: your@mail.com + Respositories location [/home/brian/repos]: + IP to start the Enterprise server on [127.0.0.1]: + Port for the Enterprise server to use [10004]: + Database type - [s]qlite, [m]ysql, [p]ostresql: + PostgreSQL selected + Database host [127.0.0.1]: + Database port [5432]: + Database username: db-user-name + Database password: somepassword + Database name: example-db-name + +5. Check the status of your installation. You |RCE| instance runs on the URL + displayed in the status message. + +.. code-block:: bash + + $ rccontrol status + + - NAME: enterprise-1 + - STATUS: RUNNING + - TYPE: Enterprise + - VERSION: 3.3.0 + - URL: http://127.0.0.1:10003 + + - NAME: vcsserver-1 + - STATUS: RUNNING + - TYPE: VCSServer + - VERSION: 3.3.0 + - URL: http://127.0.0.1:10001 + +.. note:: + + Recommended post quick start install instructions: + + * Read the documentation + * Carry out the :ref:`rhodecode-post-instal-ref` + * Set up :ref:`indexing-ref` + * Familiarise yourself with the :ref:`rhodecode-admin-ref` section. + +.. _rhodecode.com/download/: https://rhodecode.com/download/ +.. _rhodecode.com: https://rhodecode.com/ +.. _rhodecode.com/register: https://rhodecode.com/register/ diff --git a/docs/install/setup-email.rst b/docs/install/setup-email.rst new file mode 100644 --- /dev/null +++ b/docs/install/setup-email.rst @@ -0,0 +1,34 @@ +.. _set-up-mail: + +Set up Email +------------ + +To setup email with your |RCM| instance, open the default +:file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` +file and uncomment and configure the email section. If it is not there, +use the below example to insert it. + +Once configured you can check the settings for your |RCM| instance on the +:menuselection:`Admin --> Settings --> Email` page. + +.. code-block:: ini + + ################################################################################ + ## Uncomment and replace with the email address which should receive ## + ## any error reports after an application crash ## + ## Additionally these settings will be used by the RhodeCode mailing system ## + ################################################################################ + #email_to = admin@localhost + #error_email_from = paste_error@localhost + #app_email_from = rhodecode-noreply@localhost + #error_message = + #email_prefix = [RhodeCode] + + #smtp_server = mail.server.com + #smtp_username = + #smtp_password = + #smtp_port = + #smtp_use_tls = false + #smtp_use_ssl = true + ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.) + #smtp_auth = diff --git a/docs/install/using-mysql.rst b/docs/install/using-mysql.rst new file mode 100644 --- /dev/null +++ b/docs/install/using-mysql.rst @@ -0,0 +1,26 @@ +.. _install-mysql-database: + +MySQL or MariaDB +---------------- + +To use a MySQL or MariaDB database you should install and configure the +database before installing |RCM|. This is because during |RCM| installation +you will setup a connection to your MySQL or MariaDB database. To work with +either, use the following steps: + +1. Depending on your |os|, install a MySQL or MariaDB database following the + appropriate instructions from the `MySQL website`_ or `MariaDB website`_. +2. Configure the database with a username and password which you will use + with |RCM|. +3. Install |RCM|, and during installation select MySQL as your database. +4. Enter the following information during the database setup: + + * Your network IP Address + * The port number for MySQL or MariaDB access. + The default port for both is ``3306`` + * Your database username + * Your database password + * A new database name + +.. _MySQL website: http://www.mysql.com/ +.. _MariaDB website: https://mariadb.com/ diff --git a/docs/install/using-postgresql.rst b/docs/install/using-postgresql.rst new file mode 100644 --- /dev/null +++ b/docs/install/using-postgresql.rst @@ -0,0 +1,24 @@ +.. _install-postgresql-database: + +PostgreSQL +---------- + +To use a PostgreSQL database you should install and configurevthe database +before installing |RCV|. This is becausevduring |RCV| installation you will +setup a connection to your PostgreSQL database. To work with PostgreSQL, +use the following steps: + +1. Depending on your |os|, install avPostgreSQL database following the + appropriate instructions from the `PostgreSQL website`_. +2. Configure the database with a username and password which you will use + with |RCV|. +3. Install |RCV|, and during installation select PostgreSQL as your database. +4. Enter the following information to during the database setup: + + * Your network IP Address + * The port number for MySQL access. The default MySQL port is ``5434`` + * Your database username + * Your database password + * A new database name + +.. _PostgreSQL website: http://www.postgresql.org/ diff --git a/docs/install/using-sqllite.rst b/docs/install/using-sqllite.rst new file mode 100644 --- /dev/null +++ b/docs/install/using-sqllite.rst @@ -0,0 +1,32 @@ +.. _install-sqlite-database: + +SQLite +------ + +.. important:: + + We do not recommend using SQLite in a large development environment + as it has an internal locking mechanism which can become a performance + bottleneck when there are more than 5 concurrent users. + +|RCM| installs SQLite as the default database if you do not specify another +during installation. SQLite is suitable for small teams, +projects with a low load, and evaluation purposes since it is built into +|RCM| and does not require any additional database server. + +Using MySQL or PostgreSQL in an large setup gives you much greater +performance, and while migration tools exist to move from one database type +to another, it is better to get it right first time and to immediately use +MySQL or PostgreSQL when you deploy |RCM| in a production environment. + +Migrating From SQLite to PostgreSQL +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you started working with SQLite and now need to migrate your database +to PostgreSQL, you can contact support@rhodecode.com for some help. We have a +set of scripts that enable SQLite to PostgreSQL migration. These scripts have +been tested, and work with PostgreSQL 9.1+. + +.. note:: + + There are no SQLite to MySQL or MariaDB scripts available. diff --git a/docs/integrations/config-ext.rst b/docs/integrations/config-ext.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/config-ext.rst @@ -0,0 +1,150 @@ +.. _config-ext: + +Configure |RCX| +--------------- + +To get the the built in plugins and extensions working the way you want them +to, you have to configure them to work with your services. An overview of +what needs to be done is: + +* :ref:`config-rcx-plugin` to carry out your desired actions once its hook is + triggered. There are default actions built in, but you may wish to alter + those. +* :ref:`config-rcx-hook` to execute actions for the plugin, when certain + actions are carried out with |RCE|. + +.. _config-rcx-plugin: + +Tweak a Default Plugin +^^^^^^^^^^^^^^^^^^^^^^ + +Each of the default plugins comes with a standard configuration, but you may +wish to change those settings. In this example, the Redmine plugin watches +for the words defined in the ``HASH_REGEX`` variable and takes actions if one +of those words is used in conjunction with a ``#{number}``, which matches a +ticket number in Redmine. You can configure this to work differently based on +the `Redmine documentation`_. + +.. code-block:: python + :emphasize-lines: 3-5, 37 + + import re + + HASH_REGEX = re.compile( + r"(?:fix|fixes|fixing|close|closes|closing)\s*#([0-9]+)\b", + re.IGNORECASE) + + + def link_to_commit(repo_url, commit_id): + rev_url = '%s/changeset/%s' % (repo_url, commit_id) + return '"%s":%s' % (commit_id[:6], rev_url) + + + def run(*args, **kwargs): + issues = kwargs['RM_ISSUES'] + if not issues: + return 0 + + # repo extra fields can control this, they should be propagated with + # extract repo fields + tracker_url = kwargs.get('redmine_tracker_url') or kwargs['RM_URL'] + project_id = kwargs.get('redmine_project_id') or kwargs['RM_PROJECT'] + api_key = kwargs.get('redmine_api_key') or kwargs['RM_APIKEY'] + + if project_id: + from redmine import Redmine + remote_redmine = Redmine(tracker_url, key=api_key) + project = remote_redmine.project.get(project_id) + repo_url = '%(server_url)s/%(repository)s' % kwargs + # for each fetched issue id make a redmine api call + for _id, details in issues.items(): + commits = ', '.join([link_to_commit(repo_url, + x['raw_id'],) + for x in details]) + issue = project.issues.get(int(_id)) + if issue: + issue.notes = 'Issue resolved by %s' % (commits,) + issue.status_id = 3 # Resolved + issue.save() + + +.. _config-rcx-hook: + +Configure a Hook +^^^^^^^^^^^^^^^^ + +To configure the default hooks in the +:file:`/home/{user}/.rccontrol/{instance-id}/rcextensions/__init.py__` file, +use the following steps. + +1. Configure the connection details, either in the file or import from a + dictionary. For these connection scenarios the following details need to + be configured. + +* **REDMINE_URL** = '<redmine-url>' +* **REDMINE_API_KEY** = '<secret>' +* **SLACK_API_URL** = '<slack-url>?token=<secret>' +* **SLACK_API_KEY** = '<secret>' + +2. You will also need to configure other variables, such as the + **SLACK_ROOM** or **RM_PROJECT** (Redmine Project). These set where the + commit message is posted. Various hooks can take different variables and + they are documented in the file. + +3. Inside each hook you can then configure it to carry out actions + per service. In this example, the push hook is pushing to the Redmine and + Slack plugins on each push if the hook criteria are matched. + +.. code-block:: python + :emphasize-lines: 21-29, 37-44 + + def _push_hook(*args, **kwargs): + kwargs['commit_ids'] = kwargs['pushed_revs'] + + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside + # the database per repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # fetch pushed commits + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # slack ! + call = load_extension('slack.py') + if call: + kwargs['INCOMING_WEBHOOK_URL'] = SLACK_API_URL + kwargs['SLACK_TOKEN'] = SLACK_API_KEY + kwargs['SLACK_ROOM'] = '#slack-channel' + kwargs['SLACK_FROM'] = 'Slack-Message-Poster' + kwargs['SLACK_FROM_ICON_EMOJI'] = ':slack-emoji:' + call(**kwargs) + + # fetch issues from given commits + call = load_extension('extract_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart commits + call = load_extension('redmine_smart_commits.py') + if call: + kwargs['RM_URL'] = REDMINE_URL + kwargs['RM_APIKEY'] = REDMINE_API_KEY + kwargs['RM_PROJECT'] = None # uses extra_fields from repo + kwargs['RM_ISSUES'] = issues + call(**kwargs) + + return 0 + PUSH_HOOK = _push_hook + + +.. _Redmine documentation: http://www.redmine.org/projects/redmine/wiki/Rest_api diff --git a/docs/integrations/example-ext.py b/docs/integrations/example-ext.py new file mode 100644 --- /dev/null +++ b/docs/integrations/example-ext.py @@ -0,0 +1,823 @@ +""" +rcextensions module. + +""" + + +import os +import imp +import string +import functools + +here = os.path.dirname(os.path.abspath(__file__)) +registered_extensions = dict() + +class DotDict(dict): + + def __contains__(self, k): + try: + return dict.__contains__(self, k) or hasattr(self, k) + except: + return False + + # only called if k not found in normal places + def __getattr__(self, k): + try: + return object.__getattribute__(self, k) + except AttributeError: + try: + return self[k] + except KeyError: + raise AttributeError(k) + + def __setattr__(self, k, v): + try: + object.__getattribute__(self, k) + except AttributeError: + try: + self[k] = v + except: + raise AttributeError(k) + else: + object.__setattr__(self, k, v) + + def __delattr__(self, k): + try: + object.__getattribute__(self, k) + except AttributeError: + try: + del self[k] + except KeyError: + raise AttributeError(k) + else: + object.__delattr__(self, k) + + def toDict(self): + return unserialize(self) + + def __repr__(self): + keys = list(self.iterkeys()) + keys.sort() + args = ', '.join(['%s=%r' % (key, self[key]) for key in keys]) + return '%s(%s)' % (self.__class__.__name__, args) + + @staticmethod + def fromDict(d): + return serialize(d) + + +def serialize(x): + if isinstance(x, dict): + return DotDict((k, serialize(v)) for k, v in x.iteritems()) + elif isinstance(x, (list, tuple)): + return type(x)(serialize(v) for v in x) + else: + return x + + +def unserialize(x): + if isinstance(x, dict): + return dict((k, unserialize(v)) for k, v in x.iteritems()) + elif isinstance(x, (list, tuple)): + return type(x)(unserialize(v) for v in x) + else: + return x + + +def load_extension(filename, async=False): + """ + use to load extensions inside rcextension folder. + for example:: + + callback = load_extension('email.py', async=False) + if callback: + callback('foobar') + + put file named email.py inside rcextensions folder to load it. Changing + async=True will make the call of the plugin async, it's useful for + blocking calls like sending an email or notification with APIs. + """ + mod = ''.join(filename.split('.')[:-1]) + loaded = imp.load_source(mod, os.path.join(here, filename)) + + callback = getattr(loaded, 'run', None) + if not callback: + raise Exception('Plugin missing `run` method') + if async: + # modify callback so it's actually an async call + def _async_callback(*args, **kwargs): + import threading + thr = threading.Thread(target=callback, args=args, kwargs=kwargs) + thr.start() + if kwargs.get('_async_block'): + del kwargs['_async_block'] + thr.join() + + return _async_callback + return callback + + +def _verify_kwargs(expected_parameters, kwargs): + """ + Verify that exactly `expected_parameters` are passed in as `kwargs`. + """ + expected_parameters = set(expected_parameters) + kwargs_keys = set(kwargs.keys()) + if kwargs_keys != expected_parameters: + missing_kwargs = expected_parameters - kwargs_keys + unexpected_kwargs = kwargs_keys - expected_parameters + raise AssertionError( + "Missing parameters: %r, unexpected parameters: %s" % + (missing_kwargs, unexpected_kwargs)) + + +def verify_kwargs(required_args): + """ + decorator to verify extension calls arguments. + + :param required_args: + """ + def wrap(func): + def wrapper(*args, **kwargs): + _verify_kwargs(required_args, kwargs) + return func(*args, **kwargs) + return wrapper + return wrap + + +def register(name=None): + def wrap(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + # register load_extensions in kwargs, so we can chain plugins + kwargs['_load_extension'] = load_extension + # append this path for us to use added plugins or modules + import sys + _cur_path = os.path.dirname(os.path.abspath(__file__)) + if _cur_path not in sys.path: + sys.path.append(_cur_path) + + registered_extensions[func.__name__] = func + return func(*args, **kwargs) + return wrapper + return wrap + +# ============================================================================= +# END OF UTILITY FUNCTIONS HERE +# ============================================================================= + +# Additional mappings that are not present in the pygments lexers +# used for building stats +# format is {'ext':['Names']} eg. {'py':['Python']} note: there can be +# more than one name for extension +# NOTE: that this will override any mappings in LANGUAGES_EXTENSIONS_MAP +# build by pygments +EXTRA_MAPPINGS = {} + +# additional lexer definitions for custom files it's overrides pygments lexers, +# and uses defined name of lexer to colorize the files. Format is {'ext': +# 'lexer_name'} List of lexers can be printed running: +# >> python -c "import pprint;from pygments import lexers; +# pprint.pprint([(x[0], x[1]) for x in lexers.get_all_lexers()]);" + +EXTRA_LEXERS = {} + + +CONFIG = DotDict( + slack=DotDict( + api_key='api-key', + api_url='slack-incoming-hook-url', + default_room='#slack-channel', + default_plugin_config={}, + ), + redmine=DotDict( + api_key='api-key', + default_tracker_url='https://redmine.tracker.url', + default_project_id=None, + default_status_resolved_id=3 + ), +) + +# slack conf +CONFIG.slack.default_plugin_config = { + 'INCOMING_WEBHOOK_URL': CONFIG.slack.api_url, + 'SLACK_TOKEN': CONFIG.slack.api_key, + 'SLACK_ROOM': CONFIG.slack.default_room, + 'SLACK_FROM': 'RhodeCode', + 'SLACK_FROM_ICON_EMOJI': ':rhodecode:', +} + +# redmine smart_pr configuration +def configure_redmine_smart_pr(issues, kwargs): + kwargs['REDMINE_ISSUES'] = issues + kwargs['redmine_tracker_url'] = kwargs.pop( + 'redmine_tracker_url', '') or CONFIG.redmine.default_tracker_url + kwargs['redmine_api_key'] = kwargs.pop( + 'redmine_api_key', '') or CONFIG.redmine.api_key + kwargs['redmine_project_id'] = kwargs.pop( + 'redmine_project_id', '') or CONFIG.redmine.default_project_id + + +@register('CREATE_REPO_HOOK') +@verify_kwargs( + ['_load_extension', 'repo_name', 'repo_type', 'description', 'private', + 'created_on', 'enable_downloads', 'repo_id', 'user_id', 'enable_statistics', + 'clone_uri', 'fork_id', 'group_id', 'created_by']) +def _create_repo_hook(*args, **kwargs): + """ + POST CREATE REPOSITORY HOOK. This function will be executed after + each repository is created. kwargs available: + + :param repo_name: + :param repo_type: + :param description: + :param private: + :param created_on: + :param enable_downloads: + :param repo_id: + :param user_id: + :param enable_statistics: + :param clone_uri: + :param fork_id: + :param group_id: + :param created_by: + """ + return 0 +CREATE_REPO_HOOK = _create_repo_hook + + +@register('CREATE_REPO_GROUP_HOOK') +@verify_kwargs( + ['_load_extension', 'group_name', 'group_parent_id', 'group_description', + 'group_id', 'user_id', 'created_by', 'created_on', 'enable_locking']) +def _create_repo_group_hook(*args, **kwargs): + """ + POST CREATE REPOSITORY GROUP HOOK, this function will be + executed after each repository group is created. kwargs available: + + :param group_name: + :param group_parent_id: + :param group_description: + :param group_id: + :param user_id: + :param created_by: + :param created_on: + :param enable_locking: + """ + return 0 +CREATE_REPO_GROUP_HOOK = _create_repo_group_hook + + +@register('PRE_CREATE_USER_HOOK') +@verify_kwargs( + ['_load_extension', 'username', 'password', 'email', 'firstname', + 'lastname', 'active', 'admin', 'created_by']) +def _pre_create_user_hook(*args, **kwargs): + """ + PRE CREATE USER HOOK, this function will be executed before each + user is created, it returns a tuple of bool, reason. + If bool is False the user creation will be stopped and reason + will be displayed to the user. kwargs available: + + :param username: + :param password: + :param email: + :param firstname: + :param lastname: + :param active: + :param admin: + :param created_by: + """ + + reason = 'allowed' + return True, reason +PRE_CREATE_USER_HOOK = _pre_create_user_hook + + +@register('CREATE_USER_HOOK') +@verify_kwargs( + ['_load_extension', 'username', 'full_name_or_username', 'full_contact', + 'user_id', 'name', 'firstname', 'short_contact', 'admin', 'lastname', + 'ip_addresses', 'extern_type', 'extern_name', 'email', 'api_key', + 'api_keys', 'last_login', 'full_name', 'active', 'password', 'emails', + 'inherit_default_permissions', 'created_by', 'created_on']) +def _create_user_hook(*args, **kwargs): + """ + POST CREATE USER HOOK, this function will be executed after each user is created + kwargs available: + + :param username: + :param full_name_or_username: + :param full_contact: + :param user_id: + :param name: + :param firstname: + :param short_contact: + :param admin: + :param lastname: + :param ip_addresses: + :param extern_type: + :param extern_name: + :param email: + :param api_key: + :param api_keys: + :param last_login: + :param full_name: + :param active: + :param password: + :param emails: + :param inherit_default_permissions: + :param created_by: + :param created_on: + """ + return 0 +CREATE_USER_HOOK = _create_user_hook + + +@register('DELETE_REPO_HOOK') +@verify_kwargs( + ['_load_extension', 'repo_name', 'repo_type', 'description', 'private', + 'created_on', 'enable_downloads', 'repo_id', 'user_id', 'enable_statistics', + 'clone_uri', 'fork_id', 'group_id', 'deleted_by', 'deleted_on']) +def _delete_repo_hook(*args, **kwargs): + """ + POST DELETE REPOSITORY HOOK, this function will be executed after + each repository deletion kwargs available: + + :param repo_name: + :param repo_type: + :param description: + :param private: + :param created_on: + :param enable_downloads: + :param repo_id: + :param user_id: + :param enable_statistics: + :param clone_uri: + :param fork_id: + :param group_id: + :param deleted_by: + :param deleted_on: + """ + return 0 +DELETE_REPO_HOOK = _delete_repo_hook + + +@register('DELETE_USER_HOOK') +@verify_kwargs( + ['_load_extension', 'username', 'full_name_or_username', 'full_contact', + 'user_id', 'name', 'firstname', 'short_contact', 'admin', 'lastname', + 'ip_addresses', 'email', 'api_key', 'last_login', 'full_name', 'active', + 'password', 'emails', 'inherit_default_permissions', 'deleted_by' + ]) +def _delete_user_hook(*args, **kwargs): + """ + POST DELETE USER HOOK, this function will be executed after each + user is deleted kwargs available: + + :param username: + :param full_name_or_username: + :param full_contact: + :param user_id: + :param name: + :param firstname: + :param short_contact: + :param admin: + :param lastname: + :param ip_addresses: + :param ldap_dn: + :param email: + :param api_key: + :param last_login: + :param full_name: + :param active: + :param password: + :param emails: + :param inherit_default_permissions: + :param deleted_by: + """ + return 0 +DELETE_USER_HOOK = _delete_user_hook + + +@register('PRE_PUSH_HOOK') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', + 'ip', 'action', 'repository', 'repo_store_path']) +def _pre_push_hook(*args, **kwargs): + """ + Post push hook + kwargs available: + + :param server_url: url of instance that triggered this hook + :param config: path to .ini config used + :param scm: type of VS 'git' or 'hg' + :param username: name of user who pushed + :param ip: ip of who pushed + :param action: push + :param repository: repository name + :param repo_store_path: full path to where repositories are stored + """ + return 0 +PRE_PUSH_HOOK = _pre_push_hook + + +@register('PUSH_HOOK') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', + 'ip', 'action', 'repository', 'repo_store_path', 'pushed_revs']) +def _push_hook(*args, **kwargs): + """ + POST PUSH HOOK, this function will be executed after each push it's + executed after the build-in hook that RhodeCode uses for logging pushes + kwargs available: + + :param server_url: url of instance that triggered this hook + :param config: path to .ini config used + :param scm: type of VS 'git' or 'hg' + :param username: name of user who pushed + :param ip: ip of who pushed + :param action: push + :param repository: repository name + :param repo_store_path: full path to where repositories are stored + :param pushed_revs: list of pushed commit ids + """ + # backward compat + kwargs['commit_ids'] = kwargs['pushed_revs'] + + # fetch extra fields from repository + call = load_extension('extra_fields.py') + _extra_fields = {} + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + _extra_fields[key] = data['field_value'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # slack ! + call = load_extension('slack_push_notify.py') + if call: + kwargs.update(CONFIG.slack.default_plugin_config) + call(**kwargs) + + # fetch redmine issues from given commits + call = load_extension('extract_redmine_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart commits + call = load_extension('redmine_smart_commits.py') + if call: + kwargs['REDMINE_ISSUES'] = issues + + kwargs['redmine_tracker_url'] = kwargs.pop( + 'redmine_tracker_url', '') or CONFIG.redmine.default_tracker_url + kwargs['redmine_api_key'] = kwargs.pop( + 'redmine_api_key', '') or CONFIG.redmine.api_key + kwargs['redmine_status_resolved_id'] = kwargs.pop( + 'redmine_status_resolved_id', '') or CONFIG.redmine.default_status_resolved_id + kwargs['redmine_project_id'] = kwargs.pop( + 'redmine_project_id', '') or CONFIG.redmine.default_project_id + call(**kwargs) + + return 0 +PUSH_HOOK = _push_hook + + +@register('PRE_PULL_HOOK') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository']) +def _pre_pull_hook(*args, **kwargs): + """ + Post pull hook + kwargs available:: + + :param server_url: url of instance that triggered this hook + :param config: path to .ini config used + :param scm: type of VS 'git' or 'hg' + :param username: name of user who pulled + :param ip: ip of who pulled + :param action: pull + :param repository: repository name + """ + return 0 +PRE_PULL_HOOK = _pre_pull_hook + + +@register('PULL_HOOK') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository']) +def _pull_hook(*args, **kwargs): + """ + POST PULL HOOK, this function will be executed after each push it's + executed after the build-in hook that RhodeCode uses for logging pulls + + kwargs available: + + :param server_url: url of instance that triggered this hook + :param config: path to .ini config used + :param scm: type of VS 'git' or 'hg' + :param username: name of user who pulled + :param ip: ip of who pulled + :param action: pull + :param repository: repository name + """ + return 0 +PULL_HOOK = _pull_hook + + +# ============================================================================= +# PULL REQUEST RELATED HOOKS +# ============================================================================= +@register('CREATE_PULL_REQUEST') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers']) +def _create_pull_request_hook(*args, **kwargs): + """ + + """ + # extract extra fields and default reviewers from target + kwargs['REPOSITORY'] = kwargs['target']['repository'] + + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + call = load_extension('default_reviewers.py') + if call: + # read default_reviewers key propagated from extra fields + kwargs['default_reviewers'] = map(string.strip, kwargs.pop( + 'default_reviewers', '').split(',')) + call(**kwargs) + + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # # fetch pushed commits, from commit_ids list + # call = load_extension('extract_commits.py') + # extracted_commits = {} + # if call: + # extracted_commits = call(**kwargs) + # # store the commits for the next call chain + # kwargs['COMMITS'] = extracted_commits + # + # # fetch issues from given commits + # call = load_extension('extract_redmine_issues.py') + # issues = {} + # if call: + # issues = call(**kwargs) + # + # # redmine smart pr update + # call = load_extension('redmine_pr_flow.py') + # if call: + # # updates kwargs on the fly + # configure_redmine_smart_pr(issues=issues, kwargs=kwargs) + # call(**kwargs) + # + # # slack notification on merging PR + # call = load_extension('slack_message.py') + # if call: + # kwargs.update(CONFIG.slack.default_plugin_config) + # kwargs['SLACK_ROOM'] = '#develop' + # kwargs['SLACK_MESSAGE'] = 'Pull request <%s|#%s> (%s) was created.' % ( + # kwargs.get('url'), kwargs.get('pull_request_id'), kwargs.get('title')) + # + # call(**kwargs) + + return 0 +CREATE_PULL_REQUEST = _create_pull_request_hook + + +@register('REVIEW_PULL_REQUEST') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers']) +def _review_pull_request_hook(*args, **kwargs): + """ + + """ + # extract extra fields and default reviewers from target + kwargs['REPOSITORY'] = kwargs['target']['repository'] + + # fetch extra fields + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # fetch issues from given commits + call = load_extension('extract_redmine_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart pr update + call = load_extension('redmine_pr_flow.py') + if call: + # updates kwargs on the fly + configure_redmine_smart_pr(issues=issues, kwargs=kwargs) + call(**kwargs) + + return 0 +REVIEW_PULL_REQUEST = _review_pull_request_hook + + +@register('UPDATE_PULL_REQUEST') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers']) +def _update_pull_request_hook(*args, **kwargs): + """ + + """ + # extract extra fields and default reviewers from target + kwargs['REPOSITORY'] = kwargs['target']['repository'] + + # fetch extra fields + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # fetch issues from given commits + call = load_extension('extract_redmine_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart pr updated + call = load_extension('redmine_pr_flow.py') + if call: + # updates kwargs on the fly + configure_redmine_smart_pr(issues=issues, kwargs=kwargs) + call(**kwargs) + + return 0 +UPDATE_PULL_REQUEST = _update_pull_request_hook + + +@register('MERGE_PULL_REQUEST') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers']) +def _merge_pull_request_hook(*args, **kwargs): + """ + + """ + # extract extra fields and default reviewers from target + kwargs['REPOSITORY'] = kwargs['target']['repository'] + + # fetch extra fields + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # fetch issues from given commits + call = load_extension('extract_redmine_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart pr update + call = load_extension('redmine_pr_flow.py') + if call: + # updates kwargs on the fly + configure_redmine_smart_pr(issues=issues, kwargs=kwargs) + call(**kwargs) + + # slack notification on merging PR + call = load_extension('slack_message.py') + if call: + kwargs.update(CONFIG.slack.default_plugin_config) + kwargs['SLACK_ROOM'] = '#develop' + kwargs['SLACK_MESSAGE'] = 'Pull request <%s|#%s> (%s) was merged.' % ( + kwargs.get('url'), kwargs.get('pull_request_id'), kwargs.get('title')) + call(**kwargs) + + return 0 +MERGE_PULL_REQUEST = _merge_pull_request_hook + + +@register('CLOSE_PULL_REQUEST') +@verify_kwargs( + ['_load_extension', 'server_url', 'config', 'scm', 'username', 'ip', + 'action', 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers']) +def _close_pull_request_hook(*args, **kwargs): + """ + + """ + # extract extra fields and default reviewers from target + kwargs['REPOSITORY'] = kwargs['target']['repository'] + + # fetch extra fields + call = load_extension('extra_fields.py') + if call: + repo_extra_fields = call(**kwargs) + # now update if we have extra fields, they have precedence + # this way users can store any configuration inside the database per + # repo + for key, data in repo_extra_fields.items(): + kwargs[key] = data['field_value'] + + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # fetch issues from given commits + call = load_extension('extract_redmine_issues.py') + issues = {} + if call: + issues = call(**kwargs) + + # redmine smart pr update + call = load_extension('redmine_pr_flow.py') + if call: + # updates kwargs on the fly + configure_redmine_smart_pr(issues=issues, kwargs=kwargs) + call(**kwargs) + + return 0 +CLOSE_PULL_REQUEST = _close_pull_request_hook diff --git a/docs/integrations/extensions.rst b/docs/integrations/extensions.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/extensions.rst @@ -0,0 +1,59 @@ +.. _dev-plug: + +Developing Plugins/Extensions +----------------------------- + +An Extension or a Plugin is simply a |PY| module with a ``run`` method that +expects a number of parameters, depending on which event it is listening +for. To get an extension working, use the following steps: + +1. Create an extension or plugin using the below example. +2. Save the plugin inside the + :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` folder. +3. Add a hook to the + :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions/__init__.py` file. + For more information, see :ref:`event-listener`. +4. Restart your |RCM| instance. + +Extension example +^^^^^^^^^^^^^^^^^ + +In the following example, the ``run`` method listens for a push to a |repo| +and parses the commit. + +.. code-block:: python + + def run(*args, **kwargs): + + revs = kwargs.get('pushed_revs') + if not revs: + return 0 + + from rhodecode.lib.utils2 import extract_mentioned_users + from rhodecode.model.db import Repository + + repo = Repository.get_by_repo_name(kwargs['repository']) + changesets = [] + reviewers = [] + + # reviewer fields from extra_fields, users can store their custom + # reviewers inside the extra fields to pre-define a set of people who + # will get notifications about changesets + field_key = kwargs.get('reviewers_extra_field') + if field_key: + for xfield in repo.extra_fields: + if xfield.field_key == field_key: + reviewers.extend(xfield.field_value.split()) + + vcs_repo = repo.scm_instance_no_cache() + for rev in kwargs['pushed_revs']: + cs = vcs_repo.get_changeset(rev) # or get_commit. See API doc + cs_data = cs.__json__() + cs_data['mentions'] = extract_mentioned_users(cs_data['message']) + cs_data['reviewers'] = reviewers + # optionally add more logic to parse the commits, like reading extra + # fields of repository to read managers of reviewers + changesets.append(cs_data) + + return changesets + \ No newline at end of file diff --git a/docs/integrations/full-blown-example.rst b/docs/integrations/full-blown-example.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/full-blown-example.rst @@ -0,0 +1,19 @@ +.. _int-full-blown: + +Extensions Extended Example +--------------------------- + +This example +:file:`/home/{user}/.rccontrol/{instance-id}/rcextensions/__init.py__` file +has been highlighted to show a Redmine integration in full. To extend your +|RCE| instances, use the below example to integrate with other +applications. + +This example file also contains a Slack integration, but it is not +highlighted. + + +.. literalinclude:: example-ext.py + :language: python + :emphasize-lines: 186,193-198,210-218,474-496,648-660,749-760,810-822 + :linenos: diff --git a/docs/integrations/hooks.rst b/docs/integrations/hooks.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/hooks.rst @@ -0,0 +1,86 @@ +.. _hooks: + +Hooks +----- + +Within |RCM| there are two types of supported hooks. + +* **Internal built-in hooks**: The internal |hg| or |git| hooks are + triggered by different VCS operations, like push, pull, + or clone and are non-configurable, but you can add your own VCS hooks, + see :ref:`custom-hooks`. +* **User defined hooks**: User defined hooks centre around the lifecycle of + certain actions such are |repo| creation, user creation etc. The actions + these hooks trigger can be rejected based on the API permissions of the + user calling them. + +Those custom hooks can be called using |RCT|, see :ref:`rc-tools`. To create +a custom hook, see the :ref:`event-listener` section. + +.. _event-listener: + +Making your Extension listen for Events +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To create a hook to work with a plugin or extension, +you need configure a listener in the +:file:`/home/{user}/{instance-id}/rcextensions/__init__.py` file, +and use the ``load_extension`` method. + +Use the following example to create your extensions. +In this example: + +* The hook is calling the ``('my_post_push_extension.py')`` extension. +* The hook is listening to |RCM| for pushes to |repos|. +* This highlighted code is the hook, and configured in the ``__init__.py`` file. +* It is inserted into the ``def _pushhook(*args, **kwargs)`` section, + if it is not in the default ``__ini__.py`` file, use the below + non-highlighted section to create it. + +.. code-block:: python + :emphasize-lines: 23-38 + + # ========================================================================== + # POST PUSH HOOK + # ========================================================================== + + # this function will be executed after each push is executed after the + # build-in hook that RhodeCode uses for logging pushes + def _pushhook(*args, **kwargs): + """ + Post push hook + kwargs available: + + :param server_url: url of instance that triggered this hook + :param config: path to .ini config used + :param scm: type of VS 'git' or 'hg' + :param username: name of user who pushed + :param ip: ip of who pushed + :param action: push + :param repository: repository name + :param repo_store_path: full path to where repositories are stored + :param pushed_revs: list of pushed revisions + """ + + # Your hook code goes in here + call = load_extension('my_post_push_extension.py') + if call: + # extra arguments in kwargs + call_kwargs = dict() + call_kwargs.update(kwargs) + my_kw = { + 'reviewers_extra_field': 'reviewers', + # defines if we have a comma + # separated list of reviewers + # in this repo stored in extra_fields + } + call_kwargs.update(my_kw) # pass in hook args + parsed_revs = call(**call_kwargs) + # returns list of dicts with changesets data + + # Default code + return 0 + PUSH_HOOK = _pushhook + +Once your plugin and hook are configured, restart your instance of |RCM| and +your event listener will triggered as soon as a user pushes to a |repo|. diff --git a/docs/integrations/install-ext.rst b/docs/integrations/install-ext.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/install-ext.rst @@ -0,0 +1,55 @@ +.. _install-rcx: + +Install |RCX| +------------- + +To install |RCX|, you need to have |RCT| installed. See the :ref:`install-tools` +and :ref:`tools-cli` sections. Use the ``--plugins`` option with +the ``rhodecode-extensions`` argument. + +Upgrading |RCX| +^^^^^^^^^^^^^^^ + +.. important:: + + You should back up any plugins or extensions that you have created before + continuing. + +To upgrade your |RCX|, use the following example: + +1. From inside the |RCT| virtualenv, upgrade to the latest version: + +.. code-block:: bash + + (venv)$ pip install -U https://my.rhodecode.com/dl/rhodecode-tools/latest + Downloading/unpacking https://my.rhodecode.com/dl/rhodecode-tools/latest + Downloading latest (143kB): 143kB downloaded + Running setup.py (path:/tmp/pip-9qYsxf-build/setup.py) egg_info + for package from https://my.rhodecode.com/dl/rhodecode-tools/latest + +2. Once |RCT| are upgraded to the latest version, you can install the latest + extensions using the following example: + +.. code-block:: bash + + (venv)$ rhodecode-extensions --instance-name=enterprise-1 \ + --ini-file=rhodecode.ini --plugins + + Extension file already exists, do you want to overwrite it? [y/N]: y + Writen new extensions file to rcextensions + Copied hipchat_push_notify.py plugin to rcextensions + Copied jira_pr_flow.py plugin to rcextensions + Copied default_reviewers.py plugin to rcextensions + Copied extract_commits.py plugin to rcextensions + Copied extract_issues.py plugin to rcextensions + Copied redmine_pr_flow.py plugin to rcextensions + Copied extra_fields.py plugin to rcextensions + Copied jira_smart_commits.py plugin to rcextensions + Copied http_notify.py plugin to rcextensions + Copied slack_push_notify.py plugin to rcextensions + Copied slack_message.py plugin to rcextensions + Copied extract_jira_issues.py plugin to rcextensions + Copied extract_redmine_issues.py plugin to rcextensions + Copied redmine_smart_commits.py plugin to rcextensions + Copied send_mail.py plugin to rcextensions + diff --git a/docs/integrations/int-slack.rst b/docs/integrations/int-slack.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/int-slack.rst @@ -0,0 +1,151 @@ +.. _slack-int: + +Integrate Slack +=============== + +To integrate |RCE| and Slack, you need to configure some things on the Slack +side of the integration, and some things on the |RCE| side. + +On the Slack side you need to allow incoming webhooks, see their +documentation on this, `Slack Webhooks`_. You will also need to get an +Authorization Token from Slack that will allow |RCE| to post to your account. + +On the |RCE| side, this is an overview of what you need to do: + +1. Configure the built-in Slack extensions to post to the correct Slack URL. +2. Set your Slack authentication details in the |RCX| :file:`__init.py__` file. +3. Configure the different hooks in the :file:`__init.py__` file to extract + whatever information you want from |RCE|, and then using the Slack extensions + post that information to your Slack channel. + +.. hint:: + + The below examples should help you to get started. Once you have your + integration up and running, there is a more detailed Slack integration in + the :ref:`int-full-blown` section. + +Configure Built-in Extensions +----------------------------- + +|RCE| comes with 3 Slack extensions: ``slack_message.py``, +``slack_push_notify.py``, and ``slack.py``. The default +location is :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions`. + +To enable these to post to your Slack account, configure each of +these files with the following Slack details. + +.. code-block:: python + + BASE_URL = 'https://your.slack.com/api/link' + INCOMING_WEBHOOK_URL = 'https://hooks.slack.com/services/your/hook/link' + API_VERSION = 1 + +Configure |RCE| to Post to Slack +-------------------------------- + +In the |RCX| :file:`__init.py__` file, configure your Slack authentication +details. The default location is +:file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` + +.. code-block:: python + + CONFIG = DotDict( + slack=DotDict( + api_key='api-key', + api_url='slack-incoming-hook-url', + default_room='#slack-channel', + default_plugin_config={}, + ), + ) + + # slack conf + CONFIG.slack.default_plugin_config = { + 'INCOMING_WEBHOOK_URL': CONFIG.slack.api_url, + 'SLACK_TOKEN': CONFIG.slack.api_key, + 'SLACK_ROOM': CONFIG.slack.default_room, + 'SLACK_FROM': 'RhodeCode', + 'SLACK_FROM_ICON_EMOJI': ':rhodecode:', + } + +Add Push Notifications to Slack +------------------------------- + +To add notification to Slack when someone pushes to |RCE|, configure the push +hook to extract the commits pushed, and then call the built-in +``slack_push_notify.py`` extension to post them into your chosen Slack +channel. To do this, add the following code to the push hook section of the +:file:`__init.py__` file + +.. code-block:: python + :emphasize-lines: 10-16,18-22 + + def _push_hook(*args, **kwargs): + """ + POST PUSH HOOK, this function will be executed after each push, it's + executed after the build-in hook that RhodeCode uses for logging pushes + kwargs available: + """ + # backward compat + kwargs['commit_ids'] = kwargs['pushed_revs'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # slack ! + call = load_extension('slack_push_notify.py') + if call: + kwargs.update(CONFIG.slack.default_plugin_config) + call(**kwargs) + return 0 + PUSH_HOOK = _push_hook + + +Add Pull Request Notifications to Slack +--------------------------------------- + +To add |pr| notifications to Slack, use the following example. This example +shows a merged |pr| notification. You can add similar notifications to the +following hooks in the :file:`__init.py__` file, and for those examples see +the :ref:`int-full-blown` section: + +* ``_create_pull_request_hook`` +* ``_review_pull_request_hook`` +* ``_update_pull_request_hook`` +* ``_close_pull_request_hook`` + +.. code-block:: python + :emphasize-lines: 5-23 + + def _merge_pull_request_hook(*args, **kwargs): + """ + + """ + # extract below from source repo as commits are there + kwargs['REPOSITORY'] = kwargs['source']['repository'] + + # fetch pushed commits, from commit_ids list + call = load_extension('extract_commits.py') + extracted_commits = {} + if call: + extracted_commits = call(**kwargs) + # store the commits for the next call chain + kwargs['COMMITS'] = extracted_commits + + # slack notification on merging PR + call = load_extension('slack_message.py') + if call: + kwargs.update(CONFIG.slack.default_plugin_config) + kwargs['SLACK_ROOM'] = '#develop' + kwargs['SLACK_MESSAGE'] = 'Pull request <%s|#%s> (%s) was merged.' % ( + kwargs.get('url'), kwargs.get('pull_request_id'), kwargs.get('title')) + call(**kwargs) + + return 0 + MERGE_PULL_REQUEST = _merge_pull_request_hook + +.. _Slack Webhooks: https://api.slack.com/incoming-webhooks diff --git a/docs/integrations/integrations.rst b/docs/integrations/integrations.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/integrations.rst @@ -0,0 +1,25 @@ +.. _integrations-ref: + +Integrations and Extensions +=========================== + +The integrations section references three concepts regularly, +so to clarify what is meant each time, read the following definitions: + +* **Plugin**: A Plugin is software that adds a specific feature to + an existing software application. +* **Extension**: An extension extends the capabilities of, + or the data available to, an existing software application. +* **Hook**: A hook intercepts function calls, messages, or events passed + between software components and can be used to trigger plugins, or their + extensions. + +.. toctree:: + + rcx + install-ext + config-ext + extensions + hooks + full-blown-example + int-slack diff --git a/docs/integrations/rcx.rst b/docs/integrations/rcx.rst new file mode 100644 --- /dev/null +++ b/docs/integrations/rcx.rst @@ -0,0 +1,53 @@ +.. _rc-ext: + +|RCX| +----- + +|RCX| add additional functionality for push/pull/create/delete |repo| hooks. +These hooks can be used to send signals to build-bots such as `Jenkins`_. It +also adds built in plugin and extension support. Once installed, you will see +a :file:`rcextensions` folder in the instance directory, for example: +:file:`home/{user}/.rccontrol/{instance-id}/rcextensions` + +Built-in Plugins +^^^^^^^^^^^^^^^^ + +* A number of `Jira`_ plugins, enabling you to integrate with that issue + tracker: ``extract_jira_issues.py``, ``jira_pr_flow.py``, + ``jira_smart_commits.py`` +* A number of `Redmine`_ plugins, enabling you to integrate with that issue + tracker: ``extract_redmine_issues.py``, ``redmine_pr_flow.py``, + ``redmine_smart_commits.py``. +* ``hipchat.py`` and ``hipchat_push.py`` enable you to integrate with + `HipChat`_ and set channel or user notifications. +* ``slack.py``, ``slack_message.py``, and ``slack_push_notify.py`` enable + you to integrate with `Slack`_ and set channel or user notifications. + +Built-in Extensions +^^^^^^^^^^^^^^^^^^^ + +* ``commit_parser.py``: Enables you to parse commit messages, + and set a list of users to get notifications about change sets. +* ``default_reviewers.py``: Enables you to add default reviewers to a |pr|. +* ``extra_fields.py``: Returns a list of extra fields added to a |repo|. +* ``http_notify``: Enables you to send data over a web hook. +* ``mail.py`` : This extension uses the |RCE| mail configuration from the + instance :file:`rhodecode.ini` file to send email. +* ``push_post.py``: Enables you to set up push based actions such as + automated Jenkins builds. + +Event Listeners +^^^^^^^^^^^^^^^ + +To enable the extensions to listen to the different events that they are +configured for, you need to also set up an event listener (hook). Event +listeners are configured in the +:file:`/home/{user}/.rccontrol/{instance-id}/rcextensions/__init.__.py` file. + +For more details, see the example hook in :ref:`event-listener`. + +.. _Jenkins: http://jenkins-ci.org/ +.. _HipChat: https://www.hipchat.com/ +.. _Slack: https://slack.com/ +.. _Redmine: http://www.redmine.org/ +.. _Jira: https://www.atlassian.com/software/jira diff --git a/docs/issue-trackers/issue-trackers.rst b/docs/issue-trackers/issue-trackers.rst new file mode 100644 --- /dev/null +++ b/docs/issue-trackers/issue-trackers.rst @@ -0,0 +1,82 @@ +.. _rhodecode-issue-trackers-ref: + +Issue Tracker Integration +========================= + +You can set an issue tracker connection in two ways with |RCE|. + +* At instance level you can set a default issue tracker. +* At |repo| level you can configure an integration with a different issue + tracker. + +To integrate |RCM| with an issue tracker you need to define a regular +expression that will fetch the issue ID stored in commit messages and replace +it with a URL. This enables |RCE| to generate a link matching each issue to the +target |repo|. + +Default Issue Tracker Configuration +----------------------------------- + +To integrate your issue tracker, use the following steps: + +1. Open :menuselection:`Admin --> Settings --> Issue Tracker`. +2. In the new entry field, enter the following information: + + * :guilabel:`Description`: A name for this set of rules. + * :guilabel:`Pattern`: The regular expression that will match issues + tagged in commit messages, or more see :ref:`issue-tr-eg-ref`. + * :guilabel:`URL`: The URL to your issue tracker. + * :guilabel:`Prefix`: The prefix with which you want to mark issues. + +3. Select **Add** so save the rule to your issue tracker configuration. + +Repository Issue Tracker Configuration +-------------------------------------- + +You can configure specific |repos| to use a different issue tracker if +you need to connect to a non-default one. See the instructions in +:ref:`repo-it` + +.. _issue-tr-eg-ref: + +Jira Integration +---------------- + +* Regex = ``(?:^#|\s#)(\w+-\d+)`` +* URL = ``https://myissueserver.com/issue/${id}`` +* Issue Prefix = ``#`` + +Confluence (Wiki) +----------------- + +* Regex = ``(?:conf-)([A-Z0-9]+)`` +* URL = ``https://example.atlassian.net/display/wiki/${id}/${repo_name}`` +* issue prefix = ``CONF-`` + +Redmine Integration +------------------- + +* Regex = ``(issue-+\d+)`` +* URL = ``https://myissueserver.com/redmine/issue/${id}`` +* Issue Prefix = ``issue-`` + +Redmine (wiki) +-------------- + +* Regex = ``(?:wiki-)([a-zA-Z0-9]+)`` +* URL = ``https://example.com/redmine/projects/wiki/${repo_name}`` +* Issue prefix = ``Issue-`` + +Pivotal Tracker +--------------- + +* Regex = ``(?:pivot-)(?<project_id>\d+)-(?<story>\d+)`` +* URL = ``https://www.pivotaltracker.com/s/projects/${project_id}/stories/${story}`` +* Issue prefix = ``Piv-`` + +Trello +------ + +* Regex = ``(?:trello-)(?<card_id>[a-zA-Z0-9]+)`` +* URL = ``https://trello.com/example.com/${card_id}`` +* Issue prefix = ``Trello-`` diff --git a/docs/issue-trackers/redmine.rst b/docs/issue-trackers/redmine.rst new file mode 100644 --- /dev/null +++ b/docs/issue-trackers/redmine.rst @@ -0,0 +1,8 @@ +.. _rhodecode-redmine-ref: + +Redmine +------- + +|RCE| tracke that issue! + + diff --git a/docs/known-issues/error-msg-guide.rst b/docs/known-issues/error-msg-guide.rst new file mode 100644 --- /dev/null +++ b/docs/known-issues/error-msg-guide.rst @@ -0,0 +1,15 @@ +.. _err-msg-ref: + +Error Message Guide +=================== + +Error Message +Error creating repository repo-name + +Cause +As of |RCM| 3.0, a VCS Server is required to run backend operations. + +Solution +Install a VCS Server. See the `Install a VCS Server`_ section of |RCC| + +.. _Install a VCS Server: https://docs.rhodecode.com/RhodeCode-Control/tasks/upgrade-from-cli.html#install-a-vcs-server \ No newline at end of file diff --git a/docs/known-issues/known-issues.rst b/docs/known-issues/known-issues.rst new file mode 100644 --- /dev/null +++ b/docs/known-issues/known-issues.rst @@ -0,0 +1,88 @@ +.. _known-issues: + +Known Issues +============ + +Subversion Issues +----------------- + +Limited |svn| support has been achieved for this release, +|release|. The following known issues are in development for improvement. + +* |svn| |repo| creation: + Terminating the VCS Server during remote importation of |svn| |repos| leaves + the the process still running in the background. + +* |svn| |repo| checkin/checkout: + |svn| cloning support is not enabled by default. Please contact support if + you want it enabled. + +Windows Upload +-------------- + +There can be an issue with uploading files from web interface on Windows, +and afterwards users cannot properly clone or synchronize with the repository. + +Early testing shows that often uploading files via HTML forms on Windows +includes the full path of the file being uploaded and not the name of the file. + +Old Format of Git Repositories +------------------------------ + +There is an issue when trying to import old |git| format |repos| into recent +versions of |RCE|. This issue can occur when importing from external |git| +repositories or from older versions of |RCE| (<=2.2.7). + +To convert the old version into a current version, clone the old +|repo| into a local machine using a recent |git| client, then push it to a new +|repo| inside |RCE|. + +VCS Server Memory Consumption +----------------------------- + +The VCS Server cache grows without limits if not configured correctly. This +applies to |RCE| versions prior to the 3.3.2 releases, as 3.3.2 +shipped with the optimal configuration as default. See the +:ref:`vcs-server-maintain` section for details. + +To fix this issue, upgrade to |RCE| 3.3.2 or greater, and if you discover +memory consumption issues check the VCS Server settings. + +Fedora 23 +--------- + +|RCC| does not run perfectly on Fedora 23 due to a locale issue. This is a +known issue under investigation due to the Nix packaging of the product, see the +`Github issue here`_. |RCC| runs fine on Fedora 21. + +To work around this problem, you need to point ``$LOCAL_ARCHIVE`` to the +workaround locale package. + +1. Download this package: + http://lipa.ms.mff.cuni.cz/~cunav5am/nix/locale-archive + +2. Point ``$LOCAL_ARCHIVE`` to the locale package. + +.. code-block:: bash + + $ export LOCALE_ARCHIVE=/home/VERSION/locale-archive # change to your path + +If you happen to be running |RCC| from systemd, use the following +example to pass the correct locale information on boot. + +.. code-block:: ini + + [Unit] + Description=Rhodecode + After=network.target + + [Service] + Type=forking + User=scm + Environment="LOCALE_ARCHIVE=/YOUR-PATH/locale-archive" + ExecStart=/YOUR-PATH/.rccontrol-profile/bin/rccontrol-self-init + + [Install] + WantedBy=multi-user.target + +.. _Github issue here: https://github.com/NixOS/nix/issues/599 diff --git a/docs/nix/add-to-env.rst b/docs/nix/add-to-env.rst new file mode 100644 --- /dev/null +++ b/docs/nix/add-to-env.rst @@ -0,0 +1,43 @@ +Adding Custom Packages +====================== + +If you wish to make additional Python modules available to use with +extensions that you have developed, use the following information. + +Prerequisite +------------ + +|RCC| manages the |RCE| environment using Supervisor. To add custom packages +you need to install your instance of |RCE| as a self managed +instance. This will let you to update the ``PYTHONPATH`` without |RCC| +overwriting it. You can then extend the ``PYTHONPATH`` to find packaged +outside of the |RCC| managed environment. To install |RCE| as a self-managed +service using |RCC|, see the +:ref:`Self-managed Instructions <control:set-self-managed-supervisor>`. + +Adding Custom Packages +---------------------- + +Once you have your instance configured as self-managed, use the following steps. + +1. Add the modules to the |RCE| instance directory, + :file:`/home/{user}/.rccontrol/{instance-id}`. +2. Add this location to your ``PYTHONPATH`` environment variable. This is set + in the :file:`/home/{user}/.rccontrol/supervisor/supervisor.ini` file. For + more information about ``PYTHONPATH``, see the `PYTHONPATH documentation`_. + +.. code-block:: ini + + [program:enterprise-1_script] + numprocs = 1 + redirect_stderr = true + environment = PYTHONPATH="",GIT_SSL_CAINFO="/home/user/.rccontrol-profile/etc/ca-bundle.crt" + +3. Specify the hook for your added module on the + :menuselection:`Admin --> Settings --> Hooks` page. For + example, ``python:rcextensions/you.custom.hook`` +4. Restart |RCE| using the ``rccontrol restart <instance-id>`` command. + For more information, see the :ref:`RhodeCode Control CLI <control:rcc-cli>` + documentation. + +.. _PYTHONPATH documentation: https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH diff --git a/docs/nix/default-env.rst b/docs/nix/default-env.rst new file mode 100644 --- /dev/null +++ b/docs/nix/default-env.rst @@ -0,0 +1,10 @@ +.. _system-pack: + +System Packaging +================ + +.. toctree:: + :maxdepth: 1 + + nix + add-to-env diff --git a/docs/nix/nix.rst b/docs/nix/nix.rst new file mode 100644 --- /dev/null +++ b/docs/nix/nix.rst @@ -0,0 +1,31 @@ +.. _rhodecode-nix-ref: + +Nix Packaging +============= + +|RCM| is installed using |Nix Package Manager|. The Nix environment provides +the following features for maintenance and deployment: + +* Atomic upgrades and rollbacks +* Complete dependency management +* Garbage collection +* Binary patching +* Secure channel updates +* Nix works on Windows, Linux, and OSX + +The complete list of dependencies can be found in +:file:`/opt/rhodecode/store/{unique-hash}`. + +.. note:: + + No |RCE| data is stored in this location. + +.. warning:: + + Never alter any of the packages in the store. Always use the + :ref:`RhodeCode Control CLI <control:rcc-cli>` update functions to keep + the packages and instances updated. + +.. |Nix Package Manager| raw:: html + + <a href="http://nixos.org/nix/" target="_blank">Nix</a> diff --git a/docs/release-notes/release-notes-1.6.0.rst b/docs/release-notes/release-notes-1.6.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-1.6.0.rst @@ -0,0 +1,18 @@ +|RCE| 1.6.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + + * released 2013-05-12 + +Fixes +^^^^^ + * #818: Bookmarks Do Not Display on Changeset View. + * Fixed issue with forks form errors rendering. + * #819 review status is showed in the main changelog. + * Permission update function is idempotent, and doesn't override default permissions when doing upgrades. + * Fixed some unicode problems with git file path. + * Fixed broken handling of adding an htsts headers. + * Fixed redirection loop on changelog for empty repository. + * Fixed issue with web-editor that didn't preserve executable bit after editing files. diff --git a/docs/release-notes/release-notes-1.7.0.rst b/docs/release-notes/release-notes-1.7.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-1.7.0.rst @@ -0,0 +1,36 @@ +|RCE| 1.7.0 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-06-08 + +News +^^^^ + * Manage User's Groups(teams): create, delete, rename, add/remove users inside by delegated user group admins. + * Implemented simple Gist functionality. + * External authentication got special flag to control user activation. + * Created whitelist for API access. Each view can now be accessed by api_key if added to whitelist. + * Added dedicated file history page. + * Added compare option into bookmarks + * Improved diff display for binary files and renames. + * Archive downloading are now stored in main action journal. + * Switch gravatar to always use ssl. + * Implements #842 RhodeCode version disclosure. + * Allow underscore to be the optionally first character of username. + +Fixes +^^^^^ + * #818: Bookmarks Do Not Display on Changeset View. + * Fixed default permissions population during upgrades. + * Fixed overwrite default user group permission flag. + * Fixed issue with h.person() function returned prematurly giving only email info from changeset metadata. + * get_changeset uses now mercurial revrange to filter out branches. Switch to branch it's around 20% faster this way. + * Fixed some issues with paginators on chrome. + * Forbid changing of repository type. + * Adde missing permission checks in list of forks in repository settings. + * Fixes #834 hooks error on remote pulling. + * Fixes issues #849. Web Commits functionality failed for non-ascii files. + * Fixed #850. Whoosh indexer should use the default revision when doing index. + * Fixed #851 and #563 make-index crashes on non-ascii files. + * Fixes #852, flash messages had issies with non-ascii messages \ No newline at end of file diff --git a/docs/release-notes/release-notes-1.7.1.rst b/docs/release-notes/release-notes-1.7.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-1.7.1.rst @@ -0,0 +1,17 @@ +|RCE| 1.7.1 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-06-13 + +News +^^^^ + * Apply to children flag on repository group also adds users to private repositories, this is now consistent with user groups. Private repos default permissions are not affected by apply to children flag. + * Removed unionrepo code as it's part of Mercurial 2.6 + * RhodeCode accepts now read only paths for serving repositories. + +Fixes +^^^^^ + * Fixed issues with how mysql handles float values. Caused gists with expiration dates not work properly on MySQL. + * Fixed issue with ldap enable/disable flag. \ No newline at end of file diff --git a/docs/release-notes/release-notes-1.7.2.rst b/docs/release-notes/release-notes-1.7.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-1.7.2.rst @@ -0,0 +1,30 @@ +|RCE| 1.7.2 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-07-18 + +News +^^^^ + * Added handling of copied files in diffs. + * Implemented issue #387 side-by-side diffs view. + * Added option to specify other than official bugtracker url to post issues with RhodeCode. + * Markdown renderer now uses github flavored syntax with a better newline handling + * Added User pre-create, create and delete hooks for rcextensions. + * Branch selectors: show closed branches too for Mercurial. + * Updated codemirror to latest version and added syntax coloring dropdown for various languages CodeMirror supports. + * Added --no-public-access / --public-access flags into setup-rhodecode command to enable setup without public access. + * Various small updates to pull requests. + * Bumped Mercurial version to latest. + * Diffs view doesn't show content of delete files anymore. + +Fixes +^^^^^ + * Added missing __get_cs_or_redirect method for file history. Fixes issue with displaying a history of file that is not present at tip. + * Pull request: urlify description and fix javascript injection. + * Fixed some missing IP extraction for action logger. + * Fixed bug with log_delete hook didn't properly store user who triggered delete action. + * Fixed show as raw link for private gists. + * Fixes issue #860. IMC web commits poisoned caches when they failed with commit. + * Fixes issue #856 file upload >1000 bytes on windows throws exception. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.0.0.rst b/docs/release-notes/release-notes-2.0.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.0.0.rst @@ -0,0 +1,28 @@ +|RCE| 2.0.0 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-08-07 + * First introduction as |RCE| + +News +^^^^ + * Renamed to RhodeCode Enterprise. + * New UI based on font icons. + * Changed buttons to Twitter Bootstrap and Flat design. + * Only the most important button on a page is green. + * Capitalized labels. + * Pluggable Auth system. + * Extended API methods. Please check the latest docs for API changes. + * Only one most important button is green in a page. + * Reduced size of summary page info. + * Moved statistics to dedicated page for consistent summary view. + * New filtered and styled select fields using select2 widget. Select fields with bigger ammount of data are lazy loaded for performance. + * Implemented separate compare page for easy comparing changesets between revisions, tags and bookmarks. + * Repository, repository groups, users and users groups pages are now using same data_table rendered for consistency. All are now sortable with a special filter box. + * Small improvements on pull requests. + +Fixes +^^^^^ + * No fixes \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.0.1.rst b/docs/release-notes/release-notes-2.0.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.0.1.rst @@ -0,0 +1,28 @@ +|RCE| 2.0.1 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-08-14 + +News +^^^^ + * Create Pull-request button is visible for all logged in users, not only for those with a created repo permission set. + * New UI on repository groups, now consistent with other views. + * UI improvements on pull request reviewers. + * Repository admin can revoke reviewers from pull requests. + * Super admins can directly edit groups/users at permission box. + * Links in footer point to website and new support pages. + +Fixes +^^^^^ + * Fixed download button size. + * Fixed empty dot occuring on page titles when no site customization was set. + * Fixed issue #893, some static resources were called without url() leading to bad address when used with proxy prefix. + * Fixed missing external values from user forms. + * Fixed one Git call in pygrack that defaulted to hardcoded 'git' instead of customized path from RhodeCode settings. + * Fixed issue with html on revoke buttons on pull request reviewers. + * Fixed all occurences of bad permission check that didn't allow repository admins to do certain actions. Only global admins could run them. + * Fixed gist url filtering for public gists. + * Newly registered users now default to 'rhodecode' as authentication type. + * Bumped Waitress version that allows setting `asyncore_use_poll` in settings to overcome 1024 open sockets limit with default `select()` implementation. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.0.2.rst b/docs/release-notes/release-notes-2.0.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.0.2.rst @@ -0,0 +1,26 @@ +|RCE| 2.0.2 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-08-27 + +News +^^^^ + * Completely new my account page. + * Added created_on field for repository groups. + * Users can now define extra email addresses in their account page. + * Updated codemirror to latest version with Nginx, Jade, Smartymixed modes. + * Better MIME-type detection of files with pygments to improve online editor syntax and mode detection. + * Added option to enable Captcha on registration page. It helps fight spam on open RhodeCode Enterprise instances. + +Fixes +^^^^^ + * Many fixes for Internet Explorer 8 and newer. + * Fix largefiles user cache location by explicitly setting the location in RhodeCode database. + * Fixed "Remove Pull Request" button HTML on "my account" page. + * Allow admin flag control for external authentication accounts + * Changed landing_rev format to <rev_type>:<rev> to overcome issues with same names in different rev types like + bookmarks and branches. + * Add strip to attr_login for LDAP Auth plugin which is a very sensitive about whitespaces. Leaving whitespaces in + there causes hard to debug issues. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.1.0.rst b/docs/release-notes/release-notes-2.1.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.1.0.rst @@ -0,0 +1,45 @@ +|RCE| 2.1.0 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-09-25 + * Pull requests work for Mercurial and Git + * New IP Whitelist inheritance + * Ability to check for new update of RhodeCode Enterprise + * Multiple API keys per user + * Strong performance improvements + * Shortcuts + +News +^^^^ + * Added Git pull request functionality + * Multiple API keys and the option to add additional API keys for a user together with description and expiration. + * Users can now delete files via web interface. + * Moved Gravatar configuration from .ini files to web interface. + * Moved custom clone URL configuration from .ini files to web interface. + * Default IP whitelist is now inheritable by all users. This allows to setup system-wide IP restrictions for all users. + * Added intermediate waiting page for forks creation. After the fork is created the user is redirected to the forked + repo summary page. + * Next/prev links on changeset are now lazy calculated with onClick actions which can boost initial rendering speed + of pages by 2-3x. + * New repo switcher based on select2. Now with keyboard control and repository groups searching.Added basic keyboard + navigation shortcuts, simply call '?' to show them. + * Added check for update mechanism in web interface. + * All alerts and confirmations can be closed with an 'x' button in the corner. + * Updated Mercurial to 2.7.1 + * Updated Waitress to 0.8.7 + +Fixes +^^^^^ + * Updated Google Noto Sans web font to fix issues for older IE versions + * Fixed Git backend calls to not use grep. Users are not required anymore to install it for Windows. + * Fixed sorting by revision in dashboard view. + * Container auth plugin preserves modified details after user is created and edited. + * Fixed issue with deleting notifications for some users. + * Fixed issue when external auth systems always regenerated tokens when user logged in (due to temp passwords on those + accounts) + * Fixed some JS errors on summary page. + * Fixed issue when external auth plugins wanted to create new users after the free limit is reached and failed with an + error. + * Removed broken prerender calls in pagination. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.0.rst b/docs/release-notes/release-notes-2.2.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.0.rst @@ -0,0 +1,47 @@ +|RCE| 2.2.0 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-10-23 + * Gists are editable + * New keyboard shortcuts + * Improved permission management + * Speed improvements + * Security improvements + +News +^^^^ + * Gists are editable. + * Gist URLs can take revisions as last parameter. + * New keyboard shortcuts 'gg' and 'gG' open private/public Gists page. + * New keyboard shortcut 'gF' opens files page with loaded files filter. + * New keyboard shortcut 'gO' opens repository permissions settings. + * 'Apply to children' becomes a 4-state radio button. It allows appling permissions to child objects of a repository group that are only repositories or only groups or both or none. + * New permission for controlling repository creation with write access on repository groups. + * Codemirror mode has added functionality of detection based on filename. + * Added get_user function to auth plugins base. Can be overriden to customize other than standard user extraction, like the one needed for container auth. + * API: added methods for permission managements for repo groups. + * API: get_nodes API function is now callable not only by users with admin permissions but also with at least read permissions to a given repo. + * Added stand-alone binary scripts for API, Gist, backup and extensions. + * Extensions has additional notification plugins. Builtin plugins hipchat (hipchat notification on push), push_post( POST data after push). Use 'rhodecode-extensions --plugins' to install them. + * Added captcha field to password_reset form. + * Removed mailto: links, for better anti-spam protection on open instances. + * Twice as fast page load of repository settings subpages. + * Added checkbox in Map & Scan Admin Setting to verify and install any missing Git hooks that RhodeCode uses. + * Bumped mako templates version to 0.9.0. + * Bumped dulwich version to 0.9.3 + * Bumped mercurial version to 2.7.2. + +Fixes +^^^^^ + * Fixed issue with container_auth tring to auth against non-container users. + * Fixed issues when authentication via container failed on Git/hg operations when using non standard (REMOTE_USER) headers. + * Fixed some JSON decode issue in Atlassian crowd auth plugin. + * Fixed Git-related issue that didn't allow to push a non-master branch on the first push to the server. + * Fixed issue on delete_user_group API call. + * Fixed styling of password reset and register forms. + * Fixed issue with Mercurial ui() object generation that caused certain extensions like hgsubversion to work incorrectly. + * Fixed issue with revoked access to repo group for admins of repos inside those groups. In that case editing of these repos no longer causes an error. + * Fixed sorting issues on tags/bookmarks/branches views. + * Fixed issue when performing 'git update-server-info' while importing existing Git repositories. It makes sure now that clients can clone it. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.1.rst b/docs/release-notes/release-notes-2.2.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.1.rst @@ -0,0 +1,16 @@ +|RCE| 2.2.1 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-10-25 + +News +^^^^ + * No news + +Fixes +^^^^^ + * Fixed issue with forking. + * Fixed redirection to previous location which was lost via container auth login. + * API: removed urllib.unquote_plus on raw body. This caused a bug with '+' chars beeing stripped out of sent JSON BODY. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.2.rst b/docs/release-notes/release-notes-2.2.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.2.rst @@ -0,0 +1,26 @@ +|RCE| 2.2.2 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-11-19 + * Push & pull up to 4x faster + * Security fixes + +News +^^^^ + * Optimized the number of permission tree builds when doing push and pull operations which leads to a significant (up + to 4x) performance increase. + +Fixes +^^^^^ + * Fixed issue with pygrack using os.cwd for working dir, that caused issues in some operating systems. + * Fixed dulwich parents function call used when building DAG graph. + * Fixed issue with revoke permissions on repository group when apply to children was set to 'none'. This call could + silently fail without proper notification to users. + * Fixed issues with Mercurial hooks when creating remote repositories. + * Strip passwords from clone urls for logging output. + * Fixed LDAP issues with unicode. LDAP bind does not support unicode passwords. + * Fixed admin UI which broke when using long names. + * Fixed rendering of READMEs that contained different line endings. + * Fixed issue with admin users of groups which could create repositories at top-level. \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.3.rst b/docs/release-notes/release-notes-2.2.3.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.3.rst @@ -0,0 +1,29 @@ +|RCE| 2.2.3 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-11-27 + * Asynchronous & more stable repo forking & creation + * Inheritable repository group permissions + +News +^^^^ + * Bumped Mercurial to 2.8.0. + * Bumped Mergely to latest version. + * Permissions from a repository group can be inherited to child repositories. + * Added side-by-side diff link to compare files diff view. + * Forking and creation of repositories can be done asynchronously via Celery. + * Forking and creation of repositories is more stable in terms of concurrency and file system errors. + * Added new visual option for number of records on admin 'data grids'. + * Repository admins can add/delete repository extra fields. + * Improved validators of remote clone urls for Git and Mercurial. + +Fixes +^^^^^ + * Fixed page links at Gists which lost filter settings on click. + * Fixed how auth plugins handle groups. + * Fixed issue on mismatch of repository fork VCS type (Git or Mercurial). + * Fixed admin UI forms which broke when using long names. + * Fixed LookupError exceptions when ambiguous identifier was given. + * Fixed issues which occured with Git under Windows. diff --git a/docs/release-notes/release-notes-2.2.4.rst b/docs/release-notes/release-notes-2.2.4.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.4.rst @@ -0,0 +1,25 @@ +|RCE| 2.2.4 |RNS| +----------------- + +General +^^^^^^^ + * released 2013-12-30 + * More secure output of a remote clone URL + * Extended API calls + * Support for latest Git versions + +News +^^^^ + * Password in a remote clone URL are not displayed anymore. + * Better Windows support on server info page. + * Extended API: added permission delegation to grant/revoke calls. + * Extended API: added copy_permissions flag to create_repo_group. + * Extended API: added apply_to_children to grant/revoke methods of repo groups. + +Fixes +^^^^^ + * Fixed forking into a repository group. + * Fixed detection of remote Git repositories. + * Fixed issue with API calls on repo names with groups. + * Fixed unescaped characters which broke Javascript in the 2-side diff view. + * Fixed git clone command by adding -q flag due to changes in the latest Git. diff --git a/docs/release-notes/release-notes-2.2.5.rst b/docs/release-notes/release-notes-2.2.5.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.5.rst @@ -0,0 +1,20 @@ +|RCE| 2.2.5 |RNS| +----------------- + +General +^^^^^^^ + * released 2014-02-13 + * Improvements for larger setups + * Extended API calls + +News +^^^^ + * Better support for larger enterprise hierarchies with more repository group levels. + * Added filters to permission boxes which makes managing of many thousand repo groups easier. + * The My Account page requires the old password for a password change. + * Removing of deprecated parts in .ini files. + * Extended API: added permission delegation on user groups calls. + +Fixes +^^^^^ + * No fixes \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.6.rst b/docs/release-notes/release-notes-2.2.6.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.6.rst @@ -0,0 +1,27 @@ +|RCE| 2.2.6 |RNS| +----------------- + +General +^^^^^^^ + * 2014-12-03 + +News +^^^^ + - Repository locking requires at least write permission to repository. + - API: added add/remove methods for extra fields + - New repositories/ repository groups should be created using 0755 mode not 0777 + - Added editable owner field for repository groups + - Added editable owner field for user groups + - API: Permission delegation on grant/revoke user permission functions + - Auth plugin can create user creation state on first login + - New license logic + +Fixes +^^^^^ + - Fix issue with unicode email addresses in custom gravatar template + - Protect against empty author string + - Fixed issue with multiprocess setup and cached global settings + - Fixed issues with IIS and proxied ports + - Fixed issue with mysql column size on installing RhodeCode + - Fixed issue with API call for update repo when a repo inside a group + was badly renamed when doing those calls \ No newline at end of file diff --git a/docs/release-notes/release-notes-2.2.7.rst b/docs/release-notes/release-notes-2.2.7.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.7.rst @@ -0,0 +1,13 @@ +|RCE| 2.2.7 |RNS| +----------------- + +General +^^^^^^^ + * 2015-02-03 + +Fixes +^^^^^ + + * Security: fixed severe issue with leaking of auth_tokens(api_keys) on the + following API calls; ``get_repo``, + ``update_repo``, ``get_locks``, and ``get_user_groups``. diff --git a/docs/release-notes/release-notes-2.2.8.rst b/docs/release-notes/release-notes-2.2.8.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-2.2.8.rst @@ -0,0 +1,12 @@ +|RCE| 2.2.8 |RNS| +----------------- + +General +^^^^^^^ + * 2015-06-30 + +Fixes +^^^^^ + + * Security: Apply the same permission checks for the API call `create_repo` + and the web interface to create a repository. diff --git a/docs/release-notes/release-notes-3.0.0.rst b/docs/release-notes/release-notes-3.0.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.0.0.rst @@ -0,0 +1,166 @@ +|RCE| 3.0.0 |RNS| +----------------- + +As |RCM| 3.0 is a big release, the release notes have been split into the following sections: + +* :ref:`general-rn-ref` +* :ref:`security-rn-ref` +* :ref:`api-rn-ref` +* :ref:`performance-rn-ref` +* :ref:`prs-rn-ref` +* :ref:`gists-rn-ref` +* :ref:`search-rn-ref` +* :ref:`fixes-rn-ref` + +.. _general-rn-ref: + +General +^^^^^^^ + * Released 2015-01-27 + * Basic |svn| support added + * GPLv3 components removed + * Server/Client architecture for VCS systems created + * Python 2.5 and 2.6 support deprecated + * Server info pages now show gist/archive cache storage, and also CPU/Memory/Load information. + * Added new bulk commit (changeset) status comment form into compare view which enables bulk code-reviews without + opening a pull-request. + * License checks and limits now only apply to active users. + * Removed CLI command for |repo| scans as it can be done via an API call. + * VCS backends can be globally enabled/disabled from the :file:`rhodecode.ini` file. + * Added a UI option to set default rendering to rst or markdown. + * Added syntax highlighting to 2 way compare diff. + * Markup rendering can now render checkboxes for easy checklists generation. + * Gravatars are now retina ready. + * Admins can define custom CSS or JavaScript in the header or footer via new pre/post code options. + * Replaced ``graph.js`` with ``commits-graph.js`` html5 implementation. + * Added editable owner field for repository groups, and user group. + * Added an option to detach/delete user repositories when deleting users from the system. + * Added a Supervisor control page that shows status of processes. + * User admin grid can now filter by username OR email. + * Added personal |repo| group link for easier fork creation. + * Added support for using subdirectories when creating and uploading new files. + * Added option to rename a file from the web interface. + * Added arrow key navigation to file filter and fixed the back button behaviour. + * Added fuzzy matching to file filter. + * Added functionality to create folder structures along with files when adding content via the web interface. + * Separated default permissions UI into `global`, `user`, or `object` permissions management. + * Added an inheritance flag to object permissions which allows for explicit permissions which disregard global + permissions. + * Added post create repository group hook. + * Added trigger push hooks on online file editor. + * Added default title for pull request. + * More detailed logs during Authentication. + * More explicit logging when permission checks occur. + * Switched the implementation of |git| ``fetch clone pull checkout`` commands to pure |py| without any subprocess + calls. + * Introduced the ``rcserver`` command for custom development. + * Added the ability to force no cache archived via the ``GET no_cache`` flag + +.. _security-rn-ref: + +Security +^^^^^^^^ + + * CSRF (Cross-Site Request Forgery) tokens now in all pages that use forms. + * The ``clone_url`` field is now AES encrypted inside the database. + * ACLs (Access Control Lists) are checked on the gist edit page for logged in users. + * New repository groups and repositories are created with 0755 permissions and not not 0777. + * Explicit RSS tokens are used for the RSS journal, when leaked, limits access to RSS only. + * Fixed XSS issues when rendering raw SVG files. + * Added force password reset option for users. + * IP list now accepts comma-separated values, and also ranges using `-` to specify multiple addresses. + * Added ``auth tokens``, these authentication tokens can be used as an alternative to passwords. + * Added roles (``http, api, rss, all, vcs``) into authentication tokens (previously called ``apikeys``). + * LDAP Group Support added. + * Added JASIG CAS auth plugin support. + * Added a plugin parameter that defines if a plugin can create new users on the fly. + +.. _api-rn-ref: + +API +^^^ + * Added permissions delegation when creating |repos| or |repo| groups. + * Added ``strip`` support for |hg| and |git| |repos|. + * Added comments API for commits. + * Added add/remove methods for extra fields in repositories. + * ``get_*`` calls now use ``permission()`` and ``permission_user_group()`` methods for unified permissions structure. + * ``get_repo_nodes`` information sending has changed and is no longer a boolean flag, it's now ``basic`` or ``full``. + * Due to configurable backends ``repo_type`` is now mandatory parameter for the ``create_repo`` call. + +.. _performance-rn-ref: + +Performance +^^^^^^^^^^^ + + * Significant performance improvements across all application functions. + * HTTP Authentication performance enhancements. + * Added a ``scope`` variable to the permissions fetching function which improves building permission trees in large + amounts by a factor of 10. + * Implemented caching logic for all authentication plugins. The ``AUTH_CACHE_TTL = <int>`` property now allow you to + set the cache in seconds. + +.. _prs-rn-ref: + +Pull Requests +^^^^^^^^^^^^^ + + * Pull requests can be now updated and merged from the web interface + * Fixed creating a Mercurial |pr| from a bookmark. + * Forbid closing pull requests when calculated status is different that the approved or rejected version. + * Properly display calculated pull request review status on listing page. + * Disable delete comment button if |pr| is closed. + +.. _gists-rn-ref: + +Gists +^^^^^ + * New UI based on grids with filtering. + * Super-admins can see all gists. + * Gists can now be created with a custom names. + +.. _search-rn-ref: + +Search +^^^^^^ + + * New API based indexer. + * Added the ability to create size limits for indexed files. + * Added a new mapping configuration file which gives a very high level of flexibility when creating full text search. + +.. _fixes-rn-ref: + +Fixes +^^^^^ + + * General: fixed issues with dependent objects, such as ``users`` in ``user groups``. Cleaning up these dependent + objects is now done in a safe way. + * General: deleting a ``user group`` from **settings > advanced** will use force removal and cleanup from all + associations. + * General: fixed issue with filter proxy middleware it's now more error prone. + * General: fixed issues with unable to create fork inside a group. + * General: fixed bad logic in ``ext_json`` lib, that checked bool on microseconds, in case it was 0 bool it returned False. + * General: authors in annotation mode shows authors of current source, not from all history (that is in normal mode) + * Permissions: fix issue when inherit flag for user group stopped working after initial permissions set. + * |git|: fixed shallow clones. + * |git|: added ``\n`` into the service line of |git| protocol. It is in the specifications and some python clients + require this. + * |hg|: fix thread safety for mercurial ``in-memory`` commits. + * Windows: fixed issue with shebang and env headers. + * MySQL: fixed database fields with 256 char length with added indexes. Mysql had problems with them. + * Database: fixed bad usage of matching using ``ILIKE``. Previously it could happen that if you had + ``marcin_1@rhodecode.com`` and ``marcin_2@rhodecode.com`` emails, using ``marcin_@rhodecode.com`` would match both. + * VCS: fixed issues with double new lines on the commit patches. + * VCS: repository locking now requires write permission to repository. If we allowed locking with read, + people can lock repository without an option to unlock it. + * Models: removed the ``isdigit`` call that can create issues when names are actually numbers on fetching objects. + * Files: Fix bug with show authors in annotate view. + * Hooks: truncate excessive commit lists on ``post_push`` hook. + * Hooks: in |git|, support added to set the default branch if it is not ``master``. + * Notifications: now can be marked as read when you are not admin. + * Notifications: marking all notifications as read will hide the counter. + * Frontend: fixed branch-tag switcher multiple ajax calls. + * Repository group: |repo| group owners can now change group settings even if they don't have access to top-level + permissions. + * Repositories: if you set ``Fork of`` in advanced repository settings it will now only show valid repositories + with the same type. + diff --git a/docs/release-notes/release-notes-3.0.1.rst b/docs/release-notes/release-notes-3.0.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.0.1.rst @@ -0,0 +1,22 @@ +|RCE| 3.0.1 |RNS| +----------------- + +General +^^^^^^^ + * 2015-02-03 + +News +^^^^ + + * Server info: added more details into server info page. + +Fixes +^^^^^ + + * Security: fixed severe issue with leaking of auth_tokens(api_keys) on + certain API calls. + * VCS Client: Improved reconnection logic. + * SVN: forbid certain actions like pull requests on svn repositories. + * Style: fixed comments with Markdown, and also multiple styling issues. + * Style: fixed re-captcha html issues. + * Style: fixed large inputs. diff --git a/docs/release-notes/release-notes-3.0.2.rst b/docs/release-notes/release-notes-3.0.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.0.2.rst @@ -0,0 +1,31 @@ +|RCE| 3.0.2 |RNS| +----------------- + +General +^^^^^^^ + * 2015-02-16 + +News +^^^^ + + * Style: Overhaul of typography styling + * Consistent use of product name in application + * Action Parser: More robust handling of data + * Permissions: More consistent sorting of permissions + * Gists: Added a ``noindex`` flag for private Gists + +Fixes +^^^^^ + + * LDAP: renamed LDAP plugins for backwards compatibility. The original + plugin is called ``auth_ldap`` and group support is with the + ``auth_ldap_group`` plugin. + * |svn|: Support "0" to get the first commit via API from Subversion + repositories + * Style: fixed display issues with select boxes in IE + * Style: fixed highlighting of commits in compare view + * Style: Preserve new-line breaks in commit messages + * Style: fixed icons on code-block elements + * Style: fixed side-by-side diff header + * Style: fixed form-inputs on login pages + * Style: fixed multiple minor display issues in the diff display \ No newline at end of file diff --git a/docs/release-notes/release-notes-3.1.0.rst b/docs/release-notes/release-notes-3.1.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.1.0.rst @@ -0,0 +1,49 @@ +|RCE| 3.1.0 |RNS| +----------------- + +General +^^^^^^^ + * 2015-03-17 + +News +^^^^ + +- API: extended the API regarding |prs|. Added the following operations to + support CI integrations. + + * ``get_pull_request`` + * ``get_pull_requests`` + * ``merge_pull_request`` + * ``close_pull_request`` + * ``comment_pull_request`` + +- VCS Server: improved handling for the user in the event that no + VCS Server is enabled. +- VCS Server: Added the ``vcs.server.enable`` configuration option, + see :ref:`vcs-server` +- VCS Server: improved system stability if the VCS Server is not installed. +- Style: changed icon colors for the vcs back ends; Git, + Mercurial and Subversion. + +Fixes +^^^^^ + +- Security: fixed XSS vulnerability in files view. +- Pull Request: fixed dataTable integration for IE8 in Pull Request overview. +- Files: adding a new file via web form has been fixed. +- Diff: renames of files which have spaces in their file names are now displayed + correctly. +- Settings: Remove supervisor statistics page. +- Style: improved headers on all Pull Request related pages to make them more + consistent. +- Style: improved headers on all repository related pages to make them more + consistent. +- Style: updated icons. +- Style: removed border around checkboxes in IE10. +- Style: improved display of permission summaries in admin settings for all + browsers. +- Style: fixed alignment of form labels across all browsers. +- Style: improved title on the Changeset page. +- Style: fixed display of select widgets in IE8 and IE9. +- Style: fixed password input field for IE8. +- Style: fixed button positioning in inline comment forms of diffs for IE8. diff --git a/docs/release-notes/release-notes-3.1.1.rst b/docs/release-notes/release-notes-3.1.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.1.1.rst @@ -0,0 +1,11 @@ +|RCE| 3.1.1 |RNS| +----------------- + +General +^^^^^^^ + * 2015-03-27 + +fixes +^^^^^ + + * Security: updated Dulwich due to CVE-2015-0838 diff --git a/docs/release-notes/release-notes-3.2.0.rst b/docs/release-notes/release-notes-3.2.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.2.0.rst @@ -0,0 +1,54 @@ +|RCE| 3.2.0 |RNS| +----------------- + +General +^^^^^^^ + * 2015-04-08 + +News +^^^^ + +- Administration: Improved the logging and rendering of tracebacks from the + VCS Server. The logging configuration in the INI file should be updated. + For information about these parts of |RCE|, see :ref:`vcs-server`, and + :ref:`debug-mode`. +- Administration: Added the ability to set a per user language. +- Gists: Added an option to restrict gists to logged in users only. +- Pull requests: Reviewer status is reset after after an update. +- Pull requests: Improved logging during an update. +- Pull requests: Added various hooks around the life-cycle and review status + changes of a |pr|. +- Security: Support added for `bcrypt`_ on Windows systems. +- Style: Added headers to tables which display commits, e.g. the changelog. +- Style: Redesigned the compare page for multiple commits. +- Style: Redesigned the error pages. +- Style: Redesigned the file details page. +- Style: Redesigned the summary pages of |repos|. +- Style: Improved the details form for managing authentication plugins. +- VCS Server: Robust push and pull operations if the VCSServer is restarted. + +Fixes +^^^^^ + +- Administration: :ref:`remap-rescan` could cause issues with empty |repo| + groups. +- Administration: Fix edit of an existing issue tracker entry. +- Comments: Allow to delete comments on regular commits. +- Comments: Fix batch comment functionality on the compare page. +- Diffs: Improve diff parser to better recognize special file names. +- |git|: Avoid errors when pushing into an empty |git| repository. +- File edit: Avoid internal server error for file edits on branches which are + not the default branch. +- Pull requests: Show initial pull request comment. +- Security: Escape repository description to avoid XSS like vulnerabilities. +- Setup: Allow to setup a new system even with expired trial license. +- Style: Fixed styling of repository extra fields. +- Style: Fixed display issues on the file page when a line is selected and the + history buttons are used to navigate back and forth. +- Style: Improve the display of the commit message on the file details page. +- Style: Improve :guilabel:`My Account` page for email addresses. +- Style: Improve :guilabel:`My Account` page for external user accounts, e.g. LDAP +- Style: Improve transition from file list to file details. +- Style: Remove light font face for improved readability on Windows. + +.. _bcrypt: https://bcrypt.codeplex.com/ \ No newline at end of file diff --git a/docs/release-notes/release-notes-3.2.1.rst b/docs/release-notes/release-notes-3.2.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.2.1.rst @@ -0,0 +1,18 @@ +|RCE| 3.2.1 |RNS| +----------------- + + +General +^^^^^^^ + +- 2015-04-20 + + +fixes +^^^^^ + +- Security: Fixed a potential XSS vulnerability in user names and user group + descriptions. + +- Style: Fixed a form misalignment for the management of user group + permissions. diff --git a/docs/release-notes/release-notes-3.2.2.rst b/docs/release-notes/release-notes-3.2.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.2.2.rst @@ -0,0 +1,14 @@ +|RCE| 3.2.2 |RNS| +----------------- + + +General +^^^^^^^ + +- 2015-04-22 + + +fixes +^^^^^ + +- API: Fix password handling in the API call `create_user`. diff --git a/docs/release-notes/release-notes-3.2.3.rst b/docs/release-notes/release-notes-3.2.3.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.2.3.rst @@ -0,0 +1,14 @@ +|RCE| 3.2.3 |RNS| +----------------- + + +General +^^^^^^^ + +- 2015-04-27 + + +fixes +^^^^^ + +- Pull request: Fix Git based pull requests in the case of missing commits. diff --git a/docs/release-notes/release-notes-3.3.0.rst b/docs/release-notes/release-notes-3.3.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.3.0.rst @@ -0,0 +1,70 @@ +|RCE| 3.3.0 |RNS| +----------------- + +General +^^^^^^^ + * 2015-05-18 + +News +^^^^ + +- Administration: Clean up |repo| groups which have been deleted on the + file system. +- Docs: Overhaul the section about integrations and extensions. +- Docs: Document how to configure the file `.rhoderc` +- Docs: Extend the documentation about the usage of Gunicorn and horizontal + scaling. +- Docs: Document that we don't support the |git| dump protocol and provide a + workaround for very old servers. +- General: Decouple from external links to allow easier maintenance. +- Pull requests: Show a warning message if the commits are missing in the + source |repo| and suggest suitable next steps. +- Pull requests: New lab setting which enables the invalidation of inline + comments during an update; currently all comments are invalidated. +- Pull requests: Add keyboard shortcut `g p` to navigate to the |prs| + page of the current |repo|. +- Pull requests: Send notifications when a new reviewer is added to a |pr|. +- Pull requests: Show information about the target of a |pr|. +- Pull requests: Show progress after clicking the button "Update" on a |pr|. +- Pull requests: Show a more informative flash message after a successful + update of a |pr|. +- Style: Unify how gravatars are displayed for a more consistent look. +- Style: Better display of the |pr| page in smaller browser windows for + IE. +- Style: Better alignment of the status indicator in the list of reviewers of a + |pr|. +- UX: Add flash message if a |repo| has been deleted in the file system. +- UX: Consistent usage of |authtoken| in the settings section. +- UX: Better help message for the authentication plugins configuration. +- VCSServer: Add support for an external configuration file. + + + +Fixes +^^^^^ + + +- API: Multiple fixes for the call `update_repo_group`, adjusting parent path + if a new parent is specified and allow to update the owner. +- API: Fix the handling of boolean values in the call `create_repo`. +- API: Fix usage of the parameter `password` in the call `create_user`. +- API: Make the call `strip` more robust. +- Auth: Better support for the parameter "Base DN" in the plugin + `auth_ldap_group`. +- Auth: Avoid concurrency issue when forking a |repo| and celery is + enabled. +- Compare: Avoid duplication of diff content in the case of commit range + comparison. +- DB: Improve `Pullrequest.revisions` to work even for empty |prs|. +- DB: Avoid extremely large varchar columns for MySQL and MariaDB +- Files: Fix an issue around "Compare to revision" for diffs which are bigger + than the per file limit. +- Files: Present submodules with an absolute URL as real links. +- |Repo| settings: Allow to rename |svn| |repos|. +- Search: |Repo| search allows to use uppercase characters in |repo| + names. +- Style: Gist header alignment issues fixed. +- Style: Line heights in side by side diff display improved. +- UX: Hide "Add comments" button if the comments form is already open. +- UX: Fix links of bookmarks and tags on the overview pages. +- VCSServer: More robust locale handling. diff --git a/docs/release-notes/release-notes-3.3.1.rst b/docs/release-notes/release-notes-3.3.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.3.1.rst @@ -0,0 +1,16 @@ +|RCE| 3.3.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2015-05-27 + + +fixes +^^^^^ + +- Pull requests: Fix for the server side merge functionality for Mercurial + repositories. +- Repository: Fix for a problem with the remote import of repositories in + combination with celery based asynchronous task execution. diff --git a/docs/release-notes/release-notes-3.3.2.rst b/docs/release-notes/release-notes-3.3.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.3.2.rst @@ -0,0 +1,25 @@ +|RCE| 3.3.2 |RNS| +----------------- + + +Release Date +^^^^^^^^^^^^ + +- 2015-06-05 + + +security fixes +^^^^^^^^^^^^^^ + +* Stored XSS attempts on user login fields, and other text input fields. +* DOM Based XSS attempts +* HTML Injection +* Cross frame scripting (XFS) +* Invalidation of concurrent sessions on password change. +* Downgrading of HTTPS connections. + +fixes +^^^^^ + +* Generation of URLs on system with custom URL prefixes. +* VCSServer: Improved memory management of the cache data used by the server. diff --git a/docs/release-notes/release-notes-3.3.3.rst b/docs/release-notes/release-notes-3.3.3.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.3.3.rst @@ -0,0 +1,16 @@ +|RCE| 3.3.3 |RNS| +----------------- + + +Release Date +^^^^^^^^^^^^ + +- 2015-06-12 + + +fixes +^^^^^ + +* File system: Better handling of filenames with encoding other than utf-8 +* Performance: Includes new cache based on LRU +* URLs: More robust URL generation in reverse proxy based setups diff --git a/docs/release-notes/release-notes-3.3.4.rst b/docs/release-notes/release-notes-3.3.4.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.3.4.rst @@ -0,0 +1,16 @@ +|RCE| 3.3.4 |RNS| +----------------- + + +Release Date +^^^^^^^^^^^^ + +- 2015-06-25 + + +fixes +^^^^^ + +* References: Support for unicode characters. +* Gists: Fixes the problem with gists when |hg| is not in VCS backends list. +* Search: Improves search speed for super admin users. diff --git a/docs/release-notes/release-notes-3.4.0.rst b/docs/release-notes/release-notes-3.4.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.4.0.rst @@ -0,0 +1,91 @@ +|RCE| 3.4.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + + * 2015-07-06 + +News +^^^^ + +- API: Improved error handling in the calls `create_repo` and `update_repo`. +- API: Extend the call `create_repo`. +- API: Extend the call `update_repo`. It now supports the new parameter + `fork_of`. +- API: Add new call `create_pull_request`. +- API: Rename call `changeset_comment` to `comment_commit`. +- General: Update many external dependencies to recent versions. +- General: Improved connection handling to the VCSServer in thread based + scenarios. +- General: Generate replacement avatar images if Gravatar is not used. +- Hooks: Add the hooks `pre-push` and `pre-pull` for `rcextensions`. + +Pull Requests +^^^^^^^^^^^^^ + +- Update inline comments during the update of a pull request. This can be + enabled with a new option in the VCS settings. +- Always show information about the merge status. +- Allow to update the title and description of a pull request. +- Also allow the author to close a pull request. +- Order pull requests based on the numeric value instead of the + string value. +- Disable merge if the target repository is locked. +- Fix link to commits of the pull request. +- Show update button in the case of missing commits. + +Style +^^^^^ + +- Update of the page "Commit" to fit better into the current style. +- Update of the page "File" to fit better into the current style. +- Remove background color for closed pull requests. +- Standardise font sizes and spacing across the display of diffs and + file sources. +- Use units from the binary system to display size information, + e.g. `KiB` and `MiB`. +- Do not try to show gravatar images for group entries in select + widgets. +- Style: Improve "increase context" and "ignore whitespace" links on the page + "Commit". +- Show information in the profile of external users as read only. +- Improve spacing in the permissions overview of users and user groups. + +Fixes +^^^^^ + +- Auth: Fix default user permissions for private repositories inside of a + repository group. +- Auth: Do not inherit permissions from disabled user groups. +- Auth: Avoid generation of a new password for external user accounts on login. +- Files: Fix the handling of the file name extension on the page "Add File". +- Files: Fix the "Show all authors" link on the file page. +- General: Fix a filedescriptor leak inside of the WSGI processes around vcs + operations. +- General: Fix system info page for Windows. +- General: Show version information in the footer if enabled. +- General: Avoid errors from the issue tracker patterns to bubble up in the + system. Logging an error and ignoring the broken pattern instead. +- Gists: Store correct ACL level for anonymous gists. +- License: Ignore default user on user count. +- Repository: Clear user permissions when detaching related objects. +- Repository: Fix issue around tags with special characters for git. + +VCS Server +^^^^^^^^^^ + +- Fix a filedescriptor leak around calls to git around vcs + operations. +- Add solid handling of lookup errors and error during diff + generation. +- VCSServer: Skip initialization of the locale subsystem if no valid locale can + be found. +- VCSServer: Increased default value for the parameter `threadpool_size`. + +Deprecations +^^^^^^^^^^^^ + +- API: The call `changeset_comment` is deprecated, use `comment_commit` + instead. The old call will be still supported for a few more releases but + eventually it will be removed. diff --git a/docs/release-notes/release-notes-3.4.1.rst b/docs/release-notes/release-notes-3.4.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.4.1.rst @@ -0,0 +1,20 @@ +|RCE| 3.4.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-07-20 + +Packaging +^^^^^^^^^ + +- |RCT| are now bundled with |RCE| installations. This makes offline + installations easier, and it also removes to need to install a separate + ``virtualenv`` on your server. + +Fixes +^^^^^ + +- Pull requests: Fixed an internal server error in case of a removed commit. +- VCS: Fix a performance regression around VCS operations. diff --git a/docs/release-notes/release-notes-3.5.0.rst b/docs/release-notes/release-notes-3.5.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.5.0.rst @@ -0,0 +1,91 @@ +|RCE| 3.5.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-08-12 + +Pull Requests +^^^^^^^^^^^^^ + +- Added full support for `pre_push` and `post_push` hooks, which ensures + |repo| locking is respected when using the server side merging of |prs|. +- Fixed horizontal scrolling of diffs. +- Improved the links of the pull request source and target references. +- Properly escape the names of added reviewers to prevent code injection. +- Fixed journal entries after a merge to provide a more complete history. +- Replaced the comment text area with a more dynamic component. +- Data now loads for :guilabel:`@mention` asynchronously. +- Added a shortcut, :kbd:`Ctrl Space`, to set the review status + out of the comment area. + +News +^^^^ + +- Diffs: Unify the display and functionality around diffs in pull requests, + commit pages, compare pages, and file diff pages. +- Files: Improved the structure of the *Add file*, *Upload file*, *Edit + file*, and *Delete file* pages. +- General: Bundle the LDAP bindings in Windows builds. +- General: Add a new page, *User profile*, which displays information about a + user. +- General: The navigation and sub-navigation are fully based on click events. +- General: Updated the front end component for comments and side-by-side diffs + to the latest version. +- Logging: The logger `JSONRPC` got renamed to reflect the module name, the new + name is `rhodecode.controllers.api.base` +- Security: |RCE| now uses `os.urandom` as a source for generating the + authentication tokens. +- Settings: Adjusted the *Edit user* and *Edit my account* pages to be + consistent with the new *User profile* page. +- Style: User names linked to the new user profile page. +- Style: Adjusted the colors in flash messages to better integrate with the rest + of the application. +- Style: Consistently applied a small border radius to the rendering of files. +- SVN: Basic support to handle Subversion client requests which can be enabled + based on a lab setting. +- SVN: Installed basic hooks into new and migrated Subversion repositories. + +VCS Server +^^^^^^^^^^ + +- Fixed the error during re-connection after a restart of the VCS Server. +- Made the streaming of data from subprocess calls more solid. + +Fixes +^^^^^ + +- Auth: Fixed user name logged as *None* in the authentication component. +- Diffs: Fixed a potential internal server error if diff contains binary files. +- Diffs: |RCE| now expands all content by default. +- General: Fixed an exceptions in the logging system around the permission + validator and on the *system info* page. +- General: Avoid internal server error if unknown error documents are requested. +- General: Keep get parameters after a login redirection. +- Gists: Fixed header in Gists tables. +- Repository: Fixed a problem around archiving repositories which contain + non-ascii characters in their name. +- Repository: Show the locked state of a repository if it has been locked + manually via the web interface. +- Repository: Better rendering of the :file:`README` file on the summary page, + especially with very long lines. +- Repository: Avoid internal server error if filtering with a wrong branch name. +- VCS: Fixed the handling of branch and tag names with special characters. + + +Style +^^^^^ + +- More consistent display of form controls in IE8. +- Improve navigation display for IE8. +- Fixed the disabled state of the + :guilabel:`Create personal user group` button in the advanced user settings. +- Corrected the position of flash messages. +- Fixed a small display issue around the avatar image in the users table. +- Fixed spacing in the head of the *Add Gist* form. +- Fixed help text in permissions form. +- Fixed the case for various action links. +- Adjusted the color of action links which delete or remove objects to + red. +- Improved vertical alignment inside of various tabular displays. diff --git a/docs/release-notes/release-notes-3.5.1.rst b/docs/release-notes/release-notes-3.5.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.5.1.rst @@ -0,0 +1,15 @@ +|RCE| 3.5.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-09-07 + +Fixes +^^^^^ + +* License: Apply a trial license if a valid one is missing during the + database upgrade process. +* License: Added a license converter URL on the + :menuselection:`Admin --> Settings --> License` page. diff --git a/docs/release-notes/release-notes-3.5.2.rst b/docs/release-notes/release-notes-3.5.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.5.2.rst @@ -0,0 +1,14 @@ +|RCE| 3.5.2 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-09-22 + +Packaging +^^^^^^^^^ + +* General: Include `Gevent`_ by default. + +.. _Gevent: http://www.gevent.org/ diff --git a/docs/release-notes/release-notes-3.6.0.rst b/docs/release-notes/release-notes-3.6.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.6.0.rst @@ -0,0 +1,99 @@ +|RCE| 3.6.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-10-19 + +Pull Requests +^^^^^^^^^^^^^ + +- The :guilabel:`Inline Comments` notification now links to the + first inline comment, enabling faster comment navigation. +- Added a link to inline comments which links to the the + previous and next one, enabling faster comment navigation. +- Pull request handling has been made more robust to avoid an internal server + error after an update which had commits removed or stripped from the + repository. + +User Experience +^^^^^^^^^^^^^^^ + +- Consistent date display in the list of |repo| forks, multi-commit + compare view. +- Consistent sorting of the permissions box on the various settings pages. +- A yellow indicator has been added to highlight the selected inline comment + on a pull request. +- The expand button for commit messages now works to minimize also. +- Language improvements on various settings pages to clarify user options. +- Consistent sorting of |repo| permissions so that it is easier to find + specific users for |repos| which have many permission entries. + +API +^^^ + +- Added a new API call ``get_license_info`` which provides details about + the current license to automate processing. +- Added a new API call ``set_license_key`` which allows the license key to + be set via the API. + +News +^^^^ + +- General: Updated the hgsubversion module to prepare for the update to a more + recent |hg| version. +- General: Added an overview of external dependencies and their licenses. +- Repository: Link Git submodules if they point to a full URL. +- Settings: Extend the internal settings handling to prepare for per repository + settings. + +VCS Server +^^^^^^^^^^ + +- VCS Server: Support IPv6 addresses in the VCS Server configuration. +- VCS Server: Prepare for the Mercurial update to version 3.5. + +Fixes +^^^^^ + +- Admin: Fill default values in the :guilabel:`Global permissions` form for user + settings. +- Admin: Improve the issue tracker form patterns, especially when + editing an existing pattern. +- Admin: Bring back the :guilabel:`Admin` column into the users overview. Use + symbols for both Boolean states. +- Auth: Avoid querying all groups when using LDAP. +- Compare: Do not offer the comment button if the comparison is empty. +- DB: Migrate the locking information for repositories to a three tuple for + old entries. +- DB: Add tables to support per repository settings. +- Diff: Remove link from context lines in diffs. +- Files: Preview functionality when editing RST files. +- General: Avoid logging an error if a commit with a not existing hash is + requested. +- General: Fix scrolling to inline comments for Firefox browsers based on the + anchor from the URL. +- Gist: Fix display in IE8 for very long lines. +- Git: Support branch names which include ``/``. +- Repository: Keep line breaks in the repository description. +- Search: Fix an issue around the highlighting of search results. Sometimes + matches were not highlighted when there were multiple matches in one line. + +Style +^^^^^ + +- Fixed overlapped displaying of notifications when a new user registers an + account. +- Consistent display of labels for version control tags. +- Better alignment of the changelog graph. +- Fix rendering of the avatar images on IE9. +- Adjust the button style on the user profile edit page. +- Consistent styling of :guilabel:`Delete` buttons. +- Changelog graph for Subversion repositories was not aligned well. +- Changelog filter button style corrected. +- Adjust link colors in password forgotten form. +- Alignment of file names in diffs. +- Adjust the alignment of the permission summary title for user groups. +- Adjust the colour of form labels in the login and register forms. +- Remove the scroll bars from text areas in IE9. diff --git a/docs/release-notes/release-notes-3.6.1.rst b/docs/release-notes/release-notes-3.6.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.6.1.rst @@ -0,0 +1,23 @@ +|RCE| 3.6.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +* 2015-10-19 + +Security +^^^^^^^^ + +* HTTP response splitting on login redirection has been secured to + prevent header injection. + +Fixes +^^^^^ + +* Alphabetically sort the external license dependencies overview for quicker + reading. +* Change directory permissions checks for Windows. +* Fixed a login redirection issue when using a custom prefix to improve the + user experience when using a proxy server. +* Skip reading |repos| with names that contain special characters. diff --git a/docs/release-notes/release-notes-3.7.0.rst b/docs/release-notes/release-notes-3.7.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.7.0.rst @@ -0,0 +1,66 @@ +|RCE| 3.7.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2015-11-09 + +Pull Requests +^^^^^^^^^^^^^ + +- Added a |pr| update overview which lists the added, updated, and removed + files as an automated comment each time a |pr| is updated. +- The :guilabel:`Comment` functionality is no longer displayed on closed + |prs|. +- Main comments which don’t change the review status are now submitted via + ajax, and no longer require a page refresh. + +Repository Settings +^^^^^^^^^^^^^^^^^^^ + +Added per |repo| settings functionality, and these override the global +settings. You can now configure the following settings per |repo|. For more +information, see the :ref:`permissions-info-add-group-ref` section. + +- The VCS settings on the + :menuselection:`Admin --> Repo name --> Edit --> VCS` page. +- The Issue Tracker settings on the + :menuselection:`Admin --> Repo name --> Edit --> Issue Tracker` page. + +Fixes +^^^^^ + +- Auth: Updated authentication logging to avoid logging an error if a user does + not yet exist in the database. +- Admin: Fixed a redirect issue when clicking the admin menu. +- Style: Fixed misaligned previous/next |pr| comment links. +- Repository Scan: Fixed a potential race condition during initial |repo| scan. + +User Experience +^^^^^^^^^^^^^^^ + +- Buttons: Fixed comments duplicating when someone clicks the + :guilabel:`comment` button multiple times. +- Buttons: Fixed an error showing when someone clicks the :guilabel:`delete` + button multiple times. +- Auto Complete: Optimized the user autocomplete listing performance. + +News +^^^^ + +- Mercurial: Changing large files settings now works without having to + restart the |RCE| instance. +- Settings: The issue tracker patterns form now save changes in bulk + rather than having to save changes individually. + +Style +^^^^^ + +- Multiple tweaks for IE8 around alert messages and the changelog display. +- Adjusted the styling of the |pr| merge and preview buttons for comments. + +Deprecations +^^^^^^^^^^^^ + +- Internet Explorer 8. This is the last release which officially supports IE8. diff --git a/docs/release-notes/release-notes-3.7.1.rst b/docs/release-notes/release-notes-3.7.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.7.1.rst @@ -0,0 +1,46 @@ +|RCE| 3.7.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2015-12-10 + +Security +^^^^^^^^ + +Removed logging of masked authentication tokens completely. This prevents +potentially logging parts of a user's password if they are not using tokens. + +Admin +^^^^^ + +- Created the ability for |RCE| to auto-detect |hg| |repos| which require the + *Largefiles* extension during *Remap and Rescan* operations. +- Allow the admin of a repository group to change the group's settings even if + he/she does not have admin permission for the parent |repo| group. + +Authentication +^^^^^^^^^^^^^^ + +Fixed support for non-ascii characters in passwords when authenticating +using external authentication tools such as LDAP. + +Pull Requests +^^^^^^^^^^^^^ + +- Fixed an issue when merging Mercurial pull requests which are not based on + branch names. +- Fixed generated URL creation when |RCE| is running under a URL prefix. + +|SVN| +^^^^^ + +Fixed streaming issues when using Gunicorn based setups. + +User Experience +^^^^^^^^^^^^^^^ + +Improved avatar rendering stability. Especially in the case of an invalid +email address being used with an external authentication backend. + diff --git a/docs/release-notes/release-notes-3.8.0.rst b/docs/release-notes/release-notes-3.8.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.8.0.rst @@ -0,0 +1,168 @@ +|RCE| 3.8.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-02-10 + + +Authentication +^^^^^^^^^^^^^^ + +- Mercurial: Added an option to avoid a loop when the password is wrong during + VCS operations. This prevents accounts in external systems being locked + due to too many login attempts from Mercurial. See the :ref:`hg-auth-loop` + section for more details. +- Auth: Speed improvements in the permission calculation of API calls. + +API +^^^ + +- Added a new method, `update_pull_request`, which allows users to + update a pull request using the API. + +Deprecation +^^^^^^^^^^^ + +- Support for Internet Explorer 9 ends with this release. + +Pull Requests +^^^^^^^^^^^^^ + +- Added functionality that now automatically fills the title and description + fields based on the forks or branches involved, and the commit messages. +- Added a new URL endpoint which redirects to the pull request page + for a given pull request ID. This is intended to support automation of + specific work flows. The URL is ``/pull_requests/<pull_request_id>``. +- Removed the :guilabel:`Close Pull Request` button. This functionality is + still available in the status drop-down menu below the comment box. +- Improved the merge logic so that merges on the same branch are + possible even if the reference type is not a branch, e.g. bookmark, tag, or + a raw commit ID. +- Escaped the description field to prevent potential XSS attacks. + +UI/UX +^^^^^ + +**D** + +- Diff: Fixed display issues around side-by-side diffs. +- Diff: The side-by-side diff has been enhanced. Small arrows now allow you to + jump to the next or previous change, and an editor mode is available as a + helper for complex diffs. + +**F** + +- Files: Allow users to add empty files through the web interface. +- Files: Do not prompt users without write permissions to add files to an empty + repository. +- Files: Prevent submitting multiple times when editing a file. +- Files: Render files with the extension :file:`.txt` as plain text. +- Files: Use the correct file name extension for markdown files. + +**J** + +- Journal: Fixed display issues in the admin journal. +- Journal: Improved the display of query examples for the search feature. + +**L** + +- License: The amount of active users is now shown on the license page and + provides the ability to disable users in bulk mode. + +**R** + +- Repository group: The buttons to add a repository or a repository group are + now displayed only if the user has those permissions for the current + repository group. +- Repository: A more informative message is now displayed in case a Mercurial + repository depends on the *largefiles* extension, but this extension is not + enabled. +- Repository: Fixed the loading of the commit summary to avoid an additional + page reload. + +**S** + +- Style: The text alignment around the settings area was improved. +- Style: IE10 no longer shows a wrong background color in the select widgets. +- Style: Small corrections in the navigation around the :guilabel:`My Account` + menu. +- Style: Consistent display of user names in tabular lists of repositories + and repository groups. +- Style: Adjust the help text around the gravatar in the profile page. +- Style: Added consistent use of the term *Commit* instead of a mix of + *Changeset* and *Revision*. +- Style: Restrict the value for custom branding to 40 characters. +- Style: Consistent rendering of markdown content. +- Subversion: Display the clone URL as read only and show a detailed help + message for Subversion repositories if the HTTP proxy for write access is not + enabled. + +Logging +^^^^^^^ + +- Logging: Added logging details about the added and removed users when a user + group is updated. +- Logging: Removed excessive error logging when detecting the server address. +- Logging: Improvements to avoid an early import of Pyro4, this is important + for advanced setups using asynchronous workers. + +VCS Server +^^^^^^^^^^ + +- VCS Server: Keep the remote traceback in case of a remote exception. This + results in more precise information in the log files and helps to track down + problems easier. +- VCS Server: Only write a PID file if requested via the command line. +- VCS Server: Explicitly close file descriptors for Git based operations to + avoid a potential leak of file descriptors. + +General +^^^^^^^ + +**A** + +- Admin: Fixed a bug that disallowed admins from deleting users which had + entries in the IP whitelist. + +**C** + +- Compare: Return a **404 Not Found** when comparing a missing commit. This + makes it consistent with the unified diff. +- Compare: Various fixes around the selection of the source and target commit. + +**G** + +- General: Allow admins to inject the initial API key in `setup_rhodecode`. This + simplifies the bootstrapping of automated setups. +- General: Added the ``pool_recycle`` option to the example :file:`.ini` file. +- General: Updated `CodeMirror`_ to 5.4.0. +- General: Speed improvements in multiple places which allow users to select a + repository or a repository group. +- Repository: Increase the maximum size for repository names and the clone URL + to prevent problems in deeply nested structures. +- General: Avoid invalid email addresses causing issues when rendering + avatar images when external authentication modules are used. + +**R** + +- Repository: Enable the Mercurial *largefiles* extension during the run of + *Remap & Rescan*. This detects *largefiles* repositories and adds them to + the system. +- Repository: Robust forking of Mercurial repositories which depend on the + *largefiles* extension in cases where this extension is not globally + enabled. +- Repository: Made the query of very large commit sets more robust on + MySQL. This affects cases when more than 500 commits are involved. + +**S** + +- Settings: Save the correct value when disabling *largefiles* for a repository. +- Settings: Add misdirection to external links in the issue tracker settings. +- Settings: Avoid a jumping lock button in the case of a validation error being + displayed. +- Settings: Speed up the repository settings by delaying the query for the fork + selection element. + +.. _CodeMirror: https://codemirror.net/ diff --git a/docs/release-notes/release-notes-3.8.1.rst b/docs/release-notes/release-notes-3.8.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.8.1.rst @@ -0,0 +1,29 @@ +|RCE| 3.8.1 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-03-10 + + +General +^^^^^^^ + +- Fixed the problem due to a missing index when migrating from very old databases. +- Fixed problem with being unable to delete users which have set permissions on user groups. + +Authentication +^^^^^^^^^^^^^^ + +- Take user group base DN in LDAP filtering. + +API +^^^ + +- Better error handling if an inactive user account is used to make an API call. + +VCS Server +^^^^^^^^^^ + +- Avoid error message around missing “object_store” being printed in logs. \ No newline at end of file diff --git a/docs/release-notes/release-notes-3.8.2.rst b/docs/release-notes/release-notes-3.8.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.8.2.rst @@ -0,0 +1,19 @@ +|RCE| 3.8.2 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-03-17 + +Admin +^^^^^ +Admin: Return a forbidden status when trying to create a repository group without sufficient permissions for the parent group. + +Security +^^^^^^^^ +Security: Update the bundled Git to version 2.7.1 (ᴄᴠᴇ-2016-2324 and ᴄᴠᴇ‑2016‑2315). + +Subversion +^^^^^^^^^^ +Subversion: Fix MKCOL requests which are used when committing new folders into a Subversion repository. \ No newline at end of file diff --git a/docs/release-notes/release-notes-3.8.3.rst b/docs/release-notes/release-notes-3.8.3.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.8.3.rst @@ -0,0 +1,11 @@ +|RCE| 3.8.3 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-03-18 + +Security +^^^^^^^^ +Security: Update the bundled Git to version 2.7.4 (ᴄᴠᴇ-2016-2324 and ᴄᴠᴇ‑2016‑2315). diff --git a/docs/release-notes/release-notes-3.8.4.rst b/docs/release-notes/release-notes-3.8.4.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-3.8.4.rst @@ -0,0 +1,12 @@ +|RCE| 3.8.4 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-05-05 + +Security +^^^^^^^^ +Security: Update the bundled Mercurial to version 3.7.3 + CVE-2016-3630, CVE-2016-3068, CVE-2015-7545, CVE-2016-3069 \ No newline at end of file diff --git a/docs/release-notes/release-notes-4.0.0.rst b/docs/release-notes/release-notes-4.0.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-4.0.0.rst @@ -0,0 +1,58 @@ +|RCE| 4.0.0 |RNS| +----------------- + +Release Date +^^^^^^^^^^^^ + +- 2016-05-24 + +General +^^^^^^^ + +- Introduced Pyramid as a Pylons framework replacement. (porting still ongoing). + Added few of components as plugins. Exposed RhodeCode plugins API for 3rd + parties to extend RhodeCode functionality with custom pyramid apps. Pyramid + is also our route to python3 support. +- Various UX/UI improvements. + - new summary page + - new file browser (more consistent) + - re-done admin section and added Panels + - various other tweaks and improvements +- Alternative fast and scalable HTTP based communication backend for VCServer. + It soon will replace Pyro4. +- Rewrote few caching techniques used and simplified those + + +New Features +^^^^^^^^^^^^ + +- RhodeCode code-review live chat (EE only). A live communication + tool built right into the code-review process to quickly + collaborate on crucial parts of code. + +- Elastic Search backend (EE only). Alternative backend to existing + Whoosh to handle, large amount of data for full text search. + +- Social Auth (EE only): added new social authentication backends including: + Github, Twitter, Bitbucket and Google. It's possible now to use your + Google account to log in to RhodeCode and take advantage of things like 2FA. + +Security +^^^^^^^^ + +- Added new action loggers for actions like adding/revoking permissions. + + +Performance +^^^^^^^^^^^ + +- Optimized admin pannels to faster load large ammount of data +- Improved file tree loading speed + + +Fixes +^^^^^ + +- Fixed backreferences to user group when deleting users +- Fixed LDAP group user-group matching +- Improved SVN support for various commands (MKOL, etc) \ No newline at end of file diff --git a/docs/release-notes/release-notes.rst b/docs/release-notes/release-notes.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes.rst @@ -0,0 +1,75 @@ +.. _rhodecode-release-notes-ref: + +Release Notes +============= + +|RCE| 4.x Versions +------------------ + + release-notes-4.0.0.rst + +|RCE| 3.x Versions +------------------ + +.. toctree:: + :maxdepth: 1 + + release-notes-3.8.4.rst + release-notes-3.8.3.rst + release-notes-3.8.2.rst + release-notes-3.8.1.rst + release-notes-3.8.0.rst + release-notes-3.7.1.rst + release-notes-3.7.0.rst + release-notes-3.6.1.rst + release-notes-3.6.0.rst + release-notes-3.5.2.rst + release-notes-3.5.1.rst + release-notes-3.5.0.rst + release-notes-3.4.1.rst + release-notes-3.4.0.rst + release-notes-3.3.4.rst + release-notes-3.3.3.rst + release-notes-3.3.2.rst + release-notes-3.3.1.rst + release-notes-3.3.0.rst + release-notes-3.2.3.rst + release-notes-3.2.2.rst + release-notes-3.2.1.rst + release-notes-3.2.0.rst + release-notes-3.1.1.rst + release-notes-3.1.0.rst + release-notes-3.0.2.rst + release-notes-3.0.1.rst + release-notes-3.0.0.rst + +|RCE| 2.x Versions +------------------ + +.. toctree:: + :maxdepth: 1 + + release-notes-2.2.8.rst + release-notes-2.2.7.rst + release-notes-2.2.6.rst + release-notes-2.2.5.rst + release-notes-2.2.4.rst + release-notes-2.2.3.rst + release-notes-2.2.2.rst + release-notes-2.2.1.rst + release-notes-2.2.0.rst + release-notes-2.1.0.rst + release-notes-2.0.2.rst + release-notes-2.0.1.rst + release-notes-2.0.0.rst + +|RCE| 1.x Versions +------------------ + +.. toctree:: + :maxdepth: 1 + + release-notes-1.7.2.rst + release-notes-1.7.1.rst + release-notes-1.7.0.rst + release-notes-1.6.0.rst diff --git a/docs/static/css/add.css b/docs/static/css/add.css new file mode 100644 --- /dev/null +++ b/docs/static/css/add.css @@ -0,0 +1,13 @@ +.menuselection, .guilabel { + font-size: .90em; + font-family: "proximanovaregular", "Proxima Nova Regular", "Proxima Nova", sans-serif; + font-style: oblique; +} + +.version{ + display: none; + } + +.pre{ + color:#000 + } diff --git a/docs/tools/install-tools.rst b/docs/tools/install-tools.rst new file mode 100644 --- /dev/null +++ b/docs/tools/install-tools.rst @@ -0,0 +1,85 @@ +.. _install-tools: + +|RCT| Installation +------------------ + +As of |RCE| 3.4.1 |RCT| is installed automatically on the server with |RCE|. You +do not need to install |RCT| on the server, but you will need to install them +on machines that need remote access. The tools are linked to the instance +folder, for example :file:`~/.rccontrol/{instance-id}/profile/bin` + +You can list the available tools using the following example, and the valid +tools options are those which correspond with those in the :ref:`rc-tools` +section. + +.. code-block:: bash + + $ ls ~/.rccontrol/enterprise-4/profile/bin/ + + gen_js_i18n rhodecode-cleanup-gists rhodecode-tools svnrdump + gen_js_routes rhodecode-cleanup-repos supervisorctl svnserve + git rhodecode-config supervisord svnsync + gunicorn rhodecode-extensions svn svnversion + hg rhodecode-gist svnadmin vcsserver + paster rhodecode-index svndumpfilter + rcserver rhodecode-list-instances svnlook + rhodecode-api rhodecode-setup-config svnmucc + +You can then use the tools as described in the :ref:`rc-tools` section using the +following example: + +.. code-block:: bash + + # Running the indexer + $ ~/.rccontrol/enterprise-1/profile/bin/rhodecode-index \ + --instance-name=enterprise-1 + + # Cleaning up gists + $ ~/.rccontrol/enterprise-4/profile/bin/rhodecode-cleanup-gists \ + --instance-name=enterprise-4 + + Scanning for gists in /home/brian/repos/.rc_gist_store... + preparing to remove [1] found gists + +Installing |RCT| +^^^^^^^^^^^^^^^^ + +|RCT| enable you to automate many of the most common |RCM| functions through +the API. Installing them on a local machine lets you carry out maintenance on +the server remotely. Once installed you can use them to index your |repos| +to setup full-text search, strip commits, or install |RC| Extensions for +additional functionality. + +For more detailed instructions about using |RCT| for indexing and full-text +search, see :ref:`indexing-ref` + +To install |RCT|, use the following steps: + +1. Set up a ``virtualenv`` on your local machine, see virtualenv_ instructions + here. +2. Install |RCT| using pip. Full url with token is available at https://rhodecode.com/u/#rhodecode-tools + ``pip install -I https://dls.rhodecode.com/dls/<token>/rhodecode-tools/latest`` + + +Once |RCT| is installed using these steps there are a few extra +configuration changes you can make. These are explained in more detail in the +:ref:`indexing-ref` section, and the :ref:`rc-tools` section. + +.. code-block:: bash + + # Create a virtualenv + brian@ubuntu:~$ virtualenv venv + New python executable in venv/bin/python + Installing setuptools, pip...done. + + # Activate the virtualenv + brian@ubuntu:~$ . venv/bin/activate + + # Install RhodeCode Tools inside the virtualenv, full url with token is available at https://rhodecode.com/u/#rhodecode-tools + $ pip install -I https://dls.rhodecode.com/dls/<token>/rhodecode-tools/latest + + # Check the installation + $ rhodecode-tools --help + +.. _virtualenv: https://virtualenv.pypa.io/en/latest/index.html + diff --git a/docs/tools/rhodecode-tools.rst b/docs/tools/rhodecode-tools.rst new file mode 100644 --- /dev/null +++ b/docs/tools/rhodecode-tools.rst @@ -0,0 +1,14 @@ +.. _rc-tools: + +|RCT| +===== + +|RCT| enable you to automate many of the most common |RCM| functions through +the API. + +.. toctree:: + :maxdepth: 1 + + tools-overview + install-tools + tools-cli diff --git a/docs/tools/tools-cli.rst b/docs/tools/tools-cli.rst new file mode 100644 --- /dev/null +++ b/docs/tools/tools-cli.rst @@ -0,0 +1,677 @@ +.. _tools-cli: + +|RCT| CLI +--------- + +The commands available with |RCT| can be split into three categories: + +- Remotely executable commands that can be run from your local machine once you + have your connection details to |RCE| configured. +- Locally executable commands the can be run on the server to carry out + general maintenance. +- Local configuration commands used to help set up your |RCT| configuration. + + +rhodecode-tools +--------------- + +Use |RCT| to setup automation, run the indexer, and install extensions for +your |RCM| instances. Options: + +.. rst-class:: dl-horizontal + + \ - -apihost <api_host> + Set the API host value. + + \ - -apikey <apikey_value> + Set the API key value. + + \-c, - -config <config_file> + Create a configuration file. The default file is created + in ``~/.rhoderc`` + + \ - -save-config + Save the configuration file. + + \ - -show-config + Show the current configuration values. + + \ - -format {json,pretty} + Set the formatted representation. + +Example usage: + +.. code-block:: bash + + $ rhodecode-tools --apikey=key --apihost=http://rhodecode.server \ + --save-config + +rhodecode-api +------------- + +The |RC| API lets you connect to |RCE| and carry out management tasks from a +remote machine, for more information about the API, see the :ref:`api`. To +pass arguments on the command-line use the ``method:option`` syntax. + +Example usage: + +.. code-block:: bash + + # Run the get_repos API call and sample output + $ rhodecode-api --instance-name=enterprise-1 create_repo \ + repo_name:brand-new repo_type:hg description:repo-desc + + { + "error": null, + "id": 1110, + "result": { + "msg": "Created new repository `brand-new`", + "success": true, + "task": null + } + } + +Options: + +.. rst-class:: dl-horizontal + + \ - -api-cache-only + Requires a cache to be present when running this call + + \ - -api-cache-rebuild + Replaces existing cached values with new ones from server + + \ - -api-cache <PATH> + Use a special cache dir to read responses from instead of the server + + \ - -api-cert-verify + Verify the endpoint ssl certificate + + \ - -api-cert <PATH> + Path to alternate CA bundle. + + \ - -apihost <api_host> + Set the API host value. + + \ - -apikey <apikey_value> + Set the API key value. + + \ - -instance-name <instance-id> + Set the instance name + + \-I, - -install-dir <DIR> + Location of application instances + + \-c, - -config <.rhoderc-file> + Location of the :file:`.rhoderc` + + \-F, - -format {json,pretty} + Set the formatted representation. + + \-h, - -help + Show help messages. + + \-v, - -verbose + Enable verbose messaging + +rhodecode-cleanup-gists +----------------------- + +Use this to delete gists within |RCM|. Options: + +.. rst-class:: dl-horizontal + + \-c, - -config <config_file> + Set the file path to the configuration file. The default file is + :file:`/home/{user}/.rhoderc` + + \ - -corrupted + Remove gists with corrupted metadata. + + \ - -dont-ask + Remove gists without asking for confirmation. + + \-h, - -help + Show help messages. current configuration values. + + \ - -instance-name <instance-id> + Set the instance name. + + \-R, - -repo-dir + Set the repository file path. + + \ - -version + Display your |RCT| version. + +Example usage: + +.. code-block:: bash + + # Clean up gists related to an instance + $ rhodecode-cleanup-gists --instance-name=enterprise-1 + Scanning for gists in /home/brian/repos/.rc_gist_store... + preparing to remove [3] found gists + + # Clean up corrupted gists in an instance + $ rhodecode-cleanup-gists --instance-name=enterprise-1 --corrupted + Scanning for gists in /home/brian/repos/.rc_gist_store... + preparing to remove [2] found gists + the following gists will be archived: + * EXPIRED: BAD METADATA | /home/brian/repos/.rc_gist_store/5 + * EXPIRED: BAD METADATA | /home/brian/repos/.rc_gist_store/8FtC + are you sure you want to archive them? [y/N]: y + removing gist /home/brian/repos/.rc_gist_store/5 + removing gist /home/brian/repos/.rc_gist_store/8FtCKdcbRKmEvRzTVsEt + +rhodecode-cleanup-repos +----------------------- + +Use this to manage |repos| and |repo| groups within |RCM|. Options: + +.. rst-class:: dl-horizontal + + \-c, - -config <config_file> + Set the file path to the configuration file. The default file is + :file:`/home/{user}/.rhoderc`. + + \-h, - -help + Show help messages. current configuration values. + + \ - -interactive + Enable an interactive prompt for each repository when deleting. + + \ - -include-groups + Remove repository groups. + + \ - -instance-name <instance-id> + Set the instance name. + + \ - -list-only + Display repositories selected for deletion. + + \ - -older-than <str> + Delete repositories older that a specified time. + You can use the following suffixes; d for days, h for hours, + m for minutes, s for seconds. + + \-R, - -repo-dir + Set the repository file path + +Example usage: + +.. code-block:: bash + + # Cleaning up repos using tools installed with RCE 350 and above + $ ~/.rccontrol/enterprise-4/profile/bin/rhodecode-cleanup-repos \ + --instance-name=enterprise-4 --older-than=1d + Scanning for repositories in /home/brian/repos... + preparing to remove [2] found repositories older than 1 day, 0:00:00 (1d) + + the following repositories will be deleted completely: + * REMOVED: 2015-08-05 00:23:18 | /home/brian/repos/rm__20150805_002318_831 + * REMOVED: 2015-08-04 01:22:10 | /home/brian/repos/rm__20150804_012210_336 + are you sure you want to remove them? [y/N]: + + # Clean up repos older than 1 year + # If using virtualenv and pre RCE 350 tools installation + (venv)$ rhodecode-cleanup-repos --instance-name=enterprise-1 \ + --older-than=365d + + Scanning for repositories in /home/brian/repos... + preparing to remove [343] found repositories older than 365 days + + # clean up repos older than 3 days + # If using virtualenv and pre RCE 350 tools installation + (venv)$ rhodecode-cleanup-repos --instance-name=enterprise-1 \ + --older-than=3d + Scanning for repositories in /home/brian/repos... + preparing to remove [3] found repositories older than 3 days + +.. _tools-config: + +rhodecode-config +---------------- + +Use this to create or update a |RCE| configuration file on the local machine. + +.. rst-class:: dl-horizontal + + \- -filename </path/to/config_file> + Set the file path to the |RCE| configuration file. + + \- -show-defaults + Display the defaults set in the |RCE| configuration file. + + \- -update + Update the configuration with the new settings passed on the command + line. + +.. code-block:: bash + + # Create a new config file + $ rhodecode-config --filename=dev.ini + Wrote new config file in /Users/user/dev.ini + + # Update config value for given section: + $ rhodecode-config --update --filename=prod.ini [handler_console]level=INFO + + $ rhodecode-config --filename=dev.ini --show-defaults + lang=en + cpu_number=4 + uuid=<function <lambda> at 0x10d86ac08> + license_token=ff1e-aa9c-bb66-11e5 + host=127.0.0.1 + here=/Users/brian + error_aggregation_service=None + database_url=sqlite:///%(here)s/rhodecode.db?timeout=30 + git_path=git + http_server=waitress + port=5000 + +.. _tools-rhodecode-extensions: + +rhodecode-extensions +-------------------- + +|RCT| adds additional mapping for :ref:`indexing-ref`, statistics, and adds +additional code for push/pull/create/delete |repo| hooks. These hooks can be +used to send signals to build-bots such as jenkins. Options: + +.. rst-class:: dl-horizontal + + \-c, - -config <config_file> + Create a configuration file. The default file is created + in ``~/.rhoderc`` + + \-h, - -help + Show help messages. + + \-F, - -format {json,pretty} + Set the formatted representation. + + \-I, - -install-dir <str> + Set the location of the |RCE| installation. The default location is + :file:`/home/{user}/.rccontrol/`. + + \ - -ini-file <str> + Path to the :file:`rhodecode.ini` file for that instance. + + \ - -instance-name <instance-id> + Set the instance name. + + \ - -plugins + Add plugins to your |RCE| installation. See the + :ref:`integrations-ref` section for more details. + + \ - -version + Display your |RCT| version. + + +Once installed, you will see a :file:`rcextensions` folder in the instance +directory, for example :file:`home/{user}/.rccontrol/{instance-id}/rcextensions` + +To install ``rcextensions``, use the following example: + +.. code-block:: bash + + # install extensions on the given instance + # If using virtualenv prior to RCE 350 + (venv)$ rhodecode-extensions --instance-name=enterprise-1 \ + --ini-file=rhodecode.ini + Writen new extensions file to rcextensions + + # install extensions with additional plugins on the given instance + (venv)$ rhodecode-extensions --instance-name=enterprise-1 \ + --ini-file=rhodecode.ini --plugins + Writen new extensions file to rcextensions + + # installing extensions from 350 onwards + # as they are packaged with RCE + $ .rccontrol/enterprise-4/profile/bin/rhodecode-extensions --plugins \ + --instance-name=enterprise-4 --ini-file=rhodecode.ini + + Writen new extensions file to rcextensions + +See the new extensions inside this directory for more details about the +additional hooks available, for example see the ``push_post.py`` file. + +.. code-block:: python + + import urllib + import urllib2 + + def run(*args, **kwargs): + """ + Extra params + + :param URL: url to send the data to + """ + + url = kwargs.pop('URL', None) + if url: + from rhodecode.lib.compat import json + from rhodecode.model.db import Repository + + repo = Repository.get_by_repo_name(kwargs['repository']) + changesets = [] + vcs_repo = repo.scm_instance_no_cache() + for r in kwargs['pushed_revs']: + cs = vcs_repo.get_changeset(r) + changesets.append(json.dumps(cs)) + + kwargs['pushed_revs'] = changesets + headers = { + 'User-Agent': 'RhodeCode-SCM web hook', + 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', + 'Accept': 'text/javascript, text/html, application/xml, ' + 'text/xml, */*', + 'Accept-Encoding': 'gzip,deflate,sdch', + } + + data = kwargs + data = urllib.urlencode(data) + req = urllib2.Request(url, data, headers) + response = urllib2.urlopen(req) + response.read() + return 0 + + +rhodecode-gist +-------------- + +Use this to create, list, show, or delete gists within |RCM|. Options: + +.. rst-class:: dl-horizontal + + \ - -api-cache-only + Requires a cache to be present when running this call + + \ - -api-cache-rebuild + Replaces existing cached values with new ones from server + + \ - -api-cache PATH + Use a special cache dir to read responses from instead of the server + + \ - -api-cert-verify + Verify the endpoint ssl certificate + + \ - -api-cert PATH + Path to alternate CA bundle. + + \ - -apihost <api_host> + Set the API host value. + + \ - -apikey <apikey_value> + Set the API key value. + + \-c, - -config <config_file> + Create a configuration file. + The default file is created in :file:`~/.rhoderc` + + \ - -create <gistname> + create the gist + + \-d, - -description <str> + Set gist description + + \ - -delete <gistid> + Delete the gist + + \-f, - -file + Specify the filename The file extension will enable syntax highlighting. + + \-F, - -format {json,pretty} + Set the formatted representation. + + \ - -help + Show help messages. + + \-I, - -install-dir <DIR> + Location of application instances + + \ - -instance-name <instance-id> + Set the instance name. + + \ - -list + Display instance gists. + + \-l, --lifetime <minutes> + Set the gist lifetime. The default value is (-1) forever + + \ - -show <gistname> + Show the content of the gist + + \-o, - -open + After creating Gist open it in browser + + \-p, - -private + Create a private gist + + \ - -version + Display your |RCT| version. + +Example usage: + +.. code-block:: bash + + # List the gists in an instance + (venv)brian@ubuntu:~$ rhodecode-gist --instance-name=enterprise-1 list + { + "error": null, + "id": 7102, + "result": [ + { + "access_id": "2", + "content": null, + "created_on": "2015-01-19T12:52:26.494", + "description": "A public gust", + "expires": -1.0, + "gist_id": 2, + "type": "public", + "url": "http://127.0.0.1:10003/_admin/gists/2" + }, + { + "access_id": "7gs6BsSEC4pKUEPLz5AB", + "content": null, + "created_on": "2015-01-19T11:27:40.812", + "description": "Gist testing API", + "expires": -1.0, + "gist_id": 1, + "type": "private", + "url": "http://127.0.0.1:10003/_admin/gists/7gs6BsSEC4pKUEPLz5AB" + } + ] + } + + # delete a particular gist + # You use the access_id to specify the gist to delete + (venv)brian@ubuntu:~$ rhodecode-gist delete 2 --instance-name=enterprise-1 + { + "error": null, + "id": 6284, + "result": { + "gist": null, + "msg": "deleted gist ID:2" + } + } + + # cat a file and pipe to new gist + # This is if you are using virtualenv + (venv)$ cat ~/.rhoderc | rhodecode-gist --instance-name=enterprise-1 \ + -d '.rhoderc copy' create + + { + "error": null, + "id": 5374, + "result": { + "gist": { + "access_id": "7", + "content": null, + "created_on": "2015-01-26T11:31:58.774", + "description": ".rhoderc copy", + "expires": -1.0, + "gist_id": 7, + "type": "public", + "url": "http://127.0.0.1:10003/_admin/gists/7" + }, + "msg": "created new gist" + } + } + + # Cat a file and pipe to gist + # in RCE 3.5.0 tools and above + $ cat ~/.rhoderc | ~/.rccontrol/{instance-id}/profile/bin/rhodecode-gist \ + --instance-name=enterprise-4 -d '.rhoderc copy' create + { + "error": null, + "id": 9253, + "result": { + "gist": { + "access_id": "4", + "acl_level": "acl_public", + "content": null, + "created_on": "2015-08-20T05:54:11.250", + "description": ".rhoderc copy", + "expires": -1.0, + "gist_id": 4, + "modified_at": "2015-08-20T05:54:11.250", + "type": "public", + "url": "http://127.0.0.1:10000/_admin/gists/4" + }, + "msg": "created new gist" + } + } + + +rhodecode-index +--------------- + +More detailed information regarding setting up the indexer is available in +the :ref:`indexing-ref` section. Options: + +.. rst-class:: dl-horizontal + + \ - -api-cache-only + Requires a cache to be present when running this call + + \ - -api-cache-rebuild + Replaces existing cached values with new ones from server + + \ - -api-cache PATH + Use a special cache dir to read responses from instead of the server + + \ - -api-cert-verify + Verify the endpoint ssl certificate + + \ - -api-cert PATH + Path to alternate CA bundle. + + \ - -apihost <api_host> + Set the API host value. + + \ - -apikey <apikey_value> + Set the API key value. + + \-c, --config <config_file> + Create a configuration file. + The default file is created in :file:`~/.rhoderc` + + \ - -create-mapping <PATH> + Creates an example mapping configuration for indexer. + + \-F, - -format {json,pretty} + Set the formatted representation. + + \-h, - -help + Show help messages. + + \ - -instance-name <instance-id> + Set the instance name + + \-I, - -install-dir <DIR> + Location of application instances + + \-m, - -mapping <file_name> + Parse the output to the .ini mapping file. + + \ - -optimize + Optimize index for performance by amalgamating multiple index files + into one. Greatly increases incremental indexing speed. + + \-R, - -repo-dir <DIRECTORY> + Location of repositories + + \ - -source <PATH> + Use a special source JSON file to feed the indexer + + \ - -version + Display your |RCT| version. + +Example usage: + +.. code-block:: bash + + # Run the indexer + $ ~/.rccontrol/enterprise-4/profile/bin/rhodecode-index \ + --instance-name=enterprise-4 + + # Run indexer based on mapping.ini file + # This is using pre-350 virtualenv + (venv)$ rhodecode-index --instance-name=enterprise-1 + + # Index from the command line without creating + # the .rhoderc file + $ rhodecode-index --apikey=key --apihost=http://rhodecode.server \ + --instance-name=enterprise-2 --save-config + + # Create the indexing mapping file + $ ~/.rccontrol/enterprise-4/profile/bin/rhodecode-index \ + --create-mapping mapping.ini --instance-name=enterprise-4 + +.. _tools-rhodecode-list-instance: + +rhodecode-list-instances +------------------------ + +Use this command to list the instance details configured in the +:file:`~/.rhoderc` file. + +.. code-block:: bash + + $ .rccontrol/enterprise-1/profile/bin/rhodecode-list-instances + [instance:production] - Config only + API-HOST: https://some.url.com + API-KEY: some.auth.token + + [instance:development] - Config only + API-HOST: http://some.ip.address + API-KEY: some.auth.token + + +.. _tools-setup-config: + +rhodecode-setup-config +---------------------- + +Use this command to create the ``~.rhoderc`` file required by |RCT| to access +remote instances. + +.. rst-class:: dl-horizontal + + \- -instance-name <name> + Specify the instance name in the :file:`~/.rhoderc` + + \api_host <hostname> + Create a configuration file. The default file is created + in ``~/.rhoderc`` + + \api_key <auth-token> + Create a configuration file. The default file is created + in ``~/.rhoderc`` + + +.. code-block:: bash + + (venv)$ rhodecode-setup-config --instance-name=tea api_host=URL api_key=xyz + Config not found under /Users/username/.rhoderc, creating a new one + Wrote new configuration into /Users/username/.rhoderc diff --git a/docs/tools/tools-overview.rst b/docs/tools/tools-overview.rst new file mode 100644 --- /dev/null +++ b/docs/tools/tools-overview.rst @@ -0,0 +1,76 @@ +.. _tools-overview: + +|RCT| Overview +-------------- + +To install |RCT| correctly, see the installation steps covered in +:ref:`install-tools`, and :ref:`config-rhoderc`. + +Once |RCT| is installed, and the :file:`/home/{user}/.rhoderc` file is +configured you can then use |RCT| on each |RCM| instance to carry out admin +tasks. Use the following example to configure that file, +and once configured see the :ref:`tools-cli` for more details. + +.. note:: + + |RCT| require |PY| 2.7 to run. + +.. code-block:: bash + + # Get the status of each instance you wish to use with Tools + (venv)brian@ubuntu:~$ rccontrol status + + - NAME: momentum-1 + - STATUS: RUNNING + - TYPE: Momentum + - VERSION: 3.0.0-nightly-momentum + - URL: http://127.0.0.1:10003 + + - NAME: momentum-3 + - STATUS: RUNNING + - TYPE: Momentum + - VERSION: 3.0.0-nightly-momentum + - URL: http://127.0.0.1:10007 + +Example :file:`/home/{user}/.rhoderc` file. + +.. code-block:: ini + + # Configure the .rhoderc file for each instance + # API keys found in your instance + [instance:enterprise-1] + api_host = http://127.0.0.1:10003/ + api_key = 91fdbdc257289c46633ef5aab274412911de1ba9 + repo_dir = /home/brian/repos + + [instance:enterprise-3] + api_host = http://127.0.0.1:10007/ + api_key = 5a925f65438d29f8d6ced8ab8e8c3d305998d1d9 + repo_dir = /home/brian/testing-repos/ + + +Example usage of |RCT| after |RCE| 3.5.0. From this version onwards |RCT| is +packaged with |RCE| by default. + +.. code-block:: bash + + $ .rccontrol/enterprise-4/profile/bin/rhodecode-extensions --plugins \ + --instance-name=enterprise-4 --ini-file=rhodecode.ini + + Writen new extensions file to rcextensions + Copied hipchat_push_notify.py plugin to rcextensions + Copied jira_pr_flow.py plugin to rcextensions + Copied default_reviewers.py plugin to rcextensions + Copied extract_commits.py plugin to rcextensions + Copied extract_issues.py plugin to rcextensions + Copied redmine_pr_flow.py plugin to rcextensions + Copied extra_fields.py plugin to rcextensions + Copied jira_smart_commits.py plugin to rcextensions + Copied http_notify.py plugin to rcextensions + Copied slack_push_notify.py plugin to rcextensions + Copied slack_message.py plugin to rcextensions + Copied extract_jira_issues.py plugin to rcextensions + Copied extract_redmine_issues.py plugin to rcextensions + Copied redmine_smart_commits.py plugin to rcextensions + Copied send_mail.py plugin to rcextensions + diff --git a/docs/tutorials/api-examples.rst b/docs/tutorials/api-examples.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/api-examples.rst @@ -0,0 +1,66 @@ +.. _api-ex: + +API Example Usage +================= + +Use the following example uses of the |RCE| API to carry out work on your +instances, or |repo| maintanence on the server. For the complete API +documentation, see the :ref:`api` section. + +.. _api-strip: + +Stripping Commits +----------------- + +The strip command is useful for removing commits on the server, allowing +you to push changes without using force. To strip commits on the server, use +the following steps: + +1. Install |RCT|, as explained in the :ref:`install-tools` section. +2. Configure the :file:`~/.rhoderc` file with the API connection details, as + explained in the :ref:`config-rhoderc` section. +3. Check the |RCE| changelog and see from which revision onwards you wish to + strip commits. This will also strip all descendants. + +.. image:: ../images/pre-strip.png + + +4. Enter your |RCT| virtual environment, using the following example: + +.. code-block:: bash + + $ . venv/bin/activate + (venv)$ + +5. Use the API to strip a commit, or number of commits from a |repo|. In this + example I am stripping the top two commits from ``ad1e0523a4ab`` onwards. + +.. note:: + + Repositories in |repo| groups require the |repo| group to be passed as + part of the ``repoid``. + +.. code-block:: bash + + # Run the Strip API call + $ rhodecode-api --instance-name=instance-id strip \ + repoid:repo-group/repo-name revision:ad1e0523a4ab branch:stable + + # Check the JSON-RPC verification + +.. code-block:: jsonld + + { + "error": null, + "id": 5960, + "result": { + "msg": "Stripped commit ad1e0523a4ab from + repo `repo-group/repo-name`", + "repository": "repo-group/repo-name" + } + } + +6. Once the commits are stripped, you can verify that they are + stripped on the web interface. + +.. image:: ../images/post-strip.png diff --git a/docs/tutorials/appenlight-setup.rst b/docs/tutorials/appenlight-setup.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/appenlight-setup.rst @@ -0,0 +1,103 @@ +How To Use |AE| to Monitor |RCE| +================================ + +* For cloud based monitoring using |AE|, `sign up for an account`_ first and + get your user details. +* For self hosted monitoring, you'll need to download and setup |AE| first. + Contact support@rhodecode.com for more details. + +|AE| Side Of The Setup +---------------------- + +- From the interface, create an application for |AE| to monitor: + :menuselection:`Settings --> Create Application` +- Add in your |RCE| instance details. +- Take note of the Public and Private API keys on the application page. You + will need to add the private key to your |RCE| configuration file. + +For more information, see the the |AE| documentation `here`_. + +|RCE| Side Of The Setup +----------------------- + +Once you have your |AE| account details, configure the |RCE| +:file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file with the +following details to set up the connection between the two systems. + +.. tip:: + + The section below should already be present in your configuration file if + running a recent version of |RCE|. + +* Enable the |AE| connection by setting ``appenlight = true``. +* Set your |AE| URL using the ``appenlight.server_url = URL`` option. +* Set your |AE| |authtoken| using the ``appenlight.api_key = TOKEN`` option. + +.. code-block:: ini + :emphasize-lines: 10,12,13 + + ################################### + ## ERROR AND LOG HANDLING SYSTEM ## + ################################### + + ## Appenlight is tailored to work with RhodeCode, see + ## http://appenlight.com for details how to obtain an account + ## you must install python package `appenlight_client` to make it work + + ## appenlight enabled + appenlight = false + + appenlight.server_url = https://api.appenlight.com + appenlight.api_key = YOUR_PRIVATE_API_KEY + + ## TWEAK AMOUNT OF INFO SENT HERE + + ## enables 404 error logging (default False) + appenlight.report_404 = false + + ## time in seconds after request is considered being slow (default 1) + appenlight.slow_request_time = 1 + + ## record slow requests in application + ## (needs to be enabled for slow datastore recording and time tracking) + appenlight.slow_requests = true + + ## enable hooking to application loggers + appenlight.logging = true + + ## minimum log level for log capture + appenlight.logging.level = WARNING + + ## send logs only from erroneous/slow requests + ## (saves API quota for intensive logging) + appenlight.logging_on_error = false + + ## list of additonal keywords that should be grabbed from environ object + ## can be string with comma separated list of words in lowercase + ## (by default client will always send following info: + ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that + ## start with HTTP* this list be extended with additional keywords here + appenlight.environ_keys_whitelist = "" + + ## list of keywords that should be blanked from request object + ## can be string with comma separated list of words in lowercase + ## (by default client will always blank keys that contain following words + ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf' + ## this list be extended with additional keywords set here + appenlight.request_keys_blacklist = "" + + ## list of namespaces that should be ignores when gathering log entries + ## can be string with comma separated list of namespaces + ## (by default the client ignores own entries: appenlight_client.client) + appenlight.log_namespace_blacklist = "" + +Verifying The Setup +------------------- + +Once |RCE| and |AE| are working together you will see the monitoring begin on +your |AE| dashboard when you start carrying out actions in |RCE|. + +.. image:: ../images/ae-verify.png + +.. _sign up for an account: https://appenlight.rhodecode.com/ +.. _here: https://appenlight.rhodecode.com/page/api/main diff --git a/docs/tutorials/branching-vs-bookmarking.rst b/docs/tutorials/branching-vs-bookmarking.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/branching-vs-bookmarking.rst @@ -0,0 +1,41 @@ +.. _bvb: + +|hg| Branching Vs Bookmarking +============================= + +If you wish to use the branching workflow in |hg|, as mentioned in the +:ref:`workflow` section, then there is a subtle but important difference to +note between what branching means in |git| and |hg|. + +* |hg| stores branch information as a permanent part of each commit. Each + branch needs to be named and is assigned persistent symbolic links inside the + |repo|. +* In |git|, by contrast, a branch is simply a lightweight movable pointer to + a commit. + +This is where bookmarks replicate the |git| branch functionality in |hg|. A +bookmark is a references to a commit that can be automatically updated when +new commits are made. For more information, see the `Mercurial Bookmark`_ +documentation. + +To use |hg| bookmarks like |git| branches, see the following example. + +.. code-block:: bash + + # Make a bookmark particular revision + $ hg bookmark -r 3400 my-bookmark + + # push the bookmark to the server + $ hg push -B my-bookmark + + # Delete remote bookmark, by deleting locally, then push deletion + $ hg bookmark -d my-bookmark + $ hg push -B my-bookmark + +To open a |pr| from a bookmark using |RCE|, use the usual |pr| steps. + +.. image:: ../images/pr-from-bookmark.png + +.. _Mercurial Bookmark: https://mercurial.selenic.com/wiki/Bookmarks + + diff --git a/docs/tutorials/deploy-from-host.rst b/docs/tutorials/deploy-from-host.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/deploy-from-host.rst @@ -0,0 +1,220 @@ +.. _hosted-solution: + +Deploy |RCE| From a Hosted Server +================================= + +If you wish to deploy your own |RCE| instance from something like a +`Digital Ocean`_ droplet, or a `hetzner`_ server use the following +instructions to get it setup. + +I'm using an Ubuntu 14.04 image for the purposes of this +tutorial, but all other Unix environments will be pretty similar. You can +check out the full lists of supported platforms and versions in the +:ref:`system-overview-ref` section. + + +Create a Digital Ocean Droplet +------------------------------ + +1. Sign into Digital Ocean. +2. Create a Droplet choosing Ubuntu 14.04 as your |os|. +3. (Optional) Add SSH keys if you have them set up. + +Configure Your Server +--------------------- + +Once you have your server created, you need to sign into it and set it up to +host |RCE|. + +1. Open a terminal and sign into your server. Digital Ocean will mail you the + IP address. You'll need to change your password on the first login if you + don not have SSH keys set up. + +.. code-block:: bash + + $ ssh root@203.0.113.113 + +2. It is not advised to install |RCE| as the ``root`` user. So create a user + with sudo permissions and then carry out the rest of the steps from that user + account. + +.. code-block:: bash + + # Create a user with sudo permissions + root@rhodecode:~# sudo useradd -m -s /bin/bash -d /home/brian -U brian + root@rhodecode:~# sudo usermod -a -G sudo brian + + # Set the password for that user + root@rhodecode:~# passwd brian + Enter new UNIX password: + Retype new UNIX password: + passwd: password updated successfully + + # Switch to that user for the rest of the steps + root@rhodecode:~# su brian + + # You should see your home dir change to what was set during installation + brian@rhodecode:~$ cd ~ + brian@rhodecode:~$ pwd + /home/brian + +Once you have this set up, you are ready to install |RCC|. + +Install |RCC| +------------- + +|RCC| will install and manage the package dependencies for your |RCE| instance. + +1. Download the |RCC| installer from https://rhodecode.com/download/ +2. Once downloaded to your computer, transfer the package to your server + +.. note:: + + These steps happen on your computer, not on the server. + +.. code-block:: bash + + # Change to where the file is downloaded + $ cd Downloads/ + + # SFTP to your server + $ sftp brian@203.0.113.113 + + # Use mput to transfer the file + sftp> mput RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 + Uploading RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 to /home/brian/RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 + RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d 100% 289MB 4.1MB/s 01:11 + sftp> exit + +The |RCC| installer is now on your server, and you can read the full +instructions here +:ref:`Install RhodeCode Control <control:rcc-install-ref>`, +but below is the example shortcut. + +.. code-block:: bash + + # Check that the script is uploaded to your home directory + $ ls -1 + RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 + + # Change the script permissions + $ chmod 755 RhodeCode-installer-linux* + + # Run the installer and accept the prompts + $ ./RhodeCode-installer-linux-* + +.. important:: + + Once finished, exit the terminal and sign in again. This is to refresh you + session to pick up the new commands. + +Install |RCE| +------------- + +Now that |RCC| is installed, you can install |RCE|. For the full +instructions, see +:ref:`Install RhodeCode Enterprise <control:rce-cli-install-ref>`, +but the below is an example shortcut. + +.. code-block:: bash + + # Install a VCS Server and follow the prompts + $ rccontrol install VCSServer --start-at-boot + + Extracting VCSServer ... + Configuring RhodeCode VCS Server ... + Supervisord state is: RUNNING + Added process group vcsserver-1 + + # Install a RhodeCode Enterprise instance and follow the prompts + $ rccontrol install Enterprise --start-at-boot + + Configuration of RhodeCode Enterprise passed. + Supervisord state is: RUNNING + Added process group enterprise-1 + +|RCE| is now installed on your server, and is running on the port displayed +by the ``rccontrol status`` command. + +.. code-block:: bash + + brian@rhodecode:~$ rccontrol status + + - NAME: enterprise-1 + - STATUS: RUNNING + - TYPE: Enterprise + - VERSION: 3.1.1 + - URL: http://127.0.0.1:10002 + + - NAME: vcsserver-1 + - STATUS: RUNNING + - TYPE: VCSServer + - VERSION: 1.1.1 + - URL: http://127.0.0.1:10001 + +Serve |RCE| using Nginx +----------------------- + +Now that |RCE| is running, you need to use Nginx or Apache to serve it to +users. For detailed instructions about setting up your webserver, see the +:ref:`rhodecode-admin-ref` section. But the below shortcut should help serve +it. + +1. Install Nginx on your server. + +.. code-block:: bash + + # Install nginx + $ sudo apt-get install nginx + +2. Create a virtual hosts file for RhodeCode Enterprise. Create + the file in this location :file:`/etc/nginx/sites-available`. In this demo + I have called it ``vcs.conf`` + +.. code-block:: bash + + # Create the file + $ sudo vi /etc/nginx/sites-available/vcs.conf + +Use the following example to create yours. + +.. code-block:: nginx + + server { + listen 80; + # Change to your IP, or a domain name if you've set that up + server_name 203.0.113.113 ; + + location / { + # Set this line to match the RhodeCode Enterprise Instance URL + proxy_pass http://127.0.0.1:10002/; + proxy_set_header Host $Host; + proxy_buffering off; + # Setting this to a high number allows large repo pushes + client_max_body_size 4G; + } + } + +3. Symlink the virtual hosts file to the ``sites-enabled`` folder, + and then restart Nginx. + +.. code-block:: bash + + # Symlink the virtual hosts file + $ ln -s /etc/nginx/sites-available/vcs.conf /etc/nginx/sites-enabled/vcs.conf + + # You can also delete the Nginx default symlink + $ rm /etc/nginx/sites-enabled/default + + # Restart Nginx + $ sudo /etc/init.d/nginx restart + * Restarting nginx nginx [ OK ] + +Once restarted, you should see a clean |RCE| instance running on the IP +address, or the domain you have set up. + +.. image:: ../images/clean-rce.png + :alt: A fresh RhodeCode Enterprise Instance + +.. _Digital Ocean: https://www.digitalocean.com/ +.. _hetzner: https://www.hetzner.de/en/ diff --git a/docs/tutorials/docs-build.rst b/docs/tutorials/docs-build.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/docs-build.rst @@ -0,0 +1,5 @@ +Setting up docs deploy +====================== + +* some +* list diff --git a/docs/tutorials/dvcs-best-practices.rst b/docs/tutorials/dvcs-best-practices.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/dvcs-best-practices.rst @@ -0,0 +1,62 @@ +.. _vcs-bps: + +Collaboration Best Practices +============================ + +This section outlines some of the best practices when working with +Distributed Version Control Systems (DVCS). These best practices will help +you get the most out |git| and |hg| when working with others. + +Test Locally +------------ + +As most test suites are also included in the |repo|, it is good practice to +ensure your changes are passing locally before opening a pull request and +having the CI server run the tests for you. The two main benefits here are: + +* Not clogging up the test machine with untested and thus more likely to fail + test runs. +* Only opening |prs| that are passing locally increases the quality of + feedback at the peer review stage as reviewers can focus on high + quality feedback. + +Agree on Workflow +----------------- + +When working with others, one of the first things to agree upon is a workflow. +This agreement means that everyone knows what is happening at a particular +stage of the collaboration cycle and that they can deliver in accordance with +the expectations. + +Keep Commits To One Task +------------------------ + +When committing it is good practice to keep each commit to a specific task. +This allows the |repo| admin to easily cherry pick or graft work between +branches should there be a need to do so for particular release processes. It +also makes it easy for colleagues to understand the changes going into a +|repo|. + +Use Descriptive Commit Messages +------------------------------- + +When writing commit messages, it is good practice to contextualise the +message by prepending a label which will give the reader a clue about what +area the changes apply to, and to then write a brief but descriptive message +that explains in more detail. + +.. code-block:: bash + + o 10739:0fdd6cd2b97a [default] - public + | 2 days ago by Johannes Bornhold | B:,T: + | ac-tests: Change browser.click to be only locator based + +Master Your Tools +----------------- + +The best way to get good at something it to break it and fix it. One +advantage of DVCS is how cheap forking and branching is. One tip is to create +your own fork and master branching, rebasing, cherry picking, merging, or any +other skill you currently find challenging. Once you have mastered it on the +disposable branch or fork you can carry out tasks on your main |repos| with +confidence. diff --git a/docs/tutorials/hg-large-ext.rst b/docs/tutorials/hg-large-ext.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/hg-large-ext.rst @@ -0,0 +1,39 @@ +.. _hg-big-files: + +|hg| Large Files Extension +========================== + +Large files, such as image or zip files can cause a lot of bandwidth overhead +during clone, push, and pull operations. To remove this inefficiency, |hg| +has a large files extension which tracks their revisions by checksums. This +means that the large files are only downloaded when they are needed as part +of the current revision. This saves both disk space and bandwidth. + +To find out more, see the |hg| `Large Files Extensions Documentation`_. + +To configure the large files extension, you need to set up your +:file:`~/.hgrc` file. + +1. Open your :file:`~/.hgrc` file. +2. Add ``largefiles =`` to the ``[extensions]`` section. +3. Configure the ``[largefiles]`` section with the patterns and file size you + wish |hg| to handle as large. The ``minsize`` option is specified in + megabytes. +4. Save your changes. + +.. code-block:: ini + + [extensions] + hgext.churn = + largefiles = + rebase = + record = + histedit = + + [largefiles] + patterns = re:.*\.(png|bmp|jpg|zip|tar|tar.gz|rar)$ + minsize = 10 + +For a complete :file:`~/.hgrc` file example, see :ref:`config-hgrc`. + +.. _Large Files Extensions Documentation: http://mercurial.selenic.com/wiki/LargefilesExtension diff --git a/docs/tutorials/merging.rst b/docs/tutorials/merging.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/merging.rst @@ -0,0 +1,111 @@ +.. _merging: + +Merging in |hg| +=============== + +Sometimes you will need to fix conflicts when merging files. In |hg| there +are a number of different options which you can use for handling merging, and +you can set your preferred one in the :file:`~/.hgrc` file. The options fall +into two categories *internal merging* or *tool merging*. + +Internal merging marks the files with the ``<<<<<``, +``>>>>>``, and ``=======`` symbols denoting the position of the conflict +in the file and you resolve the changes on your terminal. The following +example sets `Meld`_ as the merge handler. + +.. code-block:: ini + + [ui] + merge = internal:merge + +Tool merging differs slightly depending on the tool you use, but they will +all do the same thing. Highlight the conflict area in some manner, and allow +you to make the necessary changes to resolve the conflicts. Set a merge tool +using the following example. + +.. code-block:: ini + + [merge-tools] + meld3.executable = /usr/local/bin/meld + +For more detailed information, see the :ref:`basic-vcs-cmds` section, or the +`Mercurial merge-tools`_ documentation. Use the following example steps to +handle merging conflicts. + +1. Check the list of conflicts on the command line, in this example + you can see the list as the ``default`` and ``stable`` branches are in the + process of being merged. + +.. code-block:: bash + :emphasize-lines: 10-12,16-17,20-21 + + $ hg branch + stable + $ hg merge default + note: using 4480fbc4562c as ancestor of 7c9a8dfb9dd6 and fbefb727a452 + alternatively, use --config merge.preferancestor=a1e8bd6df0ce + merging default.nix + merging docs-internal/changelog.rst + merging rhodecode/VERSION + merging rhodecode/controllers/api/utils.py + warning: conflicts during merge. + merging rhodecode/controllers/api/utils.py incomplete! + (edit conflicts, then use 'hg resolve --mark') + merging rhodecode/lib/diffs.py + merging rhodecode/model/scm.py + merging rhodecode/tests/api/test_utils.py + warning: conflicts during merge. + merging rhodecode/tests/api/test_utils.py incomplete! + (edit conflicts, then use 'hg resolve --mark') + merging rhodecode/tests/models/test_scm.py + warning: conflicts during merge. + merging rhodecode/tests/models/test_scm.py incomplete! + (edit conflicts, then use 'hg resolve --mark') + merging vcsserver/default.nix + merging vcsserver/vcsserver/VERSION + 42 files updated, 7 files merged, 2 files removed, 3 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + + +2. Open each of the highlighted files, and fix the conflicts in each. Each merge + conflict will look something like the following example, with the ``<<<<<``, + ``>>>>>``, and ``=======`` symbols denoting the position of the conflict + in the file. You need to fix the content so that it is correct. + +.. code-block:: python + + # Change this example conflict + def pre_request(worker, req): + <<<<<<<<<<<<<< + worker.log.debug("[%s] PRE WORKER: %s" %(worker.pid, req.method)) + =============== + worker.log.debug("[%s] PRE WORKER: %s %s" % (worker.pid, req.method, + req.path)) + >>>>>>>>>>>>>> + + # To this working code + def pre_request(worker, req): + worker.log.debug("[%s] PRE WORKER: %s %s" % (worker.pid, req.method, + req.path)) + +3. Once you have finished fixing the conflicts, you need to mark them as + resolved, and then commit the changes. + +.. code-block:: bash + + # Mark the merges as resolved + $ hg resolve --mark + + # Commit the changes + $ hg commit -m "merge commit message" + +5. Once you have finished your merge, if the the original |repo| history on + the server is different you have two options: + + * Push with force using ``hg push --force`` which will create a new head. + * Strip your commits on the server back to a previous revision, and then push + the new history. To strip commits on the server, see the ``strip`` + information in the :ref:`api` documentation. + +.. _Mercurial merge-tools: https://mercurial.selenic.com/wiki/MergeToolConfiguration +.. _Meld: http://meldmerge.org/ \ No newline at end of file diff --git a/docs/tutorials/multi-instance-setup.rst b/docs/tutorials/multi-instance-setup.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/multi-instance-setup.rst @@ -0,0 +1,91 @@ +.. _multi-instance-setup: + +Scaling |RCE| Using Multiple Instances +====================================== + +Running multiple instances of |RCE| from a single database can be used to +scale the application for the following deployment setups: + +* Using dedicated Continuous Integrations instances. +* Locating instances closer to geographically dispersed development teams. +* Running production and testing instances, or failover instances on a + different server. +* Running proxy read-only instances for pull operations. + +If you wish to run multiple instances of |RCE| using a single database for +settings, use the following instructions to set this up. Before you get onto +multiple instances though, you should install |RCE|, and set +up your first instance as you see fit. You can see the full instructions here +:ref:`Installing RhodeCode Enterprise <control:rcc>` + +Once you have configured your first instance, you can run additional instances +from the same database using the following steps: + +1. Install a new instance of |RCE|, choosing SQLite as the database. It is + important to choose SQLite, because this will not overwrite any other + database settings you may have. + + Once the new instance is installed you need to update the licence token and + database connection string in the + :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. + +.. code-block:: bash + + $ rccontrol install Enterprise + + Agree to the licence agreement? [y/N]: y + Username [admin]: username + Password (min 6 chars): + Repeat for confirmation: + Email: user@example.com + Respositories location [/home/brian/repos]: + IP to start the Enterprise server on [127.0.0.1]: + Port for the Enterprise server to use [10000]: + Database type - [s]qlite, [m]ysql, [p]ostresql: s + +2. The licence token used on each new instance needs to be the token from your + initial instance. This allows multiple instances to run the same licence key. + + To get the licence token, go to the |RCE| interface of your primary + instance and select :menuselection:`admin --> setting --> license`. Then + update the licence token setting in each new instance's + :file:`rhodecode.ini` file. + +.. code-block:: ini + + ## generated license token, goto license page in RhodeCode settings to get + ## new token + license_token = add-token-here + +3. Update the database connection string in the + :file:`rhodecode.ini` file to point to your database. For + more information, see :ref:`config-database`. + +.. code-block:: ini + + ######################################################### + ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### + ######################################################### + + # Default SQLite config + sqlalchemy.db1.url = sqlite:////home/user/.rccontrol/enterprise-1/rhodecode.db + + # Use this example for a PostgreSQL + sqlalchemy.db1.url = postgresql://username:password@localhost/rhodecode + +4. Restart your updated instance. Once restarted the new instance will read + the licence key in the database and will function identically as the + original instance. + +.. code-block:: bash + + $ rccontrol restart enterprise-2 + +If you wish to add additional performance to your setup, see the +:ref:`rhodecode-tuning-ref` section. + +Scaling Deployment Diagram +-------------------------- + +.. image:: ../images/scaling-diagrm.png + :align: center diff --git a/docs/tutorials/rebase-commits-git.rst b/docs/tutorials/rebase-commits-git.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/rebase-commits-git.rst @@ -0,0 +1,54 @@ +.. _rebase-rebase-git: + +How to Rebase in |git| +====================== + +Rebasing can take two form in |git|. + +* Rebasing changes when you pull from upstream +* Rebasing one branch on top of another + +If you need to understand more about branching, and the terminology, see the +:ref:`branch-wf` section. + +Rebasing When Pulling from Upstream +----------------------------------- + +This will pull any changes from the remote server, and rebase the changes on +your local branch on top of them. + +.. code-block:: bash + + # Move to the branch you wish to rebase + $ git checkout branchname + + # Pull changes on master and rebase on top of latest changes + $ git pull --rebase upstream master + + # Push the rebase to origin + $ git push -f origin branchname + +Rebasing Branches +----------------- + +Rebasing branches in |git| means that you take one branch and rebase the work +on that branch on top of another. In the following example, the +``triple`` branch will be rebased on top of the ``second-pass`` branch. + +1. List the available branches in your |repo|. + +.. code-block:: bash + + $ git branch + first-pass + * master + second-pass + triple + +2. Rebase the ``triple`` on top of the ``second-pass`` branch. + +.. code-block:: bash + + $ git rebase second-pass triple + First, rewinding head to replay your work on top of it... + Fast-forwarded triple to second-pass. diff --git a/docs/tutorials/rebase-commits.rst b/docs/tutorials/rebase-commits.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/rebase-commits.rst @@ -0,0 +1,118 @@ +.. _rebase-rebase: + +How to Rebase in |hg| +===================== + +To rebase in |hg| you will need the ``rebase`` extensions enabled in your +:file:`~/.hgrc` file. Use the following example, or for more detailed +information see the :ref:`config-hgrc` section. + +.. code-block:: ini + + [extensions] + rebase = + +Rebasing in |hg| +---------------- + +Occasionally you may have to rebase commits if you have created a new head on +your fork. In short, rebasing mean taking one commit and moving a commit, or +set of commits, from a different head on top of it. To do this, use the +following example: + +1. Check your on the right branch, and move to the correct one if needed. + +.. code-block:: bash + + # Display which branch you are on + $ hg branch + default + + # Move to the stable branch + $ hg update stable + +2. Look at your graphlog, and decide what commits need to be rebased. In this + case, I want to rebase 1206 and 1207 on top of 1226. Note how these are + already in a public state as I have already pushed to my fork. + +.. code-block:: bash + :emphasize-lines: 1,13,17 + + | o 1226:1046ed30734d [stable] - public + | | 3 days ago by Oliver Strobel | B:,T: + | | enterprise: catch failure to create repo_dir + | | + | o 1225:7aba10b8ee97 [stable] - public + | | 3 days ago by Oliver Strobel | B:,T: + | | control: bump version to 1.1.9 + | | + o | 1208:0ef7c9d4c1cc [default] - public + | | 2 weeks ago by Oliver Strobel | B:,T: + | | Added tag 1.1.7 for changeset 3acf64b88845 + | | + | | @ 1207:39562e195e34 [stable] - public + | | | 3 weeks ago by Brian | B:,T: + | | | docs: note added to *rccontrol install* regarding overwriting DB + | | | + | | o 1206:39562e195e34 [stable] - public + | |/ 3 weeks ago by Brian | B:,T: + | | docs: update command line install example + +3. To do this use the following example. + + * Draft the commits back to the source revision. + * ``-s`` is the source, essentially what you are rebasing. + * ``-d`` is the destination, which is where you are putting it. + +Rebasing the source commit will automatically rebase its descendants. In this +example I am using ``--force`` to draft commits already pushed to my fork. +Doing this is not best practices on a main |repo|. + +.. code-block:: bash + + # Put the commits into draft status + # This will draft all subsequent commits on the relevant branch + hg phase --draft --force -r 1206 + + # Rebase 1206 on top of 1226 + $ hg rebase -s 1206 -d 1226 + saved backup bundle to /repo-fork/.hg/strip-backup/39562e195e34-backup.hg + +4. Once you have rebased the commits, check them on the graphlog + +.. code-block:: bash + :emphasize-lines: 1,5,9 + + + o 1233:707ef1590e71 [stable] - draft + | 3 weeks ago by Brian | B:,T:tip + | docs: note added to *rccontrol install* regarding overwriting DB + | + o 1232:707ef1590e71 [stable] - draft + | 3 weeks ago by Brian | B:,T:tip + | docs: update command line install example + | + @ | 1225:1046ed30734d [stable] - draft + | | 3 days ago by Oliver Strobel | B:,T: + | | enterprise: catch failure to create repo_dir + +5. Once you have finished your rebase, if the the original |repo| history on + the server is different you have two options: + + * Push the specific revisions using ``hg push -r <revision>``, or push all + with force using ``hg push --force`` which will create a new head. + * Strip your commits on the server back to a previous revision, and then push + the new history. To strip commits on the server, see the ``strip`` + information in the :ref:`api` documentation. + +.. important:: + + As with all examples, this one is rather straight forward but rebasing can + become a complicated affair if you need to fix merges and conflicts + during the rebase. For more detailed rebasing information, see the + `Mercurial Rebase`_ page which has more detailed instructions for various + scenarios. + +.. _Mercurial Rebase: https://mercurial.selenic.com/wiki/RebaseExtension +.. _Mercurial Phases: https://mercurial.selenic.com/wiki/Phases + diff --git a/docs/tutorials/scaling-best-practices.rst b/docs/tutorials/scaling-best-practices.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/scaling-best-practices.rst @@ -0,0 +1,61 @@ +.. _scaling-tips: + +====================== +Scaling Best Practices +====================== + +When deploying |RCE| at scale; 100s of users, multiple instances, CI servers, +there are a number of steps you can take to ensure you are getting the +most out of your system. + +Separate Users and CI Servers +----------------------------- + +You can configure multiple |RCE| instances to point to the same database and +set of |repos|. This lets users work on an instance that has less traffic +than those being hit by CI servers. To configure this, use |RCC| to install +multiple instances and configure the database and |repos| connection. If you +do need to reset the database connection, see the +:ref:`config-database` section. + +Once configured, set your CI servers to use a particular instance and for +user specific instances you can configure loads balancing. See the +:ref:`nginx-ws-ref` section for examples. + +Switch to Database Sessions +--------------------------- + +To increase database performance switch to database-based user sessions. In a +large scale deployment, we recommend switching from file-based +sessions to database-based user sessions. For configuration details, see the +:ref:`db-session-ref` section. + +Tuning |RCE| +------------ + +There are also a number of options available to tune |RCE| for certain +scenarios, including memory cache size. See the :ref:`rhodecode-tuning-ref` +section. + +Use Authentication Tokens +------------------------- + +Set up a user account for external services, and then use Authentication +Tokens with those external services. These tokens work with +push/pull operations only, and you can manage multiple tokens through this user +account, and revoke particular ones if necessary. In this way one user can have +multiple tokens, so all your jenkins/CI servers could share one account. + +* To enable tokens, go to :menuselection:`Admin --> Authentication` and enable + the `rhodecode.lib.auth_modules.auth_token` library. + +* To create tokens, go to + :menuselection:`Username --> My Account --> Auth tokens` and generate the + necessary tokens. For more information, see the :ref:`config-token-ref` + section. + +Scaling Deployment Diagram +-------------------------- + +.. image:: ../images/scaling-diagrm.png + :align: center diff --git a/docs/tutorials/squash-commits-git.rst b/docs/tutorials/squash-commits-git.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/squash-commits-git.rst @@ -0,0 +1,62 @@ +.. _squash-git: + +How to Squash Commits in |git| +============================== + +To squash commits in |git|, use the following steps. + +1. Use ``git log`` to view the commits messages on your branch, and decide + how many you want to squash into one commit. + +2. Using the ``rebase`` command, chose the number of commits you wish to + squash. This will then open the list of commits in your default editor + allowing you to chose what to do with each. + +.. code-block:: bash + + # Squash the last 4 commits + $ git rebase -i HEAD~4 + +3. When the editor opens, pick the main commit, and the commits you wish + to squash, and then save. This will then open the editor on the + next phase where you can edit the picked commit. + +.. code-block:: bash + + pick 575447a realign bike handlebars + s 583e99c Add hipster bullhorn handlebars (dont judge me) + s 8829a05 Add initial disc brakes for stopping + s 91322e6 Add BikeEvent administration + + # Rebase d839c1a..583e99c onto d839c1a (2 TODO item(s)) + # + # Commands: + # p, pick = use commit + # r, reword = use commit, but edit the commit message + # e, edit = use commit, but stop for amending + # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commits log message + # x, exec = run command (the rest of the line) using shell + +4. Edit the picked commit to explain the squash in more detail, and then save. + +.. code-block:: bash + + # This is a combination of 4 commits. + # The first commit's message is: + + The full bike setup, with brakes, handlebars, and alignment fixed. + +5. Using ``git log``, you should now see your squashed commit message + +.. code-block:: bash + + $ git log + commit c5424b2619b1a7c01f817279df787660c76081ea + Author: user <user@ubuntu> + Date: Wed Nov 4 19:45:37 2015 +0100 + + The full bike setup, including handlebars, brakes, and alignment. + +6. If you have already push to the remote |repo|, you will need to push your + changes using force, ``git push --force`` diff --git a/docs/tutorials/squash-commits.rst b/docs/tutorials/squash-commits.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/squash-commits.rst @@ -0,0 +1,125 @@ +.. _squash-rebase: + +How to Squash Commits in |hg| +============================= + +To squash commits in |hg| you will need the ``histedit`` extensions enabled +in your :file:`~/.hgrc` file. Use the following example, or for more detailed +information see the :ref:`config-hgrc` section. + +.. code-block:: ini + + [extensions] + histedit = + +Squashing Commits +----------------- + +To squash commits, use the following instructions. + +1. Using ``hg log``, or ``hg glog``, check your repository history and + choose the revision upon which you want to squash commits. +2. The commit status needs to be in draft. If necessary, change the commit + status to draft back as far as the chosen revision, using + the following command: ``hg phase --draft --force -r rev-id``. It's not + best practices to use ``--force`` on a main |repo|, but this example is + based on a fork. To learn more about phases, read the `Mercurial Phases`_ + docs. See the following example: + +.. code-block:: bash + + # Put commits into draft status if needed + hg phase --draft --force -r 9039 + + # Check the changlog to ensure the commits are in draft + @ 9041:c680f30edc60 [default] - draft + | 7 weeks ago by Johannes Bornhold | B:,T:tip + | nix: Add version of transifex-client into default.nix + | + o 9040:66f03981cfcd [default] - draft + | 7 weeks ago by lisaq | B:,T: + | fixes #1592 removing legacy css files + | + o 9039:388db711042f [default] - draft + | 7 weeks ago by Brian | B:,T: + | docs: fixed *doCheck = false* with propogatedbuildinputs fragment + | + o 9038:ef41dce16c12 [default] - public + | 8 weeks ago by Brian | B:,T: + | Docs: updating dependencies for Sphinx 131, but staying at 122 for now + +3. Once the commits are in draft, run the ``hg histedit rev-id`` command, + specifying the earliest draft commit. This will open the history edit + function in your terminal, allowing you to fold the commit messages into + one. Select a commit to use as the one into which the others will be + squashed. Then save the file. + +.. code-block:: bash + + # Run the history edit specifying the base revision + hg histedit 9039 + + pick 388db711042f 9039 docs: fixed *doCheck = false* with propogatedbuildinputs + fold 66f03981cfcd 9040 fixes #1592 removing legacy css files + fold c680f30edc60 9041 nix: Add version of transifex-client into default.nix + + # Edit history between 388db711042f and c680f30edc60 + # + # Commits are listed from least to most recent + # + # Commands: + # p, pick = use commit + # e, edit = use commit, but stop for amending + # f, fold = use commit, but combine it with the one above + # d, drop = remove commit from history + # m, mess = edit message without changing commit content + +4. Once those settings are saved, the terminal will open up an editor and you + can change the commit message. When finished, save again. + +.. code-block:: bash + + # add a new commit message or keep the original one + docs: added translations and packaging. Squashed commit. + + # adding HG: in front of a line will remove it once saved + HG:docs: added translations and packaging. Squashed commit. + HG:nix: Add version of transifex-client into default.nix + HG:docs: fixed *doCheck = false* with propogatedbuildinputs fragment + +5. Your commit messages will now be squashed into a single commit. You will + also get a message about a backup bundle where |hg| will store the history of + the squashed commit. + +.. code-block:: bash + + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to /tutorials-fork/.hg/strip-backup/38b711042f-backup.hg + saved backup bundle to /tutorials-fork/.hg/strip-backup/f19da9449f-backup.hg + +6. See the squashed commit message using the ``hg log`` or ``hg glog`` command. + +.. code-block:: bash + + @ 9039:44e6fc3bf6b5 [default] - draft + | 7 weeks ago by Brian | B:,T:tip + | docs: added translations and packaging. Squashed commit. + | + o 9038:ef41dce16c12 [default] - draft + | 8 weeks ago by Brian | B:,T: + | Docs: updating dependencies for Sphinx 131, but staying at 122 + | + o 9037:411a82632f54 [default] - draft + |\ 7 weeks ago by Johannes Bornhold | B:,T: + | | release: Merge back stable into default after release 3.2.1 + + +7. Once you have squashed the commits, to push these changes to the server you + have two options: + + * Push with force using ``hg push --force`` which will create a new head. + * Strip your commits on the server back to a previous revision, and then push + the new history. To strip commits on the server, see the ``strip`` + information in the :ref:`api` documentation. + +.. _Mercurial Phases: https://mercurial.selenic.com/wiki/Phases diff --git a/docs/tutorials/tutorials.rst b/docs/tutorials/tutorials.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/tutorials.rst @@ -0,0 +1,26 @@ +.. _rc-tutorials: + +|RCE| Tutorials +=============== + +The following tutorials are aimed at helping you to deploy |RCE| in various +different ways. If you would like to see a certain scenario documented, +then please send a request to support@rhodecode.com + +.. toctree:: + :maxdepth: 1 + + deploy-from-host + hg-large-ext + multi-instance-setup + scaling-best-practices + squash-commits + squash-commits-git + rebase-commits + rebase-commits-git + api-examples + merging + branching-vs-bookmarking + windows-to-linux + dvcs-best-practices + appenlight-setup diff --git a/docs/tutorials/windows-to-linux.rst b/docs/tutorials/windows-to-linux.rst new file mode 100644 --- /dev/null +++ b/docs/tutorials/windows-to-linux.rst @@ -0,0 +1,121 @@ +Moving From Windows to Linux +============================ + +If you are moving from a Windows server to a Linux server, especially from +running an older version of |RCE| pre 2.x, use the following information to +successfully migrate your instances and database. + +Overview +-------- + +* Install |RCC| on your Linux server, use the + :ref:`RhodeCode Control Docs <control:rcc>` to guide you through this. +* Copy your |repos| directory to the Linux server. +* Copy your original :file:`rhodecode.ini` file to the Linux server, named + :file:`production.ini` in older versions, and make a minor edit to + point to the copied database. +* Copy your original instance database and update Windows paths to Linux + paths pointing to your |repos| directory. +* Use |RCC| to import and upgrade your |RCE| instance, using the copied and + edited file and database. + +Pre-requisites +-------------- + +* For MySQL, do not use `localhost` in the database connection string of the + :file:`rhodecode.ini` file. +* InnoDB must be the database tables engine. +* Contact |RC| for a new licence Key/Token pair. If you don't, a trial licence + will be applied so you are not locked out of the upgraded instance. + +You can find the specific instructions to carry out these pre-requisite steps +in the :ref:`RhodeCode Control upgrade <control:rce-upgrade-2x>` docs. + +Configuration File Update +------------------------- + +Configure the copied :file:`rhodecode.ini` file to connect to your copied +database. Use the following steps: + +1. Open the copied :file:`rhodecode.ini` file. +2. When you open the file, find the database configuration section, + and use the below example to change the connection details: + +.. code-block:: ini + + ######################################################### + ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### + ######################################################### + + # Point to copied DB + sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode.db.copy + sqlalchemy.db1.url = mysql://root:qweqwe@127.0.0.1/rhodecode.db.copy + +Database Update +--------------- + +Update the Windows paths in the ``rhodecode.rhodecode_ui`` database tables. +To do this log into the database and reset the file paths to +Unix format. One login option is to use iShell, see usage examples in the +:ref:`rhodecode-reset-ref` section. + +.. code-block:: python + + In [28]: from rhodecode.model.settings import SettingsModel + In [29]: paths = SettingsModel().get_ui_by_section('paths') + In [30]: paths[0].value = '/home/user/repos' + In [32]: Session().add(paths[0]) + In [33]: Session().commit() + +Import and Upgrade +------------------ + +Once you have made your changes, use |RCC| to import and upgrade your |RCE| +instance to the latest version. + +.. code-block:: bash + + # Import original instance as explained above + $ rccontrol import Enterprise path/to/rhodecode.ini + + # Install a VCS Server as explained above + $ rccontrol install VCSServer + + # Check the status of them + $ rccontrol status + + - NAME: enterprise-1 + - STATUS: RUNNING + - TYPE: Enterprise + - VERSION: 1.5.0 + - URL: http://127.0.0.1:10000 + + - NAME: vcsserver-1 + - STATUS: RUNNING + - TYPE: VCSServer + - VERSION: 3.5.0 + - URL: http://127.0.0.1:10001 + + # Upgrade from version 1.5.0 to 3.5.0 + $ rccontrol upgrade enterprise-1 --version 3.5.0 + + Checking for available update for enterprise-1 @ 1.5.0 + Stopped enterprise-1 + Initiating upgrade to version 3.5.0 + ... + **************************************** + *** UPGRADE TO VERSION 45 SUCCESSFUL *** + **************************************** + + Note that RCE 3.x requires a new license please contact support@rhodecode.com + + Upgrade of RhodeCode Enterprise successful. + Auto starting enterprise-1 + +Post Migration Tasks +-------------------- + +* From the |RCE| :menuselection:`Admin --> Settings --> VCS` page, check that + the :guilabel:`Repositories Location` is correctly pointing to your |repos|. +* Remap and rescan |repos| so that the new instance picks them up, see + :ref:`remap-rescan`. diff --git a/docs/usage/adding-deleting-files.rst b/docs/usage/adding-deleting-files.rst new file mode 100644 --- /dev/null +++ b/docs/usage/adding-deleting-files.rst @@ -0,0 +1,50 @@ +.. _vers-add-delete-ref: + +File Management +--------------- + +From within the |RCE| interface you can create, edit, delete, +or import files into a |repo|. All files, except gists, +must live in a |repo|. Gists are standalone files which can act as a private +or public note taking or sharing utility. + +Creating Files Online +^^^^^^^^^^^^^^^^^^^^^ + +To create a file in |RCE|, use the following steps. + +1. From the |RCE| interface, select + :menuselection:`Admin --> Repositories --> the repo --> Files`. +2. Select the :guilabel:`Add File` button. +3. In the input box enter a file name and extension. +4. Select :guilabel:`commit change` to save the new file. + +.. note:: + + To add subfolders to your |repo| add the folder name in the file path. For + example ``usr/bin/new_file.py`` + +Uploading Files +^^^^^^^^^^^^^^^ + +To upload a file using the |RCE| interface, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories`. +2. Select the |repo| to which you wish to upload a file, + and go to the :guilabel:`Files` tab. +3. Select the :guilabel:`Add File` sign, and on the next page + :guilabel:`Upload file` +4. Select the :guilabel:`Browse` button, and choose the file you wish to + upload, and add a commit message. +5. Select :guilabel:`Commit change` to save the new file. + +Deleting Files +^^^^^^^^^^^^^^ + +To delete a file in |RCE|, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories`. +2. Select the |repo| in which you want to delete a file. +3. Select the file you wish to delete. +4. Click the red :guilabel:`delete` button, and add a commit message. +5. Select :guilabel:`commit changes`. diff --git a/docs/usage/basic-usage.rst b/docs/usage/basic-usage.rst new file mode 100644 --- /dev/null +++ b/docs/usage/basic-usage.rst @@ -0,0 +1,13 @@ +.. _rhodecode-basic-ref: + +Basic Usage +=========== + +.. toctree:: + + adding-deleting-files + create-a-repository + import-a-repository + online-editing + basic-vcs-commands + keyboard-shortcuts diff --git a/docs/usage/basic-vcs-commands.rst b/docs/usage/basic-vcs-commands.rst new file mode 100644 --- /dev/null +++ b/docs/usage/basic-vcs-commands.rst @@ -0,0 +1,23 @@ +.. _basic-vcs-cmds: + +Getting Started with VCS +------------------------ + +When using |RCM|, you will be working with |git| or |hg| |repos| from the +command line. + +If you have never used either before, the following information should +help you set up your local machine so that you can sync changes with the +|RCM| server. + +All of the following instructions assume you have a |RCM| account, +and you can access your |repos| from the web interface. + +.. note:: + + |svn| |repo| management is currently only available from the web interface. + +.. toctree:: + + get-start-hg + get-start-git diff --git a/docs/usage/create-a-repository.rst b/docs/usage/create-a-repository.rst new file mode 100644 --- /dev/null +++ b/docs/usage/create-a-repository.rst @@ -0,0 +1,60 @@ +Repository Functions +-------------------- + +Creating a |repo| +^^^^^^^^^^^^^^^^^ + +To create a |repo| in |RCE|, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories` +2. From the |repo| page, select :guilabel:`Add Repository` +3. On the :guilabel:`Add Repository` page, complete the following |repo| + details: + + * :guilabel:`Name` + * :guilabel:`Description` + * :guilabel:`Set the repository group` + * :guilabel:`Set the repository type` + * :guilabel:`Specify if it is a public or private repository` +4. Select :guilabel:`Save` + +Importing a |repo| +^^^^^^^^^^^^^^^^^^ + +To import a |repo| in |RCE|, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories` +2. From the |repo| page, select :guilabel:`Add Repository` +3. On the :guilabel:`Add Repository` page, select + :guilabel:`Import existing repository` +4. In the :guilabel:`clone from` input field, specify the URL to the + repository you want to import. +5. Complete the following repository details: + + * Name + * Description + * Set the |repo| group + * Set the |repo| type + * Specify if it is a public or private |repo| + +6. Select :guilabel:`Add` + + .. note:: + + | Make sure your |RCE| server can access the external |repo|. + | Depending on the size of the repository the clone process may take a bit. + + +Cloning |repos| +^^^^^^^^^^^^^^^ + +To clone a |repo| in |RCE|, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories` + and choose the |repo| you wish to clone. +2. Use the link in the :guilabel:`Clone URL` field to clone the |repo| +3. To clone, open a terminal on you computer and use one of the following + examples + +For |git|, use ``git clone URL`` +For |hg|, use ``hg clone URL`` diff --git a/docs/usage/file-editing.rst b/docs/usage/file-editing.rst new file mode 100644 --- /dev/null +++ b/docs/usage/file-editing.rst @@ -0,0 +1,17 @@ +File Editing +^^^^^^^^^^^^ + +To edit files using the online editor, use the following steps. + +1. From the |RCM| interface, select :menuselection:`Admin --> Repositories` +2. Select the |repo| in which you want to edit a file. +3. Select the :guilabel:`file` view of the |repo|, and double-click on the file. +4. To open the editor, select the :guilabel:`edit on branch:default` button. + + * If the filename has an extension |RCM| recognises, + the syntax highlighting will appear automatically. + * If the filename does not have an extension |RCM| recognises, + you can set the language syntax highlighter by + choosing from the file type drop down menu. +5. To save your changes, select :guilabel:`Commit changes` + diff --git a/docs/usage/get-start-git.rst b/docs/usage/get-start-git.rst new file mode 100644 --- /dev/null +++ b/docs/usage/get-start-git.rst @@ -0,0 +1,132 @@ + +|git| Getting Started +--------------------- + + +To work locally with |git| |repos|, use the following configuration examples +and command line instructions. + +* :ref:`config-git-config` +* :ref:`config-gitignore` +* :ref:`use-basic-git` + +.. _config-git-config: + +Configure the ``.gitconfig`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :file:`~/.gitconfig` file is a configuration file which controls how +|git| interacts between the server and your local setup. + +For |git|, you can set this up in your ``home`` directory and it will be +applied to all |repos|. Use the following example configuration to set up +your file, and put your own information into the relevant sections. + +For more detailed information, and a full rundown of all configuration options, +see the `gitconfig documentation`_. + +.. code-block:: ini + + [user] + name = username + email = user@mail.com + + [core] + editor = vim + whitespace = fix,-indent-with-non-tab,trailing-space,cr-at-eol + excludesfile = ~/.gitignore + + [rerere] + enabled = 1 + autoupdate = 1 + + [push] + default = matching + + [color] + ui = auto + + [color "branch"] + current = yellow bold + local = green bold + remote = cyan bold + + [color "diff"] + meta = yellow bold + frag = magenta bold + old = red bold + new = green bold + whitespace = red reverse + + [color "status"] + added = green bold + changed = yellow bold + untracked = red bold + + [diff] + tool = vimdiff + + [difftool] + prompt = false + + [alias] + a = add --all + ai = add -i + ap = apply + as = apply --stat + ac = apply --check + +.. _config-gitignore: + +Configure the ``.gitignore`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :file:`{~path}/{to}/{repo}/.gitignore` file is a configuration file that +tells |git| to ignore certain files and not commit them to the |repo|. Files +such as build files, or editor tracking files are usually not committed to a +|repo|. + +Create the ``.gitignore`` file in your |repo| and configure it using the +following example to ignore the files you do not wish to be added to version +control. For more information, see the `gitignore documentation`_ + +.. code-block:: vim + + syntax: glob + result + www + *_build/* + *result/* + *.pyc + *.pyo + *.idea + .DS_Store + +.. _use-basic-git: + +Using basic |git| commands +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will get you through the basics of using |git| on the +command line. For a full run through of all |git| commands and options, +see the `Git Command Line Reference Guide`_ + +* ``git init`` - create a new git repository. +* ``git clone URI`` - Clone a |repo| to your local machine. +* ``git add <filename>`` - Add a file to staging. +* ``git commit -m "Commit message"`` - Commit files in staging to the |repo| +* ``git push origin master`` - Push changes to the ``master`` branch. +* ``git checkout -b feature_name`` - Create a new branch named *feature_name* + and switch to it using. +* ``git checkout master`` - Switch back to the master branch. +* ``git branch -d feature_name`` - Delete the branced named *feature_name*. +* ``git pull`` - Pull changes on the server into the local |repo|. +* ``git merge <branch>`` - Merge another branch into your active branch. + + +.. _Mercurial .hgrc config: http://www.selenic.com/mercurial/hgrc.5.html +.. _hgignore documentation: http://www.selenic.com/mercurial/hgignore.5.html +.. _Mercurial Command Line Reference Guide: http://www.selenic.com/mercurial/hg.1.html +.. _Git Command Line Reference Guide: http://git-scm.com/doc +.. _gitconfig documentation: http://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration +.. _gitignore documentation: http://git-scm.com/docs/gitignore \ No newline at end of file diff --git a/docs/usage/get-start-hg.rst b/docs/usage/get-start-hg.rst new file mode 100644 --- /dev/null +++ b/docs/usage/get-start-hg.rst @@ -0,0 +1,152 @@ + +|hg| Getting Started +-------------------- + +To work locally with |hg| |repos|, use the following configuration examples +and command line instructions. + +* :ref:`config-hgrc` +* :ref:`config-hgignore` +* :ref:`basic-hg-cmds` + +.. _config-hgrc: + +Configure the ``.hgrc`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :file:`~/.hgrc` file is a configuration file which control how |hg| +interacts between the server and your local setup. + +For |hg| usage, you can configure this in your ``home`` directory and it will +apply to all |repos|. Use the following example configuration, +and put your own information into the relevant sections. + +For more detailed information, and a full rundown of all configuration options, +see the `Mercurial .hgrc config`_ documentation. + +.. code-block:: ini + + [ui] + username = username <user@mail.com> + password = password-here + + [defaults] + commit = -v + + [auth] + rcdev.prefix = code.server.com + rcdev.username = username + rcdev.password = set-pw + + [merge-tools] + meld3.executable = /usr/local/bin/meld + + [diff] + git = 1 + showfunc = 1 + unified = 8 + + [alias] + cherry-pick = graft + pull = pull --rebase + push-all = push + push = push --rev . + amend = commit --amend + record-interactive=crecord + + [extensions] + progress = + mq = + purge = + bookmarks = + hgext.churn = + largefiles = + rebase = + crecord = /Users/brian/crecord/crecord + + [largefiles] + patterns = re:.*\.(png|bmp|jpg|zip|tar|tar.gz|rar)$ + minsize = 10 + + [progress] + delay = 1.5 + + [bookmarks] + track.current = True + + [color] + status.modified = green + status.removed = red bold + status.added = cyan bold + status.unknown = white bold + custom.rev = yellow + custom.author = bold + custom.book = green + custom.branch = red bold underline + custom.date = underline + changeset.draft = yellow + changeset.public = green + + [pager] + pager = LESS='FSRX' less + + +.. _config-hgignore: + +Configure the ``.hgignore`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :file:`{~path}/{to}/{repo}/.hgignore` file is a configuration file that +instructs |hg| to ignore certain files and not commit them to the |repo|. Files +such as build files, or editor tracking files are usually not committed to a +|repo|. + +Create the ``.hgignore`` file in your |repo|, and configure it using the +following example to ignore the files you do not wish to be added to version +control. For more information, see the `hgignore documentation`_ + +.. code-block:: vim + + syntax: glob + result + www + *_build/* + *result/* + *.pyc + *.pyo + *.idea + .DS_Store + +.. _basic-hg-cmds: + +Using basic |hg| commands +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following commands will get you through the basics of using |hg| on the +command line. For a full run through of all |hg| commands and options, +see the `Mercurial Command Line Reference Guide`_ + +* ``hg init`` - Create a |hg| |repo|. +* ``hg clone URI`` - Clone a |repo| to your local machine. +* ``hg status`` - Display the status of a |repo|. +* ``hg commit -m “xx”`` - Commit changes with an 'xx' commit message. +* ``hg pull`` - Pull changes on server into the local |repo|. +* ``hg push`` - Push your local changes to the server. +* ``hg outgoing`` - Display commits in your next push. +* ``hg incoming`` - Display commits being pulled locally on the next pull. +* ``hg heads`` - Display |repo| versions, when multiple heads get created you + need to merge them. +* ``hg update -r REV`` - Revert to specified revision. +* ``hg update -C`` - Disregards any uncommited changes. +* ``hg merge -r tip`` - Merge changes with tip. +* ``hg log`` - Show the |repo| history. +* ``hg rollback`` - Rollback certain revisions. +* ``hg diff`` - Show file diffs on your terminal. + + +.. _Mercurial .hgrc config: http://www.selenic.com/mercurial/hgrc.5.html +.. _hgignore documentation: http://www.selenic.com/mercurial/hgignore.5.html +.. _Mercurial Command Line Reference Guide: http://www.selenic.com/mercurial/hg.1.html +.. _Git Command Line Reference Guide: http://git-scm.com/doc +.. _gitconfig documentation: http://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration +.. _gitignore documentation: http://git-scm.com/docs/gitignore \ No newline at end of file diff --git a/docs/usage/gist-editing.rst b/docs/usage/gist-editing.rst new file mode 100644 --- /dev/null +++ b/docs/usage/gist-editing.rst @@ -0,0 +1,33 @@ +.. _gist-edit: + +Gist Editing +^^^^^^^^^^^^ + +Gists are standalone files that only the creator can edit. To work with +gists, click on the :guilabel:`Gists` tab on the |RCM| header. The gist +editor also has syntax highlighting. + +You can set the following properties for each gist: + +* :guilabel:`Public`: Public gists are as the name suggests, + and will show up in searches. +* :guilabel:`Gist Lifetime`: You can set a gist to expire after a set + period by using the :guilabel:`Gist Lifetime` dropdown menu. + This means that when the gist expires it will be deleted from the |RCM| + gist database. +* :guilabel:`Private`: This means that the gist will not show up in searches. +* :guilabel:`Gist access level`: If you create a private gist you can have + two levels of privacy with the gist link. + + * :guilabel:`Requires registered account`: This option requires users to + have a registered account on the |RCE| instance, otherwise they will not + have access to the gist. + * :guilabel:`Can be accessed by anonymous users`: This option hides the + link so that it does not show up in searches, but you can still share it + with people outside of your organisation. + +For more advanced use of gists, see the gist API options in the :ref:`api` + +.. image:: ../images/gists-acl.png + :alt: Gist Management + :scale: 50 % diff --git a/docs/usage/import-a-repository.rst b/docs/usage/import-a-repository.rst new file mode 100644 --- /dev/null +++ b/docs/usage/import-a-repository.rst @@ -0,0 +1,27 @@ +Importing a |repo| +------------------ + +To import a |repo| in |RCE|, use the following steps. + +1. From the |RCE| interface, select :menuselection:`Admin --> Repositories` +2. From the |repo| page, select :guilabel:`Add Repository` +3. On the :guilabel:`Add Repository` page, select + :guilabel:`Import existing repository` +4. In the :guilabel:`clone from` input field, specify the URL to the + repository you want to import. +5. Complete the following repository details: + + * Name + * Description + * Set the |repo| group + * Set the |repo| type + * Specify if it is a public or private |repo| + +6. Select :guilabel:`Add` + + .. note:: + + Make sure your |RCE| server can access the external |repo|. + + Depending on the size of the repository the clone process may take some + time. diff --git a/docs/usage/keyboard-shortcuts.rst b/docs/usage/keyboard-shortcuts.rst new file mode 100644 --- /dev/null +++ b/docs/usage/keyboard-shortcuts.rst @@ -0,0 +1,59 @@ +.. _keyboard-shortcuts: + +Keyboard Shortcuts +================== + +|RCE| has a number of user interface shortcut keys. + +System Wide Shortcuts +--------------------- + +.. rst-class:: dl-horizontal + + \--:kbd:`/` + Open the |repo| search box. + + \--:kbd:`?` + Open the |RCE| keyboard shortcuts page. + + \--:kbd:`gh` + Go to the home page. + + \--:kbd:`gg` + Go to my private gists page. + + \--:kbd:`gG` + Go to my public gists page. + + \--:kbd:`nr` + Go to the create new repository page. + + \--:kbd:`ng` + Go to the new gist page. + +Repository Shortcuts +-------------------- + +.. rst-class:: dl-horizontal + + + \--:kbd:`gs` + Go to the |repo| summary page. + + \--:kbd:`gc` + Go to the changelog page. + + \--:kbd:`gf` + Go to the files page. + + \--:kbd:`gF` + Go to the files page with file search activated. + + \--:kbd:`gp` + Go to the pull requests page. + + \--:kbd:`go` + Go to the repository settings page. + + \--:kbd:`gO` + Go to the repository permissions settings. diff --git a/docs/usage/online-editing.rst b/docs/usage/online-editing.rst new file mode 100644 --- /dev/null +++ b/docs/usage/online-editing.rst @@ -0,0 +1,11 @@ +Online Editing +-------------- + +|RCM| has an integrated online editor, allowing you to edit files in the +browser. The online editor has syntax highlighting and the ability to fork, +merge, and commit changes to files. + +.. toctree:: + + file-editing + gist-editing \ No newline at end of file diff --git a/license.nix b/license.nix new file mode 100644 --- /dev/null +++ b/license.nix @@ -0,0 +1,163 @@ +# Utility to generate the license information +# +# Usage: +# +# nix-build -I ~/dev license.nix -A result +# +# Afterwards ./result will contain the license information as JSON files. +# +# +# Overview +# +# Uses two steps to get the relevant license information: +# +# 1. Walk down the derivations based on "buildInputs" and +# "propagatedBuildInputs". This results in all dependencies based on the nix +# declartions. +# +# 2. Build Enterprise and query nix-store to get a list of runtime +# dependencies. The results from step 1 are then limited to the ones which +# are in this list. +# +# The result is then available in ./result/license.json. +# + + +let + + nixpkgs = import <nixpkgs> {}; + + stdenv = nixpkgs.stdenv; + + # Enterprise as simple as possible, goal here is just to identify the runtime + # dependencies. Ideally we could avoid building Enterprise at all and somehow + # figure it out without calling into nix-store. + enterprise = import ./default.nix { + doCheck = false; + with_vcsserver = false; + with_pyramid = false; + cythonize = false; + }; + + # For a given derivation, return the list of all dependencies + drvToDependencies = drv: nixpkgs.lib.flatten [ + drv.nativeBuildInputs or [] + drv.propagatedNativeBuildInputs or [] + ]; + + # Transform the given derivation into the meta information which we need in + # the resulting JSON files. + drvToMeta = drv: { + name = drv.name or "UNNAMED"; + license = if drv ? meta.license then drv.meta.license else "UNKNOWN"; + }; + + # Walk the tree of buildInputs and propagatedBuildInputs and return it as a + # flat list. Duplicates are avoided. + listDrvDependencies = drv: let + addElement = element: seen: + if (builtins.elem element seen) + then seen + else let + newSeen = seen ++ [ element ]; + newDeps = drvToDependencies element; + in nixpkgs.lib.fold addElement newSeen newDeps; + initialElements = drvToDependencies drv; + in nixpkgs.lib.fold addElement [] initialElements; + + # Reads in a file with store paths and returns a list of derivation names. + # + # Reads the file, splits the lines, then removes the prefix, so that we + # end up with a list of derivation names in the end. + storePathsToDrvNames = srcPath: let + rawStorePaths = nixpkgs.lib.removeSuffix "\n" ( + builtins.readFile srcPath); + storePaths = nixpkgs.lib.splitString "\n" rawStorePaths; + # TODO: johbo: Would be nice to use some sort of utility here to convert + # the path to a derivation name. + storePathPrefix = ( + builtins.stringLength "/nix/store/zwy7aavnif9ayw30rya1k6xiacafzzl6-"); + storePathToName = path: + builtins.substring storePathPrefix (builtins.stringLength path) path; + in (map storePathToName storePaths); + +in rec { + + # Build Enterprise and call nix-store to retrieve the runtime + # dependencies. The result is available in the nix store. + runtimeDependencies = stdenv.mkDerivation { + name = "runtime-dependencies"; + buildInputs = [ + # Needed to query the store + nixpkgs.nix + ]; + unpackPhase = '' + echo "Nothing to unpack" + ''; + buildPhase = '' + # Get a list of runtime dependencies + nix-store -q --references ${enterprise} > nix-store-references + ''; + installPhase = '' + mkdir -p $out + cp -v nix-store-references $out/ + ''; + }; + + # Produce the license overview files. + result = let + + # Dependencies according to the nix-store + runtimeDependencyNames = ( + storePathsToDrvNames "${runtimeDependencies}/nix-store-references"); + + # Dependencies based on buildInputs and propagatedBuildInputs + enterpriseAllDependencies = listDrvDependencies enterprise; + enterpriseRuntimeDependencies = let + elemName = element: element.name or "UNNAMED"; + isRuntime = element: builtins.elem (elemName element) runtimeDependencyNames; + in builtins.filter isRuntime enterpriseAllDependencies; + + # Extract relevant meta information + enterpriseAllLicenses = map drvToMeta enterpriseAllDependencies; + enterpriseRuntimeLicenses = map drvToMeta enterpriseRuntimeDependencies; + + in stdenv.mkDerivation { + + name = "licenses"; + + buildInputs = []; + + unpackPhase = '' + echo "Nothing to unpack" + ''; + + buildPhase = '' + mkdir build + + # Copy list of runtime dependencies for the Python processor + cp "${runtimeDependencies}/nix-store-references" ./build/nix-store-references + + # All licenses which we found by walking buildInputs and + # propagatedBuildInputs + cat > build/all-licenses.json <<EOF + ${builtins.toJSON enterpriseAllLicenses} + EOF + + # License information for our runtime dependencies only. Basically all + # licenses limited to the items which where also reported by nix-store as + # a dependency. + cat > build/licenses.json <<EOF + ${builtins.toJSON enterpriseRuntimeLicenses} + EOF + ''; + + installPhase = '' + mkdir -p $out + + # Store it all, that helps when things go wrong + cp -rv ./build/* $out + ''; + }; + +} diff --git a/licenses/msgpack_license.txt b/licenses/msgpack_license.txt new file mode 100644 --- /dev/null +++ b/licenses/msgpack_license.txt @@ -0,0 +1,13 @@ +Copyright (C) 2008-2011 INADA Naoki <songofacandy@gmail.com> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/package.json b/package.json new file mode 100644 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "rhodecode-enterprise", + "version": "0.0.1", + "devDependencies": { + "grunt": "^0.4.5", + "grunt-contrib-concat": "^0.5.1", + "grunt-contrib-jshint": "^0.12.0", + "grunt-contrib-less": "^1.1.0", + "grunt-contrib-watch": "^0.6.1", + "jshint": "^2.9.1-rc3" + } +} diff --git a/pip2nix.ini b/pip2nix.ini new file mode 100644 --- /dev/null +++ b/pip2nix.ini @@ -0,0 +1,3 @@ +[pip2nix] +requirements = ., -r ./requirements.txt +output = ./pkgs/python-packages.nix diff --git a/pkgs/node-packages.nix b/pkgs/node-packages.nix new file mode 100644 --- /dev/null +++ b/pkgs/node-packages.nix @@ -0,0 +1,3341 @@ +{ self, fetchurl, fetchgit ? null, lib }: + +{ + by-spec."abbrev"."1" = + self.by-version."abbrev"."1.0.7"; + by-version."abbrev"."1.0.7" = lib.makeOverridable self.buildNodePackage { + name = "abbrev-1.0.7"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"; + name = "abbrev-1.0.7.tgz"; + sha1 = "5b6035b2ee9d4fb5cf859f08a9be81b208491843"; + }) + ]; + buildInputs = + (self.nativeDeps."abbrev" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "abbrev" ]; + }; + by-spec."amdefine".">=0.0.4" = + self.by-version."amdefine"."1.0.0"; + by-version."amdefine"."1.0.0" = lib.makeOverridable self.buildNodePackage { + name = "amdefine-1.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"; + name = "amdefine-1.0.0.tgz"; + sha1 = "fd17474700cb5cc9c2b709f0be9d23ce3c198c33"; + }) + ]; + buildInputs = + (self.nativeDeps."amdefine" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "amdefine" ]; + }; + by-spec."ansi-regex"."^0.2.0" = + self.by-version."ansi-regex"."0.2.1"; + by-version."ansi-regex"."0.2.1" = lib.makeOverridable self.buildNodePackage { + name = "ansi-regex-0.2.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"; + name = "ansi-regex-0.2.1.tgz"; + sha1 = "0d8e946967a3d8143f93e24e298525fc1b2235f9"; + }) + ]; + buildInputs = + (self.nativeDeps."ansi-regex" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "ansi-regex" ]; + }; + by-spec."ansi-regex"."^0.2.1" = + self.by-version."ansi-regex"."0.2.1"; + by-spec."ansi-regex"."^2.0.0" = + self.by-version."ansi-regex"."2.0.0"; + by-version."ansi-regex"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "ansi-regex-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"; + name = "ansi-regex-2.0.0.tgz"; + sha1 = "c5061b6e0ef8a81775e50f5d66151bf6bf371107"; + }) + ]; + buildInputs = + (self.nativeDeps."ansi-regex" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "ansi-regex" ]; + }; + by-spec."ansi-styles"."^1.1.0" = + self.by-version."ansi-styles"."1.1.0"; + by-version."ansi-styles"."1.1.0" = lib.makeOverridable self.buildNodePackage { + name = "ansi-styles-1.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"; + name = "ansi-styles-1.1.0.tgz"; + sha1 = "eaecbf66cd706882760b2f4691582b8f55d7a7de"; + }) + ]; + buildInputs = + (self.nativeDeps."ansi-styles" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "ansi-styles" ]; + }; + by-spec."ansi-styles"."^2.1.0" = + self.by-version."ansi-styles"."2.1.0"; + by-version."ansi-styles"."2.1.0" = lib.makeOverridable self.buildNodePackage { + name = "ansi-styles-2.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"; + name = "ansi-styles-2.1.0.tgz"; + sha1 = "990f747146927b559a932bf92959163d60c0d0e2"; + }) + ]; + buildInputs = + (self.nativeDeps."ansi-styles" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "ansi-styles" ]; + }; + by-spec."argparse"."~ 0.1.11" = + self.by-version."argparse"."0.1.16"; + by-version."argparse"."0.1.16" = lib.makeOverridable self.buildNodePackage { + name = "argparse-0.1.16"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz"; + name = "argparse-0.1.16.tgz"; + sha1 = "cfd01e0fbba3d6caed049fbd758d40f65196f57c"; + }) + ]; + buildInputs = + (self.nativeDeps."argparse" or []); + deps = { + "underscore-1.7.0" = self.by-version."underscore"."1.7.0"; + "underscore.string-2.4.0" = self.by-version."underscore.string"."2.4.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "argparse" ]; + }; + by-spec."asap"."~1.0.0" = + self.by-version."asap"."1.0.0"; + by-version."asap"."1.0.0" = lib.makeOverridable self.buildNodePackage { + name = "asap-1.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/asap/-/asap-1.0.0.tgz"; + name = "asap-1.0.0.tgz"; + sha1 = "b2a45da5fdfa20b0496fc3768cc27c12fa916a7d"; + }) + ]; + buildInputs = + (self.nativeDeps."asap" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "asap" ]; + }; + by-spec."asn1".">=0.2.3 <0.3.0" = + self.by-version."asn1"."0.2.3"; + by-version."asn1"."0.2.3" = lib.makeOverridable self.buildNodePackage { + name = "asn1-0.2.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"; + name = "asn1-0.2.3.tgz"; + sha1 = "dac8787713c9966849fc8180777ebe9c1ddf3b86"; + }) + ]; + buildInputs = + (self.nativeDeps."asn1" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "asn1" ]; + }; + by-spec."assert-plus".">=0.2.0 <0.3.0" = + self.by-version."assert-plus"."0.2.0"; + by-version."assert-plus"."0.2.0" = lib.makeOverridable self.buildNodePackage { + name = "assert-plus-0.2.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"; + name = "assert-plus-0.2.0.tgz"; + sha1 = "d74e1b87e7affc0db8aadb7021f3fe48101ab234"; + }) + ]; + buildInputs = + (self.nativeDeps."assert-plus" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "assert-plus" ]; + }; + by-spec."assert-plus"."^0.1.5" = + self.by-version."assert-plus"."0.1.5"; + by-version."assert-plus"."0.1.5" = lib.makeOverridable self.buildNodePackage { + name = "assert-plus-0.1.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"; + name = "assert-plus-0.1.5.tgz"; + sha1 = "ee74009413002d84cec7219c6ac811812e723160"; + }) + ]; + buildInputs = + (self.nativeDeps."assert-plus" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "assert-plus" ]; + }; + by-spec."assert-plus"."^0.2.0" = + self.by-version."assert-plus"."0.2.0"; + by-spec."async"."^0.9.0" = + self.by-version."async"."0.9.2"; + by-version."async"."0.9.2" = lib.makeOverridable self.buildNodePackage { + name = "async-0.9.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/async/-/async-0.9.2.tgz"; + name = "async-0.9.2.tgz"; + sha1 = "aea74d5e61c1f899613bf64bda66d4c78f2fd17d"; + }) + ]; + buildInputs = + (self.nativeDeps."async" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "async" ]; + }; + by-spec."async"."^1.4.0" = + self.by-version."async"."1.5.2"; + by-version."async"."1.5.2" = lib.makeOverridable self.buildNodePackage { + name = "async-1.5.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/async/-/async-1.5.2.tgz"; + name = "async-1.5.2.tgz"; + sha1 = "ec6a61ae56480c0c3cb241c95618e20892f9672a"; + }) + ]; + buildInputs = + (self.nativeDeps."async" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "async" ]; + }; + by-spec."async"."~0.1.22" = + self.by-version."async"."0.1.22"; + by-version."async"."0.1.22" = lib.makeOverridable self.buildNodePackage { + name = "async-0.1.22"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/async/-/async-0.1.22.tgz"; + name = "async-0.1.22.tgz"; + sha1 = "0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061"; + }) + ]; + buildInputs = + (self.nativeDeps."async" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "async" ]; + }; + by-spec."async"."~0.2.9" = + self.by-version."async"."0.2.10"; + by-version."async"."0.2.10" = lib.makeOverridable self.buildNodePackage { + name = "async-0.2.10"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/async/-/async-0.2.10.tgz"; + name = "async-0.2.10.tgz"; + sha1 = "b6bbe0b0674b9d719708ca38de8c237cb526c3d1"; + }) + ]; + buildInputs = + (self.nativeDeps."async" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "async" ]; + }; + by-spec."aws-sign2"."~0.6.0" = + self.by-version."aws-sign2"."0.6.0"; + by-version."aws-sign2"."0.6.0" = lib.makeOverridable self.buildNodePackage { + name = "aws-sign2-0.6.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"; + name = "aws-sign2-0.6.0.tgz"; + sha1 = "14342dd38dbcc94d0e5b87d763cd63612c0e794f"; + }) + ]; + buildInputs = + (self.nativeDeps."aws-sign2" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "aws-sign2" ]; + }; + by-spec."balanced-match"."^0.3.0" = + self.by-version."balanced-match"."0.3.0"; + by-version."balanced-match"."0.3.0" = lib.makeOverridable self.buildNodePackage { + name = "balanced-match-0.3.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz"; + name = "balanced-match-0.3.0.tgz"; + sha1 = "a91cdd1ebef1a86659e70ff4def01625fc2d6756"; + }) + ]; + buildInputs = + (self.nativeDeps."balanced-match" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "balanced-match" ]; + }; + by-spec."bl"."~1.0.0" = + self.by-version."bl"."1.0.1"; + by-version."bl"."1.0.1" = lib.makeOverridable self.buildNodePackage { + name = "bl-1.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/bl/-/bl-1.0.1.tgz"; + name = "bl-1.0.1.tgz"; + sha1 = "0e6df7330308c46515751676cafa7334dc9852fd"; + }) + ]; + buildInputs = + (self.nativeDeps."bl" or []); + deps = { + "readable-stream-2.0.5" = self.by-version."readable-stream"."2.0.5"; + }; + peerDependencies = [ + ]; + passthru.names = [ "bl" ]; + }; + by-spec."boom"."2.x.x" = + self.by-version."boom"."2.10.1"; + by-version."boom"."2.10.1" = lib.makeOverridable self.buildNodePackage { + name = "boom-2.10.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/boom/-/boom-2.10.1.tgz"; + name = "boom-2.10.1.tgz"; + sha1 = "39c8918ceff5799f83f9492a848f625add0c766f"; + }) + ]; + buildInputs = + (self.nativeDeps."boom" or []); + deps = { + "hoek-2.16.3" = self.by-version."hoek"."2.16.3"; + }; + peerDependencies = [ + ]; + passthru.names = [ "boom" ]; + }; + by-spec."brace-expansion"."^1.0.0" = + self.by-version."brace-expansion"."1.1.2"; + by-version."brace-expansion"."1.1.2" = lib.makeOverridable self.buildNodePackage { + name = "brace-expansion-1.1.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.2.tgz"; + name = "brace-expansion-1.1.2.tgz"; + sha1 = "f21445d0488b658e2771efd870eff51df29f04ef"; + }) + ]; + buildInputs = + (self.nativeDeps."brace-expansion" or []); + deps = { + "balanced-match-0.3.0" = self.by-version."balanced-match"."0.3.0"; + "concat-map-0.0.1" = self.by-version."concat-map"."0.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "brace-expansion" ]; + }; + by-spec."caseless"."~0.11.0" = + self.by-version."caseless"."0.11.0"; + by-version."caseless"."0.11.0" = lib.makeOverridable self.buildNodePackage { + name = "caseless-0.11.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"; + name = "caseless-0.11.0.tgz"; + sha1 = "715b96ea9841593cc33067923f5ec60ebda4f7d7"; + }) + ]; + buildInputs = + (self.nativeDeps."caseless" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "caseless" ]; + }; + by-spec."chalk"."^0.5.1" = + self.by-version."chalk"."0.5.1"; + by-version."chalk"."0.5.1" = lib.makeOverridable self.buildNodePackage { + name = "chalk-0.5.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz"; + name = "chalk-0.5.1.tgz"; + sha1 = "663b3a648b68b55d04690d49167aa837858f2174"; + }) + ]; + buildInputs = + (self.nativeDeps."chalk" or []); + deps = { + "ansi-styles-1.1.0" = self.by-version."ansi-styles"."1.1.0"; + "escape-string-regexp-1.0.4" = self.by-version."escape-string-regexp"."1.0.4"; + "has-ansi-0.1.0" = self.by-version."has-ansi"."0.1.0"; + "strip-ansi-0.3.0" = self.by-version."strip-ansi"."0.3.0"; + "supports-color-0.2.0" = self.by-version."supports-color"."0.2.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "chalk" ]; + }; + by-spec."chalk"."^1.0.0" = + self.by-version."chalk"."1.1.1"; + by-version."chalk"."1.1.1" = lib.makeOverridable self.buildNodePackage { + name = "chalk-1.1.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"; + name = "chalk-1.1.1.tgz"; + sha1 = "509afb67066e7499f7eb3535c77445772ae2d019"; + }) + ]; + buildInputs = + (self.nativeDeps."chalk" or []); + deps = { + "ansi-styles-2.1.0" = self.by-version."ansi-styles"."2.1.0"; + "escape-string-regexp-1.0.4" = self.by-version."escape-string-regexp"."1.0.4"; + "has-ansi-2.0.0" = self.by-version."has-ansi"."2.0.0"; + "strip-ansi-3.0.0" = self.by-version."strip-ansi"."3.0.0"; + "supports-color-2.0.0" = self.by-version."supports-color"."2.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "chalk" ]; + }; + by-spec."chalk"."^1.1.1" = + self.by-version."chalk"."1.1.1"; + by-spec."cli"."0.6.x" = + self.by-version."cli"."0.6.6"; + by-version."cli"."0.6.6" = lib.makeOverridable self.buildNodePackage { + name = "cli-0.6.6"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/cli/-/cli-0.6.6.tgz"; + name = "cli-0.6.6.tgz"; + sha1 = "02ad44a380abf27adac5e6f0cdd7b043d74c53e3"; + }) + ]; + buildInputs = + (self.nativeDeps."cli" or []); + deps = { + "glob-3.2.11" = self.by-version."glob"."3.2.11"; + "exit-0.1.2" = self.by-version."exit"."0.1.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "cli" ]; + }; + by-spec."coffee-script"."~1.3.3" = + self.by-version."coffee-script"."1.3.3"; + by-version."coffee-script"."1.3.3" = lib.makeOverridable self.buildNodePackage { + name = "coffee-script-1.3.3"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz"; + name = "coffee-script-1.3.3.tgz"; + sha1 = "150d6b4cb522894369efed6a2101c20bc7f4a4f4"; + }) + ]; + buildInputs = + (self.nativeDeps."coffee-script" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "coffee-script" ]; + }; + by-spec."colors"."~0.6.2" = + self.by-version."colors"."0.6.2"; + by-version."colors"."0.6.2" = lib.makeOverridable self.buildNodePackage { + name = "colors-0.6.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz"; + name = "colors-0.6.2.tgz"; + sha1 = "2423fe6678ac0c5dae8852e5d0e5be08c997abcc"; + }) + ]; + buildInputs = + (self.nativeDeps."colors" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "colors" ]; + }; + by-spec."combined-stream"."^1.0.5" = + self.by-version."combined-stream"."1.0.5"; + by-version."combined-stream"."1.0.5" = lib.makeOverridable self.buildNodePackage { + name = "combined-stream-1.0.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"; + name = "combined-stream-1.0.5.tgz"; + sha1 = "938370a57b4a51dea2c77c15d5c5fdf895164009"; + }) + ]; + buildInputs = + (self.nativeDeps."combined-stream" or []); + deps = { + "delayed-stream-1.0.0" = self.by-version."delayed-stream"."1.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "combined-stream" ]; + }; + by-spec."combined-stream"."~1.0.5" = + self.by-version."combined-stream"."1.0.5"; + by-spec."commander"."^2.9.0" = + self.by-version."commander"."2.9.0"; + by-version."commander"."2.9.0" = lib.makeOverridable self.buildNodePackage { + name = "commander-2.9.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/commander/-/commander-2.9.0.tgz"; + name = "commander-2.9.0.tgz"; + sha1 = "9c99094176e12240cb22d6c5146098400fe0f7d4"; + }) + ]; + buildInputs = + (self.nativeDeps."commander" or []); + deps = { + "graceful-readlink-1.0.1" = self.by-version."graceful-readlink"."1.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "commander" ]; + }; + by-spec."concat-map"."0.0.1" = + self.by-version."concat-map"."0.0.1"; + by-version."concat-map"."0.0.1" = lib.makeOverridable self.buildNodePackage { + name = "concat-map-0.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"; + name = "concat-map-0.0.1.tgz"; + sha1 = "d8a96bd77fd68df7793a73036a3ba0d5405d477b"; + }) + ]; + buildInputs = + (self.nativeDeps."concat-map" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "concat-map" ]; + }; + by-spec."console-browserify"."1.1.x" = + self.by-version."console-browserify"."1.1.0"; + by-version."console-browserify"."1.1.0" = lib.makeOverridable self.buildNodePackage { + name = "console-browserify-1.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz"; + name = "console-browserify-1.1.0.tgz"; + sha1 = "f0241c45730a9fc6323b206dbf38edc741d0bb10"; + }) + ]; + buildInputs = + (self.nativeDeps."console-browserify" or []); + deps = { + "date-now-0.1.4" = self.by-version."date-now"."0.1.4"; + }; + peerDependencies = [ + ]; + passthru.names = [ "console-browserify" ]; + }; + by-spec."core-util-is"."~1.0.0" = + self.by-version."core-util-is"."1.0.2"; + by-version."core-util-is"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "core-util-is-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"; + name = "core-util-is-1.0.2.tgz"; + sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7"; + }) + ]; + buildInputs = + (self.nativeDeps."core-util-is" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "core-util-is" ]; + }; + by-spec."cryptiles"."2.x.x" = + self.by-version."cryptiles"."2.0.5"; + by-version."cryptiles"."2.0.5" = lib.makeOverridable self.buildNodePackage { + name = "cryptiles-2.0.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"; + name = "cryptiles-2.0.5.tgz"; + sha1 = "3bdfecdc608147c1c67202fa291e7dca59eaa3b8"; + }) + ]; + buildInputs = + (self.nativeDeps."cryptiles" or []); + deps = { + "boom-2.10.1" = self.by-version."boom"."2.10.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "cryptiles" ]; + }; + by-spec."dashdash".">=1.10.1 <2.0.0" = + self.by-version."dashdash"."1.12.2"; + by-version."dashdash"."1.12.2" = lib.makeOverridable self.buildNodePackage { + name = "dashdash-1.12.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/dashdash/-/dashdash-1.12.2.tgz"; + name = "dashdash-1.12.2.tgz"; + sha1 = "1c6f70588498d047b8cd5777b32ba85a5e25be36"; + }) + ]; + buildInputs = + (self.nativeDeps."dashdash" or []); + deps = { + "assert-plus-0.2.0" = self.by-version."assert-plus"."0.2.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "dashdash" ]; + }; + by-spec."date-now"."^0.1.4" = + self.by-version."date-now"."0.1.4"; + by-version."date-now"."0.1.4" = lib.makeOverridable self.buildNodePackage { + name = "date-now-0.1.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz"; + name = "date-now-0.1.4.tgz"; + sha1 = "eaf439fd4d4848ad74e5cc7dbef200672b9e345b"; + }) + ]; + buildInputs = + (self.nativeDeps."date-now" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "date-now" ]; + }; + by-spec."dateformat"."1.0.2-1.2.3" = + self.by-version."dateformat"."1.0.2-1.2.3"; + by-version."dateformat"."1.0.2-1.2.3" = lib.makeOverridable self.buildNodePackage { + name = "dateformat-1.0.2-1.2.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz"; + name = "dateformat-1.0.2-1.2.3.tgz"; + sha1 = "b0220c02de98617433b72851cf47de3df2cdbee9"; + }) + ]; + buildInputs = + (self.nativeDeps."dateformat" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "dateformat" ]; + }; + by-spec."debug"."~0.7.0" = + self.by-version."debug"."0.7.4"; + by-version."debug"."0.7.4" = lib.makeOverridable self.buildNodePackage { + name = "debug-0.7.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/debug/-/debug-0.7.4.tgz"; + name = "debug-0.7.4.tgz"; + sha1 = "06e1ea8082c2cb14e39806e22e2f6f757f92af39"; + }) + ]; + buildInputs = + (self.nativeDeps."debug" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "debug" ]; + }; + by-spec."delayed-stream"."~1.0.0" = + self.by-version."delayed-stream"."1.0.0"; + by-version."delayed-stream"."1.0.0" = lib.makeOverridable self.buildNodePackage { + name = "delayed-stream-1.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"; + name = "delayed-stream-1.0.0.tgz"; + sha1 = "df3ae199acadfb7d440aaae0b29e2272b24ec619"; + }) + ]; + buildInputs = + (self.nativeDeps."delayed-stream" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "delayed-stream" ]; + }; + by-spec."dom-serializer"."0" = + self.by-version."dom-serializer"."0.1.0"; + by-version."dom-serializer"."0.1.0" = lib.makeOverridable self.buildNodePackage { + name = "dom-serializer-0.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz"; + name = "dom-serializer-0.1.0.tgz"; + sha1 = "073c697546ce0780ce23be4a28e293e40bc30c82"; + }) + ]; + buildInputs = + (self.nativeDeps."dom-serializer" or []); + deps = { + "domelementtype-1.1.3" = self.by-version."domelementtype"."1.1.3"; + "entities-1.1.1" = self.by-version."entities"."1.1.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "dom-serializer" ]; + }; + by-spec."domelementtype"."1" = + self.by-version."domelementtype"."1.3.0"; + by-version."domelementtype"."1.3.0" = lib.makeOverridable self.buildNodePackage { + name = "domelementtype-1.3.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"; + name = "domelementtype-1.3.0.tgz"; + sha1 = "b17aed82e8ab59e52dd9c19b1756e0fc187204c2"; + }) + ]; + buildInputs = + (self.nativeDeps."domelementtype" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "domelementtype" ]; + }; + by-spec."domelementtype"."~1.1.1" = + self.by-version."domelementtype"."1.1.3"; + by-version."domelementtype"."1.1.3" = lib.makeOverridable self.buildNodePackage { + name = "domelementtype-1.1.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"; + name = "domelementtype-1.1.3.tgz"; + sha1 = "bd28773e2642881aec51544924299c5cd822185b"; + }) + ]; + buildInputs = + (self.nativeDeps."domelementtype" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "domelementtype" ]; + }; + by-spec."domhandler"."2.3" = + self.by-version."domhandler"."2.3.0"; + by-version."domhandler"."2.3.0" = lib.makeOverridable self.buildNodePackage { + name = "domhandler-2.3.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"; + name = "domhandler-2.3.0.tgz"; + sha1 = "2de59a0822d5027fabff6f032c2b25a2a8abe738"; + }) + ]; + buildInputs = + (self.nativeDeps."domhandler" or []); + deps = { + "domelementtype-1.3.0" = self.by-version."domelementtype"."1.3.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "domhandler" ]; + }; + by-spec."domutils"."1.5" = + self.by-version."domutils"."1.5.1"; + by-version."domutils"."1.5.1" = lib.makeOverridable self.buildNodePackage { + name = "domutils-1.5.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"; + name = "domutils-1.5.1.tgz"; + sha1 = "dcd8488a26f563d61079e48c9f7b7e32373682cf"; + }) + ]; + buildInputs = + (self.nativeDeps."domutils" or []); + deps = { + "dom-serializer-0.1.0" = self.by-version."dom-serializer"."0.1.0"; + "domelementtype-1.3.0" = self.by-version."domelementtype"."1.3.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "domutils" ]; + }; + by-spec."ecc-jsbn".">=0.0.1 <1.0.0" = + self.by-version."ecc-jsbn"."0.1.1"; + by-version."ecc-jsbn"."0.1.1" = lib.makeOverridable self.buildNodePackage { + name = "ecc-jsbn-0.1.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"; + name = "ecc-jsbn-0.1.1.tgz"; + sha1 = "0fc73a9ed5f0d53c38193398523ef7e543777505"; + }) + ]; + buildInputs = + (self.nativeDeps."ecc-jsbn" or []); + deps = { + "jsbn-0.1.0" = self.by-version."jsbn"."0.1.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "ecc-jsbn" ]; + }; + by-spec."entities"."1.0" = + self.by-version."entities"."1.0.0"; + by-version."entities"."1.0.0" = lib.makeOverridable self.buildNodePackage { + name = "entities-1.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/entities/-/entities-1.0.0.tgz"; + name = "entities-1.0.0.tgz"; + sha1 = "b2987aa3821347fcde642b24fdfc9e4fb712bf26"; + }) + ]; + buildInputs = + (self.nativeDeps."entities" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "entities" ]; + }; + by-spec."entities"."~1.1.1" = + self.by-version."entities"."1.1.1"; + by-version."entities"."1.1.1" = lib.makeOverridable self.buildNodePackage { + name = "entities-1.1.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/entities/-/entities-1.1.1.tgz"; + name = "entities-1.1.1.tgz"; + sha1 = "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"; + }) + ]; + buildInputs = + (self.nativeDeps."entities" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "entities" ]; + }; + by-spec."errno"."^0.1.1" = + self.by-version."errno"."0.1.4"; + by-version."errno"."0.1.4" = lib.makeOverridable self.buildNodePackage { + name = "errno-0.1.4"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/errno/-/errno-0.1.4.tgz"; + name = "errno-0.1.4.tgz"; + sha1 = "b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"; + }) + ]; + buildInputs = + (self.nativeDeps."errno" or []); + deps = { + "prr-0.0.0" = self.by-version."prr"."0.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "errno" ]; + }; + by-spec."escape-string-regexp"."^1.0.0" = + self.by-version."escape-string-regexp"."1.0.4"; + by-version."escape-string-regexp"."1.0.4" = lib.makeOverridable self.buildNodePackage { + name = "escape-string-regexp-1.0.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.4.tgz"; + name = "escape-string-regexp-1.0.4.tgz"; + sha1 = "b85e679b46f72d03fbbe8a3bf7259d535c21b62f"; + }) + ]; + buildInputs = + (self.nativeDeps."escape-string-regexp" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "escape-string-regexp" ]; + }; + by-spec."escape-string-regexp"."^1.0.2" = + self.by-version."escape-string-regexp"."1.0.4"; + by-spec."esprima"."~ 1.0.2" = + self.by-version."esprima"."1.0.4"; + by-version."esprima"."1.0.4" = lib.makeOverridable self.buildNodePackage { + name = "esprima-1.0.4"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz"; + name = "esprima-1.0.4.tgz"; + sha1 = "9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"; + }) + ]; + buildInputs = + (self.nativeDeps."esprima" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "esprima" ]; + }; + by-spec."eventemitter2"."~0.4.13" = + self.by-version."eventemitter2"."0.4.14"; + by-version."eventemitter2"."0.4.14" = lib.makeOverridable self.buildNodePackage { + name = "eventemitter2-0.4.14"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz"; + name = "eventemitter2-0.4.14.tgz"; + sha1 = "8f61b75cde012b2e9eb284d4545583b5643b61ab"; + }) + ]; + buildInputs = + (self.nativeDeps."eventemitter2" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "eventemitter2" ]; + }; + by-spec."exit"."0.1.2" = + self.by-version."exit"."0.1.2"; + by-version."exit"."0.1.2" = lib.makeOverridable self.buildNodePackage { + name = "exit-0.1.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/exit/-/exit-0.1.2.tgz"; + name = "exit-0.1.2.tgz"; + sha1 = "0632638f8d877cc82107d30a0fff1a17cba1cd0c"; + }) + ]; + buildInputs = + (self.nativeDeps."exit" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "exit" ]; + }; + by-spec."exit"."0.1.x" = + self.by-version."exit"."0.1.2"; + by-spec."exit"."~0.1.1" = + self.by-version."exit"."0.1.2"; + by-spec."extend"."~3.0.0" = + self.by-version."extend"."3.0.0"; + by-version."extend"."3.0.0" = lib.makeOverridable self.buildNodePackage { + name = "extend-3.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/extend/-/extend-3.0.0.tgz"; + name = "extend-3.0.0.tgz"; + sha1 = "5a474353b9f3353ddd8176dfd37b91c83a46f1d4"; + }) + ]; + buildInputs = + (self.nativeDeps."extend" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "extend" ]; + }; + by-spec."extsprintf"."1.0.2" = + self.by-version."extsprintf"."1.0.2"; + by-version."extsprintf"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "extsprintf-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"; + name = "extsprintf-1.0.2.tgz"; + sha1 = "e1080e0658e300b06294990cc70e1502235fd550"; + }) + ]; + buildInputs = + (self.nativeDeps."extsprintf" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "extsprintf" ]; + }; + by-spec."faye-websocket"."~0.4.3" = + self.by-version."faye-websocket"."0.4.4"; + by-version."faye-websocket"."0.4.4" = lib.makeOverridable self.buildNodePackage { + name = "faye-websocket-0.4.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz"; + name = "faye-websocket-0.4.4.tgz"; + sha1 = "c14c5b3bf14d7417ffbfd990c0a7495cd9f337bc"; + }) + ]; + buildInputs = + (self.nativeDeps."faye-websocket" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "faye-websocket" ]; + }; + by-spec."findup-sync"."~0.1.2" = + self.by-version."findup-sync"."0.1.3"; + by-version."findup-sync"."0.1.3" = lib.makeOverridable self.buildNodePackage { + name = "findup-sync-0.1.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz"; + name = "findup-sync-0.1.3.tgz"; + sha1 = "7f3e7a97b82392c653bf06589bd85190e93c3683"; + }) + ]; + buildInputs = + (self.nativeDeps."findup-sync" or []); + deps = { + "glob-3.2.11" = self.by-version."glob"."3.2.11"; + "lodash-2.4.2" = self.by-version."lodash"."2.4.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "findup-sync" ]; + }; + by-spec."forever-agent"."~0.6.1" = + self.by-version."forever-agent"."0.6.1"; + by-version."forever-agent"."0.6.1" = lib.makeOverridable self.buildNodePackage { + name = "forever-agent-0.6.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"; + name = "forever-agent-0.6.1.tgz"; + sha1 = "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"; + }) + ]; + buildInputs = + (self.nativeDeps."forever-agent" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "forever-agent" ]; + }; + by-spec."form-data"."~1.0.0-rc3" = + self.by-version."form-data"."1.0.0-rc3"; + by-version."form-data"."1.0.0-rc3" = lib.makeOverridable self.buildNodePackage { + name = "form-data-1.0.0-rc3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz"; + name = "form-data-1.0.0-rc3.tgz"; + sha1 = "d35bc62e7fbc2937ae78f948aaa0d38d90607577"; + }) + ]; + buildInputs = + (self.nativeDeps."form-data" or []); + deps = { + "async-1.5.2" = self.by-version."async"."1.5.2"; + "combined-stream-1.0.5" = self.by-version."combined-stream"."1.0.5"; + "mime-types-2.1.9" = self.by-version."mime-types"."2.1.9"; + }; + peerDependencies = [ + ]; + passthru.names = [ "form-data" ]; + }; + by-spec."gaze"."~0.5.1" = + self.by-version."gaze"."0.5.2"; + by-version."gaze"."0.5.2" = lib.makeOverridable self.buildNodePackage { + name = "gaze-0.5.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz"; + name = "gaze-0.5.2.tgz"; + sha1 = "40b709537d24d1d45767db5a908689dfe69ac44f"; + }) + ]; + buildInputs = + (self.nativeDeps."gaze" or []); + deps = { + "globule-0.1.0" = self.by-version."globule"."0.1.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "gaze" ]; + }; + by-spec."generate-function"."^2.0.0" = + self.by-version."generate-function"."2.0.0"; + by-version."generate-function"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "generate-function-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"; + name = "generate-function-2.0.0.tgz"; + sha1 = "6858fe7c0969b7d4e9093337647ac79f60dfbe74"; + }) + ]; + buildInputs = + (self.nativeDeps."generate-function" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "generate-function" ]; + }; + by-spec."generate-object-property"."^1.1.0" = + self.by-version."generate-object-property"."1.2.0"; + by-version."generate-object-property"."1.2.0" = lib.makeOverridable self.buildNodePackage { + name = "generate-object-property-1.2.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"; + name = "generate-object-property-1.2.0.tgz"; + sha1 = "9c0e1c40308ce804f4783618b937fa88f99d50d0"; + }) + ]; + buildInputs = + (self.nativeDeps."generate-object-property" or []); + deps = { + "is-property-1.0.2" = self.by-version."is-property"."1.0.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "generate-object-property" ]; + }; + by-spec."getobject"."~0.1.0" = + self.by-version."getobject"."0.1.0"; + by-version."getobject"."0.1.0" = lib.makeOverridable self.buildNodePackage { + name = "getobject-0.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz"; + name = "getobject-0.1.0.tgz"; + sha1 = "047a449789fa160d018f5486ed91320b6ec7885c"; + }) + ]; + buildInputs = + (self.nativeDeps."getobject" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "getobject" ]; + }; + by-spec."glob"."~ 3.2.1" = + self.by-version."glob"."3.2.11"; + by-version."glob"."3.2.11" = lib.makeOverridable self.buildNodePackage { + name = "glob-3.2.11"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/glob/-/glob-3.2.11.tgz"; + name = "glob-3.2.11.tgz"; + sha1 = "4a973f635b9190f715d10987d5c00fd2815ebe3d"; + }) + ]; + buildInputs = + (self.nativeDeps."glob" or []); + deps = { + "inherits-2.0.1" = self.by-version."inherits"."2.0.1"; + "minimatch-0.3.0" = self.by-version."minimatch"."0.3.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "glob" ]; + }; + by-spec."glob"."~3.1.21" = + self.by-version."glob"."3.1.21"; + by-version."glob"."3.1.21" = lib.makeOverridable self.buildNodePackage { + name = "glob-3.1.21"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/glob/-/glob-3.1.21.tgz"; + name = "glob-3.1.21.tgz"; + sha1 = "d29e0a055dea5138f4d07ed40e8982e83c2066cd"; + }) + ]; + buildInputs = + (self.nativeDeps."glob" or []); + deps = { + "minimatch-0.2.14" = self.by-version."minimatch"."0.2.14"; + "graceful-fs-1.2.3" = self.by-version."graceful-fs"."1.2.3"; + "inherits-1.0.2" = self.by-version."inherits"."1.0.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "glob" ]; + }; + by-spec."glob"."~3.2.9" = + self.by-version."glob"."3.2.11"; + by-spec."globule"."~0.1.0" = + self.by-version."globule"."0.1.0"; + by-version."globule"."0.1.0" = lib.makeOverridable self.buildNodePackage { + name = "globule-0.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/globule/-/globule-0.1.0.tgz"; + name = "globule-0.1.0.tgz"; + sha1 = "d9c8edde1da79d125a151b79533b978676346ae5"; + }) + ]; + buildInputs = + (self.nativeDeps."globule" or []); + deps = { + "lodash-1.0.2" = self.by-version."lodash"."1.0.2"; + "glob-3.1.21" = self.by-version."glob"."3.1.21"; + "minimatch-0.2.14" = self.by-version."minimatch"."0.2.14"; + }; + peerDependencies = [ + ]; + passthru.names = [ "globule" ]; + }; + by-spec."graceful-fs"."^3.0.5" = + self.by-version."graceful-fs"."3.0.8"; + by-version."graceful-fs"."3.0.8" = lib.makeOverridable self.buildNodePackage { + name = "graceful-fs-3.0.8"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"; + name = "graceful-fs-3.0.8.tgz"; + sha1 = "ce813e725fa82f7e6147d51c9a5ca68270551c22"; + }) + ]; + buildInputs = + (self.nativeDeps."graceful-fs" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "graceful-fs" ]; + }; + by-spec."graceful-fs"."~1.2.0" = + self.by-version."graceful-fs"."1.2.3"; + by-version."graceful-fs"."1.2.3" = lib.makeOverridable self.buildNodePackage { + name = "graceful-fs-1.2.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz"; + name = "graceful-fs-1.2.3.tgz"; + sha1 = "15a4806a57547cb2d2dbf27f42e89a8c3451b364"; + }) + ]; + buildInputs = + (self.nativeDeps."graceful-fs" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "graceful-fs" ]; + }; + by-spec."graceful-readlink".">= 1.0.0" = + self.by-version."graceful-readlink"."1.0.1"; + by-version."graceful-readlink"."1.0.1" = lib.makeOverridable self.buildNodePackage { + name = "graceful-readlink-1.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"; + name = "graceful-readlink-1.0.1.tgz"; + sha1 = "4cafad76bc62f02fa039b2f94e9a3dd3a391a725"; + }) + ]; + buildInputs = + (self.nativeDeps."graceful-readlink" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "graceful-readlink" ]; + }; + by-spec."grunt".">=0.4.0" = + self.by-version."grunt"."0.4.5"; + by-version."grunt"."0.4.5" = lib.makeOverridable self.buildNodePackage { + name = "grunt-0.4.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz"; + name = "grunt-0.4.5.tgz"; + sha1 = "56937cd5194324adff6d207631832a9d6ba4e7f0"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt" or []); + deps = { + "async-0.1.22" = self.by-version."async"."0.1.22"; + "coffee-script-1.3.3" = self.by-version."coffee-script"."1.3.3"; + "colors-0.6.2" = self.by-version."colors"."0.6.2"; + "dateformat-1.0.2-1.2.3" = self.by-version."dateformat"."1.0.2-1.2.3"; + "eventemitter2-0.4.14" = self.by-version."eventemitter2"."0.4.14"; + "findup-sync-0.1.3" = self.by-version."findup-sync"."0.1.3"; + "glob-3.1.21" = self.by-version."glob"."3.1.21"; + "hooker-0.2.3" = self.by-version."hooker"."0.2.3"; + "iconv-lite-0.2.11" = self.by-version."iconv-lite"."0.2.11"; + "minimatch-0.2.14" = self.by-version."minimatch"."0.2.14"; + "nopt-1.0.10" = self.by-version."nopt"."1.0.10"; + "rimraf-2.2.8" = self.by-version."rimraf"."2.2.8"; + "lodash-0.9.2" = self.by-version."lodash"."0.9.2"; + "underscore.string-2.2.1" = self.by-version."underscore.string"."2.2.1"; + "which-1.0.9" = self.by-version."which"."1.0.9"; + "js-yaml-2.0.5" = self.by-version."js-yaml"."2.0.5"; + "exit-0.1.2" = self.by-version."exit"."0.1.2"; + "getobject-0.1.0" = self.by-version."getobject"."0.1.0"; + "grunt-legacy-util-0.2.0" = self.by-version."grunt-legacy-util"."0.2.0"; + "grunt-legacy-log-0.1.3" = self.by-version."grunt-legacy-log"."0.1.3"; + }; + peerDependencies = [ + ]; + passthru.names = [ "grunt" ]; + }; + by-spec."grunt"."^0.4.5" = + self.by-version."grunt"."0.4.5"; + "grunt" = self.by-version."grunt"."0.4.5"; + by-spec."grunt"."~0.4.0" = + self.by-version."grunt"."0.4.5"; + by-spec."grunt-contrib-concat"."^0.5.1" = + self.by-version."grunt-contrib-concat"."0.5.1"; + by-version."grunt-contrib-concat"."0.5.1" = lib.makeOverridable self.buildNodePackage { + name = "grunt-contrib-concat-0.5.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz"; + name = "grunt-contrib-concat-0.5.1.tgz"; + sha1 = "953c6efdfdfd2c107ab9c85077f2d4b24d31cd49"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-contrib-concat" or []); + deps = { + "chalk-0.5.1" = self.by-version."chalk"."0.5.1"; + "source-map-0.3.0" = self.by-version."source-map"."0.3.0"; + }; + peerDependencies = [ + self.by-version."grunt"."0.4.5" + ]; + passthru.names = [ "grunt-contrib-concat" ]; + }; + "grunt-contrib-concat" = self.by-version."grunt-contrib-concat"."0.5.1"; + by-spec."grunt-contrib-jshint"."^0.12.0" = + self.by-version."grunt-contrib-jshint"."0.12.0"; + by-version."grunt-contrib-jshint"."0.12.0" = lib.makeOverridable self.buildNodePackage { + name = "grunt-contrib-jshint-0.12.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-0.12.0.tgz"; + name = "grunt-contrib-jshint-0.12.0.tgz"; + sha1 = "f6b2f06fc715264837a7ab6c69a1ce1a689c2c29"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-contrib-jshint" or []); + deps = { + "hooker-0.2.3" = self.by-version."hooker"."0.2.3"; + "jshint-2.9.1" = self.by-version."jshint"."2.9.1"; + }; + peerDependencies = [ + self.by-version."grunt"."0.4.5" + ]; + passthru.names = [ "grunt-contrib-jshint" ]; + }; + "grunt-contrib-jshint" = self.by-version."grunt-contrib-jshint"."0.12.0"; + by-spec."grunt-contrib-less"."^1.1.0" = + self.by-version."grunt-contrib-less"."1.1.0"; + by-version."grunt-contrib-less"."1.1.0" = lib.makeOverridable self.buildNodePackage { + name = "grunt-contrib-less-1.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-1.1.0.tgz"; + name = "grunt-contrib-less-1.1.0.tgz"; + sha1 = "44d5c5521ad76f3675a12374125d019b5dd03f51"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-contrib-less" or []); + deps = { + "async-0.9.2" = self.by-version."async"."0.9.2"; + "chalk-1.1.1" = self.by-version."chalk"."1.1.1"; + "less-2.5.3" = self.by-version."less"."2.5.3"; + "lodash-3.10.1" = self.by-version."lodash"."3.10.1"; + }; + peerDependencies = [ + self.by-version."grunt"."0.4.5" + ]; + passthru.names = [ "grunt-contrib-less" ]; + }; + "grunt-contrib-less" = self.by-version."grunt-contrib-less"."1.1.0"; + by-spec."grunt-contrib-watch"."^0.6.1" = + self.by-version."grunt-contrib-watch"."0.6.1"; + by-version."grunt-contrib-watch"."0.6.1" = lib.makeOverridable self.buildNodePackage { + name = "grunt-contrib-watch-0.6.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-0.6.1.tgz"; + name = "grunt-contrib-watch-0.6.1.tgz"; + sha1 = "64fdcba25a635f5b4da1b6ce6f90da0aeb6e3f15"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-contrib-watch" or []); + deps = { + "gaze-0.5.2" = self.by-version."gaze"."0.5.2"; + "tiny-lr-fork-0.0.5" = self.by-version."tiny-lr-fork"."0.0.5"; + "lodash-2.4.2" = self.by-version."lodash"."2.4.2"; + "async-0.2.10" = self.by-version."async"."0.2.10"; + }; + peerDependencies = [ + self.by-version."grunt"."0.4.5" + ]; + passthru.names = [ "grunt-contrib-watch" ]; + }; + "grunt-contrib-watch" = self.by-version."grunt-contrib-watch"."0.6.1"; + by-spec."grunt-legacy-log"."~0.1.0" = + self.by-version."grunt-legacy-log"."0.1.3"; + by-version."grunt-legacy-log"."0.1.3" = lib.makeOverridable self.buildNodePackage { + name = "grunt-legacy-log-0.1.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz"; + name = "grunt-legacy-log-0.1.3.tgz"; + sha1 = "ec29426e803021af59029f87d2f9cd7335a05531"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-legacy-log" or []); + deps = { + "colors-0.6.2" = self.by-version."colors"."0.6.2"; + "grunt-legacy-log-utils-0.1.1" = self.by-version."grunt-legacy-log-utils"."0.1.1"; + "hooker-0.2.3" = self.by-version."hooker"."0.2.3"; + "lodash-2.4.2" = self.by-version."lodash"."2.4.2"; + "underscore.string-2.3.3" = self.by-version."underscore.string"."2.3.3"; + }; + peerDependencies = [ + ]; + passthru.names = [ "grunt-legacy-log" ]; + }; + by-spec."grunt-legacy-log-utils"."~0.1.1" = + self.by-version."grunt-legacy-log-utils"."0.1.1"; + by-version."grunt-legacy-log-utils"."0.1.1" = lib.makeOverridable self.buildNodePackage { + name = "grunt-legacy-log-utils-0.1.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz"; + name = "grunt-legacy-log-utils-0.1.1.tgz"; + sha1 = "c0706b9dd9064e116f36f23fe4e6b048672c0f7e"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-legacy-log-utils" or []); + deps = { + "lodash-2.4.2" = self.by-version."lodash"."2.4.2"; + "underscore.string-2.3.3" = self.by-version."underscore.string"."2.3.3"; + "colors-0.6.2" = self.by-version."colors"."0.6.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "grunt-legacy-log-utils" ]; + }; + by-spec."grunt-legacy-util"."~0.2.0" = + self.by-version."grunt-legacy-util"."0.2.0"; + by-version."grunt-legacy-util"."0.2.0" = lib.makeOverridable self.buildNodePackage { + name = "grunt-legacy-util-0.2.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz"; + name = "grunt-legacy-util-0.2.0.tgz"; + sha1 = "93324884dbf7e37a9ff7c026dff451d94a9e554b"; + }) + ]; + buildInputs = + (self.nativeDeps."grunt-legacy-util" or []); + deps = { + "hooker-0.2.3" = self.by-version."hooker"."0.2.3"; + "async-0.1.22" = self.by-version."async"."0.1.22"; + "lodash-0.9.2" = self.by-version."lodash"."0.9.2"; + "exit-0.1.2" = self.by-version."exit"."0.1.2"; + "underscore.string-2.2.1" = self.by-version."underscore.string"."2.2.1"; + "getobject-0.1.0" = self.by-version."getobject"."0.1.0"; + "which-1.0.9" = self.by-version."which"."1.0.9"; + }; + peerDependencies = [ + ]; + passthru.names = [ "grunt-legacy-util" ]; + }; + by-spec."har-validator"."~2.0.2" = + self.by-version."har-validator"."2.0.6"; + by-version."har-validator"."2.0.6" = lib.makeOverridable self.buildNodePackage { + name = "har-validator-2.0.6"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz"; + name = "har-validator-2.0.6.tgz"; + sha1 = "cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"; + }) + ]; + buildInputs = + (self.nativeDeps."har-validator" or []); + deps = { + "chalk-1.1.1" = self.by-version."chalk"."1.1.1"; + "commander-2.9.0" = self.by-version."commander"."2.9.0"; + "is-my-json-valid-2.12.4" = self.by-version."is-my-json-valid"."2.12.4"; + "pinkie-promise-2.0.0" = self.by-version."pinkie-promise"."2.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "har-validator" ]; + }; + by-spec."has-ansi"."^0.1.0" = + self.by-version."has-ansi"."0.1.0"; + by-version."has-ansi"."0.1.0" = lib.makeOverridable self.buildNodePackage { + name = "has-ansi-0.1.0"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz"; + name = "has-ansi-0.1.0.tgz"; + sha1 = "84f265aae8c0e6a88a12d7022894b7568894c62e"; + }) + ]; + buildInputs = + (self.nativeDeps."has-ansi" or []); + deps = { + "ansi-regex-0.2.1" = self.by-version."ansi-regex"."0.2.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "has-ansi" ]; + }; + by-spec."has-ansi"."^2.0.0" = + self.by-version."has-ansi"."2.0.0"; + by-version."has-ansi"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "has-ansi-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"; + name = "has-ansi-2.0.0.tgz"; + sha1 = "34f5049ce1ecdf2b0649af3ef24e45ed35416d91"; + }) + ]; + buildInputs = + (self.nativeDeps."has-ansi" or []); + deps = { + "ansi-regex-2.0.0" = self.by-version."ansi-regex"."2.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "has-ansi" ]; + }; + by-spec."hawk"."~3.1.0" = + self.by-version."hawk"."3.1.3"; + by-version."hawk"."3.1.3" = lib.makeOverridable self.buildNodePackage { + name = "hawk-3.1.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"; + name = "hawk-3.1.3.tgz"; + sha1 = "078444bd7c1640b0fe540d2c9b73d59678e8e1c4"; + }) + ]; + buildInputs = + (self.nativeDeps."hawk" or []); + deps = { + "hoek-2.16.3" = self.by-version."hoek"."2.16.3"; + "boom-2.10.1" = self.by-version."boom"."2.10.1"; + "cryptiles-2.0.5" = self.by-version."cryptiles"."2.0.5"; + "sntp-1.0.9" = self.by-version."sntp"."1.0.9"; + }; + peerDependencies = [ + ]; + passthru.names = [ "hawk" ]; + }; + by-spec."hoek"."2.x.x" = + self.by-version."hoek"."2.16.3"; + by-version."hoek"."2.16.3" = lib.makeOverridable self.buildNodePackage { + name = "hoek-2.16.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"; + name = "hoek-2.16.3.tgz"; + sha1 = "20bb7403d3cea398e91dc4710a8ff1b8274a25ed"; + }) + ]; + buildInputs = + (self.nativeDeps."hoek" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "hoek" ]; + }; + by-spec."hooker"."^0.2.3" = + self.by-version."hooker"."0.2.3"; + by-version."hooker"."0.2.3" = lib.makeOverridable self.buildNodePackage { + name = "hooker-0.2.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz"; + name = "hooker-0.2.3.tgz"; + sha1 = "b834f723cc4a242aa65963459df6d984c5d3d959"; + }) + ]; + buildInputs = + (self.nativeDeps."hooker" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "hooker" ]; + }; + by-spec."hooker"."~0.2.3" = + self.by-version."hooker"."0.2.3"; + by-spec."htmlparser2"."3.8.x" = + self.by-version."htmlparser2"."3.8.3"; + by-version."htmlparser2"."3.8.3" = lib.makeOverridable self.buildNodePackage { + name = "htmlparser2-3.8.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz"; + name = "htmlparser2-3.8.3.tgz"; + sha1 = "996c28b191516a8be86501a7d79757e5c70c1068"; + }) + ]; + buildInputs = + (self.nativeDeps."htmlparser2" or []); + deps = { + "domhandler-2.3.0" = self.by-version."domhandler"."2.3.0"; + "domutils-1.5.1" = self.by-version."domutils"."1.5.1"; + "domelementtype-1.3.0" = self.by-version."domelementtype"."1.3.0"; + "readable-stream-1.1.13" = self.by-version."readable-stream"."1.1.13"; + "entities-1.0.0" = self.by-version."entities"."1.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "htmlparser2" ]; + }; + by-spec."http-signature"."~1.1.0" = + self.by-version."http-signature"."1.1.0"; + by-version."http-signature"."1.1.0" = lib.makeOverridable self.buildNodePackage { + name = "http-signature-1.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz"; + name = "http-signature-1.1.0.tgz"; + sha1 = "5d2d7e9b6ef49980ad5b128d8e4ef09a31c90d95"; + }) + ]; + buildInputs = + (self.nativeDeps."http-signature" or []); + deps = { + "assert-plus-0.1.5" = self.by-version."assert-plus"."0.1.5"; + "jsprim-1.2.2" = self.by-version."jsprim"."1.2.2"; + "sshpk-1.7.3" = self.by-version."sshpk"."1.7.3"; + }; + peerDependencies = [ + ]; + passthru.names = [ "http-signature" ]; + }; + by-spec."iconv-lite"."~0.2.11" = + self.by-version."iconv-lite"."0.2.11"; + by-version."iconv-lite"."0.2.11" = lib.makeOverridable self.buildNodePackage { + name = "iconv-lite-0.2.11"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz"; + name = "iconv-lite-0.2.11.tgz"; + sha1 = "1ce60a3a57864a292d1321ff4609ca4bb965adc8"; + }) + ]; + buildInputs = + (self.nativeDeps."iconv-lite" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "iconv-lite" ]; + }; + by-spec."image-size"."~0.3.5" = + self.by-version."image-size"."0.3.5"; + by-version."image-size"."0.3.5" = lib.makeOverridable self.buildNodePackage { + name = "image-size-0.3.5"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/image-size/-/image-size-0.3.5.tgz"; + name = "image-size-0.3.5.tgz"; + sha1 = "83240eab2fb5b00b04aab8c74b0471e9cba7ad8c"; + }) + ]; + buildInputs = + (self.nativeDeps."image-size" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "image-size" ]; + }; + by-spec."inherits"."1" = + self.by-version."inherits"."1.0.2"; + by-version."inherits"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "inherits-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz"; + name = "inherits-1.0.2.tgz"; + sha1 = "ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"; + }) + ]; + buildInputs = + (self.nativeDeps."inherits" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "inherits" ]; + }; + by-spec."inherits"."2" = + self.by-version."inherits"."2.0.1"; + by-version."inherits"."2.0.1" = lib.makeOverridable self.buildNodePackage { + name = "inherits-2.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"; + name = "inherits-2.0.1.tgz"; + sha1 = "b17d08d326b4423e568eff719f91b0b1cbdf69f1"; + }) + ]; + buildInputs = + (self.nativeDeps."inherits" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "inherits" ]; + }; + by-spec."inherits"."~2.0.1" = + self.by-version."inherits"."2.0.1"; + by-spec."is-my-json-valid"."^2.12.4" = + self.by-version."is-my-json-valid"."2.12.4"; + by-version."is-my-json-valid"."2.12.4" = lib.makeOverridable self.buildNodePackage { + name = "is-my-json-valid-2.12.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.4.tgz"; + name = "is-my-json-valid-2.12.4.tgz"; + sha1 = "d4ed2bc1d7f88daf8d0f763b3e3e39a69bd37880"; + }) + ]; + buildInputs = + (self.nativeDeps."is-my-json-valid" or []); + deps = { + "generate-function-2.0.0" = self.by-version."generate-function"."2.0.0"; + "generate-object-property-1.2.0" = self.by-version."generate-object-property"."1.2.0"; + "jsonpointer-2.0.0" = self.by-version."jsonpointer"."2.0.0"; + "xtend-4.0.1" = self.by-version."xtend"."4.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "is-my-json-valid" ]; + }; + by-spec."is-property"."^1.0.0" = + self.by-version."is-property"."1.0.2"; + by-version."is-property"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "is-property-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"; + name = "is-property-1.0.2.tgz"; + sha1 = "57fe1c4e48474edd65b09911f26b1cd4095dda84"; + }) + ]; + buildInputs = + (self.nativeDeps."is-property" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "is-property" ]; + }; + by-spec."is-typedarray"."~1.0.0" = + self.by-version."is-typedarray"."1.0.0"; + by-version."is-typedarray"."1.0.0" = lib.makeOverridable self.buildNodePackage { + name = "is-typedarray-1.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"; + name = "is-typedarray-1.0.0.tgz"; + sha1 = "e479c80858df0c1b11ddda6940f96011fcda4a9a"; + }) + ]; + buildInputs = + (self.nativeDeps."is-typedarray" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "is-typedarray" ]; + }; + by-spec."isarray"."0.0.1" = + self.by-version."isarray"."0.0.1"; + by-version."isarray"."0.0.1" = lib.makeOverridable self.buildNodePackage { + name = "isarray-0.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"; + name = "isarray-0.0.1.tgz"; + sha1 = "8a18acfca9a8f4177e09abfc6038939b05d1eedf"; + }) + ]; + buildInputs = + (self.nativeDeps."isarray" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "isarray" ]; + }; + by-spec."isstream"."~0.1.2" = + self.by-version."isstream"."0.1.2"; + by-version."isstream"."0.1.2" = lib.makeOverridable self.buildNodePackage { + name = "isstream-0.1.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"; + name = "isstream-0.1.2.tgz"; + sha1 = "47e63f7af55afa6f92e1500e690eb8b8529c099a"; + }) + ]; + buildInputs = + (self.nativeDeps."isstream" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "isstream" ]; + }; + by-spec."jodid25519".">=1.0.0 <2.0.0" = + self.by-version."jodid25519"."1.0.2"; + by-version."jodid25519"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "jodid25519-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"; + name = "jodid25519-1.0.2.tgz"; + sha1 = "06d4912255093419477d425633606e0e90782967"; + }) + ]; + buildInputs = + (self.nativeDeps."jodid25519" or []); + deps = { + "jsbn-0.1.0" = self.by-version."jsbn"."0.1.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "jodid25519" ]; + }; + by-spec."js-yaml"."~2.0.5" = + self.by-version."js-yaml"."2.0.5"; + by-version."js-yaml"."2.0.5" = lib.makeOverridable self.buildNodePackage { + name = "js-yaml-2.0.5"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz"; + name = "js-yaml-2.0.5.tgz"; + sha1 = "a25ae6509999e97df278c6719da11bd0687743a8"; + }) + ]; + buildInputs = + (self.nativeDeps."js-yaml" or []); + deps = { + "argparse-0.1.16" = self.by-version."argparse"."0.1.16"; + "esprima-1.0.4" = self.by-version."esprima"."1.0.4"; + }; + peerDependencies = [ + ]; + passthru.names = [ "js-yaml" ]; + }; + by-spec."jsbn".">=0.1.0 <0.2.0" = + self.by-version."jsbn"."0.1.0"; + by-version."jsbn"."0.1.0" = lib.makeOverridable self.buildNodePackage { + name = "jsbn-0.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"; + name = "jsbn-0.1.0.tgz"; + sha1 = "650987da0dd74f4ebf5a11377a2aa2d273e97dfd"; + }) + ]; + buildInputs = + (self.nativeDeps."jsbn" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "jsbn" ]; + }; + by-spec."jsbn"."~0.1.0" = + self.by-version."jsbn"."0.1.0"; + by-spec."jshint"."^2.9.1-rc3" = + self.by-version."jshint"."2.9.1"; + by-version."jshint"."2.9.1" = lib.makeOverridable self.buildNodePackage { + name = "jshint-2.9.1"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/jshint/-/jshint-2.9.1.tgz"; + name = "jshint-2.9.1.tgz"; + sha1 = "3136b68f8b6fa37423aacb8ec5e18a1ada7a2638"; + }) + ]; + buildInputs = + (self.nativeDeps."jshint" or []); + deps = { + "cli-0.6.6" = self.by-version."cli"."0.6.6"; + "console-browserify-1.1.0" = self.by-version."console-browserify"."1.1.0"; + "exit-0.1.2" = self.by-version."exit"."0.1.2"; + "htmlparser2-3.8.3" = self.by-version."htmlparser2"."3.8.3"; + "minimatch-2.0.10" = self.by-version."minimatch"."2.0.10"; + "shelljs-0.3.0" = self.by-version."shelljs"."0.3.0"; + "strip-json-comments-1.0.4" = self.by-version."strip-json-comments"."1.0.4"; + "lodash-3.7.0" = self.by-version."lodash"."3.7.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "jshint" ]; + }; + "jshint" = self.by-version."jshint"."2.9.1"; + by-spec."jshint"."~2.9.1" = + self.by-version."jshint"."2.9.1"; + by-spec."json-schema"."0.2.2" = + self.by-version."json-schema"."0.2.2"; + by-version."json-schema"."0.2.2" = lib.makeOverridable self.buildNodePackage { + name = "json-schema-0.2.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz"; + name = "json-schema-0.2.2.tgz"; + sha1 = "50354f19f603917c695f70b85afa77c3b0f23506"; + }) + ]; + buildInputs = + (self.nativeDeps."json-schema" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "json-schema" ]; + }; + by-spec."json-stringify-safe"."~5.0.1" = + self.by-version."json-stringify-safe"."5.0.1"; + by-version."json-stringify-safe"."5.0.1" = lib.makeOverridable self.buildNodePackage { + name = "json-stringify-safe-5.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"; + name = "json-stringify-safe-5.0.1.tgz"; + sha1 = "1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"; + }) + ]; + buildInputs = + (self.nativeDeps."json-stringify-safe" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "json-stringify-safe" ]; + }; + by-spec."jsonpointer"."2.0.0" = + self.by-version."jsonpointer"."2.0.0"; + by-version."jsonpointer"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "jsonpointer-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"; + name = "jsonpointer-2.0.0.tgz"; + sha1 = "3af1dd20fe85463910d469a385e33017d2a030d9"; + }) + ]; + buildInputs = + (self.nativeDeps."jsonpointer" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "jsonpointer" ]; + }; + by-spec."jsprim"."^1.2.2" = + self.by-version."jsprim"."1.2.2"; + by-version."jsprim"."1.2.2" = lib.makeOverridable self.buildNodePackage { + name = "jsprim-1.2.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz"; + name = "jsprim-1.2.2.tgz"; + sha1 = "f20c906ac92abd58e3b79ac8bc70a48832512da1"; + }) + ]; + buildInputs = + (self.nativeDeps."jsprim" or []); + deps = { + "extsprintf-1.0.2" = self.by-version."extsprintf"."1.0.2"; + "json-schema-0.2.2" = self.by-version."json-schema"."0.2.2"; + "verror-1.3.6" = self.by-version."verror"."1.3.6"; + }; + peerDependencies = [ + ]; + passthru.names = [ "jsprim" ]; + }; + by-spec."less"."~2.5.0" = + self.by-version."less"."2.5.3"; + by-version."less"."2.5.3" = lib.makeOverridable self.buildNodePackage { + name = "less-2.5.3"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/less/-/less-2.5.3.tgz"; + name = "less-2.5.3.tgz"; + sha1 = "9ff586e8a703515fc18dc99c7bc498d2f3ad4849"; + }) + ]; + buildInputs = + (self.nativeDeps."less" or []); + deps = { + "errno-0.1.4" = self.by-version."errno"."0.1.4"; + "graceful-fs-3.0.8" = self.by-version."graceful-fs"."3.0.8"; + "image-size-0.3.5" = self.by-version."image-size"."0.3.5"; + "mime-1.3.4" = self.by-version."mime"."1.3.4"; + "mkdirp-0.5.1" = self.by-version."mkdirp"."0.5.1"; + "promise-6.1.0" = self.by-version."promise"."6.1.0"; + "request-2.67.0" = self.by-version."request"."2.67.0"; + "source-map-0.4.4" = self.by-version."source-map"."0.4.4"; + }; + peerDependencies = [ + ]; + passthru.names = [ "less" ]; + }; + by-spec."lodash"."3.7.x" = + self.by-version."lodash"."3.7.0"; + by-version."lodash"."3.7.0" = lib.makeOverridable self.buildNodePackage { + name = "lodash-3.7.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz"; + name = "lodash-3.7.0.tgz"; + sha1 = "3678bd8ab995057c07ade836ed2ef087da811d45"; + }) + ]; + buildInputs = + (self.nativeDeps."lodash" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lodash" ]; + }; + by-spec."lodash"."^3.2.0" = + self.by-version."lodash"."3.10.1"; + by-version."lodash"."3.10.1" = lib.makeOverridable self.buildNodePackage { + name = "lodash-3.10.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"; + name = "lodash-3.10.1.tgz"; + sha1 = "5bf45e8e49ba4189e17d482789dfd15bd140b7b6"; + }) + ]; + buildInputs = + (self.nativeDeps."lodash" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lodash" ]; + }; + by-spec."lodash"."~0.9.2" = + self.by-version."lodash"."0.9.2"; + by-version."lodash"."0.9.2" = lib.makeOverridable self.buildNodePackage { + name = "lodash-0.9.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz"; + name = "lodash-0.9.2.tgz"; + sha1 = "8f3499c5245d346d682e5b0d3b40767e09f1a92c"; + }) + ]; + buildInputs = + (self.nativeDeps."lodash" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lodash" ]; + }; + by-spec."lodash"."~1.0.1" = + self.by-version."lodash"."1.0.2"; + by-version."lodash"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "lodash-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"; + name = "lodash-1.0.2.tgz"; + sha1 = "8f57560c83b59fc270bd3d561b690043430e2551"; + }) + ]; + buildInputs = + (self.nativeDeps."lodash" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lodash" ]; + }; + by-spec."lodash"."~2.4.1" = + self.by-version."lodash"."2.4.2"; + by-version."lodash"."2.4.2" = lib.makeOverridable self.buildNodePackage { + name = "lodash-2.4.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz"; + name = "lodash-2.4.2.tgz"; + sha1 = "fadd834b9683073da179b3eae6d9c0d15053f73e"; + }) + ]; + buildInputs = + (self.nativeDeps."lodash" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lodash" ]; + }; + by-spec."lru-cache"."2" = + self.by-version."lru-cache"."2.7.3"; + by-version."lru-cache"."2.7.3" = lib.makeOverridable self.buildNodePackage { + name = "lru-cache-2.7.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"; + name = "lru-cache-2.7.3.tgz"; + sha1 = "6d4524e8b955f95d4f5b58851ce21dd72fb4e952"; + }) + ]; + buildInputs = + (self.nativeDeps."lru-cache" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "lru-cache" ]; + }; + by-spec."mime"."^1.2.11" = + self.by-version."mime"."1.3.4"; + by-version."mime"."1.3.4" = lib.makeOverridable self.buildNodePackage { + name = "mime-1.3.4"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/mime/-/mime-1.3.4.tgz"; + name = "mime-1.3.4.tgz"; + sha1 = "115f9e3b6b3daf2959983cb38f149a2d40eb5d53"; + }) + ]; + buildInputs = + (self.nativeDeps."mime" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "mime" ]; + }; + by-spec."mime-db"."~1.21.0" = + self.by-version."mime-db"."1.21.0"; + by-version."mime-db"."1.21.0" = lib.makeOverridable self.buildNodePackage { + name = "mime-db-1.21.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/mime-db/-/mime-db-1.21.0.tgz"; + name = "mime-db-1.21.0.tgz"; + sha1 = "9b5239e3353cf6eb015a00d890261027c36d4bac"; + }) + ]; + buildInputs = + (self.nativeDeps."mime-db" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "mime-db" ]; + }; + by-spec."mime-types"."^2.1.3" = + self.by-version."mime-types"."2.1.9"; + by-version."mime-types"."2.1.9" = lib.makeOverridable self.buildNodePackage { + name = "mime-types-2.1.9"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/mime-types/-/mime-types-2.1.9.tgz"; + name = "mime-types-2.1.9.tgz"; + sha1 = "dfb396764b5fdf75be34b1f4104bc3687fb635f8"; + }) + ]; + buildInputs = + (self.nativeDeps."mime-types" or []); + deps = { + "mime-db-1.21.0" = self.by-version."mime-db"."1.21.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "mime-types" ]; + }; + by-spec."mime-types"."~2.1.7" = + self.by-version."mime-types"."2.1.9"; + by-spec."minimatch"."0.3" = + self.by-version."minimatch"."0.3.0"; + by-version."minimatch"."0.3.0" = lib.makeOverridable self.buildNodePackage { + name = "minimatch-0.3.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz"; + name = "minimatch-0.3.0.tgz"; + sha1 = "275d8edaac4f1bb3326472089e7949c8394699dd"; + }) + ]; + buildInputs = + (self.nativeDeps."minimatch" or []); + deps = { + "lru-cache-2.7.3" = self.by-version."lru-cache"."2.7.3"; + "sigmund-1.0.1" = self.by-version."sigmund"."1.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "minimatch" ]; + }; + by-spec."minimatch"."2.0.x" = + self.by-version."minimatch"."2.0.10"; + by-version."minimatch"."2.0.10" = lib.makeOverridable self.buildNodePackage { + name = "minimatch-2.0.10"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz"; + name = "minimatch-2.0.10.tgz"; + sha1 = "8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"; + }) + ]; + buildInputs = + (self.nativeDeps."minimatch" or []); + deps = { + "brace-expansion-1.1.2" = self.by-version."brace-expansion"."1.1.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "minimatch" ]; + }; + by-spec."minimatch"."~0.2.11" = + self.by-version."minimatch"."0.2.14"; + by-version."minimatch"."0.2.14" = lib.makeOverridable self.buildNodePackage { + name = "minimatch-0.2.14"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz"; + name = "minimatch-0.2.14.tgz"; + sha1 = "c74e780574f63c6f9a090e90efbe6ef53a6a756a"; + }) + ]; + buildInputs = + (self.nativeDeps."minimatch" or []); + deps = { + "lru-cache-2.7.3" = self.by-version."lru-cache"."2.7.3"; + "sigmund-1.0.1" = self.by-version."sigmund"."1.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "minimatch" ]; + }; + by-spec."minimatch"."~0.2.12" = + self.by-version."minimatch"."0.2.14"; + by-spec."minimist"."0.0.8" = + self.by-version."minimist"."0.0.8"; + by-version."minimist"."0.0.8" = lib.makeOverridable self.buildNodePackage { + name = "minimist-0.0.8"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"; + name = "minimist-0.0.8.tgz"; + sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d"; + }) + ]; + buildInputs = + (self.nativeDeps."minimist" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "minimist" ]; + }; + by-spec."mkdirp"."^0.5.0" = + self.by-version."mkdirp"."0.5.1"; + by-version."mkdirp"."0.5.1" = lib.makeOverridable self.buildNodePackage { + name = "mkdirp-0.5.1"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"; + name = "mkdirp-0.5.1.tgz"; + sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903"; + }) + ]; + buildInputs = + (self.nativeDeps."mkdirp" or []); + deps = { + "minimist-0.0.8" = self.by-version."minimist"."0.0.8"; + }; + peerDependencies = [ + ]; + passthru.names = [ "mkdirp" ]; + }; + by-spec."node-uuid"."~1.4.7" = + self.by-version."node-uuid"."1.4.7"; + by-version."node-uuid"."1.4.7" = lib.makeOverridable self.buildNodePackage { + name = "node-uuid-1.4.7"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"; + name = "node-uuid-1.4.7.tgz"; + sha1 = "6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f"; + }) + ]; + buildInputs = + (self.nativeDeps."node-uuid" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "node-uuid" ]; + }; + by-spec."nopt"."~1.0.10" = + self.by-version."nopt"."1.0.10"; + by-version."nopt"."1.0.10" = lib.makeOverridable self.buildNodePackage { + name = "nopt-1.0.10"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"; + name = "nopt-1.0.10.tgz"; + sha1 = "6ddd21bd2a31417b92727dd585f8a6f37608ebee"; + }) + ]; + buildInputs = + (self.nativeDeps."nopt" or []); + deps = { + "abbrev-1.0.7" = self.by-version."abbrev"."1.0.7"; + }; + peerDependencies = [ + ]; + passthru.names = [ "nopt" ]; + }; + by-spec."nopt"."~2.0.0" = + self.by-version."nopt"."2.0.0"; + by-version."nopt"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "nopt-2.0.0"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/nopt/-/nopt-2.0.0.tgz"; + name = "nopt-2.0.0.tgz"; + sha1 = "ca7416f20a5e3f9c3b86180f96295fa3d0b52e0d"; + }) + ]; + buildInputs = + (self.nativeDeps."nopt" or []); + deps = { + "abbrev-1.0.7" = self.by-version."abbrev"."1.0.7"; + }; + peerDependencies = [ + ]; + passthru.names = [ "nopt" ]; + }; + by-spec."noptify"."~0.0.3" = + self.by-version."noptify"."0.0.3"; + by-version."noptify"."0.0.3" = lib.makeOverridable self.buildNodePackage { + name = "noptify-0.0.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/noptify/-/noptify-0.0.3.tgz"; + name = "noptify-0.0.3.tgz"; + sha1 = "58f654a73d9753df0c51d9686dc92104a67f4bbb"; + }) + ]; + buildInputs = + (self.nativeDeps."noptify" or []); + deps = { + "nopt-2.0.0" = self.by-version."nopt"."2.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "noptify" ]; + }; + by-spec."oauth-sign"."~0.8.0" = + self.by-version."oauth-sign"."0.8.0"; + by-version."oauth-sign"."0.8.0" = lib.makeOverridable self.buildNodePackage { + name = "oauth-sign-0.8.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"; + name = "oauth-sign-0.8.0.tgz"; + sha1 = "938fdc875765ba527137d8aec9d178e24debc553"; + }) + ]; + buildInputs = + (self.nativeDeps."oauth-sign" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "oauth-sign" ]; + }; + by-spec."pinkie"."^2.0.0" = + self.by-version."pinkie"."2.0.1"; + by-version."pinkie"."2.0.1" = lib.makeOverridable self.buildNodePackage { + name = "pinkie-2.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz"; + name = "pinkie-2.0.1.tgz"; + sha1 = "4236c86fc29f261c2045bbe81f78cbb2a5e8306c"; + }) + ]; + buildInputs = + (self.nativeDeps."pinkie" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "pinkie" ]; + }; + by-spec."pinkie-promise"."^2.0.0" = + self.by-version."pinkie-promise"."2.0.0"; + by-version."pinkie-promise"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "pinkie-promise-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz"; + name = "pinkie-promise-2.0.0.tgz"; + sha1 = "4c83538de1f6e660c29e0a13446844f7a7e88259"; + }) + ]; + buildInputs = + (self.nativeDeps."pinkie-promise" or []); + deps = { + "pinkie-2.0.1" = self.by-version."pinkie"."2.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "pinkie-promise" ]; + }; + by-spec."process-nextick-args"."~1.0.6" = + self.by-version."process-nextick-args"."1.0.6"; + by-version."process-nextick-args"."1.0.6" = lib.makeOverridable self.buildNodePackage { + name = "process-nextick-args-1.0.6"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz"; + name = "process-nextick-args-1.0.6.tgz"; + sha1 = "0f96b001cea90b12592ce566edb97ec11e69bd05"; + }) + ]; + buildInputs = + (self.nativeDeps."process-nextick-args" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "process-nextick-args" ]; + }; + by-spec."promise"."^6.0.1" = + self.by-version."promise"."6.1.0"; + by-version."promise"."6.1.0" = lib.makeOverridable self.buildNodePackage { + name = "promise-6.1.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/promise/-/promise-6.1.0.tgz"; + name = "promise-6.1.0.tgz"; + sha1 = "2ce729f6b94b45c26891ad0602c5c90e04c6eef6"; + }) + ]; + buildInputs = + (self.nativeDeps."promise" or []); + deps = { + "asap-1.0.0" = self.by-version."asap"."1.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "promise" ]; + }; + by-spec."prr"."~0.0.0" = + self.by-version."prr"."0.0.0"; + by-version."prr"."0.0.0" = lib.makeOverridable self.buildNodePackage { + name = "prr-0.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/prr/-/prr-0.0.0.tgz"; + name = "prr-0.0.0.tgz"; + sha1 = "1a84b85908325501411853d0081ee3fa86e2926a"; + }) + ]; + buildInputs = + (self.nativeDeps."prr" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "prr" ]; + }; + by-spec."qs"."~0.5.2" = + self.by-version."qs"."0.5.6"; + by-version."qs"."0.5.6" = lib.makeOverridable self.buildNodePackage { + name = "qs-0.5.6"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/qs/-/qs-0.5.6.tgz"; + name = "qs-0.5.6.tgz"; + sha1 = "31b1ad058567651c526921506b9a8793911a0384"; + }) + ]; + buildInputs = + (self.nativeDeps."qs" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "qs" ]; + }; + by-spec."qs"."~5.2.0" = + self.by-version."qs"."5.2.0"; + by-version."qs"."5.2.0" = lib.makeOverridable self.buildNodePackage { + name = "qs-5.2.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/qs/-/qs-5.2.0.tgz"; + name = "qs-5.2.0.tgz"; + sha1 = "a9f31142af468cb72b25b30136ba2456834916be"; + }) + ]; + buildInputs = + (self.nativeDeps."qs" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "qs" ]; + }; + by-spec."readable-stream"."1.1" = + self.by-version."readable-stream"."1.1.13"; + by-version."readable-stream"."1.1.13" = lib.makeOverridable self.buildNodePackage { + name = "readable-stream-1.1.13"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"; + name = "readable-stream-1.1.13.tgz"; + sha1 = "f6eef764f514c89e2b9e23146a75ba106756d23e"; + }) + ]; + buildInputs = + (self.nativeDeps."readable-stream" or []); + deps = { + "core-util-is-1.0.2" = self.by-version."core-util-is"."1.0.2"; + "isarray-0.0.1" = self.by-version."isarray"."0.0.1"; + "string_decoder-0.10.31" = self.by-version."string_decoder"."0.10.31"; + "inherits-2.0.1" = self.by-version."inherits"."2.0.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "readable-stream" ]; + }; + by-spec."readable-stream"."~2.0.5" = + self.by-version."readable-stream"."2.0.5"; + by-version."readable-stream"."2.0.5" = lib.makeOverridable self.buildNodePackage { + name = "readable-stream-2.0.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.5.tgz"; + name = "readable-stream-2.0.5.tgz"; + sha1 = "a2426f8dcd4551c77a33f96edf2886a23c829669"; + }) + ]; + buildInputs = + (self.nativeDeps."readable-stream" or []); + deps = { + "core-util-is-1.0.2" = self.by-version."core-util-is"."1.0.2"; + "inherits-2.0.1" = self.by-version."inherits"."2.0.1"; + "isarray-0.0.1" = self.by-version."isarray"."0.0.1"; + "process-nextick-args-1.0.6" = self.by-version."process-nextick-args"."1.0.6"; + "string_decoder-0.10.31" = self.by-version."string_decoder"."0.10.31"; + "util-deprecate-1.0.2" = self.by-version."util-deprecate"."1.0.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "readable-stream" ]; + }; + by-spec."request"."^2.51.0" = + self.by-version."request"."2.67.0"; + by-version."request"."2.67.0" = lib.makeOverridable self.buildNodePackage { + name = "request-2.67.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/request/-/request-2.67.0.tgz"; + name = "request-2.67.0.tgz"; + sha1 = "8af74780e2bf11ea0ae9aa965c11f11afd272742"; + }) + ]; + buildInputs = + (self.nativeDeps."request" or []); + deps = { + "bl-1.0.1" = self.by-version."bl"."1.0.1"; + "caseless-0.11.0" = self.by-version."caseless"."0.11.0"; + "extend-3.0.0" = self.by-version."extend"."3.0.0"; + "forever-agent-0.6.1" = self.by-version."forever-agent"."0.6.1"; + "form-data-1.0.0-rc3" = self.by-version."form-data"."1.0.0-rc3"; + "json-stringify-safe-5.0.1" = self.by-version."json-stringify-safe"."5.0.1"; + "mime-types-2.1.9" = self.by-version."mime-types"."2.1.9"; + "node-uuid-1.4.7" = self.by-version."node-uuid"."1.4.7"; + "qs-5.2.0" = self.by-version."qs"."5.2.0"; + "tunnel-agent-0.4.2" = self.by-version."tunnel-agent"."0.4.2"; + "tough-cookie-2.2.1" = self.by-version."tough-cookie"."2.2.1"; + "http-signature-1.1.0" = self.by-version."http-signature"."1.1.0"; + "oauth-sign-0.8.0" = self.by-version."oauth-sign"."0.8.0"; + "hawk-3.1.3" = self.by-version."hawk"."3.1.3"; + "aws-sign2-0.6.0" = self.by-version."aws-sign2"."0.6.0"; + "stringstream-0.0.5" = self.by-version."stringstream"."0.0.5"; + "combined-stream-1.0.5" = self.by-version."combined-stream"."1.0.5"; + "isstream-0.1.2" = self.by-version."isstream"."0.1.2"; + "is-typedarray-1.0.0" = self.by-version."is-typedarray"."1.0.0"; + "har-validator-2.0.6" = self.by-version."har-validator"."2.0.6"; + }; + peerDependencies = [ + ]; + passthru.names = [ "request" ]; + }; + by-spec."rimraf"."~2.2.8" = + self.by-version."rimraf"."2.2.8"; + by-version."rimraf"."2.2.8" = lib.makeOverridable self.buildNodePackage { + name = "rimraf-2.2.8"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"; + name = "rimraf-2.2.8.tgz"; + sha1 = "e439be2aaee327321952730f99a8929e4fc50582"; + }) + ]; + buildInputs = + (self.nativeDeps."rimraf" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "rimraf" ]; + }; + by-spec."shelljs"."0.3.x" = + self.by-version."shelljs"."0.3.0"; + by-version."shelljs"."0.3.0" = lib.makeOverridable self.buildNodePackage { + name = "shelljs-0.3.0"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz"; + name = "shelljs-0.3.0.tgz"; + sha1 = "3596e6307a781544f591f37da618360f31db57b1"; + }) + ]; + buildInputs = + (self.nativeDeps."shelljs" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "shelljs" ]; + }; + by-spec."sigmund"."~1.0.0" = + self.by-version."sigmund"."1.0.1"; + by-version."sigmund"."1.0.1" = lib.makeOverridable self.buildNodePackage { + name = "sigmund-1.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"; + name = "sigmund-1.0.1.tgz"; + sha1 = "3ff21f198cad2175f9f3b781853fd94d0d19b590"; + }) + ]; + buildInputs = + (self.nativeDeps."sigmund" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "sigmund" ]; + }; + by-spec."sntp"."1.x.x" = + self.by-version."sntp"."1.0.9"; + by-version."sntp"."1.0.9" = lib.makeOverridable self.buildNodePackage { + name = "sntp-1.0.9"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"; + name = "sntp-1.0.9.tgz"; + sha1 = "6541184cc90aeea6c6e7b35e2659082443c66198"; + }) + ]; + buildInputs = + (self.nativeDeps."sntp" or []); + deps = { + "hoek-2.16.3" = self.by-version."hoek"."2.16.3"; + }; + peerDependencies = [ + ]; + passthru.names = [ "sntp" ]; + }; + by-spec."source-map"."^0.3.0" = + self.by-version."source-map"."0.3.0"; + by-version."source-map"."0.3.0" = lib.makeOverridable self.buildNodePackage { + name = "source-map-0.3.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz"; + name = "source-map-0.3.0.tgz"; + sha1 = "8586fb9a5a005e5b501e21cd18b6f21b457ad1f9"; + }) + ]; + buildInputs = + (self.nativeDeps."source-map" or []); + deps = { + "amdefine-1.0.0" = self.by-version."amdefine"."1.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "source-map" ]; + }; + by-spec."source-map"."^0.4.2" = + self.by-version."source-map"."0.4.4"; + by-version."source-map"."0.4.4" = lib.makeOverridable self.buildNodePackage { + name = "source-map-0.4.4"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"; + name = "source-map-0.4.4.tgz"; + sha1 = "eba4f5da9c0dc999de68032d8b4f76173652036b"; + }) + ]; + buildInputs = + (self.nativeDeps."source-map" or []); + deps = { + "amdefine-1.0.0" = self.by-version."amdefine"."1.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "source-map" ]; + }; + by-spec."sshpk"."^1.7.0" = + self.by-version."sshpk"."1.7.3"; + by-version."sshpk"."1.7.3" = lib.makeOverridable self.buildNodePackage { + name = "sshpk-1.7.3"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/sshpk/-/sshpk-1.7.3.tgz"; + name = "sshpk-1.7.3.tgz"; + sha1 = "caa8ef95e30765d856698b7025f9f211ab65962f"; + }) + ]; + buildInputs = + (self.nativeDeps."sshpk" or []); + deps = { + "asn1-0.2.3" = self.by-version."asn1"."0.2.3"; + "assert-plus-0.2.0" = self.by-version."assert-plus"."0.2.0"; + "dashdash-1.12.2" = self.by-version."dashdash"."1.12.2"; + "jsbn-0.1.0" = self.by-version."jsbn"."0.1.0"; + "tweetnacl-0.13.3" = self.by-version."tweetnacl"."0.13.3"; + "jodid25519-1.0.2" = self.by-version."jodid25519"."1.0.2"; + "ecc-jsbn-0.1.1" = self.by-version."ecc-jsbn"."0.1.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "sshpk" ]; + }; + by-spec."string_decoder"."~0.10.x" = + self.by-version."string_decoder"."0.10.31"; + by-version."string_decoder"."0.10.31" = lib.makeOverridable self.buildNodePackage { + name = "string_decoder-0.10.31"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"; + name = "string_decoder-0.10.31.tgz"; + sha1 = "62e203bc41766c6c28c9fc84301dab1c5310fa94"; + }) + ]; + buildInputs = + (self.nativeDeps."string_decoder" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "string_decoder" ]; + }; + by-spec."stringstream"."~0.0.4" = + self.by-version."stringstream"."0.0.5"; + by-version."stringstream"."0.0.5" = lib.makeOverridable self.buildNodePackage { + name = "stringstream-0.0.5"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"; + name = "stringstream-0.0.5.tgz"; + sha1 = "4e484cd4de5a0bbbee18e46307710a8a81621878"; + }) + ]; + buildInputs = + (self.nativeDeps."stringstream" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "stringstream" ]; + }; + by-spec."strip-ansi"."^0.3.0" = + self.by-version."strip-ansi"."0.3.0"; + by-version."strip-ansi"."0.3.0" = lib.makeOverridable self.buildNodePackage { + name = "strip-ansi-0.3.0"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz"; + name = "strip-ansi-0.3.0.tgz"; + sha1 = "25f48ea22ca79187f3174a4db8759347bb126220"; + }) + ]; + buildInputs = + (self.nativeDeps."strip-ansi" or []); + deps = { + "ansi-regex-0.2.1" = self.by-version."ansi-regex"."0.2.1"; + }; + peerDependencies = [ + ]; + passthru.names = [ "strip-ansi" ]; + }; + by-spec."strip-ansi"."^3.0.0" = + self.by-version."strip-ansi"."3.0.0"; + by-version."strip-ansi"."3.0.0" = lib.makeOverridable self.buildNodePackage { + name = "strip-ansi-3.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"; + name = "strip-ansi-3.0.0.tgz"; + sha1 = "7510b665567ca914ccb5d7e072763ac968be3724"; + }) + ]; + buildInputs = + (self.nativeDeps."strip-ansi" or []); + deps = { + "ansi-regex-2.0.0" = self.by-version."ansi-regex"."2.0.0"; + }; + peerDependencies = [ + ]; + passthru.names = [ "strip-ansi" ]; + }; + by-spec."strip-json-comments"."1.0.x" = + self.by-version."strip-json-comments"."1.0.4"; + by-version."strip-json-comments"."1.0.4" = lib.makeOverridable self.buildNodePackage { + name = "strip-json-comments-1.0.4"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz"; + name = "strip-json-comments-1.0.4.tgz"; + sha1 = "1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"; + }) + ]; + buildInputs = + (self.nativeDeps."strip-json-comments" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "strip-json-comments" ]; + }; + by-spec."supports-color"."^0.2.0" = + self.by-version."supports-color"."0.2.0"; + by-version."supports-color"."0.2.0" = lib.makeOverridable self.buildNodePackage { + name = "supports-color-0.2.0"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"; + name = "supports-color-0.2.0.tgz"; + sha1 = "d92de2694eb3f67323973d7ae3d8b55b4c22190a"; + }) + ]; + buildInputs = + (self.nativeDeps."supports-color" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "supports-color" ]; + }; + by-spec."supports-color"."^2.0.0" = + self.by-version."supports-color"."2.0.0"; + by-version."supports-color"."2.0.0" = lib.makeOverridable self.buildNodePackage { + name = "supports-color-2.0.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"; + name = "supports-color-2.0.0.tgz"; + sha1 = "535d045ce6b6363fa40117084629995e9df324c7"; + }) + ]; + buildInputs = + (self.nativeDeps."supports-color" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "supports-color" ]; + }; + by-spec."tiny-lr-fork"."0.0.5" = + self.by-version."tiny-lr-fork"."0.0.5"; + by-version."tiny-lr-fork"."0.0.5" = lib.makeOverridable self.buildNodePackage { + name = "tiny-lr-fork-0.0.5"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz"; + name = "tiny-lr-fork-0.0.5.tgz"; + sha1 = "1e99e1e2a8469b736ab97d97eefa98c71f76ed0a"; + }) + ]; + buildInputs = + (self.nativeDeps."tiny-lr-fork" or []); + deps = { + "qs-0.5.6" = self.by-version."qs"."0.5.6"; + "faye-websocket-0.4.4" = self.by-version."faye-websocket"."0.4.4"; + "noptify-0.0.3" = self.by-version."noptify"."0.0.3"; + "debug-0.7.4" = self.by-version."debug"."0.7.4"; + }; + peerDependencies = [ + ]; + passthru.names = [ "tiny-lr-fork" ]; + }; + by-spec."tough-cookie"."~2.2.0" = + self.by-version."tough-cookie"."2.2.1"; + by-version."tough-cookie"."2.2.1" = lib.makeOverridable self.buildNodePackage { + name = "tough-cookie-2.2.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz"; + name = "tough-cookie-2.2.1.tgz"; + sha1 = "3b0516b799e70e8164436a1446e7e5877fda118e"; + }) + ]; + buildInputs = + (self.nativeDeps."tough-cookie" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "tough-cookie" ]; + }; + by-spec."tunnel-agent"."~0.4.1" = + self.by-version."tunnel-agent"."0.4.2"; + by-version."tunnel-agent"."0.4.2" = lib.makeOverridable self.buildNodePackage { + name = "tunnel-agent-0.4.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"; + name = "tunnel-agent-0.4.2.tgz"; + sha1 = "1104e3f36ac87125c287270067d582d18133bfee"; + }) + ]; + buildInputs = + (self.nativeDeps."tunnel-agent" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "tunnel-agent" ]; + }; + by-spec."tweetnacl".">=0.13.0 <1.0.0" = + self.by-version."tweetnacl"."0.13.3"; + by-version."tweetnacl"."0.13.3" = lib.makeOverridable self.buildNodePackage { + name = "tweetnacl-0.13.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz"; + name = "tweetnacl-0.13.3.tgz"; + sha1 = "d628b56f3bcc3d5ae74ba9d4c1a704def5ab4b56"; + }) + ]; + buildInputs = + (self.nativeDeps."tweetnacl" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "tweetnacl" ]; + }; + by-spec."underscore"."~1.7.0" = + self.by-version."underscore"."1.7.0"; + by-version."underscore"."1.7.0" = lib.makeOverridable self.buildNodePackage { + name = "underscore-1.7.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz"; + name = "underscore-1.7.0.tgz"; + sha1 = "6bbaf0877500d36be34ecaa584e0db9fef035209"; + }) + ]; + buildInputs = + (self.nativeDeps."underscore" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "underscore" ]; + }; + by-spec."underscore.string"."~2.2.1" = + self.by-version."underscore.string"."2.2.1"; + by-version."underscore.string"."2.2.1" = lib.makeOverridable self.buildNodePackage { + name = "underscore.string-2.2.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz"; + name = "underscore.string-2.2.1.tgz"; + sha1 = "d7c0fa2af5d5a1a67f4253daee98132e733f0f19"; + }) + ]; + buildInputs = + (self.nativeDeps."underscore.string" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "underscore.string" ]; + }; + by-spec."underscore.string"."~2.3.3" = + self.by-version."underscore.string"."2.3.3"; + by-version."underscore.string"."2.3.3" = lib.makeOverridable self.buildNodePackage { + name = "underscore.string-2.3.3"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz"; + name = "underscore.string-2.3.3.tgz"; + sha1 = "71c08bf6b428b1133f37e78fa3a21c82f7329b0d"; + }) + ]; + buildInputs = + (self.nativeDeps."underscore.string" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "underscore.string" ]; + }; + by-spec."underscore.string"."~2.4.0" = + self.by-version."underscore.string"."2.4.0"; + by-version."underscore.string"."2.4.0" = lib.makeOverridable self.buildNodePackage { + name = "underscore.string-2.4.0"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz"; + name = "underscore.string-2.4.0.tgz"; + sha1 = "8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"; + }) + ]; + buildInputs = + (self.nativeDeps."underscore.string" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "underscore.string" ]; + }; + by-spec."util-deprecate"."~1.0.1" = + self.by-version."util-deprecate"."1.0.2"; + by-version."util-deprecate"."1.0.2" = lib.makeOverridable self.buildNodePackage { + name = "util-deprecate-1.0.2"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"; + name = "util-deprecate-1.0.2.tgz"; + sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf"; + }) + ]; + buildInputs = + (self.nativeDeps."util-deprecate" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "util-deprecate" ]; + }; + by-spec."verror"."1.3.6" = + self.by-version."verror"."1.3.6"; + by-version."verror"."1.3.6" = lib.makeOverridable self.buildNodePackage { + name = "verror-1.3.6"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/verror/-/verror-1.3.6.tgz"; + name = "verror-1.3.6.tgz"; + sha1 = "cff5df12946d297d2baaefaa2689e25be01c005c"; + }) + ]; + buildInputs = + (self.nativeDeps."verror" or []); + deps = { + "extsprintf-1.0.2" = self.by-version."extsprintf"."1.0.2"; + }; + peerDependencies = [ + ]; + passthru.names = [ "verror" ]; + }; + by-spec."which"."~1.0.5" = + self.by-version."which"."1.0.9"; + by-version."which"."1.0.9" = lib.makeOverridable self.buildNodePackage { + name = "which-1.0.9"; + bin = true; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/which/-/which-1.0.9.tgz"; + name = "which-1.0.9.tgz"; + sha1 = "460c1da0f810103d0321a9b633af9e575e64486f"; + }) + ]; + buildInputs = + (self.nativeDeps."which" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "which" ]; + }; + by-spec."xtend"."^4.0.0" = + self.by-version."xtend"."4.0.1"; + by-version."xtend"."4.0.1" = lib.makeOverridable self.buildNodePackage { + name = "xtend-4.0.1"; + bin = false; + src = [ + (fetchurl { + url = "http://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"; + name = "xtend-4.0.1.tgz"; + sha1 = "a5c6d532be656e23db820efb943a1f04998d63af"; + }) + ]; + buildInputs = + (self.nativeDeps."xtend" or []); + deps = { + }; + peerDependencies = [ + ]; + passthru.names = [ "xtend" ]; + }; +} diff --git a/pkgs/patch-kombu-msgpack.diff b/pkgs/patch-kombu-msgpack.diff new file mode 100644 --- /dev/null +++ b/pkgs/patch-kombu-msgpack.diff @@ -0,0 +1,12 @@ +diff -rup kombu-1.5.1-orig/kombu/serialization.py kombu-1.5.1/kombu/serialization.py +--- kombu-1.5.1-orig/kombu/serialization.py 2016-03-09 15:11:34.000000000 +0100 ++++ kombu-1.5.1/kombu/serialization.py 2016-03-09 15:19:20.000000000 +0100 +@@ -318,7 +318,7 @@ def register_msgpack(): + """See http://msgpack.sourceforge.net/""" + try: + import msgpack +- registry.register('msgpack', msgpack.packs, msgpack.unpacks, ++ registry.register('msgpack', msgpack.packb, msgpack.unpackb, + content_type='application/x-msgpack', + content_encoding='binary') + except ImportError: diff --git a/pkgs/patch-kombu-py-2-7-11.diff b/pkgs/patch-kombu-py-2-7-11.diff new file mode 100644 --- /dev/null +++ b/pkgs/patch-kombu-py-2-7-11.diff @@ -0,0 +1,15 @@ +diff -rup kombu-1.5.1-orig/kombu/utils/__init__.py kombu-1.5.1/kombu/utils/__init__.py +--- kombu-1.5.1-orig/kombu/utils/__init__.py 2016-03-09 15:11:34.000000000 +0100 ++++ kombu-1.5.1/kombu/utils/__init__.py 2016-03-09 15:15:52.000000000 +0100 +@@ -11,7 +11,10 @@ Internal utilities. + import sys + + from time import sleep +-from uuid import UUID, uuid4 as _uuid4, _uuid_generate_random ++from uuid import UUID, uuid4 as _uuid4 ++ ++# Fix for Python 2.7.11 ++_uuid_generate_random = None + + from kombu.utils.encoding import safe_repr as _safe_repr + diff --git a/pkgs/patch-rhodecode-tools-setup.diff b/pkgs/patch-rhodecode-tools-setup.diff new file mode 100644 --- /dev/null +++ b/pkgs/patch-rhodecode-tools-setup.diff @@ -0,0 +1,13 @@ +diff --git a/requirements.txt b/requirements.txt +--- a/requirements.txt ++++ b/requirements.txt +@@ -1,8 +1,8 @@ + click==5.1 + future==0.14.3 + six==1.9.0 + mako==1.0.1 + markupsafe==0.23 +-requests==2.5.1 ++requests + whoosh==2.7.0 + pyelasticsearch==1.4 diff --git a/pkgs/python-packages-overrides.nix b/pkgs/python-packages-overrides.nix new file mode 100644 --- /dev/null +++ b/pkgs/python-packages-overrides.nix @@ -0,0 +1,151 @@ +# Overrides for the generated python-packages.nix +# +# This function is intended to be used as an extension to the generated file +# python-packages.nix. The main objective is to add needed dependencies of C +# libraries and tweak the build instructions where needed. + +{ pkgs, basePythonPackages }: + +let + sed = "sed -i"; +in + +self: super: { + + gnureadline = super.gnureadline.override (attrs: { + buildInputs = attrs.buildInputs ++ [ + pkgs.ncurses + ]; + patchPhase = '' + substituteInPlace setup.py --replace "/bin/bash" "${pkgs.bash}/bin/bash" + ''; + }); + + kombu = super.kombu.override (attrs: { + # The current version of kombu needs some patching to work with the + # other libs. Should be removed once we update celery and kombu. + patches = [ + ./patch-kombu-py-2-7-11.diff + ./patch-kombu-msgpack.diff + ]; + }); + + lxml = super.lxml.override (attrs: { + buildInputs = with self; [ + pkgs.libxml2 + pkgs.libxslt + ]; + }); + + MySQL-python = super.MySQL-python.override (attrs: { + buildInputs = attrs.buildInputs ++ [ + pkgs.openssl + ]; + propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ + pkgs.mysql.lib + pkgs.zlib + ]; + }); + + psutil = super.psutil.override (attrs: { + buildInputs = attrs.buildInputs ++ + pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.darwin.IOKit; + }); + + psycopg2 = super.psycopg2.override (attrs: { + buildInputs = attrs.buildInputs ++ + pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.openssl; + propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ + pkgs.postgresql + ]; + }); + + pycurl = super.pycurl.override (attrs: { + propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ + pkgs.curl + pkgs.openssl + ]; + preConfigure = '' + substituteInPlace setup.py --replace '--static-libs' '--libs' + export PYCURL_SSL_LIBRARY=openssl + ''; + }); + + Pylons = super.Pylons.override (attrs: { + name = "Pylons-1.0.1-patch1"; + src = pkgs.fetchgit { + url = "https://code.rhodecode.com/upstream/pylons"; + rev = "707354ee4261b9c10450404fc9852ccea4fd667d"; + sha256 = "b2763274c2780523a335f83a1df65be22ebe4ff413a7bc9e9288d23c1f62032e"; + }; + }); + + pyramid = super.pyramid.override (attrs: { + postFixup = '' + wrapPythonPrograms + # TODO: johbo: "wrapPython" adds this magic line which + # confuses pserve. + ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped + ''; + }); + + Pyro4 = super.Pyro4.override (attrs: { + # TODO: Was not able to generate this version, needs further + # investigation. + name = "Pyro4-4.35"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/source/P/Pyro4/Pyro4-4.35.src.tar.gz"; + md5 = "cbe6cb855f086a0f092ca075005855f3"; + }; + }); + + pysqlite = super.pysqlite.override (attrs: { + propagatedBuildInputs = [ + pkgs.sqlite + ]; + }); + + pytest-runner = super.pytest-runner.override (attrs: { + propagatedBuildInputs = [ + self.setuptools-scm + ]; + }); + + python-ldap = super.python-ldap.override (attrs: { + propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ + pkgs.cyrus_sasl + pkgs.openldap + pkgs.openssl + ]; + NIX_CFLAGS_COMPILE = "-I${pkgs.cyrus_sasl}/include/sasl"; + }); + + python-pam = super.python-pam.override (attrs: + let + includeLibPam = pkgs.stdenv.isLinux; + in { + # TODO: johbo: Move the option up into the default.nix, we should + # include python-pam only on supported platforms. + propagatedBuildInputs = attrs.propagatedBuildInputs ++ + pkgs.lib.optional includeLibPam [ + pkgs.pam + ]; + # TODO: johbo: Check if this can be avoided, or transform into + # a real patch + patchPhase = pkgs.lib.optionals includeLibPam '' + substituteInPlace pam.py \ + --replace 'find_library("pam")' '"${pkgs.pam}/lib/libpam.so.0"' + ''; + }); + + rhodecode-tools = super.rhodecode-tools.override (attrs: { + patches = [ + ./patch-rhodecode-tools-setup.diff + ]; + }); + + # Avoid that setuptools is replaced, this leads to trouble + # with buildPythonPackage. + setuptools = basePythonPackages.setuptools; + +} diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix new file mode 100644 --- /dev/null +++ b/pkgs/python-packages.nix @@ -0,0 +1,1273 @@ +{ + Babel = super.buildPythonPackage { + name = "Babel-1.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pytz]; + src = fetchurl { + url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz"; + md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; + }; + }; + Beaker = super.buildPythonPackage { + name = "Beaker-1.7.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz"; + md5 = "386be3f7fe427358881eee4622b428b3"; + }; + }; + CProfileV = super.buildPythonPackage { + name = "CProfileV-1.0.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [bottle]; + src = fetchurl { + url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz"; + md5 = "08c7c242b6e64237bc53c5d13537e03d"; + }; + }; + Fabric = super.buildPythonPackage { + name = "Fabric-1.10.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [paramiko]; + src = fetchurl { + url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz"; + md5 = "2cb96473387f0e7aa035210892352f4a"; + }; + }; + FormEncode = super.buildPythonPackage { + name = "FormEncode-1.2.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz"; + md5 = "6bc17fb9aed8aea198975e888e2077f4"; + }; + }; + Jinja2 = super.buildPythonPackage { + name = "Jinja2-2.7.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [MarkupSafe]; + src = fetchurl { + url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz"; + md5 = "b9dffd2f3b43d673802fe857c8445b1a"; + }; + }; + Mako = super.buildPythonPackage { + name = "Mako-1.0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [MarkupSafe]; + src = fetchurl { + url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz"; + md5 = "9f0aafd177b039ef67b90ea350497a54"; + }; + }; + Markdown = super.buildPythonPackage { + name = "Markdown-2.6.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz"; + md5 = "256d19afcc564dc4ce4c229bb762f7ae"; + }; + }; + MarkupSafe = super.buildPythonPackage { + name = "MarkupSafe-0.23"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; + md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; + }; + }; + MySQL-python = super.buildPythonPackage { + name = "MySQL-python-1.2.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip"; + md5 = "654f75b302db6ed8dc5a898c625e030c"; + }; + }; + Paste = super.buildPythonPackage { + name = "Paste-2.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [six]; + src = fetchurl { + url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz"; + md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c"; + }; + }; + PasteDeploy = super.buildPythonPackage { + name = "PasteDeploy-1.5.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz"; + md5 = "352b7205c78c8de4987578d19431af3b"; + }; + }; + PasteScript = super.buildPythonPackage { + name = "PasteScript-1.7.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [Paste PasteDeploy]; + src = fetchurl { + url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz"; + md5 = "4c72d78dcb6bb993f30536842c16af4d"; + }; + }; + Pygments = super.buildPythonPackage { + name = "Pygments-2.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz"; + md5 = "238587a1370d62405edabd0794b3ec4a"; + }; + }; + Pylons = super.buildPythonPackage { + name = "Pylons-1.0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [Routes WebHelpers Beaker Paste PasteDeploy PasteScript FormEncode simplejson decorator nose Mako WebError WebTest Tempita MarkupSafe WebOb]; + src = fetchurl { + url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz"; + md5 = "6cb880d75fa81213192142b07a6e4915"; + }; + }; + Pyro4 = super.buildPythonPackage { + name = "Pyro4-4.41"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [serpent]; + src = fetchurl { + url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz"; + md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c"; + }; + }; + Routes = super.buildPythonPackage { + name = "Routes-1.13"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [repoze.lru]; + src = fetchurl { + url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz"; + md5 = "d527b0ab7dd9172b1275a41f97448783"; + }; + }; + SQLAlchemy = super.buildPythonPackage { + name = "SQLAlchemy-0.9.9"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz"; + md5 = "8a10a9bd13ed3336ef7333ac2cc679ff"; + }; + }; + Sphinx = super.buildPythonPackage { + name = "Sphinx-1.2.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [Pygments docutils Jinja2]; + src = fetchurl { + url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz"; + md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4"; + }; + }; + Tempita = super.buildPythonPackage { + name = "Tempita-0.5.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz"; + md5 = "4c2f17bb9d481821c41b6fbee904cea1"; + }; + }; + URLObject = super.buildPythonPackage { + name = "URLObject-2.4.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz"; + md5 = "2ed819738a9f0a3051f31dc9924e3065"; + }; + }; + WebError = super.buildPythonPackage { + name = "WebError-0.10.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [WebOb Tempita Pygments Paste]; + src = fetchurl { + url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz"; + md5 = "84b9990b0baae6fd440b1e60cdd06f9a"; + }; + }; + WebHelpers = super.buildPythonPackage { + name = "WebHelpers-1.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [MarkupSafe]; + src = fetchurl { + url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz"; + md5 = "32749ffadfc40fea51075a7def32588b"; + }; + }; + WebHelpers2 = super.buildPythonPackage { + name = "WebHelpers2-2.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [MarkupSafe six]; + src = fetchurl { + url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz"; + md5 = "0f6b68d70c12ee0aed48c00b24da13d3"; + }; + }; + WebOb = super.buildPythonPackage { + name = "WebOb-1.3.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz"; + md5 = "20918251c5726956ba8fef22d1556177"; + }; + }; + WebTest = super.buildPythonPackage { + name = "WebTest-1.4.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [WebOb]; + src = fetchurl { + url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip"; + md5 = "631ce728bed92c681a4020a36adbc353"; + }; + }; + Whoosh = super.buildPythonPackage { + name = "Whoosh-2.7.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip"; + md5 = "7abfd970f16fadc7311960f3fa0bc7a9"; + }; + }; + alembic = super.buildPythonPackage { + name = "alembic-0.8.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor]; + src = fetchurl { + url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz"; + md5 = "5f95d8ee62b443f9b37eb5bee76c582d"; + }; + }; + amqplib = super.buildPythonPackage { + name = "amqplib-1.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz"; + md5 = "5c92f17fbedd99b2b4a836d4352d1e2f"; + }; + }; + anyjson = super.buildPythonPackage { + name = "anyjson-0.3.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz"; + md5 = "2ea28d6ec311aeeebaf993cb3008b27c"; + }; + }; + appenlight-client = super.buildPythonPackage { + name = "appenlight-client-0.6.14"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [WebOb requests]; + src = fetchurl { + url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz"; + md5 = "578c69b09f4356d898fff1199b98a95c"; + }; + }; + authomatic = super.buildPythonPackage { + name = "authomatic-0.1.0.post1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz"; + md5 = "be3f3ce08747d776aae6d6cc8dcb49a9"; + }; + }; + backport-ipaddress = super.buildPythonPackage { + name = "backport-ipaddress-0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz"; + md5 = "9c1f45f4361f71b124d7293a60006c05"; + }; + }; + bottle = super.buildPythonPackage { + name = "bottle-0.12.8"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz"; + md5 = "13132c0a8f607bf860810a6ee9064c5b"; + }; + }; + bumpversion = super.buildPythonPackage { + name = "bumpversion-0.5.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz"; + md5 = "c66a3492eafcf5ad4b024be9fca29820"; + }; + }; + celery = super.buildPythonPackage { + name = "celery-2.2.10"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [python-dateutil anyjson kombu pyparsing]; + src = fetchurl { + url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz"; + md5 = "898bc87e54f278055b561316ba73e222"; + }; + }; + certifi = super.buildPythonPackage { + name = "certifi-2016.02.28"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/5c/f8/f6c54727c74579c6bbe5926f5deb9677c5810a33e11da58d1a4e2d09d041/certifi-2016.2.28.tar.gz"; + md5 = "5d672aa766e1f773c75cfeccd02d3650"; + }; + }; + click = super.buildPythonPackage { + name = "click-5.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz"; + md5 = "9c5323008cccfe232a8b161fc8196d41"; + }; + }; + colander = super.buildPythonPackage { + name = "colander-1.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [translationstring iso8601]; + src = fetchurl { + url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz"; + md5 = "83db21b07936a0726e588dae1914b9ed"; + }; + }; + configobj = super.buildPythonPackage { + name = "configobj-5.0.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [six]; + src = fetchurl { + url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz"; + md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6"; + }; + }; + cov-core = super.buildPythonPackage { + name = "cov-core-1.15.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [coverage]; + src = fetchurl { + url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz"; + md5 = "f519d4cb4c4e52856afb14af52919fe6"; + }; + }; + coverage = super.buildPythonPackage { + name = "coverage-3.7.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz"; + md5 = "c47b36ceb17eaff3ecfab3bcd347d0df"; + }; + }; + cssselect = super.buildPythonPackage { + name = "cssselect-0.9.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz"; + md5 = "c74f45966277dc7a0f768b9b0f3522ac"; + }; + }; + decorator = super.buildPythonPackage { + name = "decorator-3.4.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz"; + md5 = "9e0536870d2b83ae27d58dbf22582f4d"; + }; + }; + docutils = super.buildPythonPackage { + name = "docutils-0.12"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; + md5 = "4622263b62c5c771c03502afa3157768"; + }; + }; + dogpile.cache = super.buildPythonPackage { + name = "dogpile.cache-0.5.7"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [dogpile.core]; + src = fetchurl { + url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz"; + md5 = "3e58ce41af574aab41d78e9c4190f194"; + }; + }; + dogpile.core = super.buildPythonPackage { + name = "dogpile.core-0.4.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz"; + md5 = "01cb19f52bba3e95c9b560f39341f045"; + }; + }; + dulwich = super.buildPythonPackage { + name = "dulwich-0.12.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz"; + md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa"; + }; + }; + ecdsa = super.buildPythonPackage { + name = "ecdsa-0.11"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz"; + md5 = "8ef586fe4dbb156697d756900cb41d7c"; + }; + }; + elasticsearch = super.buildPythonPackage { + name = "elasticsearch-1.9.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [urllib3]; + src = fetchurl { + url = "https://pypi.python.org/packages/13/9b/540e311b31a10c2a904acfb08030c656047e5c7ba479d35df2799e5dccfe/elasticsearch-1.9.0.tar.gz"; + md5 = "3550390baea1639479f79758d66ab032"; + }; + }; + flake8 = super.buildPythonPackage { + name = "flake8-2.4.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pyflakes pep8 mccabe]; + src = fetchurl { + url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz"; + md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65"; + }; + }; + future = super.buildPythonPackage { + name = "future-0.14.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz"; + md5 = "e94079b0bd1fc054929e8769fc0f6083"; + }; + }; + futures = super.buildPythonPackage { + name = "futures-3.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz"; + md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a"; + }; + }; + gnureadline = super.buildPythonPackage { + name = "gnureadline-6.3.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz"; + md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c"; + }; + }; + gprof2dot = super.buildPythonPackage { + name = "gprof2dot-2015.12.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz"; + md5 = "e23bf4e2f94db032750c193384b4165b"; + }; + }; + greenlet = super.buildPythonPackage { + name = "greenlet-0.4.7"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/7a/9f/a1a0d9bdf3203ae1502c5a8434fe89d323599d78a106985bc327351a69d4/greenlet-0.4.7.zip"; + md5 = "c2333a8ff30fa75c5d5ec0e67b461086"; + }; + }; + gunicorn = super.buildPythonPackage { + name = "gunicorn-19.6.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz"; + md5 = "338e5e8a83ea0f0625f768dba4597530"; + }; + }; + infrae.cache = super.buildPythonPackage { + name = "infrae.cache-1.0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [Beaker repoze.lru]; + src = fetchurl { + url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz"; + md5 = "b09076a766747e6ed2a755cc62088e32"; + }; + }; + invoke = super.buildPythonPackage { + name = "invoke-0.11.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/d3/bb/36a5558ea19882073def7b0edeef4a0e6282056fed96506dd10b1d532bd4/invoke-0.11.1.tar.gz"; + md5 = "3d4ecbe26779ceef1046ecf702c9c4a8"; + }; + }; + ipdb = super.buildPythonPackage { + name = "ipdb-0.8"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [ipython]; + src = fetchurl { + url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip"; + md5 = "96dca0712efa01aa5eaf6b22071dd3ed"; + }; + }; + ipython = super.buildPythonPackage { + name = "ipython-3.1.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [gnureadline]; + src = fetchurl { + url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz"; + md5 = "a749d90c16068687b0ec45a27e72ef8f"; + }; + }; + iso8601 = super.buildPythonPackage { + name = "iso8601-0.1.11"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz"; + md5 = "b06d11cd14a64096f907086044f0fe38"; + }; + }; + itsdangerous = super.buildPythonPackage { + name = "itsdangerous-0.24"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; + md5 = "a3d55aa79369aef5345c036a8a26307f"; + }; + }; + kombu = super.buildPythonPackage { + name = "kombu-1.5.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [anyjson amqplib]; + src = fetchurl { + url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz"; + md5 = "50662f3c7e9395b3d0721fb75d100b63"; + }; + }; + lxml = super.buildPythonPackage { + name = "lxml-3.4.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz"; + md5 = "a9a65972afc173ec7a39c585f4eea69c"; + }; + }; + mccabe = super.buildPythonPackage { + name = "mccabe-0.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz"; + md5 = "81640948ff226f8c12b3277059489157"; + }; + }; + meld3 = super.buildPythonPackage { + name = "meld3-1.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz"; + md5 = "3ccc78cd79cffd63a751ad7684c02c91"; + }; + }; + mock = super.buildPythonPackage { + name = "mock-1.0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip"; + md5 = "869f08d003c289a97c1a6610faf5e913"; + }; + }; + msgpack-python = super.buildPythonPackage { + name = "msgpack-python-0.4.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz"; + md5 = "8b317669314cf1bc881716cccdaccb30"; + }; + }; + nose = super.buildPythonPackage { + name = "nose-1.3.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz"; + md5 = "0ca546d81ca8309080fc80cb389e7a16"; + }; + }; + objgraph = super.buildPythonPackage { + name = "objgraph-2.0.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz"; + md5 = "25b0d5e5adc74aa63ead15699614159c"; + }; + }; + packaging = super.buildPythonPackage { + name = "packaging-15.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz"; + md5 = "c16093476f6ced42128bf610e5db3784"; + }; + }; + paramiko = super.buildPythonPackage { + name = "paramiko-1.15.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pycrypto ecdsa]; + src = fetchurl { + url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz"; + md5 = "48c274c3f9b1282932567b21f6acf3b5"; + }; + }; + pep8 = super.buildPythonPackage { + name = "pep8-1.5.7"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz"; + md5 = "f6adbdd69365ecca20513c709f9b7c93"; + }; + }; + psutil = super.buildPythonPackage { + name = "psutil-2.2.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz"; + md5 = "1a2b58cd9e3a53528bb6148f0c4d5244"; + }; + }; + psycopg2 = super.buildPythonPackage { + name = "psycopg2-2.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz"; + md5 = "fbbb039a8765d561a1c04969bbae7c74"; + }; + }; + py = super.buildPythonPackage { + name = "py-1.4.29"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz"; + md5 = "c28e0accba523a29b35a48bb703fb96c"; + }; + }; + py-bcrypt = super.buildPythonPackage { + name = "py-bcrypt-0.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz"; + md5 = "dd8b367d6b716a2ea2e72392525f4e36"; + }; + }; + pycrypto = super.buildPythonPackage { + name = "pycrypto-2.6.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz"; + md5 = "55a61a054aa66812daf5161a0d5d7eda"; + }; + }; + pycurl = super.buildPythonPackage { + name = "pycurl-7.19.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz"; + md5 = "47b4eac84118e2606658122104e62072"; + }; + }; + pyelasticsearch = super.buildPythonPackage { + name = "pyelasticsearch-1.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [certifi elasticsearch urllib3 simplejson six]; + src = fetchurl { + url = "https://pypi.python.org/packages/2f/3a/7643cfcfc4cbdbb20ada800bbd54ac9705d0c047d7b8f8d5eeeb3047b4eb/pyelasticsearch-1.4.tar.gz"; + md5 = "ed61ebb7b253364e55b4923d11e17049"; + }; + }; + pyflakes = super.buildPythonPackage { + name = "pyflakes-0.8.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz"; + md5 = "905fe91ad14b912807e8fdc2ac2e2c23"; + }; + }; + pyparsing = super.buildPythonPackage { + name = "pyparsing-1.5.7"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip"; + md5 = "b86854857a368d6ccb4d5b6e76d0637f"; + }; + }; + pyramid = super.buildPythonPackage { + name = "pyramid-1.6.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy]; + src = fetchurl { + url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz"; + md5 = "b18688ff3cc33efdbb098a35b45dd122"; + }; + }; + pyramid-beaker = super.buildPythonPackage { + name = "pyramid-beaker-0.8"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pyramid Beaker]; + src = fetchurl { + url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz"; + md5 = "22f14be31b06549f80890e2c63a93834"; + }; + }; + pyramid-debugtoolbar = super.buildPythonPackage { + name = "pyramid-debugtoolbar-2.4.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments]; + src = fetchurl { + url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz"; + md5 = "073ea67086cc4bd5decc3a000853642d"; + }; + }; + pyramid-jinja2 = super.buildPythonPackage { + name = "pyramid-jinja2-2.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe]; + src = fetchurl { + url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz"; + md5 = "07cb6547204ac5e6f0b22a954ccee928"; + }; + }; + pyramid-mako = super.buildPythonPackage { + name = "pyramid-mako-1.0.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pyramid Mako]; + src = fetchurl { + url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz"; + md5 = "ee25343a97eb76bd90abdc2a774eb48a"; + }; + }; + pysqlite = super.buildPythonPackage { + name = "pysqlite-2.6.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz"; + md5 = "7ff1cedee74646b50117acff87aa1cfa"; + }; + }; + pytest = super.buildPythonPackage { + name = "pytest-2.8.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [py]; + src = fetchurl { + url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip"; + md5 = "8493b06f700862f1294298d6c1b715a9"; + }; + }; + pytest-catchlog = super.buildPythonPackage { + name = "pytest-catchlog-1.2.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [py pytest]; + src = fetchurl { + url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip"; + md5 = "09d890c54c7456c818102b7ff8c182c8"; + }; + }; + pytest-cov = super.buildPythonPackage { + name = "pytest-cov-1.8.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [py pytest coverage cov-core]; + src = fetchurl { + url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz"; + md5 = "76c778afa2494088270348be42d759fc"; + }; + }; + pytest-profiling = super.buildPythonPackage { + name = "pytest-profiling-1.0.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [six pytest gprof2dot]; + src = fetchurl { + url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz"; + md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b"; + }; + }; + pytest-runner = super.buildPythonPackage { + name = "pytest-runner-2.7.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz"; + md5 = "e56f0bc8d79a6bd91772b44ef4215c7e"; + }; + }; + pytest-timeout = super.buildPythonPackage { + name = "pytest-timeout-0.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [pytest]; + src = fetchurl { + url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz"; + md5 = "03b28aff69cbbfb959ed35ade5fde262"; + }; + }; + python-dateutil = super.buildPythonPackage { + name = "python-dateutil-1.5"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz"; + md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5"; + }; + }; + python-editor = super.buildPythonPackage { + name = "python-editor-1.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/f5/d9/01eb441489c8bd2adb33ee4f3aea299a3db531a584cb39c57a0ecf516d9c/python-editor-1.0.tar.gz"; + md5 = "a5ead611360b17b52507297d8590b4e8"; + }; + }; + python-ldap = super.buildPythonPackage { + name = "python-ldap-2.4.19"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz"; + md5 = "b941bf31d09739492aa19ef679e94ae3"; + }; + }; + python-memcached = super.buildPythonPackage { + name = "python-memcached-1.57"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [six]; + src = fetchurl { + url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz"; + md5 = "de21f64b42b2d961f3d4ad7beb5468a1"; + }; + }; + python-pam = super.buildPythonPackage { + name = "python-pam-1.8.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz"; + md5 = "db71b6b999246fb05d78ecfbe166629d"; + }; + }; + pytz = super.buildPythonPackage { + name = "pytz-2015.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip"; + md5 = "233f2a2b370d03f9b5911700cc9ebf3c"; + }; + }; + pyzmq = super.buildPythonPackage { + name = "pyzmq-14.6.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz"; + md5 = "395b5de95a931afa5b14c9349a5b8024"; + }; + }; + recaptcha-client = super.buildPythonPackage { + name = "recaptcha-client-1.0.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz"; + md5 = "74228180f7e1fb76c4d7089160b0d919"; + }; + }; + repoze.lru = super.buildPythonPackage { + name = "repoze.lru-0.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz"; + md5 = "2c3b64b17a8e18b405f55d46173e14dd"; + }; + }; + requests = super.buildPythonPackage { + name = "requests-2.9.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz"; + md5 = "0b7f480d19012ec52bab78292efd976d"; + }; + }; + rhodecode-enterprise-ce = super.buildPythonPackage { + name = "rhodecode-enterprise-ce-4.0.0"; + buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-runner pytest-cov]; + doCheck = true; + propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt]; + src = ./.; + }; + rhodecode-tools = super.buildPythonPackage { + name = "rhodecode-tools-0.7.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests Whoosh pyelasticsearch]; + src = fetchurl { + url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.7.1.zip"; + md5 = "91daea803aaa264ce7a8213bc2220d4c"; + }; + }; + serpent = super.buildPythonPackage { + name = "serpent-1.12"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz"; + md5 = "05869ac7b062828b34f8f927f0457b65"; + }; + }; + setproctitle = super.buildPythonPackage { + name = "setproctitle-1.1.8"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz"; + md5 = "728f4c8c6031bbe56083a48594027edd"; + }; + }; + setuptools = super.buildPythonPackage { + name = "setuptools-20.8.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip"; + md5 = "fe58a5cac0df20bb83942b252a4b0543"; + }; + }; + setuptools-scm = super.buildPythonPackage { + name = "setuptools-scm-1.11.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz"; + md5 = "4c5c896ba52e134bbc3507bac6400087"; + }; + }; + simplejson = super.buildPythonPackage { + name = "simplejson-3.7.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz"; + md5 = "a5fc7d05d4cb38492285553def5d4b46"; + }; + }; + six = super.buildPythonPackage { + name = "six-1.9.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz"; + md5 = "476881ef4012262dfc8adc645ee786c4"; + }; + }; + subprocess32 = super.buildPythonPackage { + name = "subprocess32-3.2.6"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz"; + md5 = "754c5ab9f533e764f931136974b618f1"; + }; + }; + supervisor = super.buildPythonPackage { + name = "supervisor-3.1.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [meld3]; + src = fetchurl { + url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz"; + md5 = "aad263c4fbc070de63dd354864d5e552"; + }; + }; + transifex-client = super.buildPythonPackage { + name = "transifex-client-0.10"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz"; + md5 = "5549538d84b8eede6b254cd81ae024fa"; + }; + }; + translationstring = super.buildPythonPackage { + name = "translationstring-1.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz"; + md5 = "a4b62e0f3c189c783a1685b3027f7c90"; + }; + }; + trollius = super.buildPythonPackage { + name = "trollius-1.0.4"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [futures]; + src = fetchurl { + url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz"; + md5 = "3631a464d49d0cbfd30ab2918ef2b783"; + }; + }; + uWSGI = super.buildPythonPackage { + name = "uWSGI-2.0.11.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz"; + md5 = "1f02dcbee7f6f61de4b1fd68350cf16f"; + }; + }; + urllib3 = super.buildPythonPackage { + name = "urllib3-1.15.1"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/49/26/a7d12ea00cb4b9fa1e13b5980e5a04a1fe7c477eb8f657ce0b757a7a497d/urllib3-1.15.1.tar.gz"; + md5 = "5be254b0dbb55d1307ede99e1895c8dd"; + }; + }; + venusian = super.buildPythonPackage { + name = "venusian-1.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz"; + md5 = "dccf2eafb7113759d60c86faf5538756"; + }; + }; + waitress = super.buildPythonPackage { + name = "waitress-0.8.9"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz"; + md5 = "da3f2e62b3676be5dd630703a68e2a04"; + }; + }; + wsgiref = super.buildPythonPackage { + name = "wsgiref-0.1.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip"; + md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb"; + }; + }; + zope.cachedescriptors = super.buildPythonPackage { + name = "zope.cachedescriptors-4.0.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz"; + md5 = "8d308de8c936792c8e758058fcb7d0f0"; + }; + }; + zope.deprecation = super.buildPythonPackage { + name = "zope.deprecation-4.1.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz"; + md5 = "e9a663ded58f4f9f7881beb56cae2782"; + }; + }; + zope.event = super.buildPythonPackage { + name = "zope.event-4.0.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz"; + md5 = "9a3780916332b18b8b85f522bcc3e249"; + }; + }; + zope.interface = super.buildPythonPackage { + name = "zope.interface-4.1.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; [setuptools]; + src = fetchurl { + url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz"; + md5 = "9ae3d24c0c7415deb249dd1a132f0f79"; + }; + }; + +### Test requirements + + +} diff --git a/pytest.ini b/pytest.ini new file mode 100644 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,12 @@ +[pytest] +testpaths = ./rhodecode +pylons_config = test.ini +vcsserver_protocol = pyro4 +vcsserver_config = rhodecode/tests/vcsserver.ini +vcsserver_config_http = rhodecode/tests/vcsserver_pyramid.ini +norecursedirs = tests/scripts +addopts = -k "not _BaseTest" +markers = + vcs_operations: Mark tests depending on a running RhodeCode instance. + xfail_backends: Mark tests as xfail for given backends. + skip_backends: Mark tests as skipped for given backends. diff --git a/release.nix b/release.nix new file mode 100644 --- /dev/null +++ b/release.nix @@ -0,0 +1,231 @@ +# +# About +# ===== +# +# This file defines jobs for our CI system and the attribute "build" is used +# as the input for packaging. +# +# +# CI details +# ========== +# +# This file defines an attribute set of derivations. Each of these attributes is +# then used in our CI system as one job to run. This way we keep the +# configuration for the CI jobs as well under version control. +# +# Run CI jobs locally +# ------------------- +# +# Since it is all based on normal Nix derivations, the jobs can be tested +# locally with a run of "nix-build" like the following example: +# +# nix-build release.nix -A test-api -I vcsserver=~/rhodecode-vcsserver +# +# Note: Replace "~/rhodecode-vcsserver" with a path where a clone of the +# vcsserver resides. + +{ pkgs ? import <nixpkgs> {} +}: + +let + + inherit (pkgs) + stdenv + system; + + testing = import <nixpkgs/nixos/lib/testing.nix> { + inherit system; + }; + + runInMachine = testing.runInMachine; + + sphinx = import ./docs/default.nix {}; + + mkDocs = kind: stdenv.mkDerivation { + name = kind; + srcs = [ + (./. + (builtins.toPath "/${kind}")) + (builtins.filterSource + (path: type: baseNameOf path == "VERSION") + ./rhodecode) + ]; + sourceRoot = kind; + buildInputs = [ sphinx ]; + configurePhase = null; + buildPhase = '' + make SPHINXBUILD=sphinx-build html + ''; + installPhase = '' + mkdir -p $out + mv _build/html $out/ + + mkdir -p $out/nix-support + echo "doc manual $out/html index.html" >> \ + "$out/nix-support/hydra-build-products" + ''; + }; + + enterprise = import ./default.nix { + inherit + pkgs; + + # TODO: for quick local testing + doCheck = false; + }; + + test-cfg = stdenv.mkDerivation { + name = "test-cfg"; + unpackPhase = "true"; + buildInputs = [ + enterprise.src + ]; + installPhase = '' + mkdir -p $out/etc + cp ${enterprise.src}/test.ini $out/etc/enterprise.ini + # TODO: johbo: Needed, so that the login works, this causes + # probably some side effects + substituteInPlace $out/etc/enterprise.ini --replace "is_test = True" "" + + # Gevent configuration + cp $out/etc/enterprise.ini $out/etc/enterprise-gevent.ini; + cat >> $out/etc/enterprise-gevent.ini <<EOF + + [server:main] + use = egg:gunicorn#main + worker_class = gevent + EOF + + cp ${enterprise.src}/vcsserver/test.ini $out/etc/vcsserver.ini + ''; + }; + + ac-test-drv = import ./acceptance_tests { + withExternals = false; + }; + + # TODO: johbo: Currently abusing buildPythonPackage to make the + # needed environment for the ac-test tools. + mkAcTests = { + # Path to an INI file which will be used to run Enterprise. + # + # Intended usage is to provide different configuration files to + # run the tests against a different configuration. + enterpriseCfg ? "${test-cfg}/etc/enterprise.ini" + + # Path to an INI file which will be used to run the VCSServer. + , vcsserverCfg ? "${test-cfg}/etc/vcsserver.ini" + }: pkgs.pythonPackages.buildPythonPackage { + name = "enterprise-ac-tests"; + src = ./acceptance_tests; + + buildInputs = with pkgs; [ + curl + enterprise + ac-test-drv + ]; + + buildPhase = '' + cp ${enterpriseCfg} enterprise.ini + + echo "Creating a fake home directory" + mkdir fake-home + export HOME=$PWD/fake-home + + echo "Creating a repository directory" + mkdir repos + + echo "Preparing the database" + paster setup-rhodecode \ + --user=admin \ + --email=admin@example.com \ + --password=secret \ + --api-key=9999999999999999999999999999999999999999 \ + --force-yes \ + --repos=$PWD/repos \ + enterprise.ini > /dev/null + + echo "Starting rcserver" + vcsserver --config ${vcsserverCfg} >vcsserver.log 2>&1 & + rcserver enterprise.ini >rcserver.log 2>&1 & + + while ! curl -f -s http://localhost:5000 > /dev/null + do + echo "Waiting for server to be ready..." + sleep 3 + done + echo "Webserver is ready." + + echo "Starting the test run" + py.test -c example.ini -vs --maxfail=5 tests + + echo "Kill rcserver" + kill %2 + kill %1 + ''; + + # TODO: johbo: Use the install phase again once the normal mkDerivation + # can be used again. + postInstall = '' + mkdir -p $out + cp enterprise.ini $out + cp ${vcsserverCfg} $out/vcsserver.ini + cp rcserver.log $out + cp vcsserver.log $out + + mkdir -p $out/nix-support + echo "report config $out enterprise.ini" >> $out/nix-support/hydra-build-products + echo "report config $out vcsserver.ini" >> $out/nix-support/hydra-build-products + echo "report rcserver $out rcserver.log" >> $out/nix-support/hydra-build-products + echo "report vcsserver $out vcsserver.log" >> $out/nix-support/hydra-build-products + ''; + }; + + vcsserver = import <vcsserver> { + inherit pkgs; + + # TODO: johbo: Think of a more elegant solution to this problem + pythonExternalOverrides = self: super: (enterprise.myPythonPackagesUnfix self); + }; + + runTests = optionString: (enterprise.override (attrs: { + doCheck = true; + name = "test-run"; + buildInputs = attrs.buildInputs ++ [ + vcsserver + ]; + checkPhase = '' + py.test ${optionString} -vv -ra + ''; + buildPhase = attrs.shellHook; + installPhase = '' + echo "Intentionally not installing anything" + ''; + meta.description = "Enterprise test run ${optionString}"; + })); + + jobs = { + + build = enterprise; + + # johbo: Currently this is simply running the tests against the sources. Nicer + # would be to run xdist and against the installed application, so that we also + # cover the impact of installing the application. + test-api = runTests "rhodecode/api"; + test-functional = runTests "rhodecode/tests/functional"; + test-rest = runTests "rhodecode/tests --ignore=rhodecode/tests/functional"; + test-full = runTests "rhodecode"; + + docs = mkDocs "docs"; + + aggregate = pkgs.releaseTools.aggregate { + name = "aggregated-jobs"; + constituents = [ + jobs.build + jobs.test-api + jobs.test-rest + jobs.docs + ]; + }; + }; + +in jobs diff --git a/requirements.txt b/requirements.txt new file mode 100644 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,151 @@ +Babel==1.3 +Beaker==1.7.0 +CProfileV==1.0.6 +Fabric==1.10.0 +FormEncode==1.2.4 +Jinja2==2.7.3 +Mako==1.0.1 +Markdown==2.6.2 +MarkupSafe==0.23 +MySQL-python==1.2.5 +Paste==2.0.2 +PasteDeploy==1.5.2 +PasteScript==1.7.5 +pyelasticsearch==1.4 +Pygments==2.0.2 + +# TODO: This version is not available on PyPI +# Pylons==1.0.2.dev20160108 +Pylons==1.0.1 + +# TODO: This version is not available, but newer ones are +# Pyro4==4.35 +Pyro4==4.41 + +# TODO: This should probably not be in here +# -e hg+https://johbo@code.rhodecode.com/johbo/rhodecode-fork@3a454bd1f17c0b2b2a951cf2b111e0320d7942a9#egg=RhodeCodeEnterprise-dev + +# TODO: This is not really a dependency, we should add it only +# into the development environment, since there it is useful. +# RhodeCodeVCSServer==3.9.0 + +Routes==1.13 +SQLAlchemy==0.9.9 +Sphinx==1.2.2 +Tempita==0.5.2 +URLObject==2.4.0 +WebError==0.10.3 + +# TODO: This is modified by us, needs a better integration. For now +# using the latest version before. +# WebHelpers==1.3.dev20150807 +WebHelpers==1.3 + +WebHelpers2==2.0 +WebOb==1.3.1 +WebTest==1.4.3 +Whoosh==2.7.0 +alembic==0.8.4 +amqplib==1.0.2 +anyjson==0.3.3 +appenlight-client==0.6.14 +authomatic==0.1.0.post1; +backport-ipaddress==0.1 +bottle==0.12.8 +bumpversion==0.5.3 +celery==2.2.10 +click==5.1 +colander==1.2 +configobj==5.0.6 +cov-core==1.15.0 +coverage==3.7.1 +cssselect==0.9.1 +decorator==3.4.2 +docutils==0.12 +dogpile.cache==0.5.7 +dogpile.core==0.4.1 +dulwich==0.12.0 +ecdsa==0.11 +flake8==2.4.1 +future==0.14.3 +futures==3.0.2 +gprof2dot==2015.12.1 +greenlet==0.4.7 +gunicorn==19.6.0 + +# TODO: Needs subvertpy and blows up without Subversion headers, +# actually we should not need this for Enterprise at all. +# hgsubversion==1.8.2 + +infrae.cache==1.0.1 +invoke==0.11.1 +ipdb==0.8 +ipython==3.1.0 +iso8601==0.1.11 +itsdangerous==0.24 +kombu==1.5.1 +lxml==3.4.4 +mccabe==0.3 +meld3==1.0.2 +mock==1.0.1 +msgpack-python==0.4.6 +nose==1.3.6 +objgraph==2.0.0 +packaging==15.2 +paramiko==1.15.1 +pep8==1.5.7 +psutil==2.2.1 +psycopg2==2.6 +py==1.4.29 +py-bcrypt==0.4 +pycrypto==2.6.1 +pycurl==7.19.5 +pyflakes==0.8.1 +pyparsing==1.5.7 +pyramid==1.6.1 +pyramid-beaker==0.8 +pyramid-debugtoolbar==2.4.2 +pyramid-jinja2==2.5 +pyramid-mako==1.0.2 +pysqlite==2.6.3 +pytest==2.8.5 +pytest-runner==2.7.1 +pytest-catchlog==1.2.2 +pytest-cov==1.8.1 +pytest-profiling==1.0.1 +pytest-timeout==0.4 +python-dateutil==1.5 +python-ldap==2.4.19 +python-memcached==1.57 +python-pam==1.8.2 +pytz==2015.4 +pyzmq==14.6.0 + +# TODO: This is not available in public +# rc-testdata==0.2.0 + +https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.7.1.zip#md5=91daea803aaa264ce7a8213bc2220d4c + + +recaptcha-client==1.0.6 +repoze.lru==0.6 +requests==2.9.1 +serpent==1.12 +setproctitle==1.1.8 +setuptools==20.8.1 +setuptools-scm==1.11.0 +simplejson==3.7.2 +six==1.9.0 +subprocess32==3.2.6 +supervisor==3.1.3 +transifex-client==0.10 +translationstring==1.3 +trollius==1.0.4 +uWSGI==2.0.11.2 +venusian==1.0 +waitress==0.8.9 +wsgiref==0.1.2 +zope.cachedescriptors==4.0.0 +zope.deprecation==4.1.2 +zope.event==4.0.3 +zope.interface==4.1.3 diff --git a/rhodecode/VERSION b/rhodecode/VERSION new file mode 100644 --- /dev/null +++ b/rhodecode/VERSION @@ -0,0 +1,1 @@ +4.0.0 \ No newline at end of file diff --git a/rhodecode/__init__.py b/rhodecode/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/__init__.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" + +RhodeCode, a web based repository management software +versioning implementation: http://www.python.org/dev/peps/pep-0386/ +""" + +import os +import sys +import platform + +VERSION = tuple(open(os.path.join( + os.path.dirname(__file__), 'VERSION')).read().split('.')) + +BACKENDS = { + 'hg': 'Mercurial repository', + 'git': 'Git repository', + 'svn': 'Subversion repository', +} + +CELERY_ENABLED = False +CELERY_EAGER = False + +# link to config for pylons +CONFIG = {} + +# Linked module for extensions +EXTENSIONS = {} + +__version__ = ('.'.join((str(each) for each in VERSION[:3]))) +__dbversion__ = 51 # defines current db version for migrations +__platform__ = platform.system() +__license__ = 'AGPLv3, and Commercial License' +__author__ = 'RhodeCode GmbH' +__url__ = 'http://rhodecode.com' + +is_windows = __platform__ in ['Windows'] +is_unix = not is_windows +is_test = False diff --git a/rhodecode/api/__init__.py b/rhodecode/api/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/__init__.py @@ -0,0 +1,497 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import inspect +import itertools +import logging +import types + +import decorator +import venusian +from pyramid.exceptions import ConfigurationError +from pyramid.renderers import render +from pyramid.response import Response +from pyramid.httpexceptions import HTTPNotFound + +from rhodecode.api.exc import JSONRPCBaseError, JSONRPCError, JSONRPCForbidden +from rhodecode.lib.auth import AuthUser +from rhodecode.lib.base import get_ip_addr +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils2 import safe_str +from rhodecode.lib.plugins.utils import get_plugin_settings +from rhodecode.model.db import User, UserApiKeys + +log = logging.getLogger(__name__) + +DEFAULT_RENDERER = 'jsonrpc_renderer' +DEFAULT_URL = '/_admin/apiv2' + + +class ExtJsonRenderer(object): + """ + Custom renderer that mkaes use of our ext_json lib + + """ + + def __init__(self, serializer=json.dumps, **kw): + """ Any keyword arguments will be passed to the ``serializer`` + function.""" + self.serializer = serializer + self.kw = kw + + def __call__(self, info): + """ Returns a plain JSON-encoded string with content-type + ``application/json``. The content-type may be overridden by + setting ``request.response.content_type``.""" + + def _render(value, system): + request = system.get('request') + if request is not None: + response = request.response + ct = response.content_type + if ct == response.default_content_type: + response.content_type = 'application/json' + + return self.serializer(value, **self.kw) + + return _render + + +def jsonrpc_response(request, result): + rpc_id = getattr(request, 'rpc_id', None) + response = request.response + + # store content_type before render is called + ct = response.content_type + + ret_value = '' + if rpc_id: + ret_value = { + 'id': rpc_id, + 'result': result, + 'error': None, + } + + # fetch deprecation warnings, and store it inside results + deprecation = getattr(request, 'rpc_deprecation', None) + if deprecation: + ret_value['DEPRECATION_WARNING'] = deprecation + + raw_body = render(DEFAULT_RENDERER, ret_value, request=request) + response.body = safe_str(raw_body, response.charset) + + if ct == response.default_content_type: + response.content_type = 'application/json' + + return response + + +def jsonrpc_error(request, message, retid=None, code=None): + """ + Generate a Response object with a JSON-RPC error body + + :param code: + :param retid: + :param message: + """ + err_dict = {'id': retid, 'result': None, 'error': message} + body = render(DEFAULT_RENDERER, err_dict, request=request).encode('utf-8') + return Response( + body=body, + status=code, + content_type='application/json' + ) + + +def exception_view(exc, request): + rpc_id = getattr(request, 'rpc_id', None) + + fault_message = 'undefined error' + if isinstance(exc, JSONRPCError): + fault_message = exc.message + log.debug('json-rpc error rpc_id:%s "%s"', rpc_id, fault_message) + elif isinstance(exc, JSONRPCForbidden): + fault_message = 'Access was denied to this resource.' + log.warning('json-rpc forbidden call rpc_id:%s "%s"', rpc_id, fault_message) + elif isinstance(exc, HTTPNotFound): + method = request.rpc_method + log.debug('json-rpc method `%s` not found in list of ' + 'api calls: %s, rpc_id:%s', + method, request.registry.jsonrpc_methods.keys(), rpc_id) + fault_message = "No such method: {}".format(method) + + return jsonrpc_error(request, fault_message, rpc_id) + + +def request_view(request): + """ + Main request handling method. It handles all logic to call a specific + exposed method + """ + + # check if we can find this session using api_key, get_by_auth_token + # search not expired tokens only + + try: + u = User.get_by_auth_token(request.rpc_api_key) + + if u is None: + return jsonrpc_error( + request, retid=request.rpc_id, message='Invalid API KEY') + + if not u.active: + return jsonrpc_error( + request, retid=request.rpc_id, + message='Request from this user not allowed') + + # check if we are allowed to use this IP + auth_u = AuthUser( + u.user_id, request.rpc_api_key, ip_addr=request.rpc_ip_addr) + if not auth_u.ip_allowed: + return jsonrpc_error( + request, retid=request.rpc_id, + message='Request from IP:%s not allowed' % ( + request.rpc_ip_addr,)) + else: + log.info('Access for IP:%s allowed' % (request.rpc_ip_addr,)) + + # now check if token is valid for API + role = UserApiKeys.ROLE_API + extra_auth_tokens = [ + x.api_key for x in User.extra_valid_auth_tokens(u, role=role)] + active_tokens = [u.api_key] + extra_auth_tokens + + log.debug('Checking if API key has proper role') + if request.rpc_api_key not in active_tokens: + return jsonrpc_error( + request, retid=request.rpc_id, + message='API KEY has bad role for an API call') + + except Exception as e: + log.exception('Error on API AUTH') + return jsonrpc_error( + request, retid=request.rpc_id, message='Invalid API KEY') + + method = request.rpc_method + func = request.registry.jsonrpc_methods[method] + + # now that we have a method, add request._req_params to + # self.kargs and dispatch control to WGIController + argspec = inspect.getargspec(func) + arglist = argspec[0] + defaults = map(type, argspec[3] or []) + default_empty = types.NotImplementedType + + # kw arguments required by this method + func_kwargs = dict(itertools.izip_longest( + reversed(arglist), reversed(defaults), fillvalue=default_empty)) + + # This attribute will need to be first param of a method that uses + # api_key, which is translated to instance of user at that name + user_var = 'apiuser' + request_var = 'request' + + for arg in [user_var, request_var]: + if arg not in arglist: + return jsonrpc_error( + request, + retid=request.rpc_id, + message='This method [%s] does not support ' + 'required parameter `%s`' % (func.__name__, arg)) + + # get our arglist and check if we provided them as args + for arg, default in func_kwargs.items(): + if arg in [user_var, request_var]: + # user_var and request_var are pre-hardcoded parameters and we + # don't need to do any translation + continue + + # skip the required param check if it's default value is + # NotImplementedType (default_empty) + if default == default_empty and arg not in request.rpc_params: + return jsonrpc_error( + request, + retid=request.rpc_id, + message=('Missing non optional `%s` arg in JSON DATA' % arg) + ) + + # sanitze extra passed arguments + for k in request.rpc_params.keys()[:]: + if k not in func_kwargs: + del request.rpc_params[k] + + call_params = request.rpc_params + call_params.update({ + 'request': request, + 'apiuser': auth_u + }) + try: + ret_value = func(**call_params) + return jsonrpc_response(request, ret_value) + except JSONRPCBaseError: + raise + except Exception: + log.exception('Unhandled exception occured on api call: %s', func) + return jsonrpc_error(request, retid=request.rpc_id, + message='Internal server error') + + +def setup_request(request): + """ + Parse a JSON-RPC request body. It's used inside the predicates method + to validate and bootstrap requests for usage in rpc calls. + + We need to raise JSONRPCError here if we want to return some errors back to + user. + """ + log.debug('Executing setup request: %r', request) + request.rpc_ip_addr = get_ip_addr(request.environ) + # TODO: marcink, deprecate GET at some point + if request.method not in ['POST', 'GET']: + log.debug('unsupported request method "%s"', request.method) + raise JSONRPCError( + 'unsupported request method "%s". Please use POST' % request.method) + + if 'CONTENT_LENGTH' not in request.environ: + log.debug("No Content-Length") + raise JSONRPCError("Empty body, No Content-Length in request") + + else: + length = request.environ['CONTENT_LENGTH'] + log.debug('Content-Length: %s', length) + + if length == 0: + log.debug("Content-Length is 0") + raise JSONRPCError("Content-Length is 0") + + raw_body = request.body + try: + json_body = json.loads(raw_body) + except ValueError as e: + # catch JSON errors Here + raise JSONRPCError("JSON parse error ERR:%s RAW:%r" % (e, raw_body)) + + request.rpc_id = json_body.get('id') + request.rpc_method = json_body.get('method') + + # check required base parameters + try: + api_key = json_body.get('api_key') + if not api_key: + api_key = json_body.get('auth_token') + + if not api_key: + raise KeyError('api_key or auth_token') + + request.rpc_api_key = api_key + request.rpc_id = json_body['id'] + request.rpc_method = json_body['method'] + request.rpc_params = json_body['args'] \ + if isinstance(json_body['args'], dict) else {} + + log.debug( + 'method: %s, params: %s' % (request.rpc_method, request.rpc_params)) + except KeyError as e: + raise JSONRPCError('Incorrect JSON data. Missing %s' % e) + + log.debug('setup complete, now handling method:%s rpcid:%s', + request.rpc_method, request.rpc_id, ) + + +class RoutePredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'jsonrpc route = %s' % self.val + + phash = text + + def __call__(self, info, request): + if self.val: + # potentially setup and bootstrap our call + setup_request(request) + + # Always return True so that even if it isn't a valid RPC it + # will fall through to the underlaying handlers like notfound_view + return True + + +class NotFoundPredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'jsonrpc method not found = %s' % self.val + + phash = text + + def __call__(self, info, request): + return hasattr(request, 'rpc_method') + + +class MethodPredicate(object): + def __init__(self, val, config): + self.method = val + + def text(self): + return 'jsonrpc method = %s' % self.method + + phash = text + + def __call__(self, context, request): + # we need to explicitly return False here, so pyramid doesn't try to + # execute our view directly. We need our main handler to execute things + return getattr(request, 'rpc_method') == self.method + + +def add_jsonrpc_method(config, view, **kwargs): + # pop the method name + method = kwargs.pop('method', None) + + if method is None: + raise ConfigurationError( + 'Cannot register a JSON-RPC method without specifying the ' + '"method"') + + # we define custom predicate, to enable to detect conflicting methods, + # those predicates are kind of "translation" from the decorator variables + # to internal predicates names + + kwargs['jsonrpc_method'] = method + + # register our view into global view store for validation + config.registry.jsonrpc_methods[method] = view + + # we're using our main request_view handler, here, so each method + # has a unified handler for itself + config.add_view(request_view, route_name='apiv2', **kwargs) + + +class jsonrpc_method(object): + """ + decorator that works similar to @add_view_config decorator, + but tailored for our JSON RPC + """ + + venusian = venusian # for testing injection + + def __init__(self, method=None, **kwargs): + self.method = method + self.kwargs = kwargs + + def __call__(self, wrapped): + kwargs = self.kwargs.copy() + kwargs['method'] = self.method or wrapped.__name__ + depth = kwargs.pop('_depth', 0) + + def callback(context, name, ob): + config = context.config.with_package(info.module) + config.add_jsonrpc_method(view=ob, **kwargs) + + info = venusian.attach(wrapped, callback, category='pyramid', + depth=depth + 1) + if info.scope == 'class': + # ensure that attr is set if decorating a class method + kwargs.setdefault('attr', wrapped.__name__) + + kwargs['_info'] = info.codeinfo # fbo action_method + return wrapped + + +class jsonrpc_deprecated_method(object): + """ + Marks method as deprecated, adds log.warning, and inject special key to + the request variable to mark method as deprecated. + Also injects special docstring that extract_docs will catch to mark + method as deprecated. + + :param use_method: specify which method should be used instead of + the decorated one + + Use like:: + + @jsonrpc_method() + @jsonrpc_deprecated_method(use_method='new_func', deprecated_at_version='3.0.0') + def old_func(request, apiuser, arg1, arg2): + ... + """ + + def __init__(self, use_method, deprecated_at_version): + self.use_method = use_method + self.deprecated_at_version = deprecated_at_version + self.deprecated_msg = '' + + def __call__(self, func): + self.deprecated_msg = 'Please use method `{method}` instead.'.format( + method=self.use_method) + + docstring = """\n + .. deprecated:: {version} + + {deprecation_message} + + {original_docstring} + """ + func.__doc__ = docstring.format( + version=self.deprecated_at_version, + deprecation_message=self.deprecated_msg, + original_docstring=func.__doc__) + return decorator.decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + log.warning('DEPRECATED API CALL on function %s, please ' + 'use `%s` instead', func, self.use_method) + # alter function docstring to mark as deprecated, this is picked up + # via fabric file that generates API DOC. + result = func(*fargs, **fkwargs) + + request = fargs[0] + request.rpc_deprecation = 'DEPRECATED METHOD ' + self.deprecated_msg + return result + + +def includeme(config): + plugin_module = 'rhodecode.api' + plugin_settings = get_plugin_settings( + plugin_module, config.registry.settings) + + if not hasattr(config.registry, 'jsonrpc_methods'): + config.registry.jsonrpc_methods = {} + + # match filter by given method only + config.add_view_predicate( + 'jsonrpc_method', MethodPredicate) + + config.add_renderer(DEFAULT_RENDERER, ExtJsonRenderer( + serializer=json.dumps, indent=4)) + config.add_directive('add_jsonrpc_method', add_jsonrpc_method) + + config.add_route_predicate( + 'jsonrpc_call', RoutePredicate) + + config.add_route( + 'apiv2', plugin_settings.get('url', DEFAULT_URL), jsonrpc_call=True) + + config.scan(plugin_module, ignore='rhodecode.api.tests') + # register some exception handling view + config.add_view(exception_view, context=JSONRPCBaseError) + config.add_view_predicate('jsonrpc_method_not_found', NotFoundPredicate) + config.add_notfound_view(exception_view, jsonrpc_method_not_found=True) diff --git a/rhodecode/api/exc.py b/rhodecode/api/exc.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/exc.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +class JSONRPCBaseError(Exception): + pass + + +class JSONRPCError(JSONRPCBaseError): + pass + + +class JSONRPCForbidden(JSONRPCBaseError): + pass diff --git a/rhodecode/api/tests/__init__.py b/rhodecode/api/tests/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/api/tests/conftest.py b/rhodecode/api/tests/conftest.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/conftest.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN + + +@pytest.fixture(scope="class") +def testuser_api(request, pylonsapp): + cls = request.cls + cls.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + cls.apikey = cls.usr.api_key + cls.test_user = UserModel().create_or_update( + username='test-api', + password='test', + email='test@api.rhodecode.org', + firstname='first', + lastname='last' + ) + Session().commit() + cls.TEST_USER_LOGIN = cls.test_user.username + cls.apikey_regular = cls.test_user.api_key diff --git a/rhodecode/api/tests/test_add_field_to_repo.py b/rhodecode/api/tests/test_add_field_to_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_add_field_to_repo.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import Repository, RepositoryField +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestAddFieldToRepo(object): + def test_api_add_field_to_repo(self, backend): + repo = backend.create_repo() + repo_name = repo.repo_name + id_, params = build_data( + self.apikey, 'add_field_to_repo', + repoid=repo_name, + key='extra_field', + label='extra_field_label', + description='extra_field_desc') + response = api_call(self.app, params) + expected = { + 'msg': 'Added new repository field `extra_field`', + 'success': True, + } + assert_ok(id_, expected, given=response.body) + + repo = Repository.get_by_repo_name(repo_name) + repo_field = RepositoryField.get_by_key_name('extra_field', repo) + _data = repo_field.get_dict() + assert _data['field_desc'] == 'extra_field_desc' + assert _data['field_key'] == 'extra_field' + assert _data['field_label'] == 'extra_field_label' + + id_, params = build_data( + self.apikey, 'add_field_to_repo', + repoid=repo_name, + key='extra_field', + label='extra_field_label', + description='extra_field_desc') + response = api_call(self.app, params) + expected = 'Field with key `extra_field` exists for repo `%s`' % ( + repo_name) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_add_user_to_user_group.py b/rhodecode/api/tests/test_add_user_to_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_add_user_to_user_group.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestAddUserToUserGroup(object): + def test_api_add_user_to_user_group(self, user_util): + group = user_util.create_user_group() + user = user_util.create_user() + group_name = group.users_group_name + user_name = user.username + id_, params = build_data( + self.apikey, 'add_user_to_user_group', + usergroupid=group_name, userid=user_name) + response = api_call(self.app, params) + expected = { + 'msg': 'added member `%s` to user group `%s`' % ( + user_name, group_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + def test_api_add_user_to_user_group_that_doesnt_exist(self, user_util): + user = user_util.create_user() + user_name = user.username + id_, params = build_data( + self.apikey, 'add_user_to_user_group', + usergroupid='false-group', + userid=user_name) + response = api_call(self.app, params) + + expected = 'user group `%s` does not exist' % 'false-group' + assert_error(id_, expected, given=response.body) + + @mock.patch.object(UserGroupModel, 'add_user_to_group', crash) + def test_api_add_user_to_user_group_exception_occurred(self, user_util): + group = user_util.create_user_group() + user = user_util.create_user() + group_name = group.users_group_name + user_name = user.username + id_, params = build_data( + self.apikey, 'add_user_to_user_group', + usergroupid=group_name, userid=user_name) + response = api_call(self.app, params) + + expected = 'failed to add member to user group `%s`' % (group_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_api.py b/rhodecode/api/tests/test_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_api.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.api.utils import Optional, OAttr +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApi(object): + maxDiff = None + + def test_Optional_object(self): + + option1 = Optional(None) + assert '<Optional:%s>' % (None,) == repr(option1) + assert option1() is None + + assert 1 == Optional.extract(Optional(1)) + assert 'example' == Optional.extract('example') + + def test_Optional_OAttr(self): + option1 = Optional(OAttr('apiuser')) + assert 'apiuser' == Optional.extract(option1) + + def test_OAttr_object(self): + oattr1 = OAttr('apiuser') + assert '<OptionalAttr:apiuser>' == repr(oattr1) + assert oattr1() == oattr1 + + def test_api_wrong_key(self): + id_, params = build_data('trololo', 'get_user') + response = api_call(self.app, params) + + expected = 'Invalid API KEY' + assert_error(id_, expected, given=response.body) + + def test_api_missing_non_optional_param(self): + id_, params = build_data(self.apikey, 'get_repo') + response = api_call(self.app, params) + + expected = 'Missing non optional `repoid` arg in JSON DATA' + assert_error(id_, expected, given=response.body) + + def test_api_missing_non_optional_param_args_null(self): + id_, params = build_data(self.apikey, 'get_repo') + params = params.replace('"args": {}', '"args": null') + response = api_call(self.app, params) + + expected = 'Missing non optional `repoid` arg in JSON DATA' + assert_error(id_, expected, given=response.body) + + def test_api_missing_non_optional_param_args_bad(self): + id_, params = build_data(self.apikey, 'get_repo') + params = params.replace('"args": {}', '"args": 1') + response = api_call(self.app, params) + + expected = 'Missing non optional `repoid` arg in JSON DATA' + assert_error(id_, expected, given=response.body) + + def test_api_non_existing_method(self, request): + id_, params = build_data(self.apikey, 'not_existing', args='xx') + response = api_call(self.app, params) + expected = 'No such method: not_existing' + assert_error(id_, expected, given=response.body) + + def test_api_disabled_user(self, request): + + def set_active(active): + from rhodecode.model.db import Session, User + user = User.get_by_auth_token(self.apikey) + user.active = active + Session().add(user) + Session().commit() + + request.addfinalizer(lambda: set_active(True)) + + set_active(False) + id_, params = build_data(self.apikey, 'test', args='xx') + response = api_call(self.app, params) + expected = 'Request from this user not allowed' + assert_error(id_, expected, given=response.body) + + def test_api_args_is_null(self): + __, params = build_data(self.apikey, 'get_users', ) + params = params.replace('"args": {}', '"args": null') + response = api_call(self.app, params) + assert response.status == '200 OK' + + def test_api_args_is_bad(self): + __, params = build_data(self.apikey, 'get_users', ) + params = params.replace('"args": {}', '"args": 1') + response = api_call(self.app, params) + assert response.status == '200 OK' + + def test_api_args_different_args(self): + import string + expected = { + 'ascii_letters': string.ascii_letters, + 'ws': string.whitespace, + 'printables': string.printable + } + id_, params = build_data(self.apikey, 'test', args=expected) + response = api_call(self.app, params) + assert response.status == '200 OK' + assert_ok(id_, expected, response.body) diff --git a/rhodecode/api/tests/test_close_pull_request.py b/rhodecode/api/tests/test_close_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_close_pull_request.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import UserLog +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestClosePullRequest(object): + @pytest.mark.backends("git", "hg") + def test_api_close_pull_request(self, pr_util): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + author = pull_request.user_id + repo = pull_request.target_repo.repo_id + id_, params = build_data( + self.apikey, 'close_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id) + response = api_call(self.app, params) + expected = { + 'pull_request_id': pull_request_id, + 'closed': True, + } + assert_ok(id_, expected, response.body) + action = 'user_closed_pull_request:%d' % pull_request_id + journal = UserLog.query()\ + .filter(UserLog.user_id == author)\ + .filter(UserLog.repository_id == repo)\ + .filter(UserLog.action == action)\ + .all() + assert len(journal) == 1 + + @pytest.mark.backends("git", "hg") + def test_api_close_pull_request_already_closed_error(self, pr_util): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + pull_request_repo = pull_request.target_repo.repo_name + PullRequestModel().close_pull_request( + pull_request, pull_request.author) + id_, params = build_data( + self.apikey, 'close_pull_request', + repoid=pull_request_repo, pullrequestid=pull_request_id) + response = api_call(self.app, params) + + expected = 'pull request `%s` is already closed' % pull_request_id + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_close_pull_request_repo_error(self): + id_, params = build_data( + self.apikey, 'close_pull_request', + repoid=666, pullrequestid=1) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_close_pull_request_non_admin_with_userid_error(self, + pr_util): + pull_request = pr_util.create_pull_request() + id_, params = build_data( + self.apikey_regular, 'close_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_close_pull_request_no_perms_to_close( + self, user_util, pr_util): + user = user_util.create_user() + pull_request = pr_util.create_pull_request() + + id_, params = build_data( + user.api_key, 'close_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id,) + response = api_call(self.app, params) + + expected = ('pull request `%s` close failed, ' + 'no permission to close.') % pull_request.pull_request_id + + response_json = response.json['error'] + assert response_json == expected diff --git a/rhodecode/api/tests/test_comment_commit.py b/rhodecode/api/tests/test_comment_commit.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_comment_commit.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import ChangesetStatus +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCommentCommit(object): + def test_api_comment_commit_on_empty_repo(self, backend): + repo = backend.create_repo() + id_, params = build_data( + self.apikey, 'comment_commit', repoid=repo.repo_name, + commit_id='tip', message='message', status_change=None) + response = api_call(self.app, params) + expected = 'failed to set comment on repository `%s`' % repo.repo_name + assert_error(id_, expected, given=response.body) + + @pytest.mark.parametrize("status_change, message, commit_id", [ + (None, 'Hallo', 'tip'), + (ChangesetStatus.STATUS_APPROVED, 'Approved', 'tip'), + (ChangesetStatus.STATUS_REJECTED, 'Rejected', 'tip'), + ]) + def test_api_comment_commit( + self, backend, status_change, message, commit_id, + no_notifications): + id_, params = build_data( + self.apikey, 'comment_commit', repoid=backend.repo_name, + commit_id=commit_id, message=message, status=status_change) + response = api_call(self.app, params) + repo = backend.repo.scm_instance() + expected = { + 'msg': 'Commented on commit `%s` for repository `%s`' % ( + repo.get_changeset().raw_id, backend.repo_name), + 'status_change': status_change, + 'success': True + } + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_comment_pull_request.py b/rhodecode/api/tests/test_comment_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_comment_pull_request.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.db import UserLog +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCommentPullRequest(object): + finalizers = [] + + def teardown_method(self, method): + if self.finalizers: + for finalizer in self.finalizers: + finalizer() + self.finalizers = [] + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request(self, pr_util, no_notifications): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + author = pull_request.user_id + repo = pull_request.target_repo.repo_id + id_, params = build_data( + self.apikey, 'comment_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + message='test message') + response = api_call(self.app, params) + pull_request = PullRequestModel().get(pull_request.pull_request_id) + + comments = ChangesetCommentsModel().get_comments( + pull_request.target_repo.repo_id, pull_request=pull_request) + + expected = { + 'pull_request_id': pull_request.pull_request_id, + 'comment_id': comments[-1].comment_id, + 'status': None + } + assert_ok(id_, expected, response.body) + + action = 'user_commented_pull_request:%d' % pull_request_id + journal = UserLog.query()\ + .filter(UserLog.user_id == author)\ + .filter(UserLog.repository_id == repo)\ + .filter(UserLog.action == action)\ + .all() + assert len(journal) == 2 + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request_change_status( + self, pr_util, no_notifications): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + id_, params = build_data( + self.apikey, 'comment_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + status='rejected') + response = api_call(self.app, params) + pull_request = PullRequestModel().get(pull_request_id) + + comments = ChangesetCommentsModel().get_comments( + pull_request.target_repo.repo_id, pull_request=pull_request) + expected = { + 'pull_request_id': pull_request.pull_request_id, + 'comment_id': comments[-1].comment_id, + 'status': 'rejected' + } + assert_ok(id_, expected, response.body) + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request_missing_params_error(self, pr_util): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + pull_request_repo = pull_request.target_repo.repo_name + id_, params = build_data( + self.apikey, 'comment_pull_request', + repoid=pull_request_repo, + pullrequestid=pull_request_id) + response = api_call(self.app, params) + + expected = 'message and status parameter missing' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request_unknown_status_error(self, pr_util): + pull_request = pr_util.create_pull_request() + pull_request_id = pull_request.pull_request_id + pull_request_repo = pull_request.target_repo.repo_name + id_, params = build_data( + self.apikey, 'comment_pull_request', + repoid=pull_request_repo, + pullrequestid=pull_request_id, + status='42') + response = api_call(self.app, params) + + expected = 'unknown comment status`42`' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request_repo_error(self): + id_, params = build_data( + self.apikey, 'comment_pull_request', + repoid=666, pullrequestid=1) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_comment_pull_request_non_admin_with_userid_error( + self, pr_util): + pull_request = pr_util.create_pull_request() + id_, params = build_data( + self.apikey_regular, 'comment_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_create_gist.py b/rhodecode/api/tests/test_create_gist.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_gist.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.db import Gist +from rhodecode.model.gist import GistModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) +from rhodecode.tests.fixture import Fixture + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiCreateGist(object): + @pytest.mark.parametrize("lifetime, gist_type, gist_acl_level", [ + (10, Gist.GIST_PUBLIC, Gist.ACL_LEVEL_PUBLIC), + (20, Gist.GIST_PUBLIC, Gist.ACL_LEVEL_PRIVATE), + (40, Gist.GIST_PRIVATE, Gist.ACL_LEVEL_PUBLIC), + (80, Gist.GIST_PRIVATE, Gist.ACL_LEVEL_PRIVATE), + ]) + def test_api_create_gist(self, lifetime, gist_type, gist_acl_level): + id_, params = build_data( + self.apikey_regular, 'create_gist', + lifetime=lifetime, + description='foobar-gist', + gist_type=gist_type, + acl_level=gist_acl_level, + files={'foobar': {'content': 'foo'}}) + response = api_call(self.app, params) + response_json = response.json + gist = response_json['result']['gist'] + expected = { + 'gist': { + 'access_id': gist['access_id'], + 'created_on': gist['created_on'], + 'modified_at': gist['modified_at'], + 'description': 'foobar-gist', + 'expires': gist['expires'], + 'gist_id': gist['gist_id'], + 'type': gist_type, + 'url': gist['url'], + # content is empty since we don't show it here + 'content': None, + 'acl_level': gist_acl_level, + }, + 'msg': 'created new gist' + } + try: + assert_ok(id_, expected, given=response.body) + finally: + Fixture().destroy_gists() + + @mock.patch.object(GistModel, 'create', crash) + def test_api_create_gist_exception_occurred(self): + id_, params = build_data(self.apikey_regular, 'create_gist', files={}) + response = api_call(self.app, params) + expected = 'failed to create gist' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_create_pull_request.py b/rhodecode/api/tests/test_create_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_pull_request.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import User +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.model.repo import RepoModel +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN +from rhodecode.api.tests.utils import build_data, api_call, assert_error + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCreatePullRequestApi(object): + finalizers = [] + + def teardown_method(self, method): + if self.finalizers: + for finalizer in self.finalizers: + finalizer() + self.finalizers = [] + + def test_create_with_wrong_data(self): + required_data = { + 'source_repo': 'tests/source_repo', + 'target_repo': 'tests/target_repo', + 'source_ref': 'branch:default:initial', + 'target_ref': 'branch:default:new-feature', + 'title': 'Test PR 1' + } + for key in required_data: + data = required_data.copy() + data.pop(key) + id_, params = build_data( + self.apikey, 'create_pull_request', **data) + response = api_call(self.app, params) + + expected = 'Missing non optional `{}` arg in JSON DATA'.format(key) + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_create_with_correct_data(self, backend): + data = self._prepare_data(backend) + RepoModel().revoke_user_permission( + self.source.repo_name, User.DEFAULT_USER) + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = "Created new pull request `{title}`".format( + title=data['title']) + result = response.json + assert result['result']['msg'] == expected_message + pull_request_id = result['result']['pull_request_id'] + pull_request = PullRequestModel().get(pull_request_id) + assert pull_request.title == data['title'] + assert pull_request.description == data['description'] + assert pull_request.source_ref == data['source_ref'] + assert pull_request.target_ref == data['target_ref'] + assert pull_request.source_repo.repo_name == data['source_repo'] + assert pull_request.target_repo.repo_name == data['target_repo'] + assert pull_request.revisions == [self.commit_ids['change']] + assert pull_request.reviewers == [] + + @pytest.mark.backends("git", "hg") + def test_create_with_empty_description(self, backend): + data = self._prepare_data(backend) + data.pop('description') + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = "Created new pull request `{title}`".format( + title=data['title']) + result = response.json + assert result['result']['msg'] == expected_message + pull_request_id = result['result']['pull_request_id'] + pull_request = PullRequestModel().get(pull_request_id) + assert pull_request.description == '' + + @pytest.mark.backends("git", "hg") + def test_create_with_reviewers_specified_by_names( + self, backend, no_notifications): + data = self._prepare_data(backend) + reviewers = [TEST_USER_REGULAR_LOGIN, TEST_USER_ADMIN_LOGIN] + data['reviewers'] = reviewers + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + + expected_message = "Created new pull request `{title}`".format( + title=data['title']) + result = response.json + assert result['result']['msg'] == expected_message + pull_request_id = result['result']['pull_request_id'] + pull_request = PullRequestModel().get(pull_request_id) + actual_reviewers = [r.user.username for r in pull_request.reviewers] + assert sorted(actual_reviewers) == sorted(reviewers) + + @pytest.mark.backends("git", "hg") + def test_create_with_reviewers_specified_by_ids( + self, backend, no_notifications): + data = self._prepare_data(backend) + reviewer_names = [TEST_USER_REGULAR_LOGIN, TEST_USER_ADMIN_LOGIN] + reviewers = [ + UserModel().get_by_username(n).user_id for n in reviewer_names] + data['reviewers'] = reviewers + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + + expected_message = "Created new pull request `{title}`".format( + title=data['title']) + result = response.json + assert result['result']['msg'] == expected_message + pull_request_id = result['result']['pull_request_id'] + pull_request = PullRequestModel().get(pull_request_id) + actual_reviewers = [r.user.username for r in pull_request.reviewers] + assert sorted(actual_reviewers) == sorted(reviewer_names) + + @pytest.mark.backends("git", "hg") + def test_create_fails_when_the_reviewer_is_not_found(self, backend): + data = self._prepare_data(backend) + reviewers = ['somebody'] + data['reviewers'] = reviewers + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'user `somebody` does not exist' + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_cannot_create_with_reviewers_in_wrong_format(self, backend): + data = self._prepare_data(backend) + reviewers = ','.join([TEST_USER_REGULAR_LOGIN, TEST_USER_ADMIN_LOGIN]) + data['reviewers'] = reviewers + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'reviewers should be specified as a list' + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_create_with_no_commit_hashes(self, backend): + data = self._prepare_data(backend) + expected_source_ref = data['source_ref'] + expected_target_ref = data['target_ref'] + data['source_ref'] = 'branch:{}'.format(backend.default_branch_name) + data['target_ref'] = 'branch:{}'.format(backend.default_branch_name) + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = "Created new pull request `{title}`".format( + title=data['title']) + result = response.json + assert result['result']['msg'] == expected_message + pull_request_id = result['result']['pull_request_id'] + pull_request = PullRequestModel().get(pull_request_id) + assert pull_request.source_ref == expected_source_ref + assert pull_request.target_ref == expected_target_ref + + @pytest.mark.backends("git", "hg") + @pytest.mark.parametrize("data_key", ["source_repo", "target_repo"]) + def test_create_fails_with_wrong_repo(self, backend, data_key): + repo_name = 'fake-repo' + data = self._prepare_data(backend) + data[data_key] = repo_name + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'repository `{}` does not exist'.format(repo_name) + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"]) + def test_create_fails_with_non_existing_branch(self, backend, data_key): + branch_name = 'test-branch' + data = self._prepare_data(backend) + data[data_key] = "branch:{}".format(branch_name) + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'The specified branch `{}` does not exist'.format( + branch_name) + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"]) + def test_create_fails_with_ref_in_a_wrong_format(self, backend, data_key): + data = self._prepare_data(backend) + ref = 'stange-ref' + data[data_key] = ref + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = ( + 'Ref `{ref}` given in a wrong format. Please check the API' + ' documentation for more details'.format(ref=ref)) + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"]) + def test_create_fails_with_non_existing_ref(self, backend, data_key): + commit_id = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa10' + ref = self._get_full_ref(backend, commit_id) + data = self._prepare_data(backend) + data[data_key] = ref + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'Ref `{}` does not exist'.format(ref) + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_create_fails_when_no_revisions(self, backend): + data = self._prepare_data(backend, source_head='initial') + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'no commits found' + assert_error(id_, expected_message, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_create_fails_when_no_permissions(self, backend): + data = self._prepare_data(backend) + RepoModel().revoke_user_permission( + self.source.repo_name, User.DEFAULT_USER) + RepoModel().revoke_user_permission( + self.source.repo_name, self.test_user) + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + response = api_call(self.app, params) + expected_message = 'repository `{}` does not exist'.format( + self.source.repo_name) + assert_error(id_, expected_message, given=response.body) + + def _prepare_data( + self, backend, source_head='change', target_head='initial'): + commits = [ + {'message': 'initial'}, + {'message': 'change'}, + {'message': 'new-feature', 'parents': ['initial']}, + ] + self.commit_ids = backend.create_master_repo(commits) + self.source = backend.create_repo(heads=[source_head]) + self.target = backend.create_repo(heads=[target_head]) + data = { + 'source_repo': self.source.repo_name, + 'target_repo': self.target.repo_name, + 'source_ref': self._get_full_ref( + backend, self.commit_ids[source_head]), + 'target_ref': self._get_full_ref( + backend, self.commit_ids[target_head]), + 'title': 'Test PR 1', + 'description': 'Test' + } + RepoModel().grant_user_permission( + self.source.repo_name, self.TEST_USER_LOGIN, 'repository.read') + return data + + def _get_full_ref(self, backend, commit_id): + return 'branch:{branch}:{commit_id}'.format( + branch=backend.default_branch_name, commit_id=commit_id) diff --git a/rhodecode/api/tests/test_create_repo.py b/rhodecode/api/tests/test_create_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_repo.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import json + +import mock +import pytest + +from rhodecode.lib.vcs import settings +from rhodecode.model.repo import RepoModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) +from rhodecode.tests.fixture import Fixture + + +fixture = Fixture() + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCreateRepo(object): + def test_api_create_repo(self, backend): + repo_name = 'api-repo-1' + id_, params = build_data( + self.apikey, + 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias, + ) + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(repo_name) + + assert repo is not None + ret = { + 'msg': 'Created new repository `%s`' % (repo_name,), + 'success': True, + 'task': None, + } + expected = ret + assert_ok(id_, expected, given=response.body) + + id_, params = build_data(self.apikey, 'get_repo', repoid=repo_name) + response = api_call(self.app, params) + body = json.loads(response.body) + + assert body['result']['enable_downloads'] is False + assert body['result']['enable_locking'] is False + assert body['result']['enable_statistics'] is False + + fixture.destroy_repo(repo_name) + + def test_api_create_restricted_repo_type(self, backend): + repo_name = 'api-repo-type-{0}'.format(backend.alias) + id_, params = build_data( + self.apikey, + 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias, + ) + git_backend = settings.BACKENDS['git'] + with mock.patch( + 'rhodecode.lib.vcs.settings.BACKENDS', {'git': git_backend}): + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(repo_name) + + if backend.alias == 'git': + assert repo is not None + expected = { + 'msg': 'Created new repository `{0}`'.format(repo_name,), + 'success': True, + 'task': None, + } + assert_ok(id_, expected, given=response.body) + else: + assert repo is None + + fixture.destroy_repo(repo_name) + + def test_api_create_repo_with_booleans(self, backend): + repo_name = 'api-repo-2' + id_, params = build_data( + self.apikey, + 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias, + enable_statistics=True, + enable_locking=True, + enable_downloads=True + ) + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(repo_name) + + assert repo is not None + ret = { + 'msg': 'Created new repository `%s`' % (repo_name,), + 'success': True, + 'task': None, + } + expected = ret + assert_ok(id_, expected, given=response.body) + + id_, params = build_data(self.apikey, 'get_repo', repoid=repo_name) + response = api_call(self.app, params) + body = json.loads(response.body) + + assert body['result']['enable_downloads'] is True + assert body['result']['enable_locking'] is True + assert body['result']['enable_statistics'] is True + + fixture.destroy_repo(repo_name) + + def test_api_create_repo_in_group(self, backend): + repo_group_name = 'my_gr' + # create the parent + fixture.create_repo_group(repo_group_name) + + repo_name = '%s/api-repo-gr' % (repo_group_name,) + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias,) + response = api_call(self.app, params) + repo = RepoModel().get_by_repo_name(repo_name) + assert repo is not None + assert repo.group is not None + + ret = { + 'msg': 'Created new repository `%s`' % (repo_name,), + 'success': True, + 'task': None, + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo(repo_name) + fixture.destroy_repo_group(repo_group_name) + + def test_api_create_repo_unknown_owner(self, backend): + repo_name = 'api-repo-2' + owner = 'i-dont-exist' + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=repo_name, + owner=owner, + repo_type=backend.alias) + response = api_call(self.app, params) + expected = 'user `%s` does not exist' % (owner,) + assert_error(id_, expected, given=response.body) + + def test_api_create_repo_dont_specify_owner(self, backend): + repo_name = 'api-repo-3' + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=repo_name, + repo_type=backend.alias) + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(repo_name) + assert repo is not None + ret = { + 'msg': 'Created new repository `%s`' % (repo_name,), + 'success': True, + 'task': None, + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo(repo_name) + + def test_api_create_repo_by_non_admin(self, backend): + repo_name = 'api-repo-4' + id_, params = build_data( + self.apikey_regular, 'create_repo', + repo_name=repo_name, + repo_type=backend.alias) + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(repo_name) + assert repo is not None + ret = { + 'msg': 'Created new repository `%s`' % (repo_name,), + 'success': True, + 'task': None, + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo(repo_name) + + def test_api_create_repo_by_non_admin_specify_owner(self, backend): + repo_name = 'api-repo-5' + owner = 'i-dont-exist' + id_, params = build_data( + self.apikey_regular, 'create_repo', + repo_name=repo_name, + repo_type=backend.alias, + owner=owner) + response = api_call(self.app, params) + + expected = 'Only RhodeCode admin can specify `owner` param' + assert_error(id_, expected, given=response.body) + fixture.destroy_repo(repo_name) + + def test_api_create_repo_exists(self, backend): + repo_name = backend.repo_name + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias,) + response = api_call(self.app, params) + expected = "repo `%s` already exist" % (repo_name,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'create', crash) + def test_api_create_repo_exception_occurred(self, backend): + repo_name = 'api-repo-6' + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=repo_name, + owner=TEST_USER_ADMIN_LOGIN, + repo_type=backend.alias,) + response = api_call(self.app, params) + expected = 'failed to create repository `%s`' % (repo_name,) + assert_error(id_, expected, given=response.body) + + def test_create_repo_with_extra_slashes_in_name(self, backend, user_util): + existing_repo_group = user_util.create_repo_group() + dirty_repo_name = '//{}/repo_name//'.format( + existing_repo_group.group_name) + cleaned_repo_name = '{}/repo_name'.format( + existing_repo_group.group_name) + + id_, params = build_data( + self.apikey, 'create_repo', + repo_name=dirty_repo_name, + repo_type=backend.alias, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + repo = RepoModel().get_by_repo_name(cleaned_repo_name) + assert repo is not None + + expected = { + 'msg': 'Created new repository `%s`' % (cleaned_repo_name,), + 'success': True, + 'task': None, + } + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo(cleaned_repo_name) diff --git a/rhodecode/api/tests/test_create_repo_group.py b/rhodecode/api/tests/test_create_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_repo_group.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) +from rhodecode.tests.fixture import Fixture + + +fixture = Fixture() + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCreateRepoGroup(object): + def test_api_create_repo_group(self): + repo_group_name = 'api-repo-group' + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=repo_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is not None + ret = { + 'msg': 'Created new repo group `%s`' % (repo_group_name,), + 'repo_group': repo_group.get_api_data() + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo_group(repo_group_name) + + def test_api_create_repo_group_regular_user(self): + repo_group_name = 'api-repo-group' + + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + usr.inherit_default_permissions = False + Session().add(usr) + UserModel().grant_perm( + self.TEST_USER_LOGIN, 'hg.repogroup.create.true') + Session().commit() + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + + id_, params = build_data( + self.apikey_regular, 'create_repo_group', + group_name=repo_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is not None + ret = { + 'msg': 'Created new repo group `%s`' % (repo_group_name,), + 'repo_group': repo_group.get_api_data() + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo_group(repo_group_name) + UserModel().revoke_perm( + self.TEST_USER_LOGIN, 'hg.repogroup.create.true') + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + usr.inherit_default_permissions = True + Session().add(usr) + Session().commit() + + def test_api_create_repo_group_regular_user_no_permission(self): + repo_group_name = 'api-repo-group' + + id_, params = build_data( + self.apikey_regular, 'create_repo_group', + group_name=repo_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + + expected = "Access was denied to this resource." + assert_error(id_, expected, given=response.body) + + def test_api_create_repo_group_in_another_group(self): + repo_group_name = 'api-repo-group' + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + # create the parent + fixture.create_repo_group(repo_group_name) + + full_repo_group_name = repo_group_name+'/'+repo_group_name + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=full_repo_group_name, + owner=TEST_USER_ADMIN_LOGIN, + copy_permissions=True) + response = api_call(self.app, params) + + repo_group = RepoGroupModel.cls.get_by_group_name(full_repo_group_name) + assert repo_group is not None + ret = { + 'msg': 'Created new repo group `%s`' % (full_repo_group_name,), + 'repo_group': repo_group.get_api_data() + } + expected = ret + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo_group(full_repo_group_name) + fixture.destroy_repo_group(repo_group_name) + + def test_api_create_repo_group_in_another_group_not_existing(self): + repo_group_name = 'api-repo-group-no' + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + + full_repo_group_name = repo_group_name+'/'+repo_group_name + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=full_repo_group_name, + owner=TEST_USER_ADMIN_LOGIN, + copy_permissions=True) + response = api_call(self.app, params) + expected = 'repository group `%s` does not exist' % (repo_group_name,) + assert_error(id_, expected, given=response.body) + + def test_api_create_repo_group_that_exists(self): + repo_group_name = 'api-repo-group' + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + + fixture.create_repo_group(repo_group_name) + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=repo_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + expected = 'repo group `%s` already exist' % (repo_group_name,) + assert_error(id_, expected, given=response.body) + fixture.destroy_repo_group(repo_group_name) + + @mock.patch.object(RepoGroupModel, 'create', crash) + def test_api_create_repo_group_exception_occurred(self): + repo_group_name = 'api-repo-group' + + repo_group = RepoGroupModel.cls.get_by_group_name(repo_group_name) + assert repo_group is None + + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=repo_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + expected = 'failed to create repo group `%s`' % (repo_group_name,) + assert_error(id_, expected, given=response.body) + + def test_create_group_with_extra_slashes_in_name(self, user_util): + existing_repo_group = user_util.create_repo_group() + dirty_group_name = '//{}//group2//'.format( + existing_repo_group.group_name) + cleaned_group_name = '{}/group2'.format( + existing_repo_group.group_name) + + id_, params = build_data( + self.apikey, 'create_repo_group', + group_name=dirty_group_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + repo_group = RepoGroupModel.cls.get_by_group_name(cleaned_group_name) + expected = { + 'msg': 'Created new repo group `%s`' % (cleaned_group_name,), + 'repo_group': repo_group.get_api_data() + } + assert_ok(id_, expected, given=response.body) + fixture.destroy_repo_group(cleaned_group_name) diff --git a/rhodecode/api/tests/test_create_user.py b/rhodecode/api/tests/test_create_user.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_user.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.lib.auth import check_password +from rhodecode.model.user import UserModel +from rhodecode.tests import ( + TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL) +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, jsonify, crash) +from rhodecode.tests.fixture import Fixture + + +# TODO: mikhail: remove fixture from here +fixture = Fixture() + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCreateUser(object): + def test_api_create_existing_user(self): + id_, params = build_data( + self.apikey, 'create_user', + username=TEST_USER_ADMIN_LOGIN, + email='test@foo.com', + password='trololo') + response = api_call(self.app, params) + + expected = "user `%s` already exist" % (TEST_USER_ADMIN_LOGIN,) + assert_error(id_, expected, given=response.body) + + def test_api_create_user_with_existing_email(self): + id_, params = build_data( + self.apikey, 'create_user', + username=TEST_USER_ADMIN_LOGIN + 'new', + email=TEST_USER_REGULAR_EMAIL, + password='trololo') + response = api_call(self.app, params) + + expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,) + assert_error(id_, expected, given=response.body) + + def test_api_create_user(self): + username = 'test_new_api_user' + email = username + "@foo.com" + + id_, params = build_data( + self.apikey, 'create_user', + username=username, + email=email, + password='example') + response = api_call(self.app, params) + + usr = UserModel().get_by_username(username) + ret = { + 'msg': 'created new user `%s`' % (username,), + 'user': jsonify(usr.get_api_data(include_secrets=True)), + } + try: + expected = ret + assert check_password('example', usr.password) + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_user(usr.user_id) + + def test_api_create_user_without_password(self): + username = 'test_new_api_user_passwordless' + email = username + "@foo.com" + + id_, params = build_data( + self.apikey, 'create_user', + username=username, + email=email) + response = api_call(self.app, params) + + usr = UserModel().get_by_username(username) + ret = { + 'msg': 'created new user `%s`' % (username,), + 'user': jsonify(usr.get_api_data(include_secrets=True)), + } + try: + expected = ret + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_user(usr.user_id) + + def test_api_create_user_with_extern_name(self): + username = 'test_new_api_user_passwordless' + email = username + "@foo.com" + + id_, params = build_data( + self.apikey, 'create_user', + username=username, + email=email, extern_name='rhodecode') + response = api_call(self.app, params) + + usr = UserModel().get_by_username(username) + ret = { + 'msg': 'created new user `%s`' % (username,), + 'user': jsonify(usr.get_api_data(include_secrets=True)), + } + try: + expected = ret + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_user(usr.user_id) + + def test_api_create_user_with_password_change(self): + username = 'test_new_api_user_password_change' + email = username + "@foo.com" + + id_, params = build_data( + self.apikey, 'create_user', + username=username, + email=email, extern_name='rhodecode', + force_password_change=True) + response = api_call(self.app, params) + + usr = UserModel().get_by_username(username) + ret = { + 'msg': 'created new user `%s`' % (username,), + 'user': jsonify(usr.get_api_data(include_secrets=True)), + } + try: + expected = ret + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_user(usr.user_id) + + @mock.patch.object(UserModel, 'create_or_update', crash) + def test_api_create_user_when_exception_happened(self): + + username = 'test_new_api_user' + email = username + "@foo.com" + + id_, params = build_data( + self.apikey, 'create_user', + username=username, + email=email, + password='trololo') + response = api_call(self.app, params) + expected = 'failed to create user `%s`' % (username,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_create_user_group.py b/rhodecode/api/tests/test_create_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_create_user_group.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.user import UserModel +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash, jsonify) +from rhodecode.tests.fixture import Fixture + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCreateUserGroup(object): + fixture = Fixture() + + def test_api_create_user_group(self): + group_name = 'some_new_group' + id_, params = build_data( + self.apikey, 'create_user_group', group_name=group_name) + response = api_call(self.app, params) + + ret = { + 'msg': 'created new user group `%s`' % (group_name,), + 'user_group': jsonify( + UserGroupModel() + .get_by_name(group_name) + .get_api_data() + ) + } + expected = ret + assert_ok(id_, expected, given=response.body) + self.fixture.destroy_user_group(group_name) + + def test_api_create_user_group_regular_user(self): + group_name = 'some_new_group' + + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + usr.inherit_default_permissions = False + Session().add(usr) + UserModel().grant_perm( + self.TEST_USER_LOGIN, 'hg.usergroup.create.true') + Session().commit() + + id_, params = build_data( + self.apikey_regular, 'create_user_group', group_name=group_name) + response = api_call(self.app, params) + + expected = { + 'msg': 'created new user group `%s`' % (group_name,), + 'user_group': jsonify( + UserGroupModel() + .get_by_name(group_name) + .get_api_data() + ) + } + try: + assert_ok(id_, expected, given=response.body) + finally: + self.fixture.destroy_user_group(group_name) + UserModel().revoke_perm( + self.TEST_USER_LOGIN, 'hg.usergroup.create.true') + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + usr.inherit_default_permissions = True + Session().add(usr) + Session().commit() + + def test_api_create_user_group_regular_user_no_permission(self): + group_name = 'some_new_group' + id_, params = build_data( + self.apikey_regular, 'create_user_group', group_name=group_name) + response = api_call(self.app, params) + expected = "Access was denied to this resource." + assert_error(id_, expected, given=response.body) + + def test_api_create_user_group_that_exist(self, user_util): + group = user_util.create_user_group() + group_name = group.users_group_name + + id_, params = build_data( + self.apikey, 'create_user_group', group_name=group_name) + response = api_call(self.app, params) + + expected = "user group `%s` already exist" % (group_name,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(UserGroupModel, 'create', crash) + def test_api_create_user_group_exception_occurred(self): + group_name = 'exception_happens' + id_, params = build_data( + self.apikey, 'create_user_group', group_name=group_name) + response = api_call(self.app, params) + + expected = 'failed to create group `%s`' % (group_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_delete_gist.py b/rhodecode/api/tests/test_delete_gist.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_delete_gist.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.gist import GistModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiDeleteGist(object): + def test_api_delete_gist(self, gist_util): + gist_id = gist_util.create_gist().gist_access_id + id_, params = build_data(self.apikey, 'delete_gist', gistid=gist_id) + response = api_call(self.app, params) + expected = {'gist': None, 'msg': 'deleted gist ID:%s' % (gist_id,)} + assert_ok(id_, expected, given=response.body) + + def test_api_delete_gist_regular_user(self, gist_util): + gist_id = gist_util.create_gist( + owner=self.TEST_USER_LOGIN).gist_access_id + id_, params = build_data( + self.apikey_regular, 'delete_gist', gistid=gist_id) + response = api_call(self.app, params) + expected = {'gist': None, 'msg': 'deleted gist ID:%s' % (gist_id,)} + assert_ok(id_, expected, given=response.body) + + def test_api_delete_gist_regular_user_no_permission(self, gist_util): + gist_id = gist_util.create_gist().gist_access_id + id_, params = build_data( + self.apikey_regular, 'delete_gist', gistid=gist_id) + response = api_call(self.app, params) + expected = 'gist `%s` does not exist' % (gist_id,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(GistModel, 'delete', crash) + def test_api_delete_gist_exception_occurred(self, gist_util): + gist_id = gist_util.create_gist().gist_access_id + id_, params = build_data(self.apikey, 'delete_gist', gistid=gist_id) + response = api_call(self.app, params) + expected = 'failed to delete gist ID:%s' % (gist_id,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_delete_repo.py b/rhodecode/api/tests/test_delete_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_delete_repo.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiDeleteRepo(object): + def test_api_delete_repo(self, backend): + repo = backend.create_repo() + + id_, params = build_data( + self.apikey, 'delete_repo', repoid=repo.repo_name, ) + response = api_call(self.app, params) + + expected = { + 'msg': 'Deleted repository `%s`' % (repo.repo_name,), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + def test_api_delete_repo_by_non_admin(self, backend, user_regular): + repo = backend.create_repo(cur_user=user_regular.username) + id_, params = build_data( + user_regular.api_key, 'delete_repo', repoid=repo.repo_name, ) + response = api_call(self.app, params) + + expected = { + 'msg': 'Deleted repository `%s`' % (repo.repo_name,), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + def test_api_delete_repo_by_non_admin_no_permission( + self, backend, user_regular): + repo = backend.create_repo() + id_, params = build_data( + user_regular.api_key, 'delete_repo', repoid=repo.repo_name, ) + response = api_call(self.app, params) + expected = 'repository `%s` does not exist' % (repo.repo_name) + assert_error(id_, expected, given=response.body) + + def test_api_delete_repo_exception_occurred(self, backend): + repo = backend.create_repo() + id_, params = build_data( + self.apikey, 'delete_repo', repoid=repo.repo_name, ) + with mock.patch.object(RepoModel, 'delete', crash): + response = api_call(self.app, params) + expected = 'failed to delete repository `%s`' % ( + repo.repo_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_delete_repo_group.py b/rhodecode/api/tests/test_delete_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_delete_repo_group.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiDeleteRepoGroup(object): + def test_api_delete_repo_group(self, user_util): + repo_group = user_util.create_repo_group(auto_cleanup=False) + repo_group_name = repo_group.group_name + repo_group_id = repo_group.group_id + id_, params = build_data( + self.apikey, 'delete_repo_group', repogroupid=repo_group_name, ) + response = api_call(self.app, params) + + ret = { + 'msg': 'deleted repo group ID:%s %s' % ( + repo_group_id, repo_group_name + ), + 'repo_group': None + } + expected = ret + assert_ok(id_, expected, given=response.body) + gr = RepoGroupModel()._get_repo_group(repo_group_name) + assert gr is None + + def test_api_delete_repo_group_regular_user(self, user_util): + repo_group = user_util.create_repo_group(auto_cleanup=False) + repo_group_name = repo_group.group_name + repo_group_id = repo_group.group_id + + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user_util.grant_user_permission_to_repo_group( + repo_group, user, 'group.admin') + + id_, params = build_data( + self.apikey, 'delete_repo_group', repogroupid=repo_group_name, ) + response = api_call(self.app, params) + + ret = { + 'msg': 'deleted repo group ID:%s %s' % ( + repo_group_id, repo_group_name + ), + 'repo_group': None + } + expected = ret + assert_ok(id_, expected, given=response.body) + gr = RepoGroupModel()._get_repo_group(repo_group_name) + assert gr is None + + def test_api_delete_repo_group_regular_user_no_permission(self, user_util): + repo_group = user_util.create_repo_group() + repo_group_name = repo_group.group_name + + id_, params = build_data( + self.apikey_regular, 'delete_repo_group', + repogroupid=repo_group_name, ) + response = api_call(self.app, params) + + expected = 'repository group `%s` does not exist' % ( + repo_group_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_delete_user.py b/rhodecode/api/tests/test_delete_user.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_delete_user.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestDeleteUser(object): + def test_api_delete_user(self, user_util): + usr = user_util.create_user(auto_cleanup=False) + + username = usr.username + usr_id = usr.user_id + + id_, params = build_data(self.apikey, 'delete_user', userid=username) + response = api_call(self.app, params) + + ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username), + 'user': None} + expected = ret + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(UserModel, 'delete', crash) + def test_api_delete_user_when_exception_happened(self, user_util): + usr = user_util.create_user() + username = usr.username + + id_, params = build_data( + self.apikey, 'delete_user', userid=username, ) + response = api_call(self.app, params) + ret = 'failed to delete user ID:%s %s' % (usr.user_id, + usr.username) + expected = ret + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_delete_user_group.py b/rhodecode/api/tests/test_delete_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_delete_user_group.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestDeleteUserGroup(object): + def test_api_delete_user_group(self, user_util): + user_group = user_util.create_user_group(auto_cleanup=False) + group_name = user_group.users_group_name + group_id = user_group.users_group_id + id_, params = build_data( + self.apikey, 'delete_user_group', usergroupid=group_name) + response = api_call(self.app, params) + + expected = { + 'user_group': None, + 'msg': 'deleted user group ID:%s %s' % (group_id, group_name) + } + assert_ok(id_, expected, given=response.body) + + def test_api_delete_user_group_regular_user(self, user_util): + ugroup = user_util.create_user_group(auto_cleanup=False) + group_name = ugroup.users_group_name + group_id = ugroup.users_group_id + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + + user_util.grant_user_permission_to_user_group( + ugroup, user, 'usergroup.admin') + + id_, params = build_data( + self.apikey_regular, 'delete_user_group', usergroupid=group_name) + response = api_call(self.app, params) + + expected = { + 'user_group': None, + 'msg': 'deleted user group ID:%s %s' % (group_id, group_name) + } + assert_ok(id_, expected, given=response.body) + + def test_api_delete_user_group_regular_user_no_permission(self, user_util): + user_group = user_util.create_user_group() + group_name = user_group.users_group_name + + id_, params = build_data( + self.apikey_regular, 'delete_user_group', usergroupid=group_name) + response = api_call(self.app, params) + + expected = 'user group `%s` does not exist' % (group_name) + assert_error(id_, expected, given=response.body) + + def test_api_delete_user_group_that_is_assigned(self, backend, user_util): + ugroup = user_util.create_user_group() + group_name = ugroup.users_group_name + repo = backend.create_repo() + + ugr_to_perm = user_util.grant_user_group_permission_to_repo( + repo, ugroup, 'repository.write') + msg = 'UserGroup assigned to %s' % (ugr_to_perm.repository) + + id_, params = build_data( + self.apikey, 'delete_user_group', + usergroupid=group_name) + response = api_call(self.app, params) + + expected = msg + assert_error(id_, expected, given=response.body) + + def test_api_delete_user_group_exception_occurred(self, user_util): + ugroup = user_util.create_user_group() + group_name = ugroup.users_group_name + group_id = ugroup.users_group_id + id_, params = build_data( + self.apikey, 'delete_user_group', + usergroupid=group_name) + + with mock.patch.object(UserGroupModel, 'delete', crash): + response = api_call(self.app, params) + expected = 'failed to delete user group ID:%s %s' % ( + group_id, group_name) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_deprecated_api.py b/rhodecode/api/tests/test_deprecated_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_deprecated_api.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.api.views import depracated_api +from rhodecode.lib.ext_json import json +from rhodecode.api.tests.utils import ( + build_data, api_call) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestCommitComment(object): + def test_deprecated_message_in_docstring(self): + docstring = depracated_api.changeset_comment.__doc__ + assert '.. deprecated:: 3.4.0' in docstring + assert 'Please use method `comment_commit` instead.' in docstring + + def test_deprecated_message_in_retvalue(self): + + id_, params = build_data( + self.apikey, 'show_ip') + response = api_call(self.app, params) + + expected = { + 'id': id_, + 'error': None, + 'result': json.loads(response.body)['result'], + 'DEPRECATION_WARNING': + 'DEPRECATED METHOD Please use method `get_ip` instead.' + } + assert expected == json.loads(response.body) + + # def test_calls_comment_commit(self, backend, no_notifications): + # data = { + # 'repoid': backend.repo_name, + # 'status': ChangesetStatus.STATUS_APPROVED, + # 'message': 'Approved', + # 'revision': 'tip' + # } + # with patch.object(repo_api, 'changeset_commit') as comment_mock: + # id_, params = build_data(self.apikey, 'comment_commit', **data) + # api_call(self.app, params) + # + # _, call_args = comment_mock.call_args + # data['commit_id'] = data.pop('revision') + # for key in data: + # assert call_args[key] == data[key] + + # def test_warning_log_contains_deprecation_message(self): + # api = self.SampleApi() + # with patch.object(utils, 'log') as log_mock: + # api.api_method() + # + # assert log_mock.warning.call_count == 1 + # call_args = log_mock.warning.call_args[0] + # assert ( + # call_args[0] == + # 'DEPRECATED API CALL on function %s, please use `%s` instead') + # assert call_args[1].__name__ == 'api_method' + # assert call_args[2] == 'new_method' \ No newline at end of file diff --git a/rhodecode/api/tests/test_fork_repo.py b/rhodecode/api/tests/test_fork_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_fork_repo.py @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) +from rhodecode.tests.fixture import Fixture + + +fixture = Fixture() + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiForkRepo(object): + def test_api_fork_repo(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = { + 'msg': 'Created fork of `%s` as `%s`' % (source_name, fork_name), + 'success': True, + 'task': None, + } + try: + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_repo(fork_name) + + def test_api_fork_repo_into_group(self, backend, user_util): + source_name = backend['minimal'].repo_name + repo_group = user_util.create_repo_group() + fork_name = '%s/api-repo-fork' % repo_group.group_name + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + ret = { + 'msg': 'Created fork of `%s` as `%s`' % (source_name, fork_name), + 'success': True, + 'task': None, + } + expected = ret + try: + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_repo(fork_name) + + def test_api_fork_repo_non_admin(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + + id_, params = build_data( + self.apikey_regular, 'fork_repo', + repoid=source_name, + fork_name=fork_name) + response = api_call(self.app, params) + + expected = { + 'msg': 'Created fork of `%s` as `%s`' % (source_name, fork_name), + 'success': True, + 'task': None, + } + try: + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_repo(fork_name) + + def test_api_fork_repo_non_admin_into_group(self, backend, user_util): + source_name = backend['minimal'].repo_name + repo_group = user_util.create_repo_group() + fork_name = '%s/api-repo-fork' % repo_group.group_name + + id_, params = build_data( + self.apikey_regular, 'fork_repo', + repoid=source_name, + fork_name=fork_name) + response = api_call(self.app, params) + + expected = { + 'msg': 'Created fork of `%s` as `%s`' % (source_name, fork_name), + 'success': True, + 'task': None, + } + try: + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_repo(fork_name) + + def test_api_fork_repo_non_admin_specify_owner(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + id_, params = build_data( + self.apikey_regular, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + expected = 'Only RhodeCode admin can specify `owner` param' + assert_error(id_, expected, given=response.body) + + def test_api_fork_repo_non_admin_no_permission_to_fork(self, backend): + source_name = backend['minimal'].repo_name + RepoModel().grant_user_permission(repo=source_name, + user=self.TEST_USER_LOGIN, + perm='repository.none') + fork_name = backend.new_repo_name() + id_, params = build_data( + self.apikey_regular, 'fork_repo', + repoid=backend.repo_name, + fork_name=fork_name) + response = api_call(self.app, params) + expected = 'repository `%s` does not exist' % (backend.repo_name) + assert_error(id_, expected, given=response.body) + + def test_api_fork_repo_non_admin_no_permission_to_fork_to_root_level( + self, backend): + source_name = backend['minimal'].repo_name + + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + usr.inherit_default_permissions = False + Session().add(usr) + + fork_name = backend.new_repo_name() + id_, params = build_data( + self.apikey_regular, 'fork_repo', + repoid=source_name, + fork_name=fork_name) + response = api_call(self.app, params) + expected = "Access was denied to this resource." + assert_error(id_, expected, given=response.body) + + def test_api_fork_repo_unknown_owner(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + owner = 'i-dont-exist' + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=owner) + response = api_call(self.app, params) + expected = 'user `%s` does not exist' % (owner,) + assert_error(id_, expected, given=response.body) + + def test_api_fork_repo_fork_exists(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + fork_repo = fixture.create_fork(source_name, fork_name) + + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + try: + expected = "fork `%s` already exist" % (fork_name,) + assert_error(id_, expected, given=response.body) + finally: + fixture.destroy_repo(fork_repo.repo_name) + + def test_api_fork_repo_repo_exists(self, backend): + source_name = backend['minimal'].repo_name + fork_name = source_name + + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = "repo `%s` already exist" % (fork_name,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'create_fork', crash) + def test_api_fork_repo_exception_occurred(self, backend): + source_name = backend['minimal'].repo_name + fork_name = backend.new_repo_name() + id_, params = build_data( + self.apikey, 'fork_repo', + repoid=source_name, + fork_name=fork_name, + owner=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = 'failed to fork repository `%s` as `%s`' % (source_name, + fork_name) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_gist.py b/rhodecode/api/tests/test_get_gist.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_gist.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.db import Gist +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiGetGist(object): + def test_api_get_gist(self, gist_util): + gist = gist_util.create_gist() + gist_id = gist.gist_access_id + gist_created_on = gist.created_on + gist_modified_at = gist.modified_at + id_, params = build_data( + self.apikey, 'get_gist', gistid=gist_id, ) + response = api_call(self.app, params) + + expected = { + 'access_id': gist_id, + 'created_on': gist_created_on, + 'modified_at': gist_modified_at, + 'description': 'new-gist', + 'expires': -1.0, + 'gist_id': int(gist_id), + 'type': 'public', + 'url': 'http://test.example.com:80/_admin/gists/%s' % (gist_id,), + 'acl_level': Gist.ACL_LEVEL_PUBLIC, + 'content': None, + } + + assert_ok(id_, expected, given=response.body) + + def test_api_get_gist_with_content(self, gist_util): + mapping = { + u'filename1.txt': {'content': u'hello world'}, + u'filename1ą.txt': {'content': u'hello worldę'} + } + gist = gist_util.create_gist(gist_mapping=mapping) + gist_id = gist.gist_access_id + gist_created_on = gist.created_on + gist_modified_at = gist.modified_at + id_, params = build_data( + self.apikey, 'get_gist', gistid=gist_id, content=True) + response = api_call(self.app, params) + + expected = { + 'access_id': gist_id, + 'created_on': gist_created_on, + 'modified_at': gist_modified_at, + 'description': 'new-gist', + 'expires': -1.0, + 'gist_id': int(gist_id), + 'type': 'public', + 'url': 'http://test.example.com:80/_admin/gists/%s' % (gist_id,), + 'acl_level': Gist.ACL_LEVEL_PUBLIC, + 'content': { + u'filename1.txt': u'hello world', + u'filename1ą.txt': u'hello worldę' + }, + } + + assert_ok(id_, expected, given=response.body) + + def test_api_get_gist_not_existing(self): + id_, params = build_data( + self.apikey_regular, 'get_gist', gistid='12345', ) + response = api_call(self.app, params) + expected = 'gist `%s` does not exist' % ('12345',) + assert_error(id_, expected, given=response.body) + + def test_api_get_gist_private_gist_without_permission(self, gist_util): + gist = gist_util.create_gist() + gist_id = gist.gist_access_id + id_, params = build_data( + self.apikey_regular, 'get_gist', gistid=gist_id, ) + response = api_call(self.app, params) + + expected = 'gist `%s` does not exist' % (gist_id,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_gists.py b/rhodecode/api/tests/test_get_gists.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_gists.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiGetGist(object): + def test_api_get_gists(self, gist_util): + gist_util.create_gist() + gist_util.create_gist() + + id_, params = build_data(self.apikey, 'get_gists') + response = api_call(self.app, params) + assert len(response.json['result']) == 2 + + def test_api_get_gists_regular_user(self, gist_util): + # by admin + gist_util.create_gist() + gist_util.create_gist() + + # by reg user + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + + id_, params = build_data(self.apikey_regular, 'get_gists') + response = api_call(self.app, params) + assert len(response.json['result']) == 3 + + def test_api_get_gists_only_for_regular_user(self, gist_util): + # by admin + gist_util.create_gist() + gist_util.create_gist() + + # by reg user + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + gist_util.create_gist(owner=self.TEST_USER_LOGIN) + + id_, params = build_data( + self.apikey, 'get_gists', userid=self.TEST_USER_LOGIN) + response = api_call(self.app, params) + assert len(response.json['result']) == 3 + + def test_api_get_gists_regular_user_with_different_userid(self): + id_, params = build_data( + self.apikey_regular, 'get_gists', + userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_ip.py b/rhodecode/api/tests/test_get_ip.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_ip.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.api.tests.utils import build_data, api_call, assert_ok + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetIp(object): + def test_api_get_ip(self): + id_, params = build_data(self.apikey, 'get_ip') + response = api_call(self.app, params) + expected = { + 'server_ip_addr': '0.0.0.0', + 'user_ips': [] + } + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_locks.py b/rhodecode/api/tests/test_get_locks.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_locks.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.db import Repository, User +from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetLocks(object): + def test_api_get_user_locks_regular_user(self): + id_, params = build_data(self.apikey_regular, 'get_user_locks') + response = api_call(self.app, params) + expected = [] + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_locks_with_userid_regular_user(self): + id_, params = build_data( + self.apikey_regular, 'get_user_locks', userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) + + def test_api_get_user_locks(self): + id_, params = build_data(self.apikey, 'get_user_locks') + response = api_call(self.app, params) + expected = [] + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize("apikey_attr, expect_secrets", [ + ('apikey', True), + ('apikey_regular', False), + ]) + def test_api_get_user_locks_with_one_locked_repo( + self, apikey_attr, expect_secrets, backend): + + repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) + Repository.lock( + repo, User.get_by_username(self.TEST_USER_LOGIN).user_id) + + apikey = getattr(self, apikey_attr) + + id_, params = build_data(apikey, 'get_user_locks') + if apikey_attr == 'apikey': + # super-admin should call in specific user + id_, params = build_data(apikey, 'get_user_locks', + userid=self.TEST_USER_LOGIN) + + response = api_call(self.app, params) + expected = [repo.get_api_data(include_secrets=expect_secrets)] + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_locks_with_one_locked_repo_for_specific_user( + self, backend): + repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) + + Repository.lock(repo, User.get_by_username( + self.TEST_USER_LOGIN).user_id) + id_, params = build_data( + self.apikey, 'get_user_locks', userid=self.TEST_USER_LOGIN) + response = api_call(self.app, params) + expected = [repo.get_api_data(include_secrets=True)] + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_locks_with_userid(self): + id_, params = build_data( + self.apikey, 'get_user_locks', userid=TEST_USER_REGULAR_LOGIN) + response = api_call(self.app, params) + expected = [] + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_pull_request.py b/rhodecode/api/tests/test_get_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_pull_request.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest +import urlobject +from pylons import url + +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + +pytestmark = pytest.mark.backends("git", "hg") + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetPullRequest(object): + + def test_api_get_pull_request(self, pr_util): + pull_request = pr_util.create_pull_request(mergeable=True) + id_, params = build_data( + self.apikey, 'get_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id) + + response = api_call(self.app, params) + + assert response.status == '200 OK' + + url_obj = urlobject.URLObject( + url( + 'pullrequest_show', + repo_name=pull_request.target_repo.repo_name, + pull_request_id=pull_request.pull_request_id, qualified=True)) + pr_url = unicode( + url_obj.with_netloc('test.example.com:80')) + source_url = unicode( + pull_request.source_repo.clone_url() + .with_netloc('test.example.com:80')) + target_url = unicode( + pull_request.target_repo.clone_url() + .with_netloc('test.example.com:80')) + expected = { + 'pull_request_id': pull_request.pull_request_id, + 'url': pr_url, + 'title': pull_request.title, + 'description': pull_request.description, + 'status': pull_request.status, + 'created_on': pull_request.created_on, + 'updated_on': pull_request.updated_on, + 'commit_ids': pull_request.revisions, + 'review_status': pull_request.calculated_review_status(), + 'mergeable': { + 'status': True, + 'message': 'This pull request can be automatically merged.', + }, + 'source': { + 'clone_url': source_url, + 'repository': pull_request.source_repo.repo_name, + 'reference': { + 'name': pull_request.source_ref_parts.name, + 'type': pull_request.source_ref_parts.type, + 'commit_id': pull_request.source_ref_parts.commit_id, + }, + }, + 'target': { + 'clone_url': target_url, + 'repository': pull_request.target_repo.repo_name, + 'reference': { + 'name': pull_request.target_ref_parts.name, + 'type': pull_request.target_ref_parts.type, + 'commit_id': pull_request.target_ref_parts.commit_id, + }, + }, + 'author': pull_request.author.get_api_data(include_secrets=False, + details='basic'), + 'reviewers': [ + { + 'user': reviewer.get_api_data(include_secrets=False, + details='basic'), + 'review_status': st[0][1].status if st else 'not_reviewed', + } + for reviewer, st in pull_request.reviewers_statuses() + ] + } + assert_ok(id_, expected, response.body) + + def test_api_get_pull_request_repo_error(self): + id_, params = build_data( + self.apikey, 'get_pull_request', + repoid=666, pullrequestid=1) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) + + def test_api_get_pull_request_pull_request_error(self): + id_, params = build_data( + self.apikey, 'get_pull_request', + repoid=1, pullrequestid=666) + response = api_call(self.app, params) + + expected = 'pull request `666` does not exist' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_pull_requests.py b/rhodecode/api/tests/test_get_pull_requests.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_pull_requests.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetPullRequest(object): + @pytest.mark.backends("git", "hg") + def test_api_get_pull_requests(self, pr_util): + pull_request = pr_util.create_pull_request() + pull_request_2 = PullRequestModel().create( + created_by=pull_request.author, + source_repo=pull_request.source_repo, + source_ref=pull_request.source_ref, + target_repo=pull_request.target_repo, + target_ref=pull_request.target_ref, + revisions=pull_request.revisions, + reviewers=(), + title=pull_request.title, + description=pull_request.description, + ) + Session().commit() + id_, params = build_data( + self.apikey, 'get_pull_requests', + repoid=pull_request.target_repo.repo_name) + response = api_call(self.app, params) + assert response.status == '200 OK' + assert len(response.json['result']) == 2 + + PullRequestModel().close_pull_request( + pull_request_2, pull_request_2.author) + Session().commit() + + id_, params = build_data( + self.apikey, 'get_pull_requests', + repoid=pull_request.target_repo.repo_name, + status='new') + response = api_call(self.app, params) + assert response.status == '200 OK' + assert len(response.json['result']) == 1 + + id_, params = build_data( + self.apikey, 'get_pull_requests', + repoid=pull_request.target_repo.repo_name, + status='closed') + response = api_call(self.app, params) + assert response.status == '200 OK' + assert len(response.json['result']) == 1 + + @pytest.mark.backends("git", "hg") + def test_api_get_pull_requests_repo_error(self): + id_, params = build_data(self.apikey, 'get_pull_requests', repoid=666) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo.py b/rhodecode/api/tests/test_get_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repo.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, expected_permissions) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetRepo(object): + @pytest.mark.parametrize("apikey_attr, expect_secrets", [ + ('apikey', True), + ('apikey_regular', False), + ]) + @pytest.mark.parametrize("cache_param", [ + True, + False, + None, + ]) + def test_api_get_repo( + self, apikey_attr, expect_secrets, cache_param, backend, + user_util): + repo = backend.create_repo() + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + group = user_util.create_user_group(members=[usr]) + user_util.grant_user_group_permission_to_repo( + repo=repo, user_group=group, permission_name='repository.read') + Session().commit() + kwargs = { + 'repoid': repo.repo_name, + } + if cache_param is not None: + kwargs['cache'] = cache_param + + apikey = getattr(self, apikey_attr) + id_, params = build_data(apikey, 'get_repo', **kwargs) + response = api_call(self.app, params) + + ret = repo.get_api_data() + + permissions = expected_permissions(repo) + + followers = [] + for user in repo.followers: + followers.append(user.user.get_api_data( + include_secrets=expect_secrets)) + + ret['members'] = permissions + ret['permissions'] = permissions + ret['followers'] = followers + + expected = ret + + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize("grant_perm", [ + 'repository.admin', + 'repository.write', + 'repository.read', + ]) + def test_api_get_repo_by_non_admin(self, grant_perm, backend): + # TODO: Depending on which tests are running before this one, we + # start with a different number of permissions in the database. + repo = RepoModel().get_by_repo_name(backend.repo_name) + permission_count = len(repo.repo_to_perm) + + RepoModel().grant_user_permission(repo=backend.repo_name, + user=self.TEST_USER_LOGIN, + perm=grant_perm) + Session().commit() + id_, params = build_data( + self.apikey_regular, 'get_repo', repoid=backend.repo_name) + response = api_call(self.app, params) + + repo = RepoModel().get_by_repo_name(backend.repo_name) + ret = repo.get_api_data() + + assert permission_count + 1, len(repo.repo_to_perm) + + permissions = expected_permissions(repo) + + followers = [] + for user in repo.followers: + followers.append(user.user.get_api_data()) + + ret['members'] = permissions + ret['permissions'] = permissions + ret['followers'] = followers + + expected = ret + try: + assert_ok(id_, expected, given=response.body) + finally: + RepoModel().revoke_user_permission( + backend.repo_name, self.TEST_USER_LOGIN) + + def test_api_get_repo_by_non_admin_no_permission_to_repo(self, backend): + RepoModel().grant_user_permission(repo=backend.repo_name, + user=self.TEST_USER_LOGIN, + perm='repository.none') + + id_, params = build_data( + self.apikey_regular, 'get_repo', repoid=backend.repo_name) + response = api_call(self.app, params) + + expected = 'repository `%s` does not exist' % (backend.repo_name) + assert_error(id_, expected, given=response.body) + + def test_api_get_repo_not_existing(self): + id_, params = build_data( + self.apikey, 'get_repo', repoid='no-such-repo') + response = api_call(self.app, params) + + ret = 'repository `%s` does not exist' % 'no-such-repo' + expected = ret + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo_changeset.py b/rhodecode/api/tests/test_get_repo_changeset.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repo_changeset.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.api.tests.utils import build_data, api_call, assert_error + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetRepoChangeset(object): + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + def test_get_repo_changeset(self, details, backend): + commit = backend.repo.get_commit(commit_idx=0) + __, params = build_data( + self.apikey, 'get_repo_changeset', + repoid=backend.repo_name, revision=commit.raw_id, + details=details, + ) + response = api_call(self.app, params) + result = response.json['result'] + assert result['revision'] == 0 + assert result['raw_id'] == commit.raw_id + + if details == 'full': + assert result['refs']['bookmarks'] == getattr( + commit, 'bookmarks', []) + assert result['refs']['branches'] == [commit.branch] + assert result['refs']['tags'] == commit.tags + + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + def test_get_repo_changeset_bad_type(self, details, backend): + id_, params = build_data( + self.apikey, 'get_repo_changeset', + repoid=backend.repo_name, revision=0, + details=details, + ) + response = api_call(self.app, params) + expected = 'commit_id must be a string value' + assert_error(id_, expected, given=response.body) + + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + def test_get_repo_changesets(self, details, backend): + limit = 2 + commit = backend.repo.get_commit(commit_idx=0) + __, params = build_data( + self.apikey, 'get_repo_changesets', + repoid=backend.repo_name, start_rev=commit.raw_id, limit=limit, + details=details, + ) + response = api_call(self.app, params) + result = response.json['result'] + assert result + assert len(result) == limit + for x in xrange(limit): + assert result[x]['revision'] == x + + if details == 'full': + for x in xrange(limit): + assert 'bookmarks' in result[x]['refs'] + assert 'branches' in result[x]['refs'] + assert 'tags' in result[x]['refs'] + + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + @pytest.mark.parametrize("start_rev, expected_revision", [ + ("0", 0), + ("10", 10), + ("20", 20), + ]) + @pytest.mark.backends("hg", "git") + def test_get_repo_changesets_commit_range( + self, details, backend, start_rev, expected_revision): + limit = 10 + __, params = build_data( + self.apikey, 'get_repo_changesets', + repoid=backend.repo_name, start_rev=start_rev, limit=limit, + details=details, + ) + response = api_call(self.app, params) + result = response.json['result'] + assert result + assert len(result) == limit + for i in xrange(limit): + assert result[i]['revision'] == int(expected_revision) + i + + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + @pytest.mark.parametrize("start_rev, expected_revision", [ + ("0", 0), + ("10", 9), + ("20", 19), + ]) + def test_get_repo_changesets_commit_range_svn( + self, details, backend_svn, start_rev, expected_revision): + + # TODO: johbo: SVN showed a problem here: The parameter "start_rev" + # in our API allows to pass in a "Commit ID" as well as a + # "Commit Index". In the case of Subversion it is not possible to + # distinguish these cases. As a workaround we implemented this + # behavior which gives a preference to see it as a "Commit ID". + + limit = 10 + __, params = build_data( + self.apikey, 'get_repo_changesets', + repoid=backend_svn.repo_name, start_rev=start_rev, limit=limit, + details=details, + ) + response = api_call(self.app, params) + result = response.json['result'] + assert result + assert len(result) == limit + for i in xrange(limit): + assert result[i]['revision'] == int(expected_revision) + i + + @pytest.mark.parametrize("details", ['basic', 'extended', 'full']) + def test_get_repo_changesets_bad_type(self, details, backend): + id_, params = build_data( + self.apikey, 'get_repo_changesets', + repoid=backend.repo_name, start_rev=0, limit=2, + details=details, + ) + response = api_call(self.app, params) + expected = 'commit_id must be a string value' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo_group.py b/rhodecode/api/tests/test_get_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repo_group.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, expected_permissions) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiGetRepoGroup(object): + def test_api_get_repo_group(self, user_util): + repo_group = user_util.create_repo_group() + repo_group_name = repo_group.group_name + + id_, params = build_data( + self.apikey, 'get_repo_group', repogroupid=repo_group_name) + response = api_call(self.app, params) + + repo_group = RepoGroupModel()._get_repo_group(repo_group_name) + ret = repo_group.get_api_data() + + permissions = expected_permissions(repo_group) + + ret['members'] = permissions + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_repo_group_not_existing(self): + id_, params = build_data( + self.apikey, 'get_repo_group', repogroupid='no-such-repo-group') + response = api_call(self.app, params) + + ret = 'repository group `%s` does not exist' % 'no-such-repo-group' + expected = ret + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo_groups.py b/rhodecode/api/tests/test_get_repo_groups.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repo_groups.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.api.tests.utils import build_data, api_call, assert_ok, jsonify + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiGetRepoGroups(object): + def test_api_get_repo_groups(self): + id_, params = build_data(self.apikey, 'get_repo_groups') + response = api_call(self.app, params) + + result = [] + for repo in RepoGroupModel().get_all(): + result.append(repo.get_api_data()) + ret = jsonify(result) + + expected = ret + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo_nodes.py b/rhodecode/api/tests/test_get_repo_nodes.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repo_nodes.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetRepoNodes(object): + @pytest.mark.parametrize("name, ret_type", [ + ('all', 'all'), + ('dirs', 'dirs'), + ('files', 'files'), + ]) + def test_api_get_repo_nodes(self, name, ret_type, backend): + commit_id = 'tip' + path = '/' + id_, params = build_data( + self.apikey, 'get_repo_nodes', + repoid=backend.repo_name, revision=commit_id, + root_path=path, + ret_type=ret_type) + response = api_call(self.app, params) + + # we don't the actual return types here since it's tested somewhere + # else + expected = response.json['result'] + assert_ok(id_, expected, given=response.body) + + def test_api_get_repo_nodes_bad_commits(self, backend): + commit_id = 'i-dont-exist' + path = '/' + id_, params = build_data( + self.apikey, 'get_repo_nodes', + repoid=backend.repo_name, revision=commit_id, + root_path=path, ) + response = api_call(self.app, params) + + expected = 'failed to get repo: `%s` nodes' % (backend.repo_name,) + assert_error(id_, expected, given=response.body) + + def test_api_get_repo_nodes_bad_path(self, backend): + commit_id = 'tip' + path = '/idontexits' + id_, params = build_data( + self.apikey, 'get_repo_nodes', + repoid=backend.repo_name, revision=commit_id, + root_path=path, ) + response = api_call(self.app, params) + + expected = 'failed to get repo: `%s` nodes' % (backend.repo_name,) + assert_error(id_, expected, given=response.body) + + def test_api_get_repo_nodes_bad_ret_type(self, backend): + commit_id = 'tip' + path = '/' + ret_type = 'error' + id_, params = build_data( + self.apikey, 'get_repo_nodes', + repoid=backend.repo_name, revision=commit_id, + root_path=path, + ret_type=ret_type) + response = api_call(self.app, params) + + expected = ('ret_type must be one of %s' + % (','.join(['all', 'dirs', 'files']))) + assert_error(id_, expected, given=response.body) + + @pytest.mark.parametrize("name, ret_type, grant_perm", [ + ('all', 'all', 'repository.write'), + ('dirs', 'dirs', 'repository.admin'), + ('files', 'files', 'repository.read'), + ]) + def test_api_get_repo_nodes_by_regular_user( + self, name, ret_type, grant_perm, backend): + RepoModel().grant_user_permission(repo=backend.repo_name, + user=self.TEST_USER_LOGIN, + perm=grant_perm) + Session().commit() + + commit_id = 'tip' + path = '/' + id_, params = build_data( + self.apikey_regular, 'get_repo_nodes', + repoid=backend.repo_name, revision=commit_id, + root_path=path, + ret_type=ret_type) + response = api_call(self.app, params) + + # we don't the actual return types here since it's tested somewhere + # else + expected = response.json['result'] + try: + assert_ok(id_, expected, given=response.body) + finally: + RepoModel().revoke_user_permission( + backend.repo_name, self.TEST_USER_LOGIN) diff --git a/rhodecode/api/tests/test_get_repos.py b/rhodecode/api/tests/test_get_repos.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_repos.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import build_data, api_call, assert_ok, jsonify +from rhodecode.model.db import User + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetRepos(object): + def test_api_get_repos(self): + id_, params = build_data(self.apikey, 'get_repos') + response = api_call(self.app, params) + + result = [] + for repo in RepoModel().get_all(): + result.append(repo.get_api_data(include_secrets=True)) + ret = jsonify(result) + + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_repos_non_admin(self): + id_, params = build_data(self.apikey_regular, 'get_repos') + response = api_call(self.app, params) + + user = User.get_by_username(self.TEST_USER_LOGIN) + allowed_repos = user.AuthUser.permissions['repositories'] + + result = [] + for repo in RepoModel().get_all(): + perm = allowed_repos[repo.repo_name] + if perm in ['repository.read', 'repository.write', 'repository.admin']: + result.append(repo.get_api_data()) + ret = jsonify(result) + + expected = ret + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_server_info.py b/rhodecode/api/tests/test_get_server_info.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_server_info.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest + +from rhodecode.model.scm import ScmModel +from rhodecode.api.tests.utils import build_data, api_call, assert_ok + + +@pytest.fixture +def http_host_stub(): + """ + To ensure that we can get an IP address, this test shall run with a + hostname set to "localhost". + """ + return 'localhost:80' + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetServerInfo(object): + def test_api_get_server_info(self): + id_, params = build_data(self.apikey, 'get_server_info') + response = api_call(self.app, params) + resp = response.json + expected = ScmModel().get_server_info() + expected['memory'] = resp['result']['memory'] + expected['uptime'] = resp['result']['uptime'] + expected['load'] = resp['result']['load'] + expected['cpu'] = resp['result']['cpu'] + expected['disk'] = resp['result']['disk'] + expected['server_ip'] = '127.0.0.1:80' + + assert_ok(id_, expected, given=response.body) + + def test_api_get_server_info_ip(self): + id_, params = build_data(self.apikey, 'get_server_info') + response = api_call(self.app, params) + resp = response.json + expected = ScmModel().get_server_info({'SERVER_NAME': 'unknown'}) + expected['memory'] = resp['result']['memory'] + expected['uptime'] = resp['result']['uptime'] + expected['load'] = resp['result']['load'] + expected['cpu'] = resp['result']['cpu'] + expected['disk'] = resp['result']['disk'] + expected['server_ip'] = '127.0.0.1:80' + + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_user.py b/rhodecode/api/tests/test_get_user.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_user.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.lib.auth import AuthUser +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetUser(object): + def test_api_get_user(self): + id_, params = build_data( + self.apikey, 'get_user', userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + ret = usr.get_api_data(include_secrets=True) + ret['permissions'] = AuthUser(usr.user_id).permissions + + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_not_existing(self): + id_, params = build_data(self.apikey, 'get_user', userid='trololo') + response = api_call(self.app, params) + + expected = "user `%s` does not exist" % 'trololo' + assert_error(id_, expected, given=response.body) + + def test_api_get_user_without_giving_userid(self): + id_, params = build_data(self.apikey, 'get_user') + response = api_call(self.app, params) + + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + ret = usr.get_api_data(include_secrets=True) + ret['permissions'] = AuthUser(usr.user_id).permissions + + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_without_giving_userid_non_admin(self): + id_, params = build_data(self.apikey_regular, 'get_user') + response = api_call(self.app, params) + + usr = UserModel().get_by_username(self.TEST_USER_LOGIN) + ret = usr.get_api_data(include_secrets=True) + ret['permissions'] = AuthUser(usr.user_id).permissions + + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_with_giving_userid_non_admin(self): + id_, params = build_data( + self.apikey_regular, 'get_user', + userid=self.TEST_USER_LOGIN) + response = api_call(self.app, params) + + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_user_group.py b/rhodecode/api/tests/test_get_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_user_group.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, expected_permissions) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetUserGroups(object): + def test_api_get_user_group(self, user_util): + user, group = user_util.create_user_with_group() + id_, params = build_data( + self.apikey, 'get_user_group', usergroupid=group.users_group_name) + response = api_call(self.app, params) + + ret = group.get_api_data() + ret['users'] = [user.get_api_data()] + + permissions = expected_permissions(group) + + ret['members'] = permissions + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_group_regular_user(self, user_util): + user, group = user_util.create_user_with_group() + id_, params = build_data( + self.apikey_regular, 'get_user_group', + usergroupid=group.users_group_name) + response = api_call(self.app, params) + + ret = group.get_api_data() + ret['users'] = [user.get_api_data()] + + permissions = expected_permissions(group) + + ret['members'] = permissions + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_get_user_group_regular_user_permission_denied( + self, user_util): + group = user_util.create_user_group() + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + group_name = group.users_group_name + user_util.grant_user_permission_to_user_group( + group, user, 'usergroup.none') + + id_, params = build_data( + self.apikey_regular, 'get_user_group', usergroupid=group_name) + response = api_call(self.app, params) + + expected = 'user group `%s` does not exist' % (group_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_user_groups.py b/rhodecode/api/tests/test_get_user_groups.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_user_groups.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import json + +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import build_data, api_call + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetUserGroups(object): + @pytest.mark.parametrize("apikey_attr, expect_secrets", [ + ('apikey', True), + ('apikey_regular', False), + ]) + def test_api_get_user_groups(self, apikey_attr, expect_secrets, user_util): + first_group = user_util.create_user_group() + second_group = user_util.create_user_group() + expected = [ + g.get_api_data(include_secrets=expect_secrets) + for g in (first_group, second_group)] + + apikey = getattr(self, apikey_attr) + id_, params = build_data(apikey, 'get_user_groups', ) + response = api_call(self.app, params) + self._assert_ok(id_, expected, response) + + def test_api_get_user_groups_regular_user(self, user_util): + first_group = user_util.create_user_group() + second_group = user_util.create_user_group() + expected = [g.get_api_data() for g in (first_group, second_group)] + + id_, params = build_data(self.apikey_regular, 'get_user_groups', ) + response = api_call(self.app, params) + self._assert_ok(id_, expected, response) + + def test_api_get_user_groups_regular_user_no_permission(self, user_util): + group = user_util.create_user_group() + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user_util.grant_user_permission_to_user_group( + group, user, 'usergroup.none') + id_, params = build_data(self.apikey_regular, 'get_user_groups', ) + response = api_call(self.app, params) + expected = [] + self._assert_ok(id_, expected, response) + + def _assert_ok(self, id_, expected_list, response): + result = json.loads(response.body) + assert result['id'] == id_ + assert result['error'] is None + assert sorted(result['result']) == sorted(expected_list) diff --git a/rhodecode/api/tests/test_get_users.py b/rhodecode/api/tests/test_get_users.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_users.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import User +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, jsonify) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetUsers(object): + def test_api_get_users(self): + id_, params = build_data(self.apikey, 'get_users', ) + response = api_call(self.app, params) + ret_all = [] + _users = User.query().filter(User.username != User.DEFAULT_USER) \ + .order_by(User.username).all() + for usr in _users: + ret = usr.get_api_data(include_secrets=True) + ret_all.append(jsonify(ret)) + expected = ret_all + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_group_permission.py b/rhodecode/api/tests/test_grant_user_group_permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_group_permission.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserGroupPermission(object): + @pytest.mark.parametrize("name, perm", [ + ('none', 'repository.none'), + ('read', 'repository.read'), + ('write', 'repository.write'), + ('admin', 'repository.admin') + ]) + def test_api_grant_user_group_permission( + self, name, perm, backend, user_util): + user_group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'grant_user_group_permission', + repoid=backend.repo_name, + usergroupid=user_group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + ret = { + 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % ( + perm, user_group.users_group_name, backend.repo_name + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_grant_user_group_permission_wrong_permission( + self, backend, user_util): + perm = 'haha.no.permission' + user_group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'grant_user_group_permission', + repoid=backend.repo_name, + usergroupid=user_group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + expected = 'permission `%s` does not exist' % (perm,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'grant_user_group_permission', crash) + def test_api_grant_user_group_permission_exception_when_adding( + self, backend, user_util): + perm = 'repository.read' + user_group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'grant_user_group_permission', + repoid=backend.repo_name, + usergroupid=user_group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user group: `%s` in repo: `%s`' % ( + user_group.users_group_name, backend.repo_name + ) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py b/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserGroupPermissionFromRepoGroup(object): + @pytest.mark.parametrize("name, perm, apply_to_children", [ + ('none', 'group.none', 'none'), + ('read', 'group.read', 'none'), + ('write', 'group.write', 'none'), + ('admin', 'group.admin', 'none'), + + ('none', 'group.none', 'all'), + ('read', 'group.read', 'all'), + ('write', 'group.write', 'all'), + ('admin', 'group.admin', 'all'), + + ('none', 'group.none', 'repos'), + ('read', 'group.read', 'repos'), + ('write', 'group.write', 'repos'), + ('admin', 'group.admin', 'repos'), + + ('none', 'group.none', 'groups'), + ('read', 'group.read', 'groups'), + ('write', 'group.write', 'groups'), + ('admin', 'group.admin', 'groups'), + ]) + def test_api_grant_user_group_permission_to_repo_group( + self, name, perm, apply_to_children, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + id_, params = build_data( + self.apikey, + 'grant_user_group_permission_to_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + perm=perm, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + + ret = { + 'msg': ( + 'Granted perm: `%s` (recursive:%s) for user group: `%s`' + ' in repo group: `%s`' % ( + perm, apply_to_children, user_group.users_group_name, + repo_group.name + ) + ), + 'success': True + } + expected = ret + try: + assert_ok(id_, expected, given=response.body) + finally: + RepoGroupModel().revoke_user_group_permission( + repo_group.group_id, user_group.users_group_id) + + @pytest.mark.parametrize( + "name, perm, apply_to_children, grant_admin, access_ok", [ + ('none_fails', 'group.none', 'none', False, False), + ('read_fails', 'group.read', 'none', False, False), + ('write_fails', 'group.write', 'none', False, False), + ('admin_fails', 'group.admin', 'none', False, False), + + # with granted perms + ('none_ok', 'group.none', 'none', True, True), + ('read_ok', 'group.read', 'none', True, True), + ('write_ok', 'group.write', 'none', True, True), + ('admin_ok', 'group.admin', 'none', True, True), + ] + ) + def test_api_grant_user_group_permission_to_repo_group_by_regular_user( + self, name, perm, apply_to_children, grant_admin, access_ok, + user_util): + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + if grant_admin: + user_util.grant_user_permission_to_repo_group( + repo_group, user, 'group.admin') + + id_, params = build_data( + self.apikey_regular, + 'grant_user_group_permission_to_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + perm=perm, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + if access_ok: + ret = { + 'msg': ( + 'Granted perm: `%s` (recursive:%s) for user group: `%s`' + ' in repo group: `%s`' % ( + perm, apply_to_children, user_group.users_group_name, + repo_group.name + ) + ), + 'success': True + } + expected = ret + try: + assert_ok(id_, expected, given=response.body) + finally: + RepoGroupModel().revoke_user_group_permission( + repo_group.group_id, user_group.users_group_id) + else: + expected = 'repository group `%s` does not exist' % ( + repo_group.name,) + assert_error(id_, expected, given=response.body) + + def test_api_grant_user_group_permission_to_repo_group_wrong_permission( + self, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + perm = 'haha.no.permission' + id_, params = build_data( + self.apikey, + 'grant_user_group_permission_to_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + expected = 'permission `%s` does not exist' % (perm,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoGroupModel, 'grant_user_group_permission', crash) + def test_api_grant_user_group_permission_exception_when_adding_2( + self, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + perm = 'group.read' + id_, params = build_data( + self.apikey, + 'grant_user_group_permission_to_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user group: `%s`' + ' in repo group: `%s`' % ( + user_group.users_group_name, repo_group.name) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py b/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserGroupPermissionFromUserGroup(object): + @pytest.mark.parametrize("name, perm", [ + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + ]) + def test_api_grant_user_group_permission_to_user_group( + self, name, perm, user_util): + group = user_util.create_user_group() + target_group = user_util.create_user_group() + + id_, params = build_data( + self.apikey, + 'grant_user_group_permission_to_user_group', + usergroupid=target_group.users_group_name, + sourceusergroupid=group.users_group_name, + perm=perm) + response = api_call(self.app, params) + + expected = { + 'msg': ( + 'Granted perm: `%s` for user group: `%s`' + ' in user group: `%s`' % ( + perm, group.users_group_name, + target_group.users_group_name + ) + ), + 'success': True + } + try: + assert_ok(id_, expected, given=response.body) + finally: + UserGroupModel().revoke_user_group_permission( + target_group.users_group_id, group.users_group_id) + + def test_api_grant_user_group_permission_to_user_group_same_failure( + self, user_util): + group = user_util.create_user_group() + + id_, params = build_data( + self.apikey, + 'grant_user_group_permission_to_user_group', + usergroupid=group.users_group_name, + sourceusergroupid=group.users_group_name, + perm='usergroup.none') + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user group: `%s`' + ' in user group: `%s`' % ( + group.users_group_name, group.users_group_name) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_permission.py b/rhodecode/api/tests/test_grant_user_permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_permission.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserPermission(object): + @pytest.mark.parametrize("name, perm", [ + ('none', 'repository.none'), + ('read', 'repository.read'), + ('write', 'repository.write'), + ('admin', 'repository.admin') + ]) + def test_api_grant_user_permission(self, name, perm, backend, user_util): + user = user_util.create_user() + id_, params = build_data( + self.apikey, + 'grant_user_permission', + repoid=backend.repo_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + ret = { + 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % ( + perm, user.username, backend.repo_name + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_grant_user_permission_wrong_permission( + self, backend, user_util): + user = user_util.create_user() + perm = 'haha.no.permission' + id_, params = build_data( + self.apikey, + 'grant_user_permission', + repoid=backend.repo_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + expected = 'permission `%s` does not exist' % (perm,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'grant_user_permission', crash) + def test_api_grant_user_permission_exception_when_adding( + self, backend, user_util): + user = user_util.create_user() + perm = 'repository.read' + id_, params = build_data( + self.apikey, + 'grant_user_permission', + repoid=backend.repo_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( + user.username, backend.repo_name + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py b/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserPermissionFromRepoGroup(object): + @pytest.mark.parametrize("name, perm, apply_to_children", [ + ('none', 'group.none', 'none'), + ('read', 'group.read', 'none'), + ('write', 'group.write', 'none'), + ('admin', 'group.admin', 'none'), + + ('none', 'group.none', 'all'), + ('read', 'group.read', 'all'), + ('write', 'group.write', 'all'), + ('admin', 'group.admin', 'all'), + + ('none', 'group.none', 'repos'), + ('read', 'group.read', 'repos'), + ('write', 'group.write', 'repos'), + ('admin', 'group.admin', 'repos'), + + ('none', 'group.none', 'groups'), + ('read', 'group.read', 'groups'), + ('write', 'group.write', 'groups'), + ('admin', 'group.admin', 'groups'), + ]) + def test_api_grant_user_permission_to_repo_group( + self, name, perm, apply_to_children, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + id_, params = build_data( + self.apikey, 'grant_user_permission_to_repo_group', + repogroupid=repo_group.name, userid=user.username, + perm=perm, apply_to_children=apply_to_children) + response = api_call(self.app, params) + + ret = { + 'msg': ( + 'Granted perm: `%s` (recursive:%s) for user: `%s`' + ' in repo group: `%s`' % ( + perm, apply_to_children, user.username, repo_group.name + ) + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize( + "name, perm, apply_to_children, grant_admin, access_ok", [ + ('none_fails', 'group.none', 'none', False, False), + ('read_fails', 'group.read', 'none', False, False), + ('write_fails', 'group.write', 'none', False, False), + ('admin_fails', 'group.admin', 'none', False, False), + + # with granted perms + ('none_ok', 'group.none', 'none', True, True), + ('read_ok', 'group.read', 'none', True, True), + ('write_ok', 'group.write', 'none', True, True), + ('admin_ok', 'group.admin', 'none', True, True), + ] + ) + def test_api_grant_user_permission_to_repo_group_by_regular_user( + self, name, perm, apply_to_children, grant_admin, access_ok, + user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + + if grant_admin: + test_user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user_util.grant_user_permission_to_repo_group( + repo_group, test_user, 'group.admin') + + id_, params = build_data( + self.apikey_regular, 'grant_user_permission_to_repo_group', + repogroupid=repo_group.name, userid=user.username, + perm=perm, apply_to_children=apply_to_children) + response = api_call(self.app, params) + if access_ok: + ret = { + 'msg': ( + 'Granted perm: `%s` (recursive:%s) for user: `%s`' + ' in repo group: `%s`' % ( + perm, apply_to_children, user.username, repo_group.name + ) + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + else: + expected = 'repository group `%s` does not exist' % ( + repo_group.name, ) + assert_error(id_, expected, given=response.body) + + def test_api_grant_user_permission_to_repo_group_wrong_permission( + self, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + perm = 'haha.no.permission' + id_, params = build_data( + self.apikey, + 'grant_user_permission_to_repo_group', + repogroupid=repo_group.name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + expected = 'permission `%s` does not exist' % (perm,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoGroupModel, 'grant_user_permission', crash) + def test_api_grant_user_permission_to_repo_group_exception_when_adding( + self, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + perm = 'group.read' + id_, params = build_data( + self.apikey, + 'grant_user_permission_to_repo_group', + repogroupid=repo_group.name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user: `%s` in repo group: `%s`' % ( + user.username, repo_group.name + ) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_grant_user_permission_to_user_group.py b/rhodecode/api/tests/test_grant_user_permission_to_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_grant_user_permission_to_user_group.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGrantUserPermissionFromUserGroup(object): + @pytest.mark.parametrize("name, perm", [ + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + + ('none', 'usergroup.none'), + ('read', 'usergroup.read'), + ('write', 'usergroup.write'), + ('admin', 'usergroup.admin'), + ]) + def test_api_grant_user_permission_to_user_group( + self, name, perm, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'grant_user_permission_to_user_group', + usergroupid=group.users_group_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + ret = { + 'msg': 'Granted perm: `%s` for user: `%s` in user group: `%s`' % ( + perm, user.username, group.users_group_name + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize("name, perm, grant_admin, access_ok", [ + ('none_fails', 'usergroup.none', False, False), + ('read_fails', 'usergroup.read', False, False), + ('write_fails', 'usergroup.write', False, False), + ('admin_fails', 'usergroup.admin', False, False), + + # with granted perms + ('none_ok', 'usergroup.none', True, True), + ('read_ok', 'usergroup.read', True, True), + ('write_ok', 'usergroup.write', True, True), + ('admin_ok', 'usergroup.admin', True, True), + ]) + def test_api_grant_user_permission_to_user_group_by_regular_user( + self, name, perm, grant_admin, access_ok, user_util): + api_user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user = user_util.create_user() + group = user_util.create_user_group() + # grant the user ability to at least read the group + permission = 'usergroup.admin' if grant_admin else 'usergroup.read' + user_util.grant_user_permission_to_user_group( + group, api_user, permission) + + id_, params = build_data( + self.apikey_regular, + 'grant_user_permission_to_user_group', + usergroupid=group.users_group_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + if access_ok: + ret = { + 'msg': ( + 'Granted perm: `%s` for user: `%s` in user group: `%s`' % ( + perm, user.username, group.users_group_name + ) + ), + 'success': True + } + expected = ret + assert_ok(id_, expected, given=response.body) + else: + expected = 'user group `%s` does not exist' % ( + group.users_group_name) + assert_error(id_, expected, given=response.body) + + def test_api_grant_user_permission_to_user_group_wrong_permission( + self, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + perm = 'haha.no.permission' + id_, params = build_data( + self.apikey, + 'grant_user_permission_to_user_group', + usergroupid=group.users_group_name, + userid=user.username, + perm=perm) + response = api_call(self.app, params) + + expected = 'permission `%s` does not exist' % perm + assert_error(id_, expected, given=response.body) + + def test_api_grant_user_permission_to_user_group_exception_when_adding( + self, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + + perm = 'usergroup.read' + id_, params = build_data( + self.apikey, + 'grant_user_permission_to_user_group', + usergroupid=group.users_group_name, + userid=user.username, + perm=perm) + with mock.patch.object(UserGroupModel, 'grant_user_permission', crash): + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user: `%s` in user group: `%s`' % ( + user.username, group.users_group_name + ) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_invalidate_cache.py b/rhodecode/api/tests/test_invalidate_cache.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_invalidate_cache.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.scm import ScmModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) +from rhodecode.model.repo import RepoModel + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestInvalidateCache(object): + + def _set_cache(self, repo_name): + repo = RepoModel().get_by_repo_name(repo_name) + repo.scm_instance(cache=True) + + def test_api_invalidate_cache(self, backend): + self._set_cache(backend.repo_name) + + id_, params = build_data( + self.apikey, 'invalidate_cache', repoid=backend.repo_name) + response = api_call(self.app, params) + + expected = { + 'msg': "Cache for repository `%s` was invalidated" % ( + backend.repo_name,), + 'repository': backend.repo_name, + } + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(ScmModel, 'mark_for_invalidation', crash) + def test_api_invalidate_cache_error(self, backend): + id_, params = build_data( + self.apikey, 'invalidate_cache', repoid=backend.repo_name) + response = api_call(self.app, params) + + expected = 'Error occurred during cache invalidation action' + assert_error(id_, expected, given=response.body) + + def test_api_invalidate_cache_regular_user_no_permission(self, backend): + self._set_cache(backend.repo_name) + + id_, params = build_data( + self.apikey_regular, 'invalidate_cache', repoid=backend.repo_name) + response = api_call(self.app, params) + + expected = "repository `%s` does not exist" % (backend.repo_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_merge_pull_request.py b/rhodecode/api/tests/test_merge_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_merge_pull_request.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import UserLog +from rhodecode.model.meta import Session +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestMergePullRequest(object): + @pytest.mark.backends("git", "hg") + def test_api_merge_pull_request(self, pr_util, no_notifications): + pull_request = pr_util.create_pull_request() + pull_request_2 = PullRequestModel().create( + created_by=pull_request.author, + source_repo=pull_request.source_repo, + source_ref=pull_request.source_ref, + target_repo=pull_request.target_repo, + target_ref=pull_request.target_ref, + revisions=pull_request.revisions, + reviewers=(), + title=pull_request.title, + description=pull_request.description, + ) + author = pull_request.user_id + repo = pull_request_2.target_repo.repo_id + pull_request_2_id = pull_request_2.pull_request_id + pull_request_2_repo = pull_request_2.target_repo.repo_name + Session().commit() + + id_, params = build_data( + self.apikey, 'merge_pull_request', + repoid=pull_request_2_repo, + pullrequestid=pull_request_2_id) + response = api_call(self.app, params) + + expected = { + 'executed': True, + 'failure_reason': 0, + 'possible': True + } + + response_json = response.json['result'] + assert response_json['merge_commit_id'] + response_json.pop('merge_commit_id') + assert response_json == expected + + action = 'user_merged_pull_request:%d' % (pull_request_2_id, ) + journal = UserLog.query()\ + .filter(UserLog.user_id == author)\ + .filter(UserLog.repository_id == repo)\ + .filter(UserLog.action == action)\ + .all() + assert len(journal) == 1 + + id_, params = build_data( + self.apikey, 'merge_pull_request', + repoid=pull_request_2_repo, pullrequestid=pull_request_2_id) + response = api_call(self.app, params) + + expected = 'pull request `%s` merge failed, pull request is closed' % ( + pull_request_2_id) + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_merge_pull_request_repo_error(self): + id_, params = build_data( + self.apikey, 'merge_pull_request', + repoid=666, pullrequestid=1) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) + + @pytest.mark.backends("git", "hg") + def test_api_merge_pull_request_non_admin_with_userid_error(self, + pr_util): + pull_request = pr_util.create_pull_request(mergeable=True) + id_, params = build_data( + self.apikey_regular, 'merge_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + userid=TEST_USER_ADMIN_LOGIN) + response = api_call(self.app, params) + + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_pull.py b/rhodecode/api/tests/test_pull.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_pull.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os + +import pytest + +from rhodecode.tests import TESTS_TMP_PATH +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestPull(object): + @pytest.mark.backends("git", "hg") + def test_api_pull(self, backend): + r = backend.create_repo() + repo_name = r.repo_name + r.clone_uri = os.path.join(TESTS_TMP_PATH, backend.repo_name) + + id_, params = build_data(self.apikey, 'pull', repoid=repo_name,) + response = api_call(self.app, params) + + expected = {'msg': 'Pulled from `%s`' % (repo_name,), + 'repository': repo_name} + assert_ok(id_, expected, given=response.body) + + def test_api_pull_error(self, backend): + id_, params = build_data( + self.apikey, 'pull', repoid=backend.repo_name) + response = api_call(self.app, params) + + expected = 'Unable to pull changes from `%s`' % (backend.repo_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_remove_field_from_repo.py b/rhodecode/api/tests/test_remove_field_from_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_remove_field_from_repo.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.db import Repository, RepositoryField +from rhodecode.api.tests.utils import build_data, api_call, assert_ok + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRemoveFieldFromRepo(object): + def test_api_remove_field_from_repo(self, backend): + repo = backend.create_repo() + repo_name = repo.repo_name + + id_, params = build_data( + self.apikey, 'add_field_to_repo', + repoid=repo_name, + key='extra_field', + label='extra_field_label', + description='extra_field_desc') + response = api_call(self.app, params) + expected = { + 'msg': 'Added new repository field `extra_field`', + 'success': True, + } + assert_ok(id_, expected, given=response.body) + + repo = Repository.get_by_repo_name(repo_name) + repo_field = RepositoryField.get_by_key_name('extra_field', repo) + _data = repo_field.get_dict() + assert _data['field_desc'] == 'extra_field_desc' + assert _data['field_key'] == 'extra_field' + assert _data['field_label'] == 'extra_field_label' + + id_, params = build_data( + self.apikey, 'remove_field_from_repo', + repoid=repo_name, + key='extra_field') + response = api_call(self.app, params) + expected = { + 'msg': 'Deleted repository field `extra_field`', + 'success': True, + } + assert_ok(id_, expected, given=response.body) + repo = Repository.get_by_repo_name(repo_name) + repo_field = RepositoryField.get_by_key_name('extra_field', repo) + + assert repo_field is None diff --git a/rhodecode/api/tests/test_remove_user_from_user_group.py b/rhodecode/api/tests/test_remove_user_from_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_remove_user_from_user_group.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRemoveUserFromUserGroup(object): + def test_api_remove_user_from_user_group(self, user_util): + user, group = user_util.create_user_with_group() + user_name = user.username + group_name = group.users_group_name + id_, params = build_data( + self.apikey, 'remove_user_from_user_group', + usergroupid=group_name, + userid=user.username) + response = api_call(self.app, params) + + expected = { + 'msg': 'removed member `%s` from user group `%s`' % ( + user_name, group_name + ), + 'success': True} + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash) + def test_api_remove_user_from_user_group_exception_occurred( + self, user_util): + user, group = user_util.create_user_with_group() + id_, params = build_data( + self.apikey, 'remove_user_from_user_group', + usergroupid=group.users_group_name, userid=user.username) + response = api_call(self.app, params) + expected = 'failed to remove member from user group `%s`' % ( + group.users_group_name) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_repo_locking.py b/rhodecode/api/tests/test_repo_locking.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_repo_locking.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest + +from rhodecode.model.db import Repository +from rhodecode.model.user import UserModel +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils2 import time_to_datetime +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) +from rhodecode.tests import TEST_USER_ADMIN_LOGIN + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestLock(object): + def test_api_lock_repo_lock_aquire(self, backend): + id_, params = build_data( + self.apikey, 'lock', + userid=TEST_USER_ADMIN_LOGIN, + repoid=backend.repo_name, + locked=True) + response = api_call(self.app, params) + expected = { + 'repo': backend.repo_name, 'locked': True, + 'locked_since': response.json['result']['locked_since'], + 'locked_by': TEST_USER_ADMIN_LOGIN, + 'lock_state_changed': True, + 'lock_reason': Repository.LOCK_API, + 'msg': ('User `%s` set lock state for repo `%s` to `%s`' + % (TEST_USER_ADMIN_LOGIN, backend.repo_name, True)) + } + assert_ok(id_, expected, given=response.body) + + def test_repo_lock_aquire_by_non_admin(self, backend): + repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) + repo_name = repo.repo_name + id_, params = build_data( + self.apikey_regular, 'lock', + repoid=repo_name, + locked=True) + response = api_call(self.app, params) + expected = { + 'repo': repo_name, + 'locked': True, + 'locked_since': response.json['result']['locked_since'], + 'locked_by': self.TEST_USER_LOGIN, + 'lock_state_changed': True, + 'lock_reason': Repository.LOCK_API, + 'msg': ('User `%s` set lock state for repo `%s` to `%s`' + % (self.TEST_USER_LOGIN, repo_name, True)) + } + assert_ok(id_, expected, given=response.body) + + def test_api_lock_repo_lock_aquire_non_admin_with_userid(self, backend): + repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) + repo_name = repo.repo_name + id_, params = build_data( + self.apikey_regular, 'lock', + userid=TEST_USER_ADMIN_LOGIN, + repoid=repo_name, + locked=True) + response = api_call(self.app, params) + expected = 'userid is not the same as your user' + assert_error(id_, expected, given=response.body) + + def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self, backend): + id_, params = build_data( + self.apikey_regular, 'lock', + repoid=backend.repo_name, + locked=True) + response = api_call(self.app, params) + expected = 'repository `%s` does not exist' % (backend.repo_name, ) + assert_error(id_, expected, given=response.body) + + def test_api_lock_repo_lock_release(self, backend): + id_, params = build_data( + self.apikey, 'lock', + userid=TEST_USER_ADMIN_LOGIN, + repoid=backend.repo_name, + locked=False) + response = api_call(self.app, params) + expected = { + 'repo': backend.repo_name, + 'locked': False, + 'locked_since': None, + 'locked_by': TEST_USER_ADMIN_LOGIN, + 'lock_state_changed': True, + 'lock_reason': Repository.LOCK_API, + 'msg': ('User `%s` set lock state for repo `%s` to `%s`' + % (TEST_USER_ADMIN_LOGIN, backend.repo_name, False)) + } + assert_ok(id_, expected, given=response.body) + + def test_api_lock_repo_lock_aquire_optional_userid(self, backend): + id_, params = build_data( + self.apikey, 'lock', + repoid=backend.repo_name, + locked=True) + response = api_call(self.app, params) + time_ = response.json['result']['locked_since'] + expected = { + 'repo': backend.repo_name, + 'locked': True, + 'locked_since': time_, + 'locked_by': TEST_USER_ADMIN_LOGIN, + 'lock_state_changed': True, + 'lock_reason': Repository.LOCK_API, + 'msg': ('User `%s` set lock state for repo `%s` to `%s`' + % (TEST_USER_ADMIN_LOGIN, backend.repo_name, True)) + } + + assert_ok(id_, expected, given=response.body) + + def test_api_lock_repo_lock_optional_locked(self, backend): + # TODO: Provide a fixture locked_repository or similar + repo = Repository.get_by_repo_name(backend.repo_name) + user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + Repository.lock(repo, user.user_id, lock_reason=Repository.LOCK_API) + + id_, params = build_data(self.apikey, 'lock', repoid=backend.repo_name) + response = api_call(self.app, params) + time_ = response.json['result']['locked_since'] + expected = { + 'repo': backend.repo_name, + 'locked': True, + 'locked_since': time_, + 'locked_by': TEST_USER_ADMIN_LOGIN, + 'lock_state_changed': False, + 'lock_reason': Repository.LOCK_API, + 'msg': ('Repo `%s` locked by `%s` on `%s`.' + % (backend.repo_name, TEST_USER_ADMIN_LOGIN, + json.dumps(time_to_datetime(time_)))) + } + assert_ok(id_, expected, given=response.body) + + def test_api_lock_repo_lock_optional_not_locked(self, backend): + repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) + repo_name = repo.repo_name + assert repo.locked == [None, None, None] + id_, params = build_data(self.apikey, 'lock', repoid=repo.repo_id) + response = api_call(self.app, params) + expected = { + 'repo': repo_name, + 'locked': False, + 'locked_since': None, + 'locked_by': None, + 'lock_state_changed': False, + 'lock_reason': None, + 'msg': ('Repo `%s` not locked.' % (repo_name,)) + } + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(Repository, 'lock', crash) + def test_api_lock_error(self, backend): + id_, params = build_data( + self.apikey, 'lock', + userid=TEST_USER_ADMIN_LOGIN, + repoid=backend.repo_name, + locked=True) + response = api_call(self.app, params) + + expected = 'Error occurred locking repository `%s`' % ( + backend.repo_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_rescan_repos.py b/rhodecode/api/tests/test_rescan_repos.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_rescan_repos.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.scm import ScmModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRescanRepos(object): + def test_api_rescan_repos(self): + id_, params = build_data(self.apikey, 'rescan_repos') + response = api_call(self.app, params) + + expected = {'added': [], 'removed': []} + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(ScmModel, 'repo_scan', crash) + def test_api_rescann_error(self): + id_, params = build_data(self.apikey, 'rescan_repos', ) + response = api_call(self.app, params) + + expected = 'Error occurred during rescan repositories action' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_group_permission.py b/rhodecode/api/tests/test_revoke_user_group_permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_group_permission.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserGroupPermission(object): + def test_api_revoke_user_group_permission(self, backend, user_util): + repo = backend.create_repo() + user_group = user_util.create_user_group() + user_util.grant_user_group_permission_to_repo( + repo, user_group, 'repository.read') + id_, params = build_data( + self.apikey, + 'revoke_user_group_permission', + repoid=backend.repo_name, + usergroupid=user_group.users_group_name) + response = api_call(self.app, params) + + expected = { + 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % ( + user_group.users_group_name, backend.repo_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'revoke_user_group_permission', crash) + def test_api_revoke_user_group_permission_exception_when_adding( + self, backend, user_util): + user_group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'revoke_user_group_permission', + repoid=backend.repo_name, + usergroupid=user_group.users_group_name) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user group: `%s` in repo: `%s`' % ( + user_group.users_group_name, backend.repo_name + ) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py b/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserGroupPermissionFromRepoGroup(object): + @pytest.mark.parametrize("name, apply_to_children", [ + ('none', 'none'), + ('all', 'all'), + ('repos', 'repos'), + ('groups', 'groups'), + ]) + def test_api_revoke_user_group_permission_from_repo_group( + self, name, apply_to_children, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + user_util.grant_user_group_permission_to_repo_group( + repo_group, user_group, 'group.read') + + id_, params = build_data( + self.apikey, 'revoke_user_group_permission_from_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + + expected = { + 'msg': ( + 'Revoked perm (recursive:%s) for user group: `%s`' + ' in repo group: `%s`' % ( + apply_to_children, user_group.users_group_name, + repo_group.name + ) + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize( + "name, apply_to_children, grant_admin, access_ok", [ + ('none', 'none', False, False), + ('all', 'all', False, False), + ('repos', 'repos', False, False), + ('groups', 'groups', False, False), + + # after granting admin rights + ('none', 'none', False, False), + ('all', 'all', False, False), + ('repos', 'repos', False, False), + ('groups', 'groups', False, False), + ] + ) + def test_api_revoke_user_group_permission_from_repo_group_by_regular_user( + self, name, apply_to_children, grant_admin, access_ok, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + user_util.grant_user_group_permission_to_repo_group( + repo_group, user_group, 'group.read') + + if grant_admin: + user_util.grant_user_permission_to_repo_group( + repo_group.name, self.TEST_USER_LOGIN, 'group.admin') + + id_, params = build_data( + self.apikey_regular, + 'revoke_user_group_permission_from_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + if access_ok: + expected = { + 'msg': ( + 'Revoked perm (recursive:%s) for user group: `%s`' + ' in repo group: `%s`' % ( + apply_to_children, TEST_USER_ADMIN_LOGIN, + repo_group.name + ) + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + else: + expected = 'repository group `%s` does not exist' % ( + repo_group.name,) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoGroupModel, 'revoke_user_group_permission', crash) + def test_api_revoke_user_group_permission_from_repo_group_exception_on_add( + self, user_util): + user_group = user_util.create_user_group() + repo_group = user_util.create_repo_group() + id_, params = build_data( + self.apikey, 'revoke_user_group_permission_from_repo_group', + repogroupid=repo_group.name, + usergroupid=user_group.users_group_name) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user group: `%s`' + ' in repo group: `%s`' % ( + user_group.users_group_name, repo_group.name) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py b/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import build_data, api_call, assert_ok + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserGroupPermissionFromUserGroup(object): + @pytest.mark.parametrize("name", [ + ('none',), + ('all',), + ('repos',), + ('groups',), + ]) + def test_api_revoke_user_group_permission_from_user_group( + self, name, user_util): + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + group = user_util.create_user_group() + source_group = user_util.create_user_group() + + user_util.grant_user_permission_to_user_group( + group, user, 'usergroup.read') + user_util.grant_user_group_permission_to_user_group( + source_group, group, 'usergroup.read') + + id_, params = build_data( + self.apikey, 'revoke_user_group_permission_from_user_group', + usergroupid=group.users_group_name, + sourceusergroupid=source_group.users_group_name) + response = api_call(self.app, params) + + expected = { + 'msg': 'Revoked perm for user group: `%s` in user group: `%s`' % ( + source_group.users_group_name, group.users_group_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_permission.py b/rhodecode/api/tests/test_revoke_user_permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_permission.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserPermission(object): + def test_api_revoke_user_permission(self, backend, user_util): + repo = backend.create_repo() + user = user_util.create_user() + user_util.grant_user_permission_to_repo( + repo, user, 'repository.read') + + id_, params = build_data( + self.apikey, + 'revoke_user_permission', + repoid=repo.repo_name, + userid=user.username) + response = api_call(self.app, params) + + expected = { + 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % ( + user.username, backend.repo_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + @mock.patch.object(RepoModel, 'revoke_user_permission', crash) + def test_api_revoke_user_permission_exception_when_adding( + self, backend, user_util): + user = user_util.create_user() + id_, params = build_data( + self.apikey, + 'revoke_user_permission', + repoid=backend.repo_name, + userid=user.username) + response = api_call(self.app, params) + + expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( + user.username, backend.repo_name + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py b/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserPermissionFromRepoGroup(object): + @pytest.mark.parametrize("name, apply_to_children", [ + ('none', 'none'), + ('all', 'all'), + ('repos', 'repos'), + ('groups', 'groups'), + ]) + def test_api_revoke_user_permission_from_repo_group( + self, name, apply_to_children, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + user_util.grant_user_permission_to_repo_group( + repo_group, user, 'group.read') + + id_, params = build_data( + self.apikey, + 'revoke_user_permission_from_repo_group', + repogroupid=repo_group.name, + userid=user.username, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + + expected = { + 'msg': ( + 'Revoked perm (recursive:%s) for user: `%s`' + ' in repo group: `%s`' % ( + apply_to_children, user.username, repo_group.name + ) + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize( + "name, apply_to_children, grant_admin, access_ok", [ + ('none', 'none', False, False), + ('all', 'all', False, False), + ('repos', 'repos', False, False), + ('groups', 'groups', False, False), + + # after granting admin rights + ('none', 'none', False, False), + ('all', 'all', False, False), + ('repos', 'repos', False, False), + ('groups', 'groups', False, False), + ] + ) + def test_api_revoke_user_permission_from_repo_group_by_regular_user( + self, name, apply_to_children, grant_admin, access_ok, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + permission = 'group.admin' if grant_admin else 'group.read' + user_util.grant_user_permission_to_repo_group( + repo_group, user, permission) + + id_, params = build_data( + self.apikey_regular, + 'revoke_user_permission_from_repo_group', + repogroupid=repo_group.name, + userid=user.username, + apply_to_children=apply_to_children,) + response = api_call(self.app, params) + if access_ok: + expected = { + 'msg': ( + 'Revoked perm (recursive:%s) for user: `%s`' + ' in repo group: `%s`' % ( + apply_to_children, user.username, repo_group.name + ) + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + else: + expected = 'repository group `%s` does not exist' % ( + repo_group.name) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(RepoGroupModel, 'revoke_user_permission', crash) + def test_api_revoke_user_permission_from_repo_group_exception_when_adding( + self, user_util): + user = user_util.create_user() + repo_group = user_util.create_repo_group() + id_, params = build_data( + self.apikey, + 'revoke_user_permission_from_repo_group', + repogroupid=repo_group.name, + userid=user.username + ) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user: `%s` in repo group: `%s`' % ( + user.username, repo_group.name + ) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py b/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user_group import UserGroupModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestRevokeUserPermissionFromUserGroup(object): + @pytest.mark.parametrize("name", [ + ('none',), + ('all',), + ('repos',), + ('groups',), + ]) + def test_api_revoke_user_permission_from_user_group(self, name, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + user_util.grant_user_permission_to_user_group( + group, user, 'usergroup.admin') + + id_, params = build_data( + self.apikey, + 'revoke_user_permission_from_user_group', + usergroupid=group.users_group_name, + userid=user.username) + response = api_call(self.app, params) + + expected = { + 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % ( + user.username, group.users_group_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize("name, grant_admin, access_ok", [ + ('none', False, False), + ('all', False, False), + ('repos', False, False), + ('groups', False, False), + + # after granting admin rights + ('none', False, False), + ('all', False, False), + ('repos', False, False), + ('groups', False, False), + ]) + def test_api_revoke_user_permission_from_user_group_by_regular_user( + self, name, grant_admin, access_ok, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + permission = 'usergroup.admin' if grant_admin else 'usergroup.read' + user_util.grant_user_permission_to_user_group(group, user, permission) + + id_, params = build_data( + self.apikey_regular, + 'revoke_user_permission_from_user_group', + usergroupid=group.users_group_name, + userid=user.username) + response = api_call(self.app, params) + if access_ok: + expected = { + 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % ( + user.username, group.users_group_name + ), + 'success': True + } + assert_ok(id_, expected, given=response.body) + else: + expected = 'user group `%s` does not exist' % ( + group.users_group_name) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(UserGroupModel, 'revoke_user_permission', crash) + def test_api_revoke_user_permission_from_user_group_exception_when_adding( + self, user_util): + user = user_util.create_user() + group = user_util.create_user_group() + id_, params = build_data( + self.apikey, + 'revoke_user_permission_from_user_group', + usergroupid=group.users_group_name, + userid=user.username) + response = api_call(self.app, params) + + expected = ( + 'failed to edit permission for user: `%s` in user group: `%s`' % ( + user.username, group.users_group_name) + ) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_update_pull_request.py b/rhodecode/api/tests/test_update_pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_update_pull_request.py @@ -0,0 +1,207 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.lib.vcs.nodes import FileNode +from rhodecode.model.db import User +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import (build_data, api_call) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestUpdatePullRequest(object): + + @pytest.mark.backends("git", "hg") + def test_api_update_pull_request_title_or_description( + self, pr_util, silence_action_logger, no_notifications): + pull_request = pr_util.create_pull_request() + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + title='New TITLE OF A PR', + description='New DESC OF A PR', + ) + response = api_call(self.app, params) + + expected = { + "msg": "Updated pull request `{}`".format( + pull_request.pull_request_id), + "pull_request": response.json['result']['pull_request'], + "updated_commits": {"added": [], "common": [], "removed": []}, + "updated_reviewers": {"added": [], "removed": []}, + } + + response_json = response.json['result'] + assert response_json == expected + pr = response_json['pull_request'] + assert pr['title'] == 'New TITLE OF A PR' + assert pr['description'] == 'New DESC OF A PR' + + @pytest.mark.backends("git", "hg") + def test_api_try_update_closed_pull_request( + self, pr_util, silence_action_logger, no_notifications): + pull_request = pr_util.create_pull_request() + PullRequestModel().close_pull_request( + pull_request, TEST_USER_ADMIN_LOGIN) + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id) + response = api_call(self.app, params) + + expected = 'pull request `{}` update failed, pull request ' \ + 'is closed'.format(pull_request.pull_request_id) + + response_json = response.json['error'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_update_commits( + self, pr_util, silence_action_logger, no_notifications): + commits = [ + {'message': 'a'}, + {'message': 'b', 'added': [FileNode('file_b', 'test_content\n')]}, + {'message': 'c', 'added': [FileNode('file_c', 'test_content\n')]}, + ] + pull_request = pr_util.create_pull_request( + commits=commits, target_head='a', source_head='b', revisions=['b']) + pr_util.update_source_repository(head='c') + repo = pull_request.source_repo.scm_instance() + commits = [x for x in repo.get_commits()] + + added_commit_id = commits[-1].raw_id # c commit + common_commits = commits[1].raw_id # b commit is common ancestor + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + update_commits=True + ) + response = api_call(self.app, params) + + expected = { + "msg": "Updated pull request `{}`".format( + pull_request.pull_request_id), + "pull_request": response.json['result']['pull_request'], + "updated_commits": {"added": [added_commit_id], + "common": [common_commits], "removed": []}, + "updated_reviewers": {"added": [], "removed": []}, + } + + response_json = response.json['result'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_change_reviewers( + self, pr_util, silence_action_logger, no_notifications): + + users = [x.username for x in User.get_all()] + new = [users.pop(0)] + removed = sorted(new) + added = sorted(users) + + pull_request = pr_util.create_pull_request(reviewers=new) + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + reviewers=added) + response = api_call(self.app, params) + expected = { + "msg": "Updated pull request `{}`".format( + pull_request.pull_request_id), + "pull_request": response.json['result']['pull_request'], + "updated_commits": {"added": [], "common": [], "removed": []}, + "updated_reviewers": {"added": added, "removed": removed}, + } + + response_json = response.json['result'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_bad_user_in_reviewers(self, pr_util): + pull_request = pr_util.create_pull_request() + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id, + reviewers=['bad_name']) + response = api_call(self.app, params) + + expected = 'user `bad_name` does not exist' + + response_json = response.json['error'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_repo_error(self, pr_util): + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid='fake', + pullrequestid='fake', + reviewers=['bad_name']) + response = api_call(self.app, params) + + expected = 'repository `fake` does not exist' + + response_json = response.json['error'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_pull_request_error(self, pr_util): + pull_request = pr_util.create_pull_request() + + id_, params = build_data( + self.apikey, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=999999, + reviewers=['bad_name']) + response = api_call(self.app, params) + + expected = 'pull request `999999` does not exist' + + response_json = response.json['error'] + assert response_json == expected + + @pytest.mark.backends("git", "hg") + def test_api_update_pull_request_no_perms_to_update( + self, user_util, pr_util): + user = user_util.create_user() + pull_request = pr_util.create_pull_request() + + id_, params = build_data( + user.api_key, 'update_pull_request', + repoid=pull_request.target_repo.repo_name, + pullrequestid=pull_request.pull_request_id,) + response = api_call(self.app, params) + + expected = ('pull request `%s` update failed, ' + 'no permission to update.') % pull_request.pull_request_id + + response_json = response.json['error'] + assert response_json == expected diff --git a/rhodecode/api/tests/test_update_repo.py b/rhodecode/api/tests/test_update_repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_update_repo.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.repo import RepoModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) +from rhodecode.tests.fixture import Fixture + + +fixture = Fixture() + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiUpdateRepo(object): + @pytest.mark.parametrize("changing_attr, updates", [ + ('owner', {'owner': TEST_USER_REGULAR_LOGIN}), + ('description', {'description': 'new description'}), + ('active', {'active': True}), + ('active', {'active': False}), + ('clone_uri', {'clone_uri': 'http://foo.com/repo'}), + ('clone_uri', {'clone_uri': None}), + ('landing_rev', {'landing_rev': 'branch:master'}), + ('enable_statistics', {'enable_statistics': True}), + ('enable_locking', {'enable_locking': True}), + ('enable_downloads', {'enable_downloads': True}), + ('name', {'name': 'new_repo_name'}), + ('repo_group', {'group': 'test_group_for_update'}), + ]) + def test_api_update_repo(self, changing_attr, updates, backend): + repo_name = 'api_update_me' + repo = fixture.create_repo(repo_name, repo_type=backend.alias) + if changing_attr == 'repo_group': + fixture.create_repo_group(updates['group']) + + id_, params = build_data( + self.apikey, 'update_repo', repoid=repo_name, **updates) + response = api_call(self.app, params) + if changing_attr == 'name': + repo_name = updates['name'] + if changing_attr == 'repo_group': + repo_name = '/'.join([updates['group'], repo_name]) + try: + expected = { + 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name), + 'repository': repo.get_api_data(include_secrets=True) + } + assert_ok(id_, expected, given=response.body) + finally: + fixture.destroy_repo(repo_name) + if changing_attr == 'repo_group': + + fixture.destroy_repo_group(updates['group']) + + def test_api_update_repo_fork_of_field(self, backend): + master_repo = backend.create_repo() + repo = backend.create_repo() + + updates = { + 'fork_of': master_repo.repo_name + } + id_, params = build_data( + self.apikey, 'update_repo', repoid=repo.repo_name, **updates) + response = api_call(self.app, params) + expected = { + 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name), + 'repository': repo.get_api_data(include_secrets=True) + } + assert_ok(id_, expected, given=response.body) + result = response.json['result']['repository'] + assert result['fork_of'] == master_repo.repo_name + + def test_api_update_repo_fork_of_not_found(self, backend): + master_repo_name = 'fake-parent-repo' + repo = backend.create_repo() + updates = { + 'fork_of': master_repo_name + } + id_, params = build_data( + self.apikey, 'update_repo', repoid=repo.repo_name, **updates) + response = api_call(self.app, params) + expected = 'repository `{}` does not exist'.format(master_repo_name) + assert_error(id_, expected, given=response.body) + + def test_api_update_repo_with_repo_group_not_existing(self): + repo_name = 'admin_owned' + fixture.create_repo(repo_name) + updates = {'group': 'test_group_for_update'} + id_, params = build_data( + self.apikey, 'update_repo', repoid=repo_name, **updates) + response = api_call(self.app, params) + try: + expected = 'repository group `%s` does not exist' % ( + updates['group'],) + assert_error(id_, expected, given=response.body) + finally: + fixture.destroy_repo(repo_name) + + def test_api_update_repo_regular_user_not_allowed(self): + repo_name = 'admin_owned' + fixture.create_repo(repo_name) + updates = {'active': False} + id_, params = build_data( + self.apikey_regular, 'update_repo', repoid=repo_name, **updates) + response = api_call(self.app, params) + try: + expected = 'repository `%s` does not exist' % (repo_name,) + assert_error(id_, expected, given=response.body) + finally: + fixture.destroy_repo(repo_name) + + @mock.patch.object(RepoModel, 'update', crash) + def test_api_update_repo_exception_occurred(self, backend): + repo_name = 'api_update_me' + fixture.create_repo(repo_name, repo_type=backend.alias) + id_, params = build_data( + self.apikey, 'update_repo', repoid=repo_name, + owner=TEST_USER_ADMIN_LOGIN,) + response = api_call(self.app, params) + try: + expected = 'failed to update repo `%s`' % (repo_name,) + assert_error(id_, expected, given=response.body) + finally: + fixture.destroy_repo(repo_name) diff --git a/rhodecode/api/tests/test_update_repo_group.py b/rhodecode/api/tests/test_update_repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_update_repo_group.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os + +import pytest + +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.user import UserModel +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestApiUpdateRepoGroup(object): + def test_update_group_name(self, user_util): + new_group_name = 'new-group' + initial_name = self._update(user_util, group_name=new_group_name) + assert RepoGroupModel()._get_repo_group(initial_name) is None + assert RepoGroupModel()._get_repo_group(new_group_name) is not None + + def test_update_parent(self, user_util): + parent_group = user_util.create_repo_group() + initial_name = self._update(user_util, parent=parent_group.name) + + expected_group_name = '{}/{}'.format(parent_group.name, initial_name) + repo_group = RepoGroupModel()._get_repo_group(expected_group_name) + assert repo_group is not None + assert repo_group.group_name == expected_group_name + assert repo_group.name == initial_name + assert RepoGroupModel()._get_repo_group(initial_name) is None + new_path = os.path.join( + RepoGroupModel().repos_path, *repo_group.full_path_splitted) + assert os.path.exists(new_path) + + def test_update_enable_locking(self, user_util): + initial_name = self._update(user_util, enable_locking=True) + repo_group = RepoGroupModel()._get_repo_group(initial_name) + assert repo_group.enable_locking is True + + def test_update_description(self, user_util): + description = 'New description' + initial_name = self._update(user_util, description=description) + repo_group = RepoGroupModel()._get_repo_group(initial_name) + assert repo_group.group_description == description + + def test_update_owner(self, user_util): + owner = self.TEST_USER_LOGIN + initial_name = self._update(user_util, owner=owner) + repo_group = RepoGroupModel()._get_repo_group(initial_name) + assert repo_group.user.username == owner + + def test_api_update_repo_group_by_regular_user_no_permission( + self, backend): + repo = backend.create_repo() + repo_name = repo.repo_name + + id_, params = build_data( + self.apikey_regular, 'update_repo_group', repogroupid=repo_name) + response = api_call(self.app, params) + expected = 'repository group `%s` does not exist' % (repo_name,) + assert_error(id_, expected, given=response.body) + + def _update(self, user_util, **kwargs): + repo_group = user_util.create_repo_group() + initial_name = repo_group.name + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + user_util.grant_user_permission_to_repo_group( + repo_group, user, 'group.admin') + + id_, params = build_data( + self.apikey, 'update_repo_group', repogroupid=initial_name, + **kwargs) + response = api_call(self.app, params) + ret = { + 'msg': 'updated repository group ID:{} {}'.format( + repo_group.group_id, repo_group.group_name), + 'repo_group': { + 'repositories': [], + 'group_name': repo_group.group_name, + 'group_description': repo_group.group_description, + 'owner': repo_group.user.username, + 'group_id': repo_group.group_id, + 'parent_group': ( + repo_group.parent_group.name + if repo_group.parent_group else None) + } + } + assert_ok(id_, ret, given=response.body) + return initial_name diff --git a/rhodecode/api/tests/test_update_user.py b/rhodecode/api/tests/test_update_user.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_update_user.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.db import User +from rhodecode.model.user import UserModel +from rhodecode.tests import TEST_USER_ADMIN_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_ok, assert_error, crash, jsonify) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestUpdateUser(object): + @pytest.mark.parametrize("name, expected", [ + ('firstname', 'new_username'), + ('lastname', 'new_username'), + ('email', 'new_username'), + ('admin', True), + ('admin', False), + ('extern_type', 'ldap'), + ('extern_type', None), + ('extern_name', 'test'), + ('extern_name', None), + ('active', False), + ('active', True), + ('password', 'newpass') + ]) + def test_api_update_user(self, name, expected, user_util): + usr = user_util.create_user() + + kw = {name: expected, 'userid': usr.user_id} + id_, params = build_data(self.apikey, 'update_user', **kw) + response = api_call(self.app, params) + + ret = { + 'msg': 'updated user ID:%s %s' % (usr.user_id, usr.username), + 'user': jsonify( + UserModel() + .get_by_username(usr.username) + .get_api_data(include_secrets=True) + ) + } + + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_update_user_no_changed_params(self): + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + ret = jsonify(usr.get_api_data(include_secrets=True)) + id_, params = build_data( + self.apikey, 'update_user', userid=TEST_USER_ADMIN_LOGIN) + + response = api_call(self.app, params) + ret = { + 'msg': 'updated user ID:%s %s' % ( + usr.user_id, TEST_USER_ADMIN_LOGIN), + 'user': ret + } + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_update_user_by_user_id(self): + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + ret = jsonify(usr.get_api_data(include_secrets=True)) + id_, params = build_data( + self.apikey, 'update_user', userid=usr.user_id) + + response = api_call(self.app, params) + ret = { + 'msg': 'updated user ID:%s %s' % ( + usr.user_id, TEST_USER_ADMIN_LOGIN), + 'user': ret + } + expected = ret + assert_ok(id_, expected, given=response.body) + + def test_api_update_user_default_user(self): + usr = User.get_default_user() + id_, params = build_data( + self.apikey, 'update_user', userid=usr.user_id) + + response = api_call(self.app, params) + expected = 'editing default user is forbidden' + assert_error(id_, expected, given=response.body) + + @mock.patch.object(UserModel, 'update_user', crash) + def test_api_update_user_when_exception_happens(self): + usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) + ret = jsonify(usr.get_api_data(include_secrets=True)) + id_, params = build_data( + self.apikey, 'update_user', userid=usr.user_id) + + response = api_call(self.app, params) + ret = 'failed to update user `%s`' % (usr.user_id,) + + expected = ret + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_update_user_group.py b/rhodecode/api/tests/test_update_user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_update_user_group.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pytest + +from rhodecode.model.user import UserModel +from rhodecode.model.user_group import UserGroupModel +from rhodecode.tests import TEST_USER_REGULAR_LOGIN +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok, crash) + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestUpdateUserGroup(object): + @pytest.mark.parametrize("changing_attr, updates", [ + ('group_name', {'group_name': 'new_group_name'}), + ('group_name', {'group_name': 'test_group_for_update'}), + ('owner', {'owner': TEST_USER_REGULAR_LOGIN}), + ('active', {'active': False}), + ('active', {'active': True}) + ]) + def test_api_update_user_group(self, changing_attr, updates, user_util): + user_group = user_util.create_user_group() + group_name = user_group.users_group_name + id_, params = build_data( + self.apikey, 'update_user_group', usergroupid=group_name, + **updates) + response = api_call(self.app, params) + expected = { + 'msg': 'updated user group ID:%s %s' % ( + user_group.users_group_id, user_group.users_group_name), + 'user_group': user_group.get_api_data() + } + assert_ok(id_, expected, given=response.body) + + @pytest.mark.parametrize("changing_attr, updates", [ + # TODO: mikhail: decide if we need to test against the commented params + # ('group_name', {'group_name': 'new_group_name'}), + # ('group_name', {'group_name': 'test_group_for_update'}), + ('owner', {'owner': TEST_USER_REGULAR_LOGIN}), + ('active', {'active': False}), + ('active', {'active': True}) + ]) + def test_api_update_user_group_regular_user( + self, changing_attr, updates, user_util): + user_group = user_util.create_user_group() + group_name = user_group.users_group_name + # grant permission to this user + user = UserModel().get_by_username(self.TEST_USER_LOGIN) + + user_util.grant_user_permission_to_user_group( + user_group, user, 'usergroup.admin') + id_, params = build_data( + self.apikey_regular, 'update_user_group', + usergroupid=group_name, **updates) + response = api_call(self.app, params) + expected = { + 'msg': 'updated user group ID:%s %s' % ( + user_group.users_group_id, user_group.users_group_name), + 'user_group': user_group.get_api_data() + } + assert_ok(id_, expected, given=response.body) + + def test_api_update_user_group_regular_user_no_permission(self, user_util): + user_group = user_util.create_user_group() + group_name = user_group.users_group_name + id_, params = build_data( + self.apikey_regular, 'update_user_group', usergroupid=group_name) + response = api_call(self.app, params) + + expected = 'user group `%s` does not exist' % (group_name) + assert_error(id_, expected, given=response.body) + + @mock.patch.object(UserGroupModel, 'update', crash) + def test_api_update_user_group_exception_occurred(self, user_util): + user_group = user_util.create_user_group() + group_name = user_group.users_group_name + id_, params = build_data( + self.apikey, 'update_user_group', usergroupid=group_name) + response = api_call(self.app, params) + expected = 'failed to update user group `%s`' % (group_name,) + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_utils.py b/rhodecode/api/tests/test_utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_utils.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pytest +from mock import Mock, patch + +from rhodecode.api import utils +from rhodecode.api import JSONRPCError +from rhodecode.lib.vcs.exceptions import RepositoryError + + +class TestGetCommitOrError(object): + def setup(self): + self.commit_hash = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa10' + + @pytest.mark.parametrize("ref", ['ref', '12345', 'a:b:c:d', 'branch:name']) + def test_ref_cannot_be_parsed(self, ref): + repo = Mock() + with pytest.raises(JSONRPCError) as excinfo: + utils.get_commit_or_error(ref, repo) + expected_message = ( + 'Ref `{ref}` given in a wrong format. Please check the API' + ' documentation for more details'.format(ref=ref) + ) + assert excinfo.value.message == expected_message + + def test_success_with_hash_specified(self): + repo = Mock() + ref_type = 'branch' + ref = '{}:master:{}'.format(ref_type, self.commit_hash) + + with patch('rhodecode.api.utils.get_commit_from_ref_name') as get_commit: + result = utils.get_commit_or_error(ref, repo) + get_commit.assert_called_once_with( + repo, self.commit_hash) + assert result == get_commit() + + def test_raises_an_error_when_commit_not_found(self): + repo = Mock() + ref = 'branch:master:{}'.format(self.commit_hash) + + with patch('rhodecode.api.utils.get_commit_from_ref_name') as get_commit: + get_commit.side_effect = RepositoryError('Commit not found') + with pytest.raises(JSONRPCError) as excinfo: + utils.get_commit_or_error(ref, repo) + expected_message = 'Ref `{}` does not exist'.format(ref) + assert excinfo.value.message == expected_message + + +class TestResolveRefOrError(object): + def setup(self): + self.commit_hash = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa10' + + def test_success_with_no_hash_specified(self): + repo = Mock() + ref_type = 'branch' + ref_name = 'master' + ref = '{}:{}'.format(ref_type, ref_name) + + with patch('rhodecode.api.utils._get_ref_hash') \ + as _get_ref_hash: + _get_ref_hash.return_value = self.commit_hash + result = utils.resolve_ref_or_error(ref, repo) + _get_ref_hash.assert_called_once_with(repo, ref_type, ref_name) + assert result == '{}:{}'.format(ref, self.commit_hash) + + def test_non_supported_refs(self): + repo = Mock() + ref = 'ancestor:ref' + with pytest.raises(JSONRPCError) as excinfo: + utils.resolve_ref_or_error(ref, repo) + expected_message = 'The specified ancestor `ref` does not exist' + assert excinfo.value.message == expected_message + + def test_branch_is_not_found(self): + repo = Mock() + ref = 'branch:non-existing-one' + with patch('rhodecode.api.utils._get_ref_hash')\ + as _get_ref_hash: + _get_ref_hash.side_effect = KeyError() + with pytest.raises(JSONRPCError) as excinfo: + utils.resolve_ref_or_error(ref, repo) + expected_message = ( + 'The specified branch `non-existing-one` does not exist') + assert excinfo.value.message == expected_message + + def test_bookmark_is_not_found(self): + repo = Mock() + ref = 'bookmark:non-existing-one' + with patch('rhodecode.api.utils._get_ref_hash')\ + as _get_ref_hash: + _get_ref_hash.side_effect = KeyError() + with pytest.raises(JSONRPCError) as excinfo: + utils.resolve_ref_or_error(ref, repo) + expected_message = ( + 'The specified bookmark `non-existing-one` does not exist') + assert excinfo.value.message == expected_message + + @pytest.mark.parametrize("ref", ['ref', '12345', 'a:b:c:d']) + def test_ref_cannot_be_parsed(self, ref): + repo = Mock() + with pytest.raises(JSONRPCError) as excinfo: + utils.resolve_ref_or_error(ref, repo) + expected_message = ( + 'Ref `{ref}` given in a wrong format. Please check the API' + ' documentation for more details'.format(ref=ref) + ) + assert excinfo.value.message == expected_message + + +class TestGetRefHash(object): + def setup(self): + self.commit_hash = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa10' + self.bookmark_name = 'test-bookmark' + + @pytest.mark.parametrize("alias, branch_name", [ + ("git", "master"), + ("hg", "default") + ]) + def test_returns_hash_by_branch_name(self, alias, branch_name): + with patch('rhodecode.model.db.Repository') as repo: + repo.scm_instance().alias = alias + repo.scm_instance().branches = {branch_name: self.commit_hash} + result_hash = utils._get_ref_hash(repo, 'branch', branch_name) + assert result_hash == self.commit_hash + + @pytest.mark.parametrize("alias, branch_name", [ + ("git", "master"), + ("hg", "default") + ]) + def test_raises_error_when_branch_is_not_found(self, alias, branch_name): + with patch('rhodecode.model.db.Repository') as repo: + repo.scm_instance().alias = alias + repo.scm_instance().branches = {} + with pytest.raises(KeyError): + utils._get_ref_hash(repo, 'branch', branch_name) + + def test_returns_hash_when_bookmark_is_specified_for_hg(self): + with patch('rhodecode.model.db.Repository') as repo: + repo.scm_instance().alias = 'hg' + repo.scm_instance().bookmarks = { + self.bookmark_name: self.commit_hash} + result_hash = utils._get_ref_hash( + repo, 'bookmark', self.bookmark_name) + assert result_hash == self.commit_hash + + def test_raises_error_when_bookmark_is_not_found_in_hg_repo(self): + with patch('rhodecode.model.db.Repository') as repo: + repo.scm_instance().alias = 'hg' + repo.scm_instance().bookmarks = {} + with pytest.raises(KeyError): + utils._get_ref_hash(repo, 'bookmark', self.bookmark_name) + + def test_raises_error_when_bookmark_is_specified_for_git(self): + with patch('rhodecode.model.db.Repository') as repo: + repo.scm_instance().alias = 'git' + repo.scm_instance().bookmarks = { + self.bookmark_name: self.commit_hash} + with pytest.raises(ValueError): + utils._get_ref_hash(repo, 'bookmark', self.bookmark_name) + + +class TestUserByNameOrError(object): + def test_user_found_by_id(self): + fake_user = Mock(id=123) + patcher = patch('rhodecode.model.user.UserModel.get_user') + with patcher as get_user: + get_user.return_value = fake_user + result = utils.get_user_or_error('123') + assert result == fake_user + + def test_user_found_by_name(self): + fake_user = Mock(id=123) + patcher = patch('rhodecode.model.user.UserModel.get_by_username') + with patcher as get_by_username: + get_by_username.return_value = fake_user + result = utils.get_user_or_error('test') + assert result == fake_user + + def test_user_not_found_by_id(self): + patcher = patch('rhodecode.model.user.UserModel.get_user') + with patcher as get_user: + get_user.return_value = None + with pytest.raises(JSONRPCError) as excinfo: + utils.get_user_or_error('123') + + expected_message = 'user `123` does not exist' + assert excinfo.value.message == expected_message + + def test_user_not_found_by_name(self): + patcher = patch('rhodecode.model.user.UserModel.get_by_username') + with patcher as get_by_username: + get_by_username.return_value = None + with pytest.raises(JSONRPCError) as excinfo: + utils.get_user_or_error('test') + + expected_message = 'user `test` does not exist' + assert excinfo.value.message == expected_message + + +class TestGetCommitDict: + + @pytest.mark.parametrize('filename, expected', [ + (b'sp\xc3\xa4cial', u'sp\xe4cial'), + (b'sp\xa4cial', u'sp\ufffdcial'), + ]) + def test_decodes_filenames_to_unicode(self, filename, expected): + result = utils._get_commit_dict(filename=filename, op='A') + assert result['filename'] == expected + + +class TestRepoAccess(object): + def setup_method(self, method): + + self.admin_perm_patch = patch( + 'rhodecode.api.utils.HasPermissionAnyApi') + self.repo_perm_patch = patch( + 'rhodecode.api.utils.HasRepoPermissionAnyApi') + + def test_has_superadmin_permission_checks_for_admin(self): + admin_mock = Mock() + with self.admin_perm_patch as amock: + amock.return_value = admin_mock + assert utils.has_superadmin_permission('fake_user') + amock.assert_called_once_with('hg.admin') + + admin_mock.assert_called_once_with(user='fake_user') + + def test_has_repo_permissions_checks_for_repo_access(self): + repo_mock = Mock() + fake_repo = Mock() + with self.repo_perm_patch as rmock: + rmock.return_value = repo_mock + assert utils.has_repo_permissions( + 'fake_user', 'fake_repo_id', fake_repo, + ['perm1', 'perm2']) + rmock.assert_called_once_with(*['perm1', 'perm2']) + + repo_mock.assert_called_once_with( + user='fake_user', repo_name=fake_repo.repo_name) + + def test_has_repo_permissions_raises_not_found(self): + repo_mock = Mock(return_value=False) + fake_repo = Mock() + with self.repo_perm_patch as rmock: + rmock.return_value = repo_mock + with pytest.raises(JSONRPCError) as excinfo: + utils.has_repo_permissions( + 'fake_user', 'fake_repo_id', fake_repo, 'perms') + assert 'fake_repo_id' in excinfo diff --git a/rhodecode/api/tests/utils.py b/rhodecode/api/tests/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/utils.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import random + +from rhodecode.api.utils import get_origin +from rhodecode.lib.ext_json import json + + +API_URL = '/_admin/api' + + +def assert_ok(id_, expected, given): + expected = jsonify({ + 'id': id_, + 'error': None, + 'result': expected + }) + given = json.loads(given) + assert expected == given + + +def assert_error(id_, expected, given): + expected = jsonify({ + 'id': id_, + 'error': expected, + 'result': None + }) + given = json.loads(given) + assert expected == given + + +def jsonify(obj): + return json.loads(json.dumps(obj)) + + +def build_data(apikey, method, **kw): + """ + Builds API data with given random ID + + :param random_id: + """ + random_id = random.randrange(1, 9999) + return random_id, json.dumps({ + "id": random_id, + "api_key": apikey, + "method": method, + "args": kw + }) + + +def api_call(app, params, status=None): + response = app.post( + API_URL, content_type='application/json', params=params, status=status) + return response + + +def crash(*args, **kwargs): + raise Exception('Total Crash !') + + +def expected_permissions(object_with_permissions): + """ + Returns the expected permissions structure for the given object. + + The object is expected to be a `Repository`, `RepositoryGroup`, + or `UserGroup`. They all implement the same permission handling + API. + """ + permissions = [] + for _user in object_with_permissions.permissions(): + user_data = { + 'name': _user.username, + 'permission': _user.permission, + 'origin': get_origin(_user), + 'type': "user", + } + permissions.append(user_data) + + for _user_group in object_with_permissions.permission_user_groups(): + user_group_data = { + 'name': _user_group.users_group_name, + 'permission': _user_group.permission, + 'origin': get_origin(_user_group), + 'type': "user_group", + } + permissions.append(user_group_data) + return permissions diff --git a/rhodecode/api/utils.py b/rhodecode/api/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/utils.py @@ -0,0 +1,378 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +JSON RPC utils +""" + +import collections +import logging + +from rhodecode.api.exc import JSONRPCError +from rhodecode.lib.auth import HasPermissionAnyApi, HasRepoPermissionAnyApi +from rhodecode.lib.utils import safe_unicode +from rhodecode.controllers.utils import get_commit_from_ref_name +from rhodecode.lib.vcs.exceptions import RepositoryError + +log = logging.getLogger(__name__) + + + + +class OAttr(object): + """ + Special Option that defines other attribute, and can default to them + + Example:: + + def test(apiuser, userid=Optional(OAttr('apiuser')): + user = Optional.extract(userid, evaluate_locals=local()) + #if we pass in userid, we get it, else it will default to apiuser + #attribute + """ + + def __init__(self, attr_name): + self.attr_name = attr_name + + def __repr__(self): + return '<OptionalAttr:%s>' % self.attr_name + + def __call__(self): + return self + + +class Optional(object): + """ + Defines an optional parameter:: + + param = param.getval() if isinstance(param, Optional) else param + param = param() if isinstance(param, Optional) else param + + is equivalent of:: + + param = Optional.extract(param) + + """ + + def __init__(self, type_): + self.type_ = type_ + + def __repr__(self): + return '<Optional:%s>' % self.type_.__repr__() + + def __call__(self): + return self.getval() + + def getval(self, evaluate_locals=None): + """ + returns value from this Optional instance + """ + if isinstance(self.type_, OAttr): + param_name = self.type_.attr_name + if evaluate_locals: + return evaluate_locals[param_name] + # use params name + return param_name + return self.type_ + + @classmethod + def extract(cls, val, evaluate_locals=None): + """ + Extracts value from Optional() instance + + :param val: + :return: original value if it's not Optional instance else + value of instance + """ + if isinstance(val, cls): + return val.getval(evaluate_locals) + return val + + +def parse_args(cli_args, key_prefix=''): + from rhodecode.lib.utils2 import (escape_split) + kwargs = collections.defaultdict(dict) + for el in escape_split(cli_args, ','): + kv = escape_split(el, '=', 1) + if len(kv) == 2: + k, v = kv + kwargs[key_prefix + k] = v + return kwargs + + +def get_origin(obj): + """ + Get origin of permission from object. + + :param obj: + """ + origin = 'permission' + + if getattr(obj, 'owner_row', '') and getattr(obj, 'admin_row', ''): + # admin and owner case, maybe we should use dual string ? + origin = 'owner' + elif getattr(obj, 'owner_row', ''): + origin = 'owner' + elif getattr(obj, 'admin_row', ''): + origin = 'super-admin' + return origin + + +def store_update(updates, attr, name): + """ + Stores param in updates dict if it's not instance of Optional + allows easy updates of passed in params + """ + if not isinstance(attr, Optional): + updates[name] = attr + + +def has_superadmin_permission(apiuser): + """ + Return True if apiuser is admin or return False + + :param apiuser: + """ + if HasPermissionAnyApi('hg.admin')(user=apiuser): + return True + return False + + +def has_repo_permissions(apiuser, repoid, repo, perms): + """ + Raise JsonRPCError if apiuser is not authorized or return True + + :param apiuser: + :param repoid: + :param repo: + :param perms: + """ + if not HasRepoPermissionAnyApi(*perms)( + user=apiuser, repo_name=repo.repo_name): + raise JSONRPCError( + 'repository `%s` does not exist' % repoid) + + return True + + +def get_user_or_error(userid): + """ + Get user by id or name or return JsonRPCError if not found + + :param userid: + """ + from rhodecode.model.user import UserModel + + user_model = UserModel() + try: + user = user_model.get_user(int(userid)) + except ValueError: + user = user_model.get_by_username(userid) + + if user is None: + raise JSONRPCError("user `%s` does not exist" % (userid,)) + return user + + +def get_repo_or_error(repoid): + """ + Get repo by id or name or return JsonRPCError if not found + + :param repoid: + """ + from rhodecode.model.repo import RepoModel + + repo = RepoModel().get_repo(repoid) + if repo is None: + raise JSONRPCError('repository `%s` does not exist' % (repoid,)) + return repo + + +def get_repo_group_or_error(repogroupid): + """ + Get repo group by id or name or return JsonRPCError if not found + + :param repogroupid: + """ + from rhodecode.model.repo_group import RepoGroupModel + + repo_group = RepoGroupModel()._get_repo_group(repogroupid) + if repo_group is None: + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + return repo_group + + +def get_user_group_or_error(usergroupid): + """ + Get user group by id or name or return JsonRPCError if not found + + :param usergroupid: + """ + from rhodecode.model.user_group import UserGroupModel + + user_group = UserGroupModel().get_group(usergroupid) + if user_group is None: + raise JSONRPCError('user group `%s` does not exist' % (usergroupid,)) + return user_group + + +def get_perm_or_error(permid, prefix=None): + """ + Get permission by id or name or return JsonRPCError if not found + + :param permid: + """ + from rhodecode.model.permission import PermissionModel + + perm = PermissionModel.cls.get_by_key(permid) + if perm is None: + raise JSONRPCError('permission `%s` does not exist' % (permid,)) + if prefix: + if not perm.permission_name.startswith(prefix): + raise JSONRPCError('permission `%s` is invalid, ' + 'should start with %s' % (permid, prefix)) + return perm + + +def get_gist_or_error(gistid): + """ + Get gist by id or gist_access_id or return JsonRPCError if not found + + :param gistid: + """ + from rhodecode.model.gist import GistModel + + gist = GistModel.cls.get_by_access_id(gistid) + if gist is None: + raise JSONRPCError('gist `%s` does not exist' % (gistid,)) + return gist + + +def get_pull_request_or_error(pullrequestid): + """ + Get pull request by id or return JsonRPCError if not found + + :param pullrequestid: + """ + from rhodecode.model.pull_request import PullRequestModel + + try: + pull_request = PullRequestModel().get(int(pullrequestid)) + except ValueError: + raise JSONRPCError('pullrequestid must be an integer') + if not pull_request: + raise JSONRPCError('pull request `%s` does not exist' % ( + pullrequestid,)) + return pull_request + + +def build_commit_data(commit, detail_level): + parsed_diff = [] + if detail_level == 'extended': + for f in commit.added: + parsed_diff.append(_get_commit_dict(filename=f.path, op='A')) + for f in commit.changed: + parsed_diff.append(_get_commit_dict(filename=f.path, op='M')) + for f in commit.removed: + parsed_diff.append(_get_commit_dict(filename=f.path, op='D')) + + elif detail_level == 'full': + from rhodecode.lib.diffs import DiffProcessor + diff_processor = DiffProcessor(commit.diff()) + for dp in diff_processor.prepare(): + del dp['stats']['ops'] + _stats = dp['stats'] + parsed_diff.append(_get_commit_dict( + filename=dp['filename'], op=dp['operation'], + new_revision=dp['new_revision'], + old_revision=dp['old_revision'], + raw_diff=dp['raw_diff'], stats=_stats)) + + return parsed_diff + + +def get_commit_or_error(ref, repo): + try: + ref_type, _, ref_hash = ref.split(':') + except ValueError: + raise JSONRPCError( + 'Ref `{ref}` given in a wrong format. Please check the API' + ' documentation for more details'.format(ref=ref)) + try: + # TODO: dan: refactor this to use repo.scm_instance().get_commit() + # once get_commit supports ref_types + return get_commit_from_ref_name(repo, ref_hash) + except RepositoryError: + raise JSONRPCError('Ref `{ref}` does not exist'.format(ref=ref)) + + +def resolve_ref_or_error(ref, repo): + def _parse_ref(type_, name, hash_=None): + return type_, name, hash_ + + try: + ref_type, ref_name, ref_hash = _parse_ref(*ref.split(':')) + except TypeError: + raise JSONRPCError( + 'Ref `{ref}` given in a wrong format. Please check the API' + ' documentation for more details'.format(ref=ref)) + + try: + ref_hash = ref_hash or _get_ref_hash(repo, ref_type, ref_name) + except (KeyError, ValueError): + raise JSONRPCError( + 'The specified {type} `{name}` does not exist'.format( + type=ref_type, name=ref_name)) + + return ':'.join([ref_type, ref_name, ref_hash]) + + +def _get_commit_dict( + filename, op, new_revision=None, old_revision=None, + raw_diff=None, stats=None): + if stats is None: + stats = { + "added": None, + "binary": None, + "deleted": None + } + return { + "filename": safe_unicode(filename), + "op": op, + + # extra details + "new_revision": new_revision, + "old_revision": old_revision, + + "raw_diff": raw_diff, + "stats": stats + } + + +# TODO: mikhail: Think about moving this function to some library +def _get_ref_hash(repo, type_, name): + vcs_repo = repo.scm_instance() + if type_ == 'branch' and vcs_repo.alias in ('hg', 'git'): + return vcs_repo.branches[name] + elif type_ == 'bookmark' and vcs_repo.alias == 'hg': + return vcs_repo.bookmarks[name] + else: + raise ValueError() diff --git a/rhodecode/api/views/__init__.py b/rhodecode/api/views/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2015-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/api/views/depracated_api.py b/rhodecode/api/views/depracated_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/depracated_api.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +NOTE: + Place for deprecated APIs here, if a call needs to be deprecated, please + put it here, and point to a new version +""" +import logging + +from rhodecode.api import jsonrpc_method, jsonrpc_deprecated_method +from rhodecode.api.utils import Optional, OAttr + + +log = logging.getLogger(__name__) + + +# permission check inside +@jsonrpc_method() +@jsonrpc_deprecated_method( + use_method='comment_commit', deprecated_at_version='3.4.0') +def changeset_comment(request, apiuser, repoid, revision, message, + userid=Optional(OAttr('apiuser')), + status=Optional(None)): + """ + Set a changeset comment, and optionally change the status of the + changeset. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param revision: Specify the revision for which to set a comment. + :type revision: str + :param message: The comment text. + :type message: str + :param userid: Set the user name of the comment creator. + :type userid: Optional(str or int) + :param status: Set the comment status. The following are valid options: + * not_reviewed + * approved + * rejected + * under_review + :type status: str + + Example error output: + + .. code-block:: json + + { + "id" : <id_given_in_input>, + "result" : { + "msg": "Commented on commit `<revision>` for repository `<repoid>`", + "status_change": null or <status>, + "success": true + }, + "error" : null + } + + """ + from .repo_api import comment_commit + + return comment_commit(request=request, + apiuser=apiuser, repoid=repoid, commit_id=revision, + message=message, userid=userid, status=status) + + +@jsonrpc_method() +@jsonrpc_deprecated_method( + use_method='get_ip', deprecated_at_version='4.0.0') +def show_ip(request, apiuser, userid=Optional(OAttr('apiuser'))): + from .server_api import get_ip + return get_ip(request=request, apiuser=apiuser, userid=userid) + + +@jsonrpc_method() +@jsonrpc_deprecated_method( + use_method='get_user_locks', deprecated_at_version='4.0.0') +def get_locks(request, apiuser, userid=Optional(OAttr('apiuser'))): + from .user_api import get_user_locks + return get_user_locks(request=request, apiuser=apiuser, userid=userid) \ No newline at end of file diff --git a/rhodecode/api/views/gist_api.py b/rhodecode/api/views/gist_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/gist_api.py @@ -0,0 +1,226 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import logging +import time + +from rhodecode.api import jsonrpc_method, JSONRPCError +from rhodecode.api.utils import ( + Optional, OAttr, get_gist_or_error, get_user_or_error, + has_superadmin_permission) +from rhodecode.model.db import Session, or_ +from rhodecode.model.gist import Gist, GistModel + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_gist(request, apiuser, gistid, content=Optional(False)): + """ + Get the specified gist, based on the gist ID. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param gistid: Set the id of the private or public gist + :type gistid: str + :param content: Return the gist content. Default is false. + :type content: Optional(bool) + """ + + gist = get_gist_or_error(gistid) + content = Optional.extract(content) + if not has_superadmin_permission(apiuser): + if gist.gist_owner != apiuser.user_id: + raise JSONRPCError('gist `%s` does not exist' % (gistid,)) + data = gist.get_api_data() + if content: + from rhodecode.model.gist import GistModel + rev, gist_files = GistModel().get_gist_files(gistid) + data['content'] = dict([(x.path, x.content) for x in gist_files]) + return data + + +@jsonrpc_method() +def get_gists(request, apiuser, userid=Optional(OAttr('apiuser'))): + """ + Get all gists for given user. If userid is empty returned gists + are for user who called the api + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: user to get gists for + :type userid: Optional(str or int) + """ + + if not has_superadmin_permission(apiuser): + # make sure normal user does not pass someone else userid, + # he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError( + 'userid is not the same as your user' + ) + + if isinstance(userid, Optional): + user_id = apiuser.user_id + else: + user_id = get_user_or_error(userid).user_id + + gists = [] + _gists = Gist().query() \ + .filter(or_( + Gist.gist_expires == -1, Gist.gist_expires >= time.time())) \ + .filter(Gist.gist_owner == user_id) \ + .order_by(Gist.created_on.desc()) + for gist in _gists: + gists.append(gist.get_api_data()) + return gists + + +@jsonrpc_method() +def create_gist( + request, apiuser, files, owner=Optional(OAttr('apiuser')), + gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1), + acl_level=Optional(Gist.ACL_LEVEL_PUBLIC), + description=Optional('')): + """ + Creates a new Gist. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param files: files to be added to the gist. The data structure has + to match the following example:: + + {'filename': {'content':'...', 'lexer': null}, + 'filename2': {'content':'...', 'lexer': null}} + + :type files: dict + :param owner: Set the gist owner, defaults to api method caller + :type owner: Optional(str or int) + :param gist_type: type of gist ``public`` or ``private`` + :type gist_type: Optional(str) + :param lifetime: time in minutes of gist lifetime + :type lifetime: Optional(int) + :param acl_level: acl level for this gist, can be + ``acl_public`` or ``acl_private`` If the value is set to + ``acl_private`` only logged in users are able to access this gist. + If not set it defaults to ``acl_public``. + :type acl_level: Optional(str) + :param description: gist description + :type description: Optional(str) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "created new gist", + "gist": {} + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to create gist" + } + + """ + + try: + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) + description = Optional.extract(description) + gist_type = Optional.extract(gist_type) + lifetime = Optional.extract(lifetime) + acl_level = Optional.extract(acl_level) + + gist = GistModel().create(description=description, + owner=owner, + gist_mapping=files, + gist_type=gist_type, + lifetime=lifetime, + gist_acl_level=acl_level) + Session().commit() + return { + 'msg': 'created new gist', + 'gist': gist.get_api_data() + } + except Exception: + log.exception('Error occurred during creation of gist') + raise JSONRPCError('failed to create gist') + + +@jsonrpc_method() +def delete_gist(request, apiuser, gistid): + """ + Deletes existing gist + + :param apiuser: filled automatically from apikey + :type apiuser: AuthUser + :param gistid: id of gist to delete + :type gistid: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "deleted gist ID: <gist_id>", + "gist": null + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete gist ID:<gist_id>" + } + + """ + + gist = get_gist_or_error(gistid) + if not has_superadmin_permission(apiuser): + if gist.gist_owner != apiuser.user_id: + raise JSONRPCError('gist `%s` does not exist' % (gistid,)) + + try: + GistModel().delete(gist) + Session().commit() + return { + 'msg': 'deleted gist ID:%s' % (gist.gist_access_id,), + 'gist': None + } + except Exception: + log.exception('Error occured during gist deletion') + raise JSONRPCError('failed to delete gist ID:%s' + % (gist.gist_access_id,)) \ No newline at end of file diff --git a/rhodecode/api/views/pull_request_api.py b/rhodecode/api/views/pull_request_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/pull_request_api.py @@ -0,0 +1,633 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import logging + +from rhodecode.api import jsonrpc_method, JSONRPCError +from rhodecode.api.utils import ( + has_superadmin_permission, Optional, OAttr, get_repo_or_error, + get_pull_request_or_error, get_commit_or_error, get_user_or_error, + has_repo_permissions, resolve_ref_or_error) +from rhodecode.lib.auth import (HasRepoPermissionAnyApi) +from rhodecode.lib.base import vcs_operation_context +from rhodecode.lib.utils2 import str2bool +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.db import Session, ChangesetStatus +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_pull_request(request, apiuser, repoid, pullrequestid): + """ + Get a pull request based on the given ID. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID from where the pull + request was opened. + :type repoid: str or int + :param pullrequestid: ID of the requested pull request. + :type pullrequestid: int + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + { + "pull_request_id": "<pull_request_id>", + "url": "<url>", + "title": "<title>", + "description": "<description>", + "status" : "<status>", + "created_on": "<date_time_created>", + "updated_on": "<date_time_updated>", + "commit_ids": [ + ... + "<commit_id>", + "<commit_id>", + ... + ], + "review_status": "<review_status>", + "mergeable": { + "status": "<bool>", + "message": "<message>", + }, + "source": { + "clone_url": "<clone_url>", + "repository": "<repository_name>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "target": { + "clone_url": "<clone_url>", + "repository": "<repository_name>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "author": <user_obj>, + "reviewers": [ + ... + { + "user": "<user_obj>", + "review_status": "<review_status>", + } + ... + ] + }, + "error": null + """ + get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if not PullRequestModel().check_user_read( + pull_request, apiuser, api=True): + raise JSONRPCError('repository `%s` does not exist' % (repoid,)) + data = pull_request.get_api_data() + return data + + +@jsonrpc_method() +def get_pull_requests(request, apiuser, repoid, status=Optional('new')): + """ + Get all pull requests from the repository specified in `repoid`. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID. + :type repoid: str or int + :param status: Only return pull requests with the specified status. + Valid options are. + * ``new`` (default) + * ``open`` + * ``closed`` + :type status: str + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + [ + ... + { + "pull_request_id": "<pull_request_id>", + "url": "<url>", + "title" : "<title>", + "description": "<description>", + "status": "<status>", + "created_on": "<date_time_created>", + "updated_on": "<date_time_updated>", + "commit_ids": [ + ... + "<commit_id>", + "<commit_id>", + ... + ], + "review_status": "<review_status>", + "mergeable": { + "status": "<bool>", + "message: "<message>", + }, + "source": { + "clone_url": "<clone_url>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "target": { + "clone_url": "<clone_url>", + "reference": + { + "name": "<name>", + "type": "<type>", + "commit_id": "<commit_id>", + } + }, + "author": <user_obj>, + "reviewers": [ + ... + { + "user": "<user_obj>", + "review_status": "<review_status>", + } + ... + ] + } + ... + ], + "error": null + + """ + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ( + 'repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + status = Optional.extract(status) + pull_requests = PullRequestModel().get_all(repo, statuses=[status]) + data = [pr.get_api_data() for pr in pull_requests] + return data + + +@jsonrpc_method() +def merge_pull_request(request, apiuser, repoid, pullrequestid, + userid=Optional(OAttr('apiuser'))): + """ + Merge the pull request specified by `pullrequestid` into its target + repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The Repository name or repository ID of the + target repository to which the |pr| is to be merged. + :type repoid: str or int + :param pullrequestid: ID of the pull request which shall be merged. + :type pullrequestid: int + :param userid: Merge the pull request as this user. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + { + "executed": "<bool>", + "failure_reason": "<int>", + "merge_commit_id": "<merge_commit_id>", + "possible": "<bool>" + }, + "error": null + + """ + repo = get_repo_or_error(repoid) + if not isinstance(userid, Optional): + if (has_superadmin_permission(apiuser) or + HasRepoPermissionAnyApi('repository.admin')( + user=apiuser, repo_name=repo.repo_name)): + apiuser = get_user_or_error(userid) + else: + raise JSONRPCError('userid is not the same as your user') + + pull_request = get_pull_request_or_error(pullrequestid) + if not PullRequestModel().check_user_merge( + pull_request, apiuser, api=True): + raise JSONRPCError('repository `%s` does not exist' % (repoid,)) + if pull_request.is_closed(): + raise JSONRPCError( + 'pull request `%s` merge failed, pull request is closed' % ( + pullrequestid,)) + + target_repo = pull_request.target_repo + extras = vcs_operation_context( + request.environ, repo_name=target_repo.repo_name, + username=apiuser.username, action='push', + scm=target_repo.repo_type) + data = PullRequestModel().merge(pull_request, apiuser, extras=extras) + if data.executed: + PullRequestModel().close_pull_request( + pull_request.pull_request_id, apiuser) + + Session.commit() + return data + + +@jsonrpc_method() +def close_pull_request(request, apiuser, repoid, pullrequestid, + userid=Optional(OAttr('apiuser'))): + """ + Close the pull request specified by `pullrequestid`. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Repository name or repository ID to which the pull + request belongs. + :type repoid: str or int + :param pullrequestid: ID of the pull request to be closed. + :type pullrequestid: int + :param userid: Close the pull request as this user. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + "id": <id_given_in_input>, + "result": + { + "pull_request_id": "<int>", + "closed": "<bool>" + }, + "error": null + + """ + repo = get_repo_or_error(repoid) + if not isinstance(userid, Optional): + if (has_superadmin_permission(apiuser) or + HasRepoPermissionAnyApi('repository.admin')( + user=apiuser, repo_name=repo.repo_name)): + apiuser = get_user_or_error(userid) + else: + raise JSONRPCError('userid is not the same as your user') + + pull_request = get_pull_request_or_error(pullrequestid) + if not PullRequestModel().check_user_update( + pull_request, apiuser, api=True): + raise JSONRPCError( + 'pull request `%s` close failed, no permission to close.' % ( + pullrequestid,)) + if pull_request.is_closed(): + raise JSONRPCError( + 'pull request `%s` is already closed' % (pullrequestid,)) + + PullRequestModel().close_pull_request( + pull_request.pull_request_id, apiuser) + Session.commit() + data = { + 'pull_request_id': pull_request.pull_request_id, + 'closed': True, + } + return data + + +@jsonrpc_method() +def comment_pull_request(request, apiuser, repoid, pullrequestid, + message=Optional(None), status=Optional(None), + userid=Optional(OAttr('apiuser'))): + """ + Comment on the pull request specified with the `pullrequestid`, + in the |repo| specified by the `repoid`, and optionally change the + review status. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + :param message: The text content of the comment. + :type message: str + :param status: (**Optional**) Set the approval status of the pull + request. Valid options are: + * not_reviewed + * approved + * rejected + * under_review + :type status: str + :param userid: Comment on the pull request as this user + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : + { + "pull_request_id": "<Integer>", + "comment_id": "<Integer>" + } + error : null + """ + repo = get_repo_or_error(repoid) + if not isinstance(userid, Optional): + if (has_superadmin_permission(apiuser) or + HasRepoPermissionAnyApi('repository.admin')( + user=apiuser, repo_name=repo.repo_name)): + apiuser = get_user_or_error(userid) + else: + raise JSONRPCError('userid is not the same as your user') + + pull_request = get_pull_request_or_error(pullrequestid) + if not PullRequestModel().check_user_read( + pull_request, apiuser, api=True): + raise JSONRPCError('repository `%s` does not exist' % (repoid,)) + message = Optional.extract(message) + status = Optional.extract(status) + if not message and not status: + raise JSONRPCError('message and status parameter missing') + + if (status not in (st[0] for st in ChangesetStatus.STATUSES) and + status is not None): + raise JSONRPCError('unknown comment status`%s`' % status) + + allowed_to_change_status = PullRequestModel().check_user_change_status( + pull_request, apiuser) + text = message + if status and allowed_to_change_status: + st_message = (('Status change %(transition_icon)s %(status)s') + % {'transition_icon': '>', + 'status': ChangesetStatus.get_status_lbl(status)}) + text = message or st_message + + rc_config = SettingsModel().get_all_settings() + renderer = rc_config.get('rhodecode_markup_renderer', 'rst') + comment = ChangesetCommentsModel().create( + text=text, + repo=pull_request.target_repo.repo_id, + user=apiuser.user_id, + pull_request=pull_request.pull_request_id, + f_path=None, + line_no=None, + status_change=(ChangesetStatus.get_status_lbl(status) + if status and allowed_to_change_status else None), + closing_pr=False, + renderer=renderer + ) + + if allowed_to_change_status and status: + ChangesetStatusModel().set_status( + pull_request.target_repo.repo_id, + status, + apiuser.user_id, + comment, + pull_request=pull_request.pull_request_id + ) + Session().flush() + + Session().commit() + data = { + 'pull_request_id': pull_request.pull_request_id, + 'comment_id': comment.comment_id, + 'status': status + } + return data + + +@jsonrpc_method() +def create_pull_request( + request, apiuser, source_repo, target_repo, source_ref, target_ref, + title, description=Optional(''), reviewers=Optional(None)): + """ + Creates a new pull request. + + Accepts refs in the following formats: + + * branch:<branch_name>:<sha> + * branch:<branch_name> + * bookmark:<bookmark_name>:<sha> (Mercurial only) + * bookmark:<bookmark_name> (Mercurial only) + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param source_repo: Set the source repository name. + :type source_repo: str + :param target_repo: Set the target repository name. + :type target_repo: str + :param source_ref: Set the source ref name. + :type source_ref: str + :param target_ref: Set the target ref name. + :type target_ref: str + :param title: Set the pull request title. + :type title: str + :param description: Set the pull request description. + :type description: Optional(str) + :param reviewers: Set the new pull request reviewers list. + :type reviewers: Optional(list) + """ + source = get_repo_or_error(source_repo) + target = get_repo_or_error(target_repo) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, source_repo, source, _perms) + + full_source_ref = resolve_ref_or_error(source_ref, source) + full_target_ref = resolve_ref_or_error(target_ref, target) + source_commit = get_commit_or_error(full_source_ref, source) + target_commit = get_commit_or_error(full_target_ref, target) + source_scm = source.scm_instance() + target_scm = target.scm_instance() + + commit_ranges = target_scm.compare( + target_commit.raw_id, source_commit.raw_id, source_scm, + merge=True, pre_load=[]) + + ancestor = target_scm.get_common_ancestor( + target_commit.raw_id, source_commit.raw_id, source_scm) + + if not commit_ranges: + raise JSONRPCError('no commits found') + + if not ancestor: + raise JSONRPCError('no common ancestor found') + + reviewer_names = Optional.extract(reviewers) or [] + if not isinstance(reviewer_names, list): + raise JSONRPCError('reviewers should be specified as a list') + + reviewer_users = [get_user_or_error(n) for n in reviewer_names] + reviewer_ids = [u.user_id for u in reviewer_users] + + pull_request_model = PullRequestModel() + pull_request = pull_request_model.create( + created_by=apiuser.user_id, + source_repo=source_repo, + source_ref=full_source_ref, + target_repo=target_repo, + target_ref=full_target_ref, + revisions=reversed( + [commit.raw_id for commit in reversed(commit_ranges)]), + reviewers=reviewer_ids, + title=title, + description=Optional.extract(description) + ) + + Session().commit() + data = { + 'msg': 'Created new pull request `{}`'.format(title), + 'pull_request_id': pull_request.pull_request_id, + } + return data + + +@jsonrpc_method() +def update_pull_request( + request, apiuser, repoid, pullrequestid, title=Optional(''), + description=Optional(''), reviewers=Optional(None), + update_commits=Optional(None), close_pull_request=Optional(None)): + """ + Updates a pull request. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + :param title: Set the pull request title. + :type title: str + :param description: Update pull request description. + :type description: Optional(str) + :param reviewers: Update pull request reviewers list with new value. + :type reviewers: Optional(list) + :param update_commits: Trigger update of commits for this pull request + :type: update_commits: Optional(bool) + :param close_pull_request: Close this pull request with rejected state + :type: close_pull_request: Optional(bool) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : + { + "msg": "Updated pull request `63`", + "pull_request": <pull_request_object>, + "updated_reviewers": { + "added": [ + "username" + ], + "removed": [] + }, + "updated_commits": { + "added": [ + "<sha1_hash>" + ], + "common": [ + "<sha1_hash>", + "<sha1_hash>", + ], + "removed": [] + } + } + error : null + """ + + repo = get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if not PullRequestModel().check_user_update( + pull_request, apiuser, api=True): + raise JSONRPCError( + 'pull request `%s` update failed, no permission to update.' % ( + pullrequestid,)) + if pull_request.is_closed(): + raise JSONRPCError( + 'pull request `%s` update failed, pull request is closed' % ( + pullrequestid,)) + + reviewer_names = Optional.extract(reviewers) or [] + if not isinstance(reviewer_names, list): + raise JSONRPCError('reviewers should be specified as a list') + + reviewer_users = [get_user_or_error(n) for n in reviewer_names] + reviewer_ids = [u.user_id for u in reviewer_users] + + title = Optional.extract(title) + description = Optional.extract(description) + if title or description: + PullRequestModel().edit( + pull_request, title or pull_request.title, + description or pull_request.description) + Session().commit() + + commit_changes = {"added": [], "common": [], "removed": []} + if str2bool(Optional.extract(update_commits)): + if PullRequestModel().has_valid_update_type(pull_request): + _version, _commit_changes = PullRequestModel().update_commits( + pull_request) + commit_changes = _commit_changes or commit_changes + Session().commit() + + reviewers_changes = {"added": [], "removed": []} + if reviewer_ids: + added_reviewers, removed_reviewers = \ + PullRequestModel().update_reviewers(pull_request, reviewer_ids) + + reviewers_changes['added'] = sorted( + [get_user_or_error(n).username for n in added_reviewers]) + reviewers_changes['removed'] = sorted( + [get_user_or_error(n).username for n in removed_reviewers]) + Session().commit() + + if str2bool(Optional.extract(close_pull_request)): + PullRequestModel().close_pull_request_with_comment( + pull_request, apiuser, repo) + Session().commit() + + data = { + 'msg': 'Updated pull request `{}`'.format( + pull_request.pull_request_id), + 'pull_request': pull_request.get_api_data(), + 'updated_commits': commit_changes, + 'updated_reviewers': reviewers_changes + } + return data + diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/repo_api.py @@ -0,0 +1,1774 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging +import time + +import colander + +from rhodecode import BACKENDS +from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, json +from rhodecode.api.utils import ( + has_superadmin_permission, Optional, OAttr, get_repo_or_error, + get_user_group_or_error, get_user_or_error, has_repo_permissions, + get_perm_or_error, store_update, get_repo_group_or_error, parse_args, + get_origin, build_commit_data) +from rhodecode.lib.auth import ( + HasPermissionAnyApi, HasRepoGroupPermissionAnyApi, + HasUserGroupPermissionAnyApi) +from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError +from rhodecode.lib.utils import map_groups +from rhodecode.lib.utils2 import str2bool, time_to_datetime +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.db import ( + Session, ChangesetStatus, RepositoryField, Repository) +from rhodecode.model.repo import RepoModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.scm import ScmModel, RepoList +from rhodecode.model.settings import SettingsModel +from rhodecode.model.validation_schema import RepoSchema + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_repo(request, apiuser, repoid, cache=Optional(True)): + """ + Gets an existing repository by its name or repository_id. + + The members section so the output returns users groups or users + associated with that repository. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository id. + :type repoid: str or int + :param cache: use the cached value for last changeset + :type: cache: Optional(bool) + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": <repo_id>, + "result": { + "clone_uri": null, + "created_on": "timestamp", + "description": "repo description", + "enable_downloads": false, + "enable_locking": false, + "enable_statistics": false, + "followers": [ + { + "active": true, + "admin": false, + "api_key": "****************************************", + "api_keys": [ + "****************************************" + ], + "email": "user@example.com", + "emails": [ + "user@example.com" + ], + "extern_name": "rhodecode", + "extern_type": "rhodecode", + "firstname": "username", + "ip_addresses": [], + "language": null, + "last_login": "2015-09-16T17:16:35.854", + "lastname": "surname", + "user_id": <user_id>, + "username": "name" + } + ], + "fork_of": "parent-repo", + "landing_rev": [ + "rev", + "tip" + ], + "last_changeset": { + "author": "User <user@example.com>", + "branch": "default", + "date": "timestamp", + "message": "last commit message", + "parents": [ + { + "raw_id": "commit-id" + } + ], + "raw_id": "commit-id", + "revision": <revision number>, + "short_id": "short id" + }, + "lock_reason": null, + "locked_by": null, + "locked_date": null, + "members": [ + { + "name": "super-admin-name", + "origin": "super-admin", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "repository.write", + "type": "user_group" + } + ], + "owner": "owner-name", + "permissions": [ + { + "name": "super-admin-name", + "origin": "super-admin", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "repository.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "repository.write", + "type": "user_group" + } + ], + "private": true, + "repo_id": 676, + "repo_name": "user-group/repo-name", + "repo_type": "hg" + } + } + """ + + repo = get_repo_or_error(repoid) + cache = Optional.extract(cache) + include_secrets = False + if has_superadmin_permission(apiuser): + include_secrets = True + else: + # check if we have at least read permission for this repo ! + _perms = ( + 'repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + permissions = [] + for _user in repo.permissions(): + user_data = { + 'name': _user.username, + 'permission': _user.permission, + 'origin': get_origin(_user), + 'type': "user", + } + permissions.append(user_data) + + for _user_group in repo.permission_user_groups(): + user_group_data = { + 'name': _user_group.users_group_name, + 'permission': _user_group.permission, + 'origin': get_origin(_user_group), + 'type': "user_group", + } + permissions.append(user_group_data) + + following_users = [ + user.user.get_api_data(include_secrets=include_secrets) + for user in repo.followers] + + if not cache: + repo.update_commit_cache() + data = repo.get_api_data(include_secrets=include_secrets) + data['members'] = permissions # TODO: this should be deprecated soon + data['permissions'] = permissions + data['followers'] = following_users + return data + + +@jsonrpc_method() +def get_repos(request, apiuser): + """ + Lists all existing repositories. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [ + { + "repo_id" : "<repo_id>", + "repo_name" : "<reponame>" + "repo_type" : "<repo_type>", + "clone_uri" : "<clone_uri>", + "private": : "<bool>", + "created_on" : "<datetimecreated>", + "description" : "<description>", + "landing_rev": "<landing_rev>", + "owner": "<repo_owner>", + "fork_of": "<name_of_fork_parent>", + "enable_downloads": "<bool>", + "enable_locking": "<bool>", + "enable_statistics": "<bool>", + }, + ... + ] + error: null + """ + + include_secrets = has_superadmin_permission(apiuser) + _perms = ('repository.read', 'repository.write', 'repository.admin',) + extras = {'user': apiuser} + + repo_list = RepoList( + RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras) + return [repo.get_api_data(include_secrets=include_secrets) + for repo in repo_list] + + +@jsonrpc_method() +def get_repo_changeset(request, apiuser, repoid, revision, + details=Optional('basic')): + """ + Returns information about a changeset. + + Additionally parameters define the amount of details returned by + this function. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository id + :type repoid: str or int + :param revision: revision for which listing should be done + :type revision: str + :param details: details can be 'basic|extended|full' full gives diff + info details like the diff itself, and number of changed files etc. + :type details: Optional(str) + + """ + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ( + 'repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + changes_details = Optional.extract(details) + _changes_details_types = ['basic', 'extended', 'full'] + if changes_details not in _changes_details_types: + raise JSONRPCError( + 'ret_type must be one of %s' % ( + ','.join(_changes_details_types))) + + pre_load = ['author', 'branch', 'date', 'message', 'parents', + 'status', '_commit', '_file_paths'] + + try: + cs = repo.get_commit(commit_id=revision, pre_load=pre_load) + except TypeError as e: + raise JSONRPCError(e.message) + _cs_json = cs.__json__() + _cs_json['diff'] = build_commit_data(cs, changes_details) + if changes_details == 'full': + _cs_json['refs'] = { + 'branches': [cs.branch], + 'bookmarks': getattr(cs, 'bookmarks', []), + 'tags': cs.tags + } + return _cs_json + + +@jsonrpc_method() +def get_repo_changesets(request, apiuser, repoid, start_rev, limit, + details=Optional('basic')): + """ + Returns a set of changesets limited by the number of commits starting + from the `start_rev` option. + + Additional parameters define the amount of details returned by this + function. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param start_rev: The starting revision from where to get changesets. + :type start_rev: str + :param limit: Limit the number of changesets to this amount + :type limit: str or int + :param details: Set the level of detail returned. Valid option are: + ``basic``, ``extended`` and ``full``. + :type details: Optional(str) + + .. note:: + + Setting the parameter `details` to the value ``full`` is extensive + and returns details like the diff itself, and the number + of changed files. + + """ + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ( + 'repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + changes_details = Optional.extract(details) + _changes_details_types = ['basic', 'extended', 'full'] + if changes_details not in _changes_details_types: + raise JSONRPCError( + 'ret_type must be one of %s' % ( + ','.join(_changes_details_types))) + + limit = int(limit) + pre_load = ['author', 'branch', 'date', 'message', 'parents', + 'status', '_commit', '_file_paths'] + + vcs_repo = repo.scm_instance() + # SVN needs a special case to distinguish its index and commit id + if vcs_repo.alias == 'svn' and (start_rev == '0'): + start_rev = vcs_repo.commit_ids[0] + + try: + commits = repo.scm_instance().get_commits( + start_id=start_rev, pre_load=pre_load) + except TypeError as e: + raise JSONRPCError(e.message) + + ret = [] + for cnt, commit in enumerate(commits): + if cnt >= limit != -1: + break + _cs_json = commit.__json__() + _cs_json['diff'] = build_commit_data(commit, changes_details) + if changes_details == 'full': + _cs_json['refs'] = { + 'branches': [commit.branch], + 'bookmarks': getattr(commit, 'bookmarks', []), + 'tags': commit.tags + } + ret.append(_cs_json) + return ret + + +@jsonrpc_method() +def get_repo_nodes(request, apiuser, repoid, revision, root_path, + ret_type=Optional('all'), details=Optional('basic')): + """ + Returns a list of nodes and children in a flat list for a given + path at given revision. + + It's possible to specify ret_type to show only `files` or `dirs`. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param revision: The revision for which listing should be done. + :type revision: str + :param root_path: The path from which to start displaying. + :type root_path: str + :param ret_type: Set the return type. Valid options are + ``all`` (default), ``files`` and ``dirs``. + :type ret_type: Optional(str) + :param details: Returns extended information about nodes, such as + md5, binary, and or content. The valid options are ``basic`` and + ``full``. + :type details: Optional(str) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [ + { + "name" : "<name>" + "type" : "<type>", + "binary": "<true|false>" (only in extended mode) + "md5" : "<md5 of file content>" (only in extended mode) + }, + ... + ] + error: null + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ( + 'repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + ret_type = Optional.extract(ret_type) + details = Optional.extract(details) + _extended_types = ['basic', 'full'] + if details not in _extended_types: + raise JSONRPCError( + 'ret_type must be one of %s' % (','.join(_extended_types))) + extended_info = False + content = False + if details == 'basic': + extended_info = True + + if details == 'full': + extended_info = content = True + + _map = {} + try: + # check if repo is not empty by any chance, skip quicker if it is. + _scm = repo.scm_instance() + if _scm.is_empty(): + return [] + + _d, _f = ScmModel().get_nodes( + repo, revision, root_path, flat=False, + extended_info=extended_info, content=content) + _map = { + 'all': _d + _f, + 'files': _f, + 'dirs': _d, + } + return _map[ret_type] + except KeyError: + raise JSONRPCError( + 'ret_type must be one of %s' % (','.join(sorted(_map.keys())))) + except Exception: + log.exception("Exception occurred while trying to get repo nodes") + raise JSONRPCError( + 'failed to get repo: `%s` nodes' % repo.repo_name + ) + + +@jsonrpc_method() +def get_repo_refs(request, apiuser, repoid): + """ + Returns a dictionary of current references. It returns + bookmarks, branches, closed_branches, and tags for given repository + + It's possible to specify ret_type to show only `files` or `dirs`. + + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [ + TODO... + ] + error: null + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin', 'repository.write', 'repository.read',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + # check if repo is not empty by any chance, skip quicker if it is. + vcs_instance = repo.scm_instance() + refs = vcs_instance.refs() + return refs + except Exception: + log.exception("Exception occurred while trying to get repo refs") + raise JSONRPCError( + 'failed to get repo: `%s` references' % repo.repo_name + ) + + +@jsonrpc_method() +def create_repo(request, apiuser, repo_name, repo_type, + owner=Optional(OAttr('apiuser')), description=Optional(''), + private=Optional(False), clone_uri=Optional(None), + landing_rev=Optional('rev:tip'), + enable_statistics=Optional(False), + enable_locking=Optional(False), + enable_downloads=Optional(False), + copy_permissions=Optional(False)): + """ + Creates a repository. + + * If the repository name contains "/", all the required repository + groups will be created. + + For example "foo/bar/baz" will create |repo| groups "foo" and "bar" + (with "foo" as parent). It will also create the "baz" repository + with "bar" as |repo| group. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repo_name: Set the repository name. + :type repo_name: str + :param repo_type: Set the repository type; 'hg','git', or 'svn'. + :type repo_type: str + :param owner: user_id or username + :type owner: Optional(str) + :param description: Set the repository description. + :type description: Optional(str) + :param private: + :type private: bool + :param clone_uri: + :type clone_uri: str + :param landing_rev: <rev_type>:<rev> + :type landing_rev: str + :param enable_locking: + :type enable_locking: bool + :param enable_downloads: + :type enable_downloads: bool + :param enable_statistics: + :type enable_statistics: bool + :param copy_permissions: Copy permission from group in which the + repository is being created. + :type copy_permissions: bool + + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Created new repository `<reponame>`", + "success": true, + "task": "<celery task id or None if done sync>" + } + error: null + + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + 'failed to create repository `<repo_name>` + } + + """ + schema = RepoSchema() + try: + data = schema.deserialize({ + 'repo_name': repo_name + }) + except colander.Invalid as e: + raise JSONRPCError("Validation failed: %s" % (e.asdict(),)) + repo_name = data['repo_name'] + + (repo_name_cleaned, + parent_group_name) = RepoGroupModel()._get_group_name_and_parent( + repo_name) + + if not HasPermissionAnyApi( + 'hg.admin', 'hg.create.repository')(user=apiuser): + # check if we have admin permission for this repo group if given ! + + if parent_group_name: + repogroupid = parent_group_name + repo_group = get_repo_group_or_error(parent_group_name) + + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % ( + repogroupid,)) + else: + raise JSONRPCForbidden() + + if not has_superadmin_permission(apiuser): + if not isinstance(owner, Optional): + # forbid setting owner for non-admins + raise JSONRPCError( + 'Only RhodeCode admin can specify `owner` param') + + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) + + if RepoModel().get_by_repo_name(repo_name): + raise JSONRPCError("repo `%s` already exist" % repo_name) + + defs = SettingsModel().get_default_repo_settings(strip_prefix=True) + if isinstance(private, Optional): + private = defs.get('repo_private') or Optional.extract(private) + if isinstance(repo_type, Optional): + repo_type = defs.get('repo_type') + if isinstance(enable_statistics, Optional): + enable_statistics = defs.get('repo_enable_statistics') + if isinstance(enable_locking, Optional): + enable_locking = defs.get('repo_enable_locking') + if isinstance(enable_downloads, Optional): + enable_downloads = defs.get('repo_enable_downloads') + + clone_uri = Optional.extract(clone_uri) + description = Optional.extract(description) + landing_rev = Optional.extract(landing_rev) + copy_permissions = Optional.extract(copy_permissions) + + try: + # create structure of groups and return the last group + repo_group = map_groups(repo_name) + data = { + 'repo_name': repo_name_cleaned, + 'repo_name_full': repo_name, + 'repo_type': repo_type, + 'repo_description': description, + 'owner': owner, + 'repo_private': private, + 'clone_uri': clone_uri, + 'repo_group': repo_group.group_id if repo_group else None, + 'repo_landing_rev': landing_rev, + 'enable_statistics': enable_statistics, + 'enable_locking': enable_locking, + 'enable_downloads': enable_downloads, + 'repo_copy_permissions': copy_permissions, + } + + if repo_type not in BACKENDS.keys(): + raise Exception("Invalid backend type %s" % repo_type) + task = RepoModel().create(form_data=data, cur_user=owner) + from celery.result import BaseAsyncResult + task_id = None + if isinstance(task, BaseAsyncResult): + task_id = task.task_id + # no commit, it's done in RepoModel, or async via celery + return { + 'msg': "Created new repository `%s`" % (repo_name,), + 'success': True, # cannot return the repo data here since fork + # cann be done async + 'task': task_id + } + except Exception: + log.exception( + u"Exception while trying to create the repository %s", + repo_name) + raise JSONRPCError( + 'failed to create repository `%s`' % (repo_name,)) + + +@jsonrpc_method() +def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''), + description=Optional('')): + """ + Adds an extra field to a repository. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository id. + :type repoid: str or int + :param key: Create a unique field key for this repository. + :type key: str + :param label: + :type label: Optional(str) + :param description: + :type description: Optional(str) + """ + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + label = Optional.extract(label) or key + description = Optional.extract(description) + + field = RepositoryField.get_by_key_name(key, repo) + if field: + raise JSONRPCError('Field with key ' + '`%s` exists for repo `%s`' % (key, repoid)) + + try: + RepoModel().add_repo_field(repo, key, field_label=label, + field_desc=description) + Session().commit() + return { + 'msg': "Added new repository field `%s`" % (key,), + 'success': True, + } + except Exception: + log.exception("Exception occurred while trying to add field to repo") + raise JSONRPCError( + 'failed to create new field for repository `%s`' % (repoid,)) + + +@jsonrpc_method() +def remove_field_from_repo(request, apiuser, repoid, key): + """ + Removes an extra field from a repository. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param key: Set the unique field key for this repository. + :type key: str + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + field = RepositoryField.get_by_key_name(key, repo) + if not field: + raise JSONRPCError('Field with key `%s` does not ' + 'exists for repo `%s`' % (key, repoid)) + + try: + RepoModel().delete_repo_field(repo, field_key=key) + Session().commit() + return { + 'msg': "Deleted repository field `%s`" % (key,), + 'success': True, + } + except Exception: + log.exception( + "Exception occurred while trying to delete field from repo") + raise JSONRPCError( + 'failed to delete field for repository `%s`' % (repoid,)) + + +@jsonrpc_method() +def update_repo(request, apiuser, repoid, name=Optional(None), + owner=Optional(OAttr('apiuser')), + group=Optional(None), + fork_of=Optional(None), + description=Optional(''), private=Optional(False), + clone_uri=Optional(None), landing_rev=Optional('rev:tip'), + enable_statistics=Optional(False), + enable_locking=Optional(False), + enable_downloads=Optional(False), + fields=Optional('')): + """ + Updates a repository with the given information. + + This command can only be run using an |authtoken| with at least + write permissions to the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: repository name or repository ID. + :type repoid: str or int + :param name: Update the |repo| name. + :type name: str + :param owner: Set the |repo| owner. + :type owner: str + :param group: Set the |repo| group the |repo| belongs to. + :type group: str + :param fork_of: Set the master |repo| name. + :type fork_of: str + :param description: Update the |repo| description. + :type description: str + :param private: Set the |repo| as private. (True | False) + :type private: bool + :param clone_uri: Update the |repo| clone URI. + :type clone_uri: str + :param landing_rev: Set the |repo| landing revision. Default is + ``tip``. + :type landing_rev: str + :param enable_statistics: Enable statistics on the |repo|, + (True | False). + :type enable_statistics: bool + :param enable_locking: Enable |repo| locking. + :type enable_locking: bool + :param enable_downloads: Enable downloads from the |repo|, + (True | False). + :type enable_downloads: bool + :param fields: Add extra fields to the |repo|. Use the following + example format: ``field_key=field_val,field_key2=fieldval2``. + Escape ', ' with \, + :type fields: str + """ + repo = get_repo_or_error(repoid) + include_secrets = False + if has_superadmin_permission(apiuser): + include_secrets = True + else: + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + updates = { + # update function requires this. + 'repo_name': repo.just_name + } + repo_group = group + if not isinstance(repo_group, Optional): + repo_group = get_repo_group_or_error(repo_group) + repo_group = repo_group.group_id + + repo_fork_of = fork_of + if not isinstance(repo_fork_of, Optional): + repo_fork_of = get_repo_or_error(repo_fork_of) + repo_fork_of = repo_fork_of.repo_id + + try: + store_update(updates, name, 'repo_name') + store_update(updates, repo_group, 'repo_group') + store_update(updates, repo_fork_of, 'fork_id') + store_update(updates, owner, 'user') + store_update(updates, description, 'repo_description') + store_update(updates, private, 'repo_private') + store_update(updates, clone_uri, 'clone_uri') + store_update(updates, landing_rev, 'repo_landing_rev') + store_update(updates, enable_statistics, 'repo_enable_statistics') + store_update(updates, enable_locking, 'repo_enable_locking') + store_update(updates, enable_downloads, 'repo_enable_downloads') + + # extra fields + fields = parse_args(Optional.extract(fields), key_prefix='ex_') + if fields: + updates.update(fields) + + RepoModel().update(repo, **updates) + Session().commit() + return { + 'msg': 'updated repo ID:%s %s' % ( + repo.repo_id, repo.repo_name), + 'repository': repo.get_api_data( + include_secrets=include_secrets) + } + except Exception: + log.exception( + u"Exception while trying to update the repository %s", + repoid) + raise JSONRPCError('failed to update repo `%s`' % repoid) + + +@jsonrpc_method() +def fork_repo(request, apiuser, repoid, fork_name, + owner=Optional(OAttr('apiuser')), + description=Optional(''), copy_permissions=Optional(False), + private=Optional(False), landing_rev=Optional('rev:tip')): + """ + Creates a fork of the specified |repo|. + + * If using |RCE| with Celery this will immediately return a success + message, even though the fork will be created asynchronously. + + This command can only be run using an |authtoken| with fork + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set repository name or repository ID. + :type repoid: str or int + :param fork_name: Set the fork name. + :type fork_name: str + :param owner: Set the fork owner. + :type owner: str + :param description: Set the fork descripton. + :type description: str + :param copy_permissions: Copy permissions from parent |repo|. The + default is False. + :type copy_permissions: bool + :param private: Make the fork private. The default is False. + :type private: bool + :param landing_rev: Set the landing revision. The default is tip. + + Example output: + + .. code-block:: bash + + id : <id_for_response> + api_key : "<api_key>" + args: { + "repoid" : "<reponame or repo_id>", + "fork_name": "<forkname>", + "owner": "<username or user_id = Optional(=apiuser)>", + "description": "<description>", + "copy_permissions": "<bool>", + "private": "<bool>", + "landing_rev": "<landing_rev>" + } + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Created fork of `<reponame>` as `<forkname>`", + "success": true, + "task": "<celery task id or None if done sync>" + } + error: null + + """ + if not has_superadmin_permission(apiuser): + if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser): + raise JSONRPCForbidden() + + repo = get_repo_or_error(repoid) + repo_name = repo.repo_name + + (fork_name_cleaned, + parent_group_name) = RepoGroupModel()._get_group_name_and_parent( + fork_name) + + if not has_superadmin_permission(apiuser): + # check if we have at least read permission for + # this repo that we fork ! + _perms = ( + 'repository.admin', 'repository.write', 'repository.read') + has_repo_permissions(apiuser, repoid, repo, _perms) + + if not isinstance(owner, Optional): + # forbid setting owner for non super admins + raise JSONRPCError( + 'Only RhodeCode admin can specify `owner` param' + ) + # check if we have a create.repo permission if not maybe the parent + # group permission + if not HasPermissionAnyApi('hg.create.repository')(user=apiuser): + if parent_group_name: + repogroupid = parent_group_name + repo_group = get_repo_group_or_error(parent_group_name) + + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % ( + repogroupid,)) + else: + raise JSONRPCForbidden() + + _repo = RepoModel().get_by_repo_name(fork_name) + if _repo: + type_ = 'fork' if _repo.fork else 'repo' + raise JSONRPCError("%s `%s` already exist" % (type_, fork_name)) + + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) + + try: + # create structure of groups and return the last group + repo_group = map_groups(fork_name) + form_data = { + 'repo_name': fork_name_cleaned, + 'repo_name_full': fork_name, + 'repo_group': repo_group.group_id if repo_group else None, + 'repo_type': repo.repo_type, + 'description': Optional.extract(description), + 'private': Optional.extract(private), + 'copy_permissions': Optional.extract(copy_permissions), + 'landing_rev': Optional.extract(landing_rev), + 'fork_parent_id': repo.repo_id, + } + + task = RepoModel().create_fork(form_data, cur_user=owner) + # no commit, it's done in RepoModel, or async via celery + from celery.result import BaseAsyncResult + task_id = None + if isinstance(task, BaseAsyncResult): + task_id = task.task_id + return { + 'msg': 'Created fork of `%s` as `%s`' % ( + repo.repo_name, fork_name), + 'success': True, # cannot return the repo data here since fork + # can be done async + 'task': task_id + } + except Exception: + log.exception("Exception occurred while trying to fork a repo") + raise JSONRPCError( + 'failed to fork repository `%s` as `%s`' % ( + repo_name, fork_name)) + + +@jsonrpc_method() +def delete_repo(request, apiuser, repoid, forks=Optional('')): + """ + Deletes a repository. + + * When the `forks` parameter is set it's possible to detach or delete + forks of deleted repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param forks: Set to `detach` or `delete` forks from the |repo|. + :type forks: Optional(str) + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "Deleted repository `<reponame>`", + "success": true + } + error: null + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + handle_forks = Optional.extract(forks) + _forks_msg = '' + _forks = [f for f in repo.forks] + if handle_forks == 'detach': + _forks_msg = ' ' + 'Detached %s forks' % len(_forks) + elif handle_forks == 'delete': + _forks_msg = ' ' + 'Deleted %s forks' % len(_forks) + elif _forks: + raise JSONRPCError( + 'Cannot delete `%s` it still contains attached forks' % + (repo.repo_name,) + ) + + RepoModel().delete(repo, forks=forks) + Session().commit() + return { + 'msg': 'Deleted repository `%s`%s' % ( + repo.repo_name, _forks_msg), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying to delete repo") + raise JSONRPCError( + 'failed to delete repository `%s`' % (repo.repo_name,) + ) + + +#TODO: marcink, change name ? +@jsonrpc_method() +def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)): + """ + Invalidates the cache for the specified repository. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param repoid: Sets the repository name or repository ID. + :type repoid: str or int + :param delete_keys: This deletes the invalidated keys instead of + just flagging them. + :type delete_keys: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'msg': Cache for repository `<repository name>` was invalidated, + 'repository': <repository name> + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + 'Error occurred during cache invalidation action' + } + + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin', 'repository.write',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + delete = Optional.extract(delete_keys) + try: + ScmModel().mark_for_invalidation(repo.repo_name, delete=delete) + return { + 'msg': 'Cache for repository `%s` was invalidated' % (repoid,), + 'repository': repo.repo_name + } + except Exception: + log.exception( + "Exception occurred while trying to invalidate repo cache") + raise JSONRPCError( + 'Error occurred during cache invalidation action' + ) + + +#TODO: marcink, change name ? +@jsonrpc_method() +def lock(request, apiuser, repoid, locked=Optional(None), + userid=Optional(OAttr('apiuser'))): + """ + Sets the lock state of the specified |repo| by the given user. + From more information, see :ref:`repo-locking`. + + * If the ``userid`` option is not set, the repository is locked to the + user who called the method. + * If the ``locked`` parameter is not set, the current lock state of the + repository is displayed. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Sets the repository name or repository ID. + :type repoid: str or int + :param locked: Sets the lock state. + :type locked: Optional(``True`` | ``False``) + :param userid: Set the repository lock to this user. + :type userid: Optional(str or int) + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'repo': '<reponame>', + 'locked': <bool: lock state>, + 'locked_since': <int: lock timestamp>, + 'locked_by': <username of person who made the lock>, + 'lock_reason': <str: reason for locking>, + 'lock_state_changed': <bool: True if lock state has been changed in this request>, + 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.' + or + 'msg': 'Repo `<repository name>` not locked.' + or + 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`' + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + 'Error occurred locking repository `<reponame>` + } + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + # check if we have at least write permission for this repo ! + _perms = ('repository.admin', 'repository.write',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + # make sure normal user does not pass someone else userid, + # he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError('userid is not the same as your user') + + if isinstance(userid, Optional): + userid = apiuser.user_id + + user = get_user_or_error(userid) + + if isinstance(locked, Optional): + lockobj = repo.locked + + if lockobj[0] is None: + _d = { + 'repo': repo.repo_name, + 'locked': False, + 'locked_since': None, + 'locked_by': None, + 'lock_reason': None, + 'lock_state_changed': False, + 'msg': 'Repo `%s` not locked.' % repo.repo_name + } + return _d + else: + _user_id, _time, _reason = lockobj + lock_user = get_user_or_error(userid) + _d = { + 'repo': repo.repo_name, + 'locked': True, + 'locked_since': _time, + 'locked_by': lock_user.username, + 'lock_reason': _reason, + 'lock_state_changed': False, + 'msg': ('Repo `%s` locked by `%s` on `%s`.' + % (repo.repo_name, lock_user.username, + json.dumps(time_to_datetime(_time)))) + } + return _d + + # force locked state through a flag + else: + locked = str2bool(locked) + lock_reason = Repository.LOCK_API + try: + if locked: + lock_time = time.time() + Repository.lock(repo, user.user_id, lock_time, lock_reason) + else: + lock_time = None + Repository.unlock(repo) + _d = { + 'repo': repo.repo_name, + 'locked': locked, + 'locked_since': lock_time, + 'locked_by': user.username, + 'lock_reason': lock_reason, + 'lock_state_changed': True, + 'msg': ('User `%s` set lock state for repo `%s` to `%s`' + % (user.username, repo.repo_name, locked)) + } + return _d + except Exception: + log.exception( + "Exception occurred while trying to lock repository") + raise JSONRPCError( + 'Error occurred locking repository `%s`' % repo.repo_name + ) + + +@jsonrpc_method() +def comment_commit( + request, apiuser, repoid, commit_id, message, + userid=Optional(OAttr('apiuser')), status=Optional(None)): + """ + Set a commit comment, and optionally change the status of the commit. + This command can be executed only using api_key belonging to user + with admin rights, or repository administrator. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param commit_id: Specify the commit_id for which to set a comment. + :type commit_id: str + :param message: The comment text. + :type message: str + :param userid: Set the user name of the comment creator. + :type userid: Optional(str or int) + :param status: status, one of 'not_reviewed', 'approved', 'rejected', + 'under_review' + :type status: str + + Example error output: + + .. code-block:: json + + { + "id" : <id_given_in_input>, + "result" : { + "msg": "Commented on commit `<commit_id>` for repository `<repoid>`", + "status_change": null or <status>, + "success": true + }, + "error" : null + } + + """ + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + if isinstance(userid, Optional): + userid = apiuser.user_id + + user = get_user_or_error(userid) + status = Optional.extract(status) + + allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES] + if status and status not in allowed_statuses: + raise JSONRPCError('Bad status, must be on ' + 'of %s got %s' % (allowed_statuses, status,)) + + try: + rc_config = SettingsModel().get_all_settings() + renderer = rc_config.get('rhodecode_markup_renderer', 'rst') + + comm = ChangesetCommentsModel().create( + message, repo, user, revision=commit_id, status_change=status, + renderer=renderer) + if status: + # also do a status change + try: + ChangesetStatusModel().set_status( + repo, status, user, comm, revision=commit_id, + dont_allow_on_closed_pull_request=True + ) + except StatusChangeOnClosedPullRequestError: + log.exception( + "Exception occurred while trying to change repo commit status") + msg = ('Changing status on a changeset associated with ' + 'a closed pull request is not allowed') + raise JSONRPCError(msg) + + Session().commit() + return { + 'msg': ( + 'Commented on commit `%s` for repository `%s`' % ( + comm.revision, repo.repo_name)), + 'status_change': status, + 'success': True, + } + except JSONRPCError: + # catch any inside errors, and re-raise them to prevent from + # below global catch to silence them + raise + except Exception: + log.exception("Exception occurred while trying to comment on commit") + raise JSONRPCError( + 'failed to set comment on repository `%s`' % (repo.repo_name,) + ) + + +@jsonrpc_method() +def grant_user_permission(request, apiuser, repoid, userid, perm): + """ + Grant permissions for the specified user on the given repository, + or update existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param userid: Set the user name. + :type userid: str + :param perm: Set the user permissions, using the following format + ``(repository.(none|read|write|admin))`` + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`", + "success": true + } + error: null + """ + + repo = get_repo_or_error(repoid) + user = get_user_or_error(userid) + perm = get_perm_or_error(perm) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + + RepoModel().grant_user_permission(repo=repo, user=user, perm=perm) + + Session().commit() + return { + 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % ( + perm.permission_name, user.username, repo.repo_name + ), + 'success': True + } + except Exception: + log.exception( + "Exception occurred while trying edit permissions for repo") + raise JSONRPCError( + 'failed to edit permission for user: `%s` in repo: `%s`' % ( + userid, repoid + ) + ) + + +@jsonrpc_method() +def revoke_user_permission(request, apiuser, repoid, userid): + """ + Revoke permission for a user on the specified repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param userid: Set the user name of revoked user. + :type userid: str or int + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`", + "success": true + } + error: null + """ + + repo = get_repo_or_error(repoid) + user = get_user_or_error(userid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + RepoModel().revoke_user_permission(repo=repo, user=user) + Session().commit() + return { + 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % ( + user.username, repo.repo_name + ), + 'success': True + } + except Exception: + log.exception( + "Exception occurred while trying revoke permissions to repo") + raise JSONRPCError( + 'failed to edit permission for user: `%s` in repo: `%s`' % ( + userid, repoid + ) + ) + + +@jsonrpc_method() +def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm): + """ + Grant permission for a user group on the specified repository, + or update existing permissions. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param usergroupid: Specify the ID of the user group. + :type usergroupid: str or int + :param perm: Set the user group permissions using the following + format: (repository.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`", + "success": true + + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo `<repo>`' + } + + """ + + repo = get_repo_or_error(repoid) + perm = get_perm_or_error(perm) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have at least read permission for this user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + try: + RepoModel().grant_user_group_permission( + repo=repo, group_name=user_group, perm=perm) + + Session().commit() + return { + 'msg': 'Granted perm: `%s` for user group: `%s` in ' + 'repo: `%s`' % ( + perm.permission_name, user_group.users_group_name, + repo.repo_name + ), + 'success': True + } + except Exception: + log.exception( + "Exception occurred while trying change permission on repo") + raise JSONRPCError( + 'failed to edit permission for user group: `%s` in ' + 'repo: `%s`' % ( + usergroupid, repo.repo_name + ) + ) + + +@jsonrpc_method() +def revoke_user_group_permission(request, apiuser, repoid, usergroupid): + """ + Revoke the permissions of a user group on a given repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo|. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Set the repository name or repository ID. + :type repoid: str or int + :param usergroupid: Specify the user group ID. + :type usergroupid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`", + "success": true + } + error: null + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have at least read permission for this user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + try: + RepoModel().revoke_user_group_permission( + repo=repo, group_name=user_group) + + Session().commit() + return { + 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % ( + user_group.users_group_name, repo.repo_name + ), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying revoke " + "user group permission on repo") + raise JSONRPCError( + 'failed to edit permission for user group: `%s` in ' + 'repo: `%s`' % ( + user_group.users_group_name, repo.repo_name + ) + ) + + +@jsonrpc_method() +def pull(request, apiuser, repoid): + """ + Triggers a pull on the given repository from a remote location. You + can use this to keep remote repositories up-to-date. + + This command can only be run using an |authtoken| with admin + rights to the specified repository. For more information, + see :ref:`config-token-ref`. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Pulled from `<repository name>`" + "repository": "<repository name>" + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "Unable to pull changes from `<reponame>`" + } + + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + ScmModel().pull_changes(repo.repo_name, apiuser.username) + return { + 'msg': 'Pulled from `%s`' % repo.repo_name, + 'repository': repo.repo_name + } + except Exception: + log.exception("Exception occurred while trying to " + "pull changes from remote location") + raise JSONRPCError( + 'Unable to pull changes from `%s`' % repo.repo_name + ) + + +@jsonrpc_method() +def strip(request, apiuser, repoid, revision, branch): + """ + Strips the given revision from the specified repository. + + * This will remove the revision and all of its decendants. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param revision: The revision you wish to strip. + :type revision: str + :param branch: The branch from which to strip the revision. + :type branch: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'" + "repository": "<repository name>" + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "Unable to strip commit <commit_hash> from repo `<repository name>`" + } + + """ + + repo = get_repo_or_error(repoid) + if not has_superadmin_permission(apiuser): + _perms = ('repository.admin',) + has_repo_permissions(apiuser, repoid, repo, _perms) + + try: + ScmModel().strip(repo, revision, branch) + return { + 'msg': 'Stripped commit %s from repo `%s`' % ( + revision, repo.repo_name), + 'repository': repo.repo_name + } + except Exception: + log.exception("Exception while trying to strip") + raise JSONRPCError( + 'Unable to strip commit %s from repo `%s`' % ( + revision, repo.repo_name) + ) diff --git a/rhodecode/api/views/repo_group_api.py b/rhodecode/api/views/repo_group_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/repo_group_api.py @@ -0,0 +1,699 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import logging + +import colander + +from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden +from rhodecode.api.utils import ( + has_superadmin_permission, Optional, OAttr, get_user_or_error, + store_update, get_repo_group_or_error, + get_perm_or_error, get_user_group_or_error, get_origin) +from rhodecode.lib.auth import ( + HasPermissionAnyApi, HasRepoGroupPermissionAnyApi, + HasUserGroupPermissionAnyApi) +from rhodecode.model.db import Session, RepoGroup +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.scm import RepoGroupList +from rhodecode.model.validation_schema import RepoGroupSchema + + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_repo_group(request, apiuser, repogroupid): + """ + Return the specified |repo| group, along with permissions, + and repositories inside the group + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Specify the name of ID of the repository group. + :type repogroupid: str or int + + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": repo-group-id, + "result": { + "group_description": "repo group description", + "group_id": 14, + "group_name": "group name", + "members": [ + { + "name": "super-admin-username", + "origin": "super-admin", + "permission": "group.admin", + "type": "user" + }, + { + "name": "owner-name", + "origin": "owner", + "permission": "group.admin", + "type": "user" + }, + { + "name": "user-group-name", + "origin": "permission", + "permission": "group.write", + "type": "user_group" + } + ], + "owner": "owner-name", + "parent_group": null, + "repositories": [ repo-list ] + } + } + """ + + repo_group = get_repo_group_or_error(repogroupid) + if not has_superadmin_permission(apiuser): + # check if we have at least read permission for this repo group ! + _perms = ('group.admin', 'group.write', 'group.read',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + permissions = [] + for _user in repo_group.permissions(): + user_data = { + 'name': _user.username, + 'permission': _user.permission, + 'origin': get_origin(_user), + 'type': "user", + } + permissions.append(user_data) + + for _user_group in repo_group.permission_user_groups(): + user_group_data = { + 'name': _user_group.users_group_name, + 'permission': _user_group.permission, + 'origin': get_origin(_user_group), + 'type': "user_group", + } + permissions.append(user_group_data) + + data = repo_group.get_api_data() + data["members"] = permissions # TODO: this should be named permissions + return data + + +@jsonrpc_method() +def get_repo_groups(request, apiuser): + """ + Returns all repository groups. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + """ + + result = [] + _perms = ('group.read', 'group.write', 'group.admin',) + extras = {'user': apiuser} + for repo_group in RepoGroupList(RepoGroupModel().get_all(), + perm_set=_perms, extra_kwargs=extras): + result.append(repo_group.get_api_data()) + return result + + +@jsonrpc_method() +def create_repo_group(request, apiuser, group_name, description=Optional(''), + owner=Optional(OAttr('apiuser')), + copy_permissions=Optional(False)): + """ + Creates a repository group. + + * If the repository group name contains "/", all the required repository + groups will be created. + + For example "foo/bar/baz" will create |repo| groups "foo" and "bar" + (with "foo" as parent). It will also create the "baz" repository + with "bar" as |repo| group. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param group_name: Set the repository group name. + :type group_name: str + :param description: Set the |repo| group description. + :type description: str + :param owner: Set the |repo| group owner. + :type owner: str + :param copy_permissions: + :type copy_permissions: + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Created new repo group `<repo_group_name>`" + "repo_group": <repogroup_object> + } + error : null + + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + failed to create repo group `<repogroupid>` + } + + """ + + schema = RepoGroupSchema() + try: + data = schema.deserialize({ + 'group_name': group_name + }) + except colander.Invalid as e: + raise JSONRPCError("Validation failed: %s" % (e.asdict(),)) + group_name = data['group_name'] + + if isinstance(owner, Optional): + owner = apiuser.user_id + + group_description = Optional.extract(description) + copy_permissions = Optional.extract(copy_permissions) + + # get by full name with parents, check if it already exist + if RepoGroup.get_by_group_name(group_name): + raise JSONRPCError("repo group `%s` already exist" % (group_name,)) + + (group_name_cleaned, + parent_group_name) = RepoGroupModel()._get_group_name_and_parent( + group_name) + + parent_group = None + if parent_group_name: + parent_group = get_repo_group_or_error(parent_group_name) + + if not HasPermissionAnyApi( + 'hg.admin', 'hg.repogroup.create.true')(user=apiuser): + # check if we have admin permission for this parent repo group ! + # users without admin or hg.repogroup.create can only create other + # groups in groups they own so this is a required, but can be empty + parent_group = getattr(parent_group, 'group_name', '') + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=parent_group): + raise JSONRPCForbidden() + + try: + repo_group = RepoGroupModel().create( + group_name=group_name, + group_description=group_description, + owner=owner, + copy_permissions=copy_permissions) + Session().commit() + return { + 'msg': 'Created new repo group `%s`' % group_name, + 'repo_group': repo_group.get_api_data() + } + except Exception: + log.exception("Exception occurred while trying create repo group") + raise JSONRPCError( + 'failed to create repo group `%s`' % (group_name,)) + + +@jsonrpc_method() +def update_repo_group( + request, apiuser, repogroupid, group_name=Optional(''), + description=Optional(''), owner=Optional(OAttr('apiuser')), + parent=Optional(None), enable_locking=Optional(False)): + """ + Updates repository group with the details given. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the ID of repository group. + :type repogroupid: str or int + :param group_name: Set the name of the |repo| group. + :type group_name: str + :param description: Set a description for the group. + :type description: str + :param owner: Set the |repo| group owner. + :type owner: str + :param parent: Set the |repo| group parent. + :type parent: str or int + :param enable_locking: Enable |repo| locking. The default is false. + :type enable_locking: bool + """ + + repo_group = get_repo_group_or_error(repogroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + updates = {} + try: + store_update(updates, group_name, 'group_name') + store_update(updates, description, 'group_description') + store_update(updates, owner, 'user') + store_update(updates, parent, 'group_parent_id') + store_update(updates, enable_locking, 'enable_locking') + repo_group = RepoGroupModel().update(repo_group, updates) + Session().commit() + return { + 'msg': 'updated repository group ID:%s %s' % ( + repo_group.group_id, repo_group.group_name), + 'repo_group': repo_group.get_api_data() + } + except Exception: + log.exception("Exception occurred while trying update repo group") + raise JSONRPCError('failed to update repository group `%s`' + % (repogroupid,)) + + +@jsonrpc_method() +def delete_repo_group(request, apiuser, repogroupid): + """ + Deletes a |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of repository group to be + deleted. + :type repogroupid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'msg': 'deleted repo group ID:<repogroupid> <repogroupname> + 'repo_group': null + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete repo group ID:<repogroupid> <repogroupname>" + } + + """ + + repo_group = get_repo_group_or_error(repogroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + try: + RepoGroupModel().delete(repo_group) + Session().commit() + return { + 'msg': 'deleted repo group ID:%s %s' % + (repo_group.group_id, repo_group.group_name), + 'repo_group': None + } + except Exception: + log.exception("Exception occurred while trying to delete repo group") + raise JSONRPCError('failed to delete repo group ID:%s %s' % + (repo_group.group_id, repo_group.group_name)) + + +@jsonrpc_method() +def grant_user_permission_to_repo_group( + request, apiuser, repogroupid, userid, perm, + apply_to_children=Optional('none')): + """ + Grant permission for a user on the given repository group, or update + existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of repository group. + :type repogroupid: str or int + :param userid: Set the user name. + :type userid: str + :param perm: (group.(none|read|write|admin)) + :type perm: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`" + } + + """ + + repo_group = get_repo_group_or_error(repogroupid) + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + user = get_user_or_error(userid) + perm = get_perm_or_error(perm, prefix='group.') + apply_to_children = Optional.extract(apply_to_children) + + perm_additions = [[user.user_id, perm, "user"]] + try: + RepoGroupModel().update_permissions(repo_group=repo_group, + perm_additions=perm_additions, + recursive=apply_to_children, + cur_user=apiuser) + Session().commit() + return { + 'msg': 'Granted perm: `%s` (recursive:%s) for user: ' + '`%s` in repo group: `%s`' % ( + perm.permission_name, apply_to_children, user.username, + repo_group.name + ), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying to grant " + "user permissions to repo group") + raise JSONRPCError( + 'failed to edit permission for user: ' + '`%s` in repo group: `%s`' % (userid, repo_group.name)) + + +@jsonrpc_method() +def revoke_user_permission_from_repo_group( + request, apiuser, repogroupid, userid, + apply_to_children=Optional('none')): + """ + Revoke permission for a user in a given repository group. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or ID of the repository group. + :type repogroupid: str or int + :param userid: Set the user name to revoke. + :type userid: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`" + } + + """ + + repo_group = get_repo_group_or_error(repogroupid) + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + user = get_user_or_error(userid) + apply_to_children = Optional.extract(apply_to_children) + + perm_deletions = [[user.user_id, None, "user"]] + try: + RepoGroupModel().update_permissions(repo_group=repo_group, + perm_deletions=perm_deletions, + recursive=apply_to_children, + cur_user=apiuser) + Session().commit() + return { + 'msg': 'Revoked perm (recursive:%s) for user: ' + '`%s` in repo group: `%s`' % ( + apply_to_children, user.username, repo_group.name + ), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying revoke user " + "permission from repo group") + raise JSONRPCError( + 'failed to edit permission for user: ' + '`%s` in repo group: `%s`' % (userid, repo_group.name)) + + +@jsonrpc_method() +def grant_user_group_permission_to_repo_group( + request, apiuser, repogroupid, usergroupid, perm, + apply_to_children=Optional('none'), ): + """ + Grant permission for a user group on given repository group, or update + existing permissions if found. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: Set the name or id of repository group + :type repogroupid: str or int + :param usergroupid: id of usergroup + :type usergroupid: str or int + :param perm: (group.(none|read|write|admin)) + :type perm: str + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`", + "success": true + + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`" + } + + """ + + repo_group = get_repo_group_or_error(repogroupid) + perm = get_perm_or_error(perm, prefix='group.') + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + # check if we have at least read permission for this user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + apply_to_children = Optional.extract(apply_to_children) + + perm_additions = [[user_group.users_group_id, perm, "user_group"]] + try: + RepoGroupModel().update_permissions(repo_group=repo_group, + perm_additions=perm_additions, + recursive=apply_to_children, + cur_user=apiuser) + Session().commit() + return { + 'msg': 'Granted perm: `%s` (recursive:%s) ' + 'for user group: `%s` in repo group: `%s`' % ( + perm.permission_name, apply_to_children, + user_group.users_group_name, repo_group.name + ), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying to grant user " + "group permissions to repo group") + raise JSONRPCError( + 'failed to edit permission for user group: `%s` in ' + 'repo group: `%s`' % ( + usergroupid, repo_group.name + ) + ) + + +@jsonrpc_method() +def revoke_user_group_permission_from_repo_group( + request, apiuser, repogroupid, usergroupid, + apply_to_children=Optional('none')): + """ + Revoke permission for user group on given repository. + + This command can only be run using an |authtoken| with admin + permissions on the |repo| group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repogroupid: name or id of repository group + :type repogroupid: str or int + :param usergroupid: + :param apply_to_children: 'none', 'repos', 'groups', 'all' + :type apply_to_children: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`", + "success": true + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`" + } + + + """ + + repo_group = get_repo_group_or_error(repogroupid) + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this repo group ! + _perms = ('group.admin',) + if not HasRepoGroupPermissionAnyApi(*_perms)( + user=apiuser, group_name=repo_group.group_name): + raise JSONRPCError( + 'repository group `%s` does not exist' % (repogroupid,)) + + # check if we have at least read permission for this user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + apply_to_children = Optional.extract(apply_to_children) + + perm_deletions = [[user_group.users_group_id, None, "user_group"]] + try: + RepoGroupModel().update_permissions(repo_group=repo_group, + perm_deletions=perm_deletions, + recursive=apply_to_children, + cur_user=apiuser) + Session().commit() + return { + 'msg': 'Revoked perm (recursive:%s) for user group: ' + '`%s` in repo group: `%s`' % ( + apply_to_children, user_group.users_group_name, + repo_group.name + ), + 'success': True + } + except Exception: + log.exception("Exception occurred while trying revoke user group " + "permissions from repo group") + raise JSONRPCError( + 'failed to edit permission for user group: ' + '`%s` in repo group: `%s`' % ( + user_group.users_group_name, repo_group.name + ) + ) + diff --git a/rhodecode/api/views/server_api.py b/rhodecode/api/views/server_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/server_api.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import logging + +from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden + +from rhodecode.api.utils import ( + Optional, OAttr, has_superadmin_permission, get_user_or_error) +from rhodecode.lib.utils import repo2db_mapper +from rhodecode.model.db import UserIpMap +from rhodecode.model.scm import ScmModel + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_server_info(request, apiuser): + """ + Returns the |RCE| server information. + + This includes the running version of |RCE| and all installed + packages. This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'modules': [<module name>,...] + 'py_version': <python version>, + 'platform': <platform type>, + 'rhodecode_version': <rhodecode version> + } + error : null + """ + + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + return ScmModel().get_server_info(request.environ) + + +@jsonrpc_method() +def get_ip(request, apiuser, userid=Optional(OAttr('apiuser'))): + """ + Displays the IP Address as seen from the |RCE| server. + + * This command displays the IP Address, as well as all the defined IP + addresses for the specified user. If the ``userid`` is not set, the + data returned is for the user calling the method. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid for which associated IP Address data + is returned. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "server_ip_addr": "<ip_from_clien>", + "user_ips": [ + { + "ip_addr": "<ip_with_mask>", + "ip_range": ["<start_ip>", "<end_ip>"], + }, + ... + ] + } + + """ + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + userid = Optional.extract(userid, evaluate_locals=locals()) + userid = getattr(userid, 'user_id', userid) + + user = get_user_or_error(userid) + ips = UserIpMap.query().filter(UserIpMap.user == user).all() + return { + 'server_ip_addr': request.rpc_ip_addr, + 'user_ips': ips + } + + +@jsonrpc_method() +def rescan_repos(request, apiuser, remove_obsolete=Optional(False)): + """ + Triggers a rescan of the specified repositories. + + * If the ``remove_obsolete`` option is set, it also deletes repositories + that are found in the database but not on the file system, so called + "clean zombies". + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param remove_obsolete: Deletes repositories from the database that + are not found on the filesystem. + :type remove_obsolete: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + 'added': [<added repository name>,...] + 'removed': [<removed repository name>,...] + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + 'Error occurred during rescan repositories action' + } + + """ + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + try: + rm_obsolete = Optional.extract(remove_obsolete) + added, removed = repo2db_mapper(ScmModel().repo_scan(), + remove_obsolete=rm_obsolete) + return {'added': added, 'removed': removed} + except Exception: + log.exception('Failed to run repo rescann') + raise JSONRPCError( + 'Error occurred during rescan repositories action' + ) + diff --git a/rhodecode/api/views/testing_api.py b/rhodecode/api/views/testing_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/testing_api.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import datetime +import decimal +import logging +import time + +from rhodecode.api import jsonrpc_method, jsonrpc_deprecated_method, JSONRPCError, JSONRPCForbidden + +from rhodecode.api.utils import Optional, OAttr + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def test(request, apiuser, args): + return args + + +@jsonrpc_method() +def test_ok(request, apiuser): + return { + 'who': u'hello {} '.format(apiuser), + 'obj': { + 'time': time.time(), + 'dt': datetime.datetime.now(), + 'decimal': decimal.Decimal('0.123') + } + } + + +@jsonrpc_method() +def test_error(request, apiuser): + raise JSONRPCError('error happened') + + +@jsonrpc_method() +def test_exception(request, apiuser): + raise Exception('something unhanddled') + + +@jsonrpc_method() +def test_params(request, apiuser, params): + return u'hello apiuser:{} params:{}'.format(apiuser, params) + + +@jsonrpc_method() +def test_params_opt( + request, apiuser, params, opt1=False, opt2=Optional(True), + opt3=Optional(OAttr('apiuser'))): + opt2 = Optional.extract(opt2) + opt3 = Optional.extract(opt3, evaluate_locals=locals()) + + return u'hello apiuser:{} params:{}, opt:[{},{},{}]'.format( + apiuser, params, opt1, opt2, opt3) + + +@jsonrpc_method() +@jsonrpc_deprecated_method( + use_method='test_ok', deprecated_at_version='4.0.0') +def test_deprecated_method(request, apiuser): + return u'value' + + +@jsonrpc_method() +def test_forbidden_method(request, apiuser): + raise JSONRPCForbidden() diff --git a/rhodecode/api/views/user_api.py b/rhodecode/api/views/user_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/user_api.py @@ -0,0 +1,465 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden +from rhodecode.api.utils import ( + Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update) +from rhodecode.lib.auth import AuthUser, PasswordGenerator +from rhodecode.lib.exceptions import DefaultUserException +from rhodecode.lib.utils2 import safe_int +from rhodecode.model.db import Session, User, Repository +from rhodecode.model.user import UserModel + + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))): + """ + Returns the information associated with a username or userid. + + * If the ``userid`` is not set, this command returns the information + for the ``userid`` calling the method. + + .. note:: + + Normal users may only run this command against their ``userid``. For + full privileges you must run this command using an |authtoken| with + admin rights. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid for which data will be returned. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + { + "error": null, + "id": <id>, + "result": { + "active": true, + "admin": false, + "api_key": "api-key", + "api_keys": [ list of keys ], + "email": "user@example.com", + "emails": [ + "user@example.com" + ], + "extern_name": "rhodecode", + "extern_type": "rhodecode", + "firstname": "username", + "ip_addresses": [], + "language": null, + "last_login": "Timestamp", + "lastname": "surnae", + "permissions": { + "global": [ + "hg.inherit_default_perms.true", + "usergroup.read", + "hg.repogroup.create.false", + "hg.create.none", + "hg.extern_activate.manual", + "hg.create.write_on_repogroup.false", + "hg.usergroup.create.false", + "group.none", + "repository.none", + "hg.register.none", + "hg.fork.repository" + ], + "repositories": { "username/example": "repository.write"}, + "repositories_groups": { "user-group/repo": "group.none" }, + "user_groups": { "user_group_name": "usergroup.read" } + }, + "user_id": 32, + "username": "username" + } + } + """ + + if not has_superadmin_permission(apiuser): + # make sure normal user does not pass someone else userid, + # he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError('userid is not the same as your user') + + userid = Optional.extract(userid, evaluate_locals=locals()) + userid = getattr(userid, 'user_id', userid) + + user = get_user_or_error(userid) + data = user.get_api_data(include_secrets=True) + data['permissions'] = AuthUser(user_id=user.user_id).permissions + return data + + +@jsonrpc_method() +def get_users(request, apiuser): + """ + Lists all users in the |RCE| user database. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: [<user_object>, ...] + error: null + """ + + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + result = [] + users_list = User.query().order_by(User.username) \ + .filter(User.username != User.DEFAULT_USER) \ + .all() + for user in users_list: + result.append(user.get_api_data(include_secrets=True)) + return result + + +@jsonrpc_method() +def create_user(request, apiuser, username, email, password=Optional(''), + firstname=Optional(''), lastname=Optional(''), + active=Optional(True), admin=Optional(False), + extern_name=Optional('rhodecode'), + extern_type=Optional('rhodecode'), + force_password_change=Optional(False)): + """ + Creates a new user and returns the new user object. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param username: Set the new username. + :type username: str or int + :param email: Set the user email address. + :type email: str + :param password: Set the new user password. + :type password: Optional(str) + :param firstname: Set the new user firstname. + :type firstname: Optional(str) + :param lastname: Set the new user surname. + :type lastname: Optional(str) + :param active: Set the user as active. + :type active: Optional(``True`` | ``False``) + :param admin: Give the new user admin rights. + :type admin: Optional(``True`` | ``False``) + :param extern_name: Set the authentication plugin name. + Using LDAP this is filled with LDAP UID. + :type extern_name: Optional(str) + :param extern_type: Set the new user authentication plugin. + :type extern_type: Optional(str) + :param force_password_change: Force the new user to change password + on next login. + :type force_password_change: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "created new user `<username>`", + "user": <user_obj> + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "user `<username>` already exist" + or + "email `<email>` already exist" + or + "failed to create user `<username>`" + } + + """ + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + if UserModel().get_by_username(username): + raise JSONRPCError("user `%s` already exist" % (username,)) + + if UserModel().get_by_email(email, case_insensitive=True): + raise JSONRPCError("email `%s` already exist" % (email,)) + + # generate random password if we actually given the + # extern_name and it's not rhodecode + if (not isinstance(extern_name, Optional) and + Optional.extract(extern_name) != 'rhodecode'): + # generate temporary password if user is external + password = PasswordGenerator().gen_password(length=16) + + try: + user = UserModel().create_or_update( + username=Optional.extract(username), + password=Optional.extract(password), + email=Optional.extract(email), + firstname=Optional.extract(firstname), + lastname=Optional.extract(lastname), + active=Optional.extract(active), + admin=Optional.extract(admin), + extern_type=Optional.extract(extern_type), + extern_name=Optional.extract(extern_name), + force_password_change=Optional.extract(force_password_change), + ) + Session().commit() + return { + 'msg': 'created new user `%s`' % username, + 'user': user.get_api_data(include_secrets=True) + } + except Exception: + log.exception('Error occurred during creation of user') + raise JSONRPCError('failed to create user `%s`' % (username,)) + + +@jsonrpc_method() +def update_user(request, apiuser, userid, username=Optional(None), + email=Optional(None), password=Optional(None), + firstname=Optional(None), lastname=Optional(None), + active=Optional(None), admin=Optional(None), + extern_type=Optional(None), extern_name=Optional(None), ): + """ + Updates the details for the specified user, if that user exists. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from |authtoken|. + :type apiuser: AuthUser + :param userid: Set the ``userid`` to update. + :type userid: str or int + :param username: Set the new username. + :type username: str or int + :param email: Set the new email. + :type email: str + :param password: Set the new password. + :type password: Optional(str) + :param firstname: Set the new first name. + :type firstname: Optional(str) + :param lastname: Set the new surname. + :type lastname: Optional(str) + :param active: Set the new user as active. + :type active: Optional(``True`` | ``False``) + :param admin: Give the user admin rights. + :type admin: Optional(``True`` | ``False``) + :param extern_name: Set the authentication plugin user name. + Using LDAP this is filled with LDAP UID. + :type extern_name: Optional(str) + :param extern_type: Set the authentication plugin type. + :type extern_type: Optional(str) + + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "updated user ID:<userid> <username>", + "user": <user_object>, + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to update user `<username>`" + } + + """ + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + user = get_user_or_error(userid) + + # only non optional arguments will be stored in updates + updates = {} + + try: + + store_update(updates, username, 'username') + store_update(updates, password, 'password') + store_update(updates, email, 'email') + store_update(updates, firstname, 'name') + store_update(updates, lastname, 'lastname') + store_update(updates, active, 'active') + store_update(updates, admin, 'admin') + store_update(updates, extern_name, 'extern_name') + store_update(updates, extern_type, 'extern_type') + + user = UserModel().update_user(user, **updates) + Session().commit() + return { + 'msg': 'updated user ID:%s %s' % (user.user_id, user.username), + 'user': user.get_api_data(include_secrets=True) + } + except DefaultUserException: + log.exception("Default user edit exception") + raise JSONRPCError('editing default user is forbidden') + except Exception: + log.exception("Error occurred during update of user") + raise JSONRPCError('failed to update user `%s`' % (userid,)) + + +@jsonrpc_method() +def delete_user(request, apiuser, userid): + """ + Deletes the specified user from the |RCE| user database. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + .. important:: + + Ensure all open pull requests and open code review + requests to this user are close. + + Also ensure all repositories, or repository groups owned by this + user are reassigned before deletion. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Set the user to delete. + :type userid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg" : "deleted user ID:<userid> <username>", + "user": null + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete user ID:<userid> <username>" + } + + """ + if not has_superadmin_permission(apiuser): + raise JSONRPCForbidden() + + user = get_user_or_error(userid) + + try: + UserModel().delete(userid) + Session().commit() + return { + 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username), + 'user': None + } + except Exception: + log.exception("Error occurred during deleting of user") + raise JSONRPCError( + 'failed to delete user ID:%s %s' % (user.user_id, user.username)) + + +@jsonrpc_method() +def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))): + """ + Displays all repositories locked by the specified user. + + * If this command is run by a non-admin user, it returns + a list of |repos| locked by that user. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param userid: Sets the userid whose list of locked |repos| will be + displayed. + :type userid: Optional(str or int) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + [repo_object, repo_object,...] + } + error : null + """ + + include_secrets = False + if not has_superadmin_permission(apiuser): + # make sure normal user does not pass someone else userid, + # he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError('userid is not the same as your user') + else: + include_secrets = True + + userid = Optional.extract(userid, evaluate_locals=locals()) + userid = getattr(userid, 'user_id', userid) + user = get_user_or_error(userid) + + ret = [] + + # show all locks + for r in Repository.getAll(): + _user_id, _time, _reason = r.locked + if _user_id and _time: + _api_data = r.get_api_data(include_secrets=include_secrets) + # if we use user filter just show the locks for this user + if safe_int(_user_id) == user.user_id: + ret.append(_api_data) + + return ret diff --git a/rhodecode/api/views/user_group_api.py b/rhodecode/api/views/user_group_api.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/views/user_group_api.py @@ -0,0 +1,773 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden +from rhodecode.api.utils import ( + Optional, OAttr, store_update, has_superadmin_permission, get_origin, + get_user_or_error, get_user_group_or_error, get_perm_or_error) +from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi +from rhodecode.lib.exceptions import UserGroupAssignedException +from rhodecode.model.db import Session +from rhodecode.model.scm import UserGroupList +from rhodecode.model.user_group import UserGroupModel + +log = logging.getLogger(__name__) + + +@jsonrpc_method() +def get_user_group(request, apiuser, usergroupid): + """ + Returns the data of an existing user group. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group from which to return data. + :type usergroupid: str or int + + Example error output: + + .. code-block:: bash + + { + "error": null, + "id": <id>, + "result": { + "active": true, + "group_description": "group description", + "group_name": "group name", + "members": [ + { + "name": "owner-name", + "origin": "owner", + "permission": "usergroup.admin", + "type": "user" + }, + { + { + "name": "user name", + "origin": "permission", + "permission": "usergroup.admin", + "type": "user" + }, + { + "name": "user group name", + "origin": "permission", + "permission": "usergroup.write", + "type": "user_group" + } + ], + "owner": "owner name", + "users": [], + "users_group_id": 2 + } + } + + """ + + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have at least read permission for this user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError('user group `%s` does not exist' % ( + usergroupid,)) + + permissions = [] + for _user in user_group.permissions(): + user_data = { + 'name': _user.username, + 'permission': _user.permission, + 'origin': get_origin(_user), + 'type': "user", + } + permissions.append(user_data) + + for _user_group in user_group.permission_user_groups(): + user_group_data = { + 'name': _user_group.users_group_name, + 'permission': _user_group.permission, + 'origin': get_origin(_user_group), + 'type': "user_group", + } + permissions.append(user_group_data) + + data = user_group.get_api_data() + data['members'] = permissions + + return data + + +@jsonrpc_method() +def get_user_groups(request, apiuser): + """ + Lists all the existing user groups within RhodeCode. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : [<user_group_obj>,...] + error : null + """ + + include_secrets = has_superadmin_permission(apiuser) + + result = [] + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + extras = {'user': apiuser} + for user_group in UserGroupList(UserGroupModel().get_all(), + perm_set=_perms, extra_kwargs=extras): + result.append( + user_group.get_api_data(include_secrets=include_secrets)) + return result + + +@jsonrpc_method() +def create_user_group( + request, apiuser, group_name, description=Optional(''), + owner=Optional(OAttr('apiuser')), active=Optional(True)): + """ + Creates a new user group. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param group_name: Set the name of the new user group. + :type group_name: str + :param description: Give a description of the new user group. + :type description: str + :param owner: Set the owner of the new user group. + If not set, the owner is the |authtoken| user. + :type owner: Optional(str or int) + :param active: Set this group as active. + :type active: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "msg": "created new user group `<groupname>`", + "user_group": <user_group_object> + } + error: null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "user group `<group name>` already exist" + or + "failed to create group `<group name>`" + } + + """ + + if not has_superadmin_permission(apiuser): + if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser): + raise JSONRPCForbidden() + + if UserGroupModel().get_by_name(group_name): + raise JSONRPCError("user group `%s` already exist" % (group_name,)) + + try: + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) + active = Optional.extract(active) + description = Optional.extract(description) + ug = UserGroupModel().create( + name=group_name, description=description, owner=owner, + active=active) + Session().commit() + return { + 'msg': 'created new user group `%s`' % group_name, + 'user_group': ug.get_api_data() + } + except Exception: + log.exception("Error occurred during creation of user group") + raise JSONRPCError('failed to create group `%s`' % (group_name,)) + + +@jsonrpc_method() +def update_user_group(request, apiuser, usergroupid, group_name=Optional(''), + description=Optional(''), owner=Optional(None), + active=Optional(True)): + """ + Updates the specified `user group` with the details provided. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the id of the `user group` to update. + :type usergroupid: str or int + :param group_name: Set the new name the `user group` + :type group_name: str + :param description: Give a description for the `user group` + :type description: str + :param owner: Set the owner of the `user group`. + :type owner: Optional(str or int) + :param active: Set the group as active. + :type active: Optional(``True`` | ``False``) + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": 'updated user group ID:<user group id> <user group name>', + "user_group": <user_group_object> + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to update user group `<user group name>`" + } + + """ + + user_group = get_user_group_or_error(usergroupid) + include_secrets = False + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + else: + include_secrets = True + + if not isinstance(owner, Optional): + owner = get_user_or_error(owner) + + updates = {} + store_update(updates, group_name, 'users_group_name') + store_update(updates, description, 'user_group_description') + store_update(updates, owner, 'user') + store_update(updates, active, 'users_group_active') + try: + UserGroupModel().update(user_group, updates) + Session().commit() + return { + 'msg': 'updated user group ID:%s %s' % ( + user_group.users_group_id, user_group.users_group_name), + 'user_group': user_group.get_api_data( + include_secrets=include_secrets) + } + except Exception: + log.exception("Error occurred during update of user group") + raise JSONRPCError( + 'failed to update user group `%s`' % (usergroupid,)) + + +@jsonrpc_method() +def delete_user_group(request, apiuser, usergroupid): + """ + Deletes the specified `user group`. + + This command can only be run using an |authtoken| with admin rights to + the specified repository. + + This command takes the following options: + + :param apiuser: filled automatically from apikey + :type apiuser: AuthUser + :param usergroupid: + :type usergroupid: int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "deleted user group ID:<user_group_id> <user_group_name>" + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to delete user group ID:<user_group_id> <user_group_name>" + or + "RepoGroup assigned to <repo_groups_list>" + } + + """ + + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + try: + UserGroupModel().delete(user_group) + Session().commit() + return { + 'msg': 'deleted user group ID:%s %s' % ( + user_group.users_group_id, user_group.users_group_name), + 'user_group': None + } + except UserGroupAssignedException as e: + log.exception("UserGroupAssigned error") + raise JSONRPCError(str(e)) + except Exception: + log.exception("Error occurred during deletion of user group") + raise JSONRPCError( + 'failed to delete user group ID:%s %s' %( + user_group.users_group_id, user_group.users_group_name)) + + +@jsonrpc_method() +def add_user_to_user_group(request, apiuser, usergroupid, userid): + """ + Adds a user to a `user group`. If the user already exists in the group + this command will return false. + + This command can only be run using an |authtoken| with admin rights to + the specified user group. + + This command takes the following options: + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the name of the `user group` to which a + user will be added. + :type usergroupid: int + :param userid: Set the `user_id` of the user to add to the group. + :type userid: int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "success": True|False # depends on if member is in group + "msg": "added member `<username>` to user group `<groupname>` | + User is already in that group" + + } + error : null + + Example error output: + + .. code-block:: bash + + id : <id_given_in_input> + result : null + error : { + "failed to add member to user group `<user_group_name>`" + } + + """ + + user = get_user_or_error(userid) + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError('user group `%s` does not exist' % ( + usergroupid,)) + + try: + ugm = UserGroupModel().add_user_to_group(user_group, user) + success = True if ugm is not True else False + msg = 'added member `%s` to user group `%s`' % ( + user.username, user_group.users_group_name + ) + msg = msg if success else 'User is already in that group' + Session().commit() + + return { + 'success': success, + 'msg': msg + } + except Exception: + log.exception("Error occurred during adding a member to user group") + raise JSONRPCError( + 'failed to add member to user group `%s`' % ( + user_group.users_group_name, + ) + ) + + +@jsonrpc_method() +def remove_user_from_user_group(request, apiuser, usergroupid, userid): + """ + Removes a user from a user group. + + * If the specified user is not in the group, this command will return + `false`. + + This command can only be run using an |authtoken| with admin rights to + the specified user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Sets the user group name. + :type usergroupid: str or int + :param userid: The user you wish to remove from |RCE|. + :type userid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result: { + "success": True|False, # depends on if member is in group + "msg": "removed member <username> from user group <groupname> | + User wasn't in group" + } + error: null + + """ + + user = get_user_or_error(userid) + user_group = get_user_group_or_error(usergroupid) + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + try: + success = UserGroupModel().remove_user_from_group(user_group, user) + msg = 'removed member `%s` from user group `%s`' % ( + user.username, user_group.users_group_name + ) + msg = msg if success else "User wasn't in group" + Session().commit() + return {'success': success, 'msg': msg} + except Exception: + log.exception("Error occurred during removing an member from user group") + raise JSONRPCError( + 'failed to remove member from user group `%s`' % ( + user_group.users_group_name, + ) + ) + + +@jsonrpc_method() +def grant_user_permission_to_user_group( + request, apiuser, usergroupid, userid, perm): + """ + Set permissions for a user in a user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group to edit permissions on. + :type usergroupid: str or int + :param userid: Set the user from whom you wish to set permissions. + :type userid: str + :param perm: (usergroup.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`", + "success": true + } + error : null + """ + + user_group = get_user_group_or_error(usergroupid) + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + user = get_user_or_error(userid) + perm = get_perm_or_error(perm, prefix='usergroup.') + + try: + UserGroupModel().grant_user_permission( + user_group=user_group, user=user, perm=perm) + Session().commit() + return { + 'msg': + 'Granted perm: `%s` for user: `%s` in user group: `%s`' % ( + perm.permission_name, user.username, + user_group.users_group_name + ), + 'success': True + } + except Exception: + log.exception("Error occurred during editing permissions " + "for user in user group") + raise JSONRPCError( + 'failed to edit permission for user: ' + '`%s` in user group: `%s`' % ( + userid, user_group.users_group_name)) + + +@jsonrpc_method() +def revoke_user_permission_from_user_group( + request, apiuser, usergroupid, userid): + """ + Revoke a users permissions in a user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group from which to revoke the user + permissions. + :type: usergroupid: str or int + :param userid: Set the userid of the user whose permissions will be + revoked. + :type userid: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`", + "success": true + } + error : null + """ + + user_group = get_user_group_or_error(usergroupid) + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (usergroupid,)) + + user = get_user_or_error(userid) + + try: + UserGroupModel().revoke_user_permission( + user_group=user_group, user=user) + Session().commit() + return { + 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % ( + user.username, user_group.users_group_name + ), + 'success': True + } + except Exception: + log.exception("Error occurred during editing permissions " + "for user in user group") + raise JSONRPCError( + 'failed to edit permission for user: `%s` in user group: `%s`' + % (userid, user_group.users_group_name)) + + +@jsonrpc_method() +def grant_user_group_permission_to_user_group( + request, apiuser, usergroupid, sourceusergroupid, perm): + """ + Give one user group permissions to another user group. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group on which to edit permissions. + :type usergroupid: str or int + :param sourceusergroupid: Set the source user group to which + access/permissions will be granted. + :type sourceusergroupid: str or int + :param perm: (usergroup.(none|read|write|admin)) + :type perm: str + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`", + "success": true + } + error : null + """ + + user_group = get_user_group_or_error(sourceusergroupid) + target_user_group = get_user_group_or_error(usergroupid) + perm = get_perm_or_error(perm, prefix='usergroup.') + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, + user_group_name=target_user_group.users_group_name): + raise JSONRPCError( + 'to user group `%s` does not exist' % (usergroupid,)) + + # check if we have at least read permission for source user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (sourceusergroupid,)) + + try: + UserGroupModel().grant_user_group_permission( + target_user_group=target_user_group, + user_group=user_group, perm=perm) + Session().commit() + + return { + 'msg': 'Granted perm: `%s` for user group: `%s` ' + 'in user group: `%s`' % ( + perm.permission_name, user_group.users_group_name, + target_user_group.users_group_name + ), + 'success': True + } + except Exception: + log.exception("Error occurred during editing permissions " + "for user group in user group") + raise JSONRPCError( + 'failed to edit permission for user group: `%s` in ' + 'user group: `%s`' % ( + sourceusergroupid, target_user_group.users_group_name + ) + ) + + +@jsonrpc_method() +def revoke_user_group_permission_from_user_group( + request, apiuser, usergroupid, sourceusergroupid): + """ + Revoke the permissions that one user group has to another. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param usergroupid: Set the user group on which to edit permissions. + :type usergroupid: str or int + :param sourceusergroupid: Set the user group from which permissions + are revoked. + :type sourceusergroupid: str or int + + Example output: + + .. code-block:: bash + + id : <id_given_in_input> + result : { + "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`", + "success": true + } + error : null + """ + + user_group = get_user_group_or_error(sourceusergroupid) + target_user_group = get_user_group_or_error(usergroupid) + + if not has_superadmin_permission(apiuser): + # check if we have admin permission for this user group ! + _perms = ('usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, + user_group_name=target_user_group.users_group_name): + raise JSONRPCError( + 'to user group `%s` does not exist' % (usergroupid,)) + + # check if we have at least read permission + # for the source user group ! + _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',) + if not HasUserGroupPermissionAnyApi(*_perms)( + user=apiuser, user_group_name=user_group.users_group_name): + raise JSONRPCError( + 'user group `%s` does not exist' % (sourceusergroupid,)) + + try: + UserGroupModel().revoke_user_group_permission( + target_user_group=target_user_group, user_group=user_group) + Session().commit() + + return { + 'msg': 'Revoked perm for user group: ' + '`%s` in user group: `%s`' % ( + user_group.users_group_name, + target_user_group.users_group_name + ), + 'success': True + } + except Exception: + log.exception("Error occurred during editing permissions " + "for user group in user group") + raise JSONRPCError( + 'failed to edit permission for user group: ' + '`%s` in user group: `%s`' % ( + sourceusergroupid, target_user_group.users_group_name + ) + ) diff --git a/rhodecode/authentication/__init__.py b/rhodecode/authentication/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/__init__.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pkg_resources import iter_entry_points +from pyramid.authentication import SessionAuthenticationPolicy + +from rhodecode.authentication.registry import AuthenticationPluginRegistry +from rhodecode.authentication.routes import root_factory +from rhodecode.authentication.routes import AuthnRootResource +from rhodecode.config.routing import ADMIN_PREFIX + +log = logging.getLogger(__name__) + + +# TODO: Currently this is only used to discover the authentication plugins. +# Later on this may be used in a generic way to look up and include all kinds +# of supported enterprise plugins. Therefore this has to be moved and +# refactored to a real 'plugin look up' machinery. +# TODO: When refactoring this think about splitting it up into distinct +# discover, load and include phases. +def _discover_plugins(config, entry_point='enterprise.plugins1'): + _discovered_plugins = {} + + for ep in iter_entry_points(entry_point): + plugin_id = 'egg:{}#{}'.format(ep.dist.project_name, ep.name) + log.debug('Plugin discovered: "%s"', plugin_id) + module = ep.load() + plugin = module(plugin_id=plugin_id) + config.include(plugin.includeme) + + return _discovered_plugins + + +def includeme(config): + # Set authentication policy. + authn_policy = SessionAuthenticationPolicy() + config.set_authentication_policy(authn_policy) + + # Create authentication plugin registry and add it to the pyramid registry. + authn_registry = AuthenticationPluginRegistry() + config.add_directive('add_authn_plugin', authn_registry.add_authn_plugin) + config.registry.registerUtility(authn_registry) + + # Create authentication traversal root resource. + authn_root_resource = root_factory() + config.add_directive('add_authn_resource', + authn_root_resource.add_authn_resource) + + # Add the authentication traversal route. + config.add_route('auth_home', + ADMIN_PREFIX + '/auth*traverse', + factory=root_factory) + # Add the authentication settings root views. + config.add_view('rhodecode.authentication.views.AuthSettingsView', + attr='index', + request_method='GET', + route_name='auth_home', + context=AuthnRootResource) + config.add_view('rhodecode.authentication.views.AuthSettingsView', + attr='auth_settings', + request_method='POST', + route_name='auth_home', + context=AuthnRootResource) + + # Auto discover authentication plugins and include their configuration. + _discover_plugins(config) diff --git a/rhodecode/authentication/base.py b/rhodecode/authentication/base.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/base.py @@ -0,0 +1,739 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Authentication modules +""" + +import logging +import time +import traceback + +from authomatic import Authomatic +from authomatic.adapters import WebObAdapter +from authomatic.providers import oauth2, oauth1 +from pylons import url +from pylons.controllers.util import Response +from pylons.i18n.translation import _ +from pyramid.threadlocal import get_current_registry +from sqlalchemy.ext.hybrid import hybrid_property + +import rhodecode.lib.helpers as h +from rhodecode.authentication.interface import IAuthnPluginRegistry +from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase +from rhodecode.lib import caches +from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt +from rhodecode.lib.utils2 import md5_safe, safe_int +from rhodecode.lib.utils2 import safe_str +from rhodecode.model.db import User, ExternalIdentity +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel +from rhodecode.model.user import UserModel +from rhodecode.model.user_group import UserGroupModel + + +log = logging.getLogger(__name__) + +# auth types that authenticate() function can receive +VCS_TYPE = 'vcs' +HTTP_TYPE = 'http' + + +class LazyFormencode(object): + def __init__(self, formencode_obj, *args, **kwargs): + self.formencode_obj = formencode_obj + self.args = args + self.kwargs = kwargs + + def __call__(self, *args, **kwargs): + from inspect import isfunction + formencode_obj = self.formencode_obj + if isfunction(formencode_obj): + # case we wrap validators into functions + formencode_obj = self.formencode_obj(*args, **kwargs) + return formencode_obj(*self.args, **self.kwargs) + + +class RhodeCodeAuthPluginBase(object): + # cache the authentication request for N amount of seconds. Some kind + # of authentication methods are very heavy and it's very efficient to cache + # the result of a call. If it's set to None (default) cache is off + AUTH_CACHE_TTL = None + AUTH_CACHE = {} + + auth_func_attrs = { + "username": "unique username", + "firstname": "first name", + "lastname": "last name", + "email": "email address", + "groups": '["list", "of", "groups"]', + "extern_name": "name in external source of record", + "extern_type": "type of external source of record", + "admin": 'True|False defines if user should be RhodeCode super admin', + "active": + 'True|False defines active state of user internally for RhodeCode', + "active_from_extern": + "True|False\None, active state from the external auth, " + "None means use definition from RhodeCode extern_type active value" + } + # set on authenticate() method and via set_auth_type func. + auth_type = None + + # List of setting names to store encrypted. Plugins may override this list + # to store settings encrypted. + _settings_encrypted = [] + + # Mapping of python to DB settings model types. Plugins may override or + # extend this mapping. + _settings_type_map = { + str: 'str', + int: 'int', + unicode: 'unicode', + bool: 'bool', + list: 'list', + } + + def __init__(self, plugin_id): + self._plugin_id = plugin_id + + def _get_setting_full_name(self, name): + """ + Return the full setting name used for storing values in the database. + """ + # TODO: johbo: Using the name here is problematic. It would be good to + # introduce either new models in the database to hold Plugin and + # PluginSetting or to use the plugin id here. + return 'auth_{}_{}'.format(self.name, name) + + def _get_setting_type(self, name, value): + """ + Get the type as used by the SettingsModel accordingly to type of passed + value. Optionally the suffix `.encrypted` is appended to instruct + SettingsModel to store it encrypted. + """ + type_ = self._settings_type_map.get(type(value), 'unicode') + if name in self._settings_encrypted: + type_ = '{}.encrypted'.format(type_) + return type_ + + def is_enabled(self): + """ + Returns true if this plugin is enabled. An enabled plugin can be + configured in the admin interface but it is not consulted during + authentication. + """ + auth_plugins = SettingsModel().get_auth_plugins() + return self.get_id() in auth_plugins + + def is_active(self): + """ + Returns true if the plugin is activated. An activated plugin is + consulted during authentication, assumed it is also enabled. + """ + return self.get_setting_by_name('enabled') + + def get_id(self): + """ + Returns the plugin id. + """ + return self._plugin_id + + def get_display_name(self): + """ + Returns a translation string for displaying purposes. + """ + raise NotImplementedError('Not implemented in base class') + + def get_settings_schema(self): + """ + Returns a colander schema, representing the plugin settings. + """ + return AuthnPluginSettingsSchemaBase() + + def get_setting_by_name(self, name): + """ + Returns a plugin setting by name. + """ + full_name = self._get_setting_full_name(name) + db_setting = SettingsModel().get_setting_by_name(full_name) + return db_setting.app_settings_value if db_setting else None + + def create_or_update_setting(self, name, value): + """ + Create or update a setting for this plugin in the persistent storage. + """ + full_name = self._get_setting_full_name(name) + type_ = self._get_setting_type(name, value) + db_setting = SettingsModel().create_or_update_setting( + full_name, value, type_) + return db_setting.app_settings_value + + def get_settings(self): + """ + Returns the plugin settings as dictionary. + """ + settings = {} + for node in self.get_settings_schema(): + settings[node.name] = self.get_setting_by_name(node.name) + return settings + + @property + def validators(self): + """ + Exposes RhodeCode validators modules + """ + # this is a hack to overcome issues with pylons threadlocals and + # translator object _() not beein registered properly. + class LazyCaller(object): + def __init__(self, name): + self.validator_name = name + + def __call__(self, *args, **kwargs): + from rhodecode.model import validators as v + obj = getattr(v, self.validator_name) + # log.debug('Initializing lazy formencode object: %s', obj) + return LazyFormencode(obj, *args, **kwargs) + + class ProxyGet(object): + def __getattribute__(self, name): + return LazyCaller(name) + + return ProxyGet() + + @hybrid_property + def name(self): + """ + Returns the name of this authentication plugin. + + :returns: string + """ + raise NotImplementedError("Not implemented in base class") + + @hybrid_property + def is_container_auth(self): + """ + Returns bool if this module uses container auth. + + This property will trigger an automatic call to authenticate on + a visit to the website or during a push/pull. + + :returns: bool + """ + return False + + @hybrid_property + def allows_creating_users(self): + """ + Defines if Plugin allows users to be created on-the-fly when + authentication is called. Controls how external plugins should behave + in terms if they are allowed to create new users, or not. Base plugins + should not be allowed to, but External ones should be ! + + :return: bool + """ + return False + + def set_auth_type(self, auth_type): + self.auth_type = auth_type + + def allows_authentication_from( + self, user, allows_non_existing_user=True, + allowed_auth_plugins=None, allowed_auth_sources=None): + """ + Checks if this authentication module should accept a request for + the current user. + + :param user: user object fetched using plugin's get_user() method. + :param allows_non_existing_user: if True, don't allow the + user to be empty, meaning not existing in our database + :param allowed_auth_plugins: if provided, users extern_type will be + checked against a list of provided extern types, which are plugin + auth_names in the end + :param allowed_auth_sources: authentication type allowed, + `http` or `vcs` default is both. + defines if plugin will accept only http authentication vcs + authentication(git/hg) or both + :returns: boolean + """ + if not user and not allows_non_existing_user: + log.debug('User is empty but plugin does not allow empty users,' + 'not allowed to authenticate') + return False + + expected_auth_plugins = allowed_auth_plugins or [self.name] + if user and (user.extern_type and + user.extern_type not in expected_auth_plugins): + log.debug( + 'User `%s` is bound to `%s` auth type. Plugin allows only ' + '%s, skipping', user, user.extern_type, expected_auth_plugins) + + return False + + # by default accept both + expected_auth_from = allowed_auth_sources or [HTTP_TYPE, VCS_TYPE] + if self.auth_type not in expected_auth_from: + log.debug('Current auth source is %s but plugin only allows %s', + self.auth_type, expected_auth_from) + return False + + return True + + def get_user(self, username=None, **kwargs): + """ + Helper method for user fetching in plugins, by default it's using + simple fetch by username, but this method can be custimized in plugins + eg. container auth plugin to fetch user by environ params + + :param username: username if given to fetch from database + :param kwargs: extra arguments needed for user fetching. + """ + user = None + log.debug( + 'Trying to fetch user `%s` from RhodeCode database', username) + if username: + user = User.get_by_username(username) + if not user: + log.debug('User not found, fallback to fetch user in ' + 'case insensitive mode') + user = User.get_by_username(username, case_insensitive=True) + else: + log.debug('provided username:`%s` is empty skipping...', username) + if not user: + log.debug('User `%s` not found in database', username) + return user + + def user_activation_state(self): + """ + Defines user activation state when creating new users + + :returns: boolean + """ + raise NotImplementedError("Not implemented in base class") + + def auth(self, userobj, username, passwd, settings, **kwargs): + """ + Given a user object (which may be null), username, a plaintext + password, and a settings object (containing all the keys needed as + listed in settings()), authenticate this user's login attempt. + + Return None on failure. On success, return a dictionary of the form: + + see: RhodeCodeAuthPluginBase.auth_func_attrs + This is later validated for correctness + """ + raise NotImplementedError("not implemented in base class") + + def _authenticate(self, userobj, username, passwd, settings, **kwargs): + """ + Wrapper to call self.auth() that validates call on it + + :param userobj: userobj + :param username: username + :param passwd: plaintext password + :param settings: plugin settings + """ + auth = self.auth(userobj, username, passwd, settings, **kwargs) + if auth: + # check if hash should be migrated ? + new_hash = auth.get('_hash_migrate') + if new_hash: + self._migrate_hash_to_bcrypt(username, passwd, new_hash) + return self._validate_auth_return(auth) + return auth + + def _migrate_hash_to_bcrypt(self, username, password, new_hash): + new_hash_cypher = _RhodeCodeCryptoBCrypt() + # extra checks, so make sure new hash is correct. + password_encoded = safe_str(password) + if new_hash and new_hash_cypher.hash_check( + password_encoded, new_hash): + cur_user = User.get_by_username(username) + cur_user.password = new_hash + Session().add(cur_user) + Session().flush() + log.info('Migrated user %s hash to bcrypt', cur_user) + + def _validate_auth_return(self, ret): + if not isinstance(ret, dict): + raise Exception('returned value from auth must be a dict') + for k in self.auth_func_attrs: + if k not in ret: + raise Exception('Missing %s attribute from returned data' % k) + return ret + + +class RhodeCodeExternalAuthPlugin(RhodeCodeAuthPluginBase): + + @hybrid_property + def allows_creating_users(self): + return True + + def use_fake_password(self): + """ + Return a boolean that indicates whether or not we should set the user's + password to a random value when it is authenticated by this plugin. + If your plugin provides authentication, then you will generally + want this. + + :returns: boolean + """ + raise NotImplementedError("Not implemented in base class") + + def _authenticate(self, userobj, username, passwd, settings, **kwargs): + # at this point _authenticate calls plugin's `auth()` function + auth = super(RhodeCodeExternalAuthPlugin, self)._authenticate( + userobj, username, passwd, settings, **kwargs) + if auth: + # maybe plugin will clean the username ? + # we should use the return value + username = auth['username'] + + # if external source tells us that user is not active, we should + # skip rest of the process. This can prevent from creating users in + # RhodeCode when using external authentication, but if it's + # inactive user we shouldn't create that user anyway + if auth['active_from_extern'] is False: + log.warning( + "User %s authenticated against %s, but is inactive", + username, self.__module__) + return None + + cur_user = User.get_by_username(username, case_insensitive=True) + is_user_existing = cur_user is not None + + if is_user_existing: + log.debug('Syncing user `%s` from ' + '`%s` plugin', username, self.name) + else: + log.debug('Creating non existing user `%s` from ' + '`%s` plugin', username, self.name) + + if self.allows_creating_users: + log.debug('Plugin `%s` allows to ' + 'create new users', self.name) + else: + log.debug('Plugin `%s` does not allow to ' + 'create new users', self.name) + + user_parameters = { + 'username': username, + 'email': auth["email"], + 'firstname': auth["firstname"], + 'lastname': auth["lastname"], + 'active': auth["active"], + 'admin': auth["admin"], + 'extern_name': auth["extern_name"], + 'extern_type': self.name, + 'plugin': self, + 'allow_to_create_user': self.allows_creating_users, + } + + if not is_user_existing: + if self.use_fake_password(): + # Randomize the PW because we don't need it, but don't want + # them blank either + passwd = PasswordGenerator().gen_password(length=16) + user_parameters['password'] = passwd + else: + # Since the password is required by create_or_update method of + # UserModel, we need to set it explicitly. + # The create_or_update method is smart and recognises the + # password hashes as well. + user_parameters['password'] = cur_user.password + + # we either create or update users, we also pass the flag + # that controls if this method can actually do that. + # raises NotAllowedToCreateUserError if it cannot, and we try to. + user = UserModel().create_or_update(**user_parameters) + Session().flush() + # enforce user is just in given groups, all of them has to be ones + # created from plugins. We store this info in _group_data JSON + # field + try: + groups = auth['groups'] or [] + UserGroupModel().enforce_groups(user, groups, self.name) + except Exception: + # for any reason group syncing fails, we should + # proceed with login + log.error(traceback.format_exc()) + Session().commit() + return auth + + +class AuthomaticBase(RhodeCodeExternalAuthPlugin): + + # TODO: Think about how to create and store this secret string. + # We need the secret for the authomatic library. It needs to be the same + # across requests. + def _get_authomatic_secret(self, length=40): + secret = self.get_setting_by_name('secret') + if secret is None or secret == 'None' or secret == '': + from Crypto import Random, Hash + secret_bytes = Random.new().read(length) + secret_hash = Hash.SHA256.new() + secret_hash.update(secret_bytes) + secret = secret_hash.hexdigest() + self.create_or_update_setting('secret', secret) + Session.commit() + secret = self.get_setting_by_name('secret') + return secret + + def get_authomatic(self): + scope = [] + if self.name == 'bitbucket': + provider_class = oauth1.Bitbucket + scope = ['account', 'email', 'repository', 'issue', 'issue:write'] + elif self.name == 'github': + provider_class = oauth2.GitHub + scope = ['repo', 'public_repo', 'user:email'] + elif self.name == 'google': + provider_class = oauth2.Google + scope = ['profile', 'email'] + elif self.name == 'twitter': + provider_class = oauth1.Twitter + + authomatic_conf = { + self.name: { + 'class_': provider_class, + 'consumer_key': self.get_setting_by_name('consumer_key'), + 'consumer_secret': self.get_setting_by_name('consumer_secret'), + 'scope': scope, + 'access_headers': {'User-Agent': 'TestAppAgent'}, + } + } + secret = self._get_authomatic_secret() + return Authomatic(config=authomatic_conf, + secret=secret) + + def get_provider_result(self, request): + """ + Provides `authomatic.core.LoginResult` for provider and request + + :param provider_name: + :param request: + :param config: + :return: + """ + response = Response() + adapter = WebObAdapter(request, response) + authomatic_inst = self.get_authomatic() + return authomatic_inst.login(adapter, self.name), response + + def handle_social_data(self, session, user_id, social_data): + """ + Updates user tokens in database whenever necessary + :param request: + :param user: + :param social_data: + :return: + """ + if not self.is_active(): + h.flash(_('This provider is currently disabled'), + category='warning') + return False + + social_data = social_data + update_identity = False + + existing_row = ExternalIdentity.by_external_id_and_provider( + social_data['user']['id'], + social_data['credentials.provider'] + ) + + if existing_row: + Session().delete(existing_row) + update_identity = True + + if not existing_row or update_identity: + if not update_identity: + h.flash(_('Your external identity is now ' + 'connected with your account'), category='success') + + if not social_data['user']['id']: + h.flash(_('No external user id found? Perhaps permissions' + 'for authentication are set incorrectly'), + category='error') + return False + + ex_identity = ExternalIdentity() + ex_identity.external_id = social_data['user']['id'] + ex_identity.external_username = social_data['user']['user_name'] + ex_identity.provider_name = social_data['credentials.provider'] + ex_identity.access_token = social_data['credentials.token'] + ex_identity.token_secret = social_data['credentials.token_secret'] + ex_identity.alt_token = social_data['credentials.refresh_token'] + ex_identity.local_user_id = user_id + Session().add(ex_identity) + session.pop('rhodecode.social_auth', None) + return ex_identity + + def callback_url(self): + try: + return url('social_auth', provider_name=self.name, qualified=True) + except TypeError: + pass + return '' + + +def loadplugin(plugin_id): + """ + Loads and returns an instantiated authentication plugin. + Returns the RhodeCodeAuthPluginBase subclass on success, + raises exceptions on failure. + + raises: + KeyError -- if no plugin available with given name + TypeError -- if the RhodeCodeAuthPlugin is not a subclass of + ours RhodeCodeAuthPluginBase + """ + # TODO: Disusing pyramids thread locals to retrieve the registry. + authn_registry = get_current_registry().getUtility(IAuthnPluginRegistry) + plugin = authn_registry.get_plugin(plugin_id) + if plugin is None: + log.error('Authentication plugin not found: "%s"', plugin_id) + return plugin + + +def get_auth_cache_manager(custom_ttl=None): + return caches.get_cache_manager( + 'auth_plugins', 'rhodecode.authentication', custom_ttl) + + +def authenticate(username, password, environ=None, auth_type=None, + skip_missing=False): + """ + Authentication function used for access control, + It tries to authenticate based on enabled authentication modules. + + :param username: username can be empty for container auth + :param password: password can be empty for container auth + :param environ: environ headers passed for container auth + :param auth_type: type of authentication, either `HTTP_TYPE` or `VCS_TYPE` + :param skip_missing: ignores plugins that are in db but not in environment + :returns: None if auth failed, plugin_user dict if auth is correct + """ + if not auth_type or auth_type not in [HTTP_TYPE, VCS_TYPE]: + raise ValueError('auth type must be on of http, vcs got "%s" instead' + % auth_type) + container_only = environ and not (username and password) + auth_plugins = SettingsModel().get_auth_plugins() + for plugin_id in auth_plugins: + plugin = loadplugin(plugin_id) + + if plugin is None: + log.warning('Authentication plugin missing: "{}"'.format( + plugin_id)) + continue + + if not plugin.is_active(): + log.info('Authentication plugin is inactive: "{}"'.format( + plugin_id)) + continue + + plugin.set_auth_type(auth_type) + user = plugin.get_user(username) + display_user = user.username if user else username + + if container_only and not plugin.is_container_auth: + log.debug('Auth type is for container only and plugin `%s` is not ' + 'container plugin, skipping...', plugin_id) + continue + + # load plugin settings from RhodeCode database + plugin_settings = plugin.get_settings() + log.debug('Plugin settings:%s', plugin_settings) + + log.debug('Trying authentication using ** %s **', plugin_id) + # use plugin's method of user extraction. + user = plugin.get_user(username, environ=environ, + settings=plugin_settings) + display_user = user.username if user else username + log.debug('Plugin %s extracted user is `%s`', plugin_id, display_user) + + if not plugin.allows_authentication_from(user): + log.debug('Plugin %s does not accept user `%s` for authentication', + plugin_id, display_user) + continue + else: + log.debug('Plugin %s accepted user `%s` for authentication', + plugin_id, display_user) + + log.info('Authenticating user `%s` using %s plugin', + display_user, plugin_id) + + _cache_ttl = 0 + + if isinstance(plugin.AUTH_CACHE_TTL, (int, long)): + # plugin cache set inside is more important than the settings value + _cache_ttl = plugin.AUTH_CACHE_TTL + elif plugin_settings.get('auth_cache_ttl'): + _cache_ttl = safe_int(plugin_settings.get('auth_cache_ttl'), 0) + + plugin_cache_active = bool(_cache_ttl and _cache_ttl > 0) + + # get instance of cache manager configured for a namespace + cache_manager = get_auth_cache_manager(custom_ttl=_cache_ttl) + + log.debug('Cache for plugin `%s` active: %s', plugin_id, + plugin_cache_active) + + # for environ based password can be empty, but then the validation is + # on the server that fills in the env data needed for authentication + _password_hash = md5_safe(plugin.name + username + (password or '')) + + # _authenticate is a wrapper for .auth() method of plugin. + # it checks if .auth() sends proper data. + # For RhodeCodeExternalAuthPlugin it also maps users to + # Database and maps the attributes returned from .auth() + # to RhodeCode database. If this function returns data + # then auth is correct. + start = time.time() + log.debug('Running plugin `%s` _authenticate method', + plugin_id) + + def auth_func(): + """ + This function is used internally in Cache of Beaker to calculate + Results + """ + return plugin._authenticate( + user, username, password, plugin_settings, + environ=environ or {}) + + if plugin_cache_active: + plugin_user = cache_manager.get( + _password_hash, createfunc=auth_func) + else: + plugin_user = auth_func() + + auth_time = time.time() - start + log.debug('Authentication for plugin `%s` completed in %.3fs, ' + 'expiration time of fetched cache %.1fs.', + plugin_id, auth_time, _cache_ttl) + + log.debug('PLUGIN USER DATA: %s', plugin_user) + + if plugin_user: + log.debug('Plugin returned proper authentication data') + return plugin_user + # we failed to Auth because .auth() method didn't return proper user + log.debug("User `%s` failed to authenticate against %s", + display_user, plugin_id) + return None diff --git a/rhodecode/authentication/interface.py b/rhodecode/authentication/interface.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/interface.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from zope.interface import Interface + + +class IAuthnPluginRegistry(Interface): + """ + Interface for the authentication plugin registry. Currently this is only + used to register and retrieve it via pyramids registry. + """ + pass diff --git a/rhodecode/authentication/plugins/__init__.py b/rhodecode/authentication/plugins/__init__.py new file mode 100644 diff --git a/rhodecode/authentication/plugins/auth_crowd.py b/rhodecode/authentication/plugins/auth_crowd.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/plugins/auth_crowd.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode authentication plugin for Atlassian CROWD +""" + + +import colander +import base64 +import logging +import urllib2 + +from pylons.i18n.translation import lazy_ugettext as _ +from sqlalchemy.ext.hybrid import hybrid_property + +from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin +from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase +from rhodecode.authentication.routes import AuthnPluginResourceBase +from rhodecode.lib.ext_json import json, formatted_json +from rhodecode.model.db import User + +log = logging.getLogger(__name__) + + +def plugin_factory(plugin_id, *args, **kwds): + """ + Factory function that is called during plugin discovery. + It returns the plugin instance. + """ + plugin = RhodeCodeAuthPlugin(plugin_id) + return plugin + + +class CrowdAuthnResource(AuthnPluginResourceBase): + pass + + +class CrowdSettingsSchema(AuthnPluginSettingsSchemaBase): + host = colander.SchemaNode( + colander.String(), + default='127.0.0.1', + description=_('The FQDN or IP of the Atlassian CROWD Server'), + title=_('Host'), + widget='string') + port = colander.SchemaNode( + colander.Int(), + default=8095, + description=_('The Port in use by the Atlassian CROWD Server'), + title=_('Port'), + validator=colander.Range(min=0, max=65536), + widget='int') + app_name = colander.SchemaNode( + colander.String(), + default='', + description=_('The Application Name to authenticate to CROWD'), + title=_('Application Name'), + widget='string') + app_password = colander.SchemaNode( + colander.String(), + default='', + description=_('The password to authenticate to CROWD'), + title=_('Application Password'), + widget='password') + admin_groups = colander.SchemaNode( + colander.String(), + default='', + description=_('A comma separated list of group names that identify ' + 'users as RhodeCode Administrators'), + missing='', + title=_('Admin Groups'), + widget='string') + + +class CrowdServer(object): + def __init__(self, *args, **kwargs): + """ + Create a new CrowdServer object that points to IP/Address 'host', + on the given port, and using the given method (https/http). user and + passwd can be set here or with set_credentials. If unspecified, + "version" defaults to "latest". + + example:: + + cserver = CrowdServer(host="127.0.0.1", + port="8095", + user="some_app", + passwd="some_passwd", + version="1") + """ + if not "port" in kwargs: + kwargs["port"] = "8095" + self._logger = kwargs.get("logger", logging.getLogger(__name__)) + self._uri = "%s://%s:%s/crowd" % (kwargs.get("method", "http"), + kwargs.get("host", "127.0.0.1"), + kwargs.get("port", "8095")) + self.set_credentials(kwargs.get("user", ""), + kwargs.get("passwd", "")) + self._version = kwargs.get("version", "latest") + self._url_list = None + self._appname = "crowd" + + def set_credentials(self, user, passwd): + self.user = user + self.passwd = passwd + self._make_opener() + + def _make_opener(self): + mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() + mgr.add_password(None, self._uri, self.user, self.passwd) + handler = urllib2.HTTPBasicAuthHandler(mgr) + self.opener = urllib2.build_opener(handler) + + def _request(self, url, body=None, headers=None, + method=None, noformat=False, + empty_response_ok=False): + _headers = {"Content-type": "application/json", + "Accept": "application/json"} + if self.user and self.passwd: + authstring = base64.b64encode("%s:%s" % (self.user, self.passwd)) + _headers["Authorization"] = "Basic %s" % authstring + if headers: + _headers.update(headers) + log.debug("Sent crowd: \n%s" + % (formatted_json({"url": url, "body": body, + "headers": _headers}))) + request = urllib2.Request(url, body, _headers) + if method: + request.get_method = lambda: method + + global msg + msg = "" + try: + rdoc = self.opener.open(request) + msg = "".join(rdoc.readlines()) + if not msg and empty_response_ok: + rval = {} + rval["status"] = True + rval["error"] = "Response body was empty" + elif not noformat: + rval = json.loads(msg) + rval["status"] = True + else: + rval = "".join(rdoc.readlines()) + except Exception as e: + if not noformat: + rval = {"status": False, + "body": body, + "error": str(e) + "\n" + msg} + else: + rval = None + return rval + + def user_auth(self, username, password): + """Authenticate a user against crowd. Returns brief information about + the user.""" + url = ("%s/rest/usermanagement/%s/authentication?username=%s" + % (self._uri, self._version, username)) + body = json.dumps({"value": password}) + return self._request(url, body) + + def user_groups(self, username): + """Retrieve a list of groups to which this user belongs.""" + url = ("%s/rest/usermanagement/%s/user/group/nested?username=%s" + % (self._uri, self._version, username)) + return self._request(url) + + +class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): + + def includeme(self, config): + config.add_authn_plugin(self) + config.add_authn_resource(self.get_id(), CrowdAuthnResource(self)) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_get', + request_method='GET', + route_name='auth_home', + context=CrowdAuthnResource) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_post', + request_method='POST', + route_name='auth_home', + context=CrowdAuthnResource) + + def get_settings_schema(self): + return CrowdSettingsSchema() + + def get_display_name(self): + return _('CROWD') + + @hybrid_property + def name(self): + return "crowd" + + def use_fake_password(self): + return True + + def user_activation_state(self): + def_user_perms = User.get_default_user().AuthUser.permissions['global'] + return 'hg.extern_activate.auto' in def_user_perms + + def auth(self, userobj, username, password, settings, **kwargs): + """ + Given a user object (which may be null), username, a plaintext password, + and a settings object (containing all the keys needed as listed in settings()), + authenticate this user's login attempt. + + Return None on failure. On success, return a dictionary of the form: + + see: RhodeCodeAuthPluginBase.auth_func_attrs + This is later validated for correctness + """ + if not username or not password: + log.debug('Empty username or password skipping...') + return None + + log.debug("Crowd settings: \n%s" % (formatted_json(settings))) + server = CrowdServer(**settings) + server.set_credentials(settings["app_name"], settings["app_password"]) + crowd_user = server.user_auth(username, password) + log.debug("Crowd returned: \n%s" % (formatted_json(crowd_user))) + if not crowd_user["status"]: + return None + + res = server.user_groups(crowd_user["name"]) + log.debug("Crowd groups: \n%s" % (formatted_json(res))) + crowd_user["groups"] = [x["name"] for x in res["groups"]] + + # old attrs fetched from RhodeCode database + admin = getattr(userobj, 'admin', False) + active = getattr(userobj, 'active', True) + email = getattr(userobj, 'email', '') + username = getattr(userobj, 'username', username) + firstname = getattr(userobj, 'firstname', '') + lastname = getattr(userobj, 'lastname', '') + extern_type = getattr(userobj, 'extern_type', '') + + user_attrs = { + 'username': username, + 'firstname': crowd_user["first-name"] or firstname, + 'lastname': crowd_user["last-name"] or lastname, + 'groups': crowd_user["groups"], + 'email': crowd_user["email"] or email, + 'admin': admin, + 'active': active, + 'active_from_extern': crowd_user.get('active'), + 'extern_name': crowd_user["name"], + 'extern_type': extern_type, + } + + # set an admin if we're in admin_groups of crowd + for group in settings["admin_groups"]: + if group in user_attrs["groups"]: + user_attrs["admin"] = True + log.debug("Final crowd user object: \n%s" % (formatted_json(user_attrs))) + log.info('user %s authenticated correctly' % user_attrs['username']) + return user_attrs diff --git a/rhodecode/authentication/plugins/auth_jasig_cas.py b/rhodecode/authentication/plugins/auth_jasig_cas.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/plugins/auth_jasig_cas.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode authentication plugin for Jasig CAS +http://www.jasig.org/cas +""" + + +import colander +import logging +import rhodecode +import urllib +import urllib2 + +from pylons.i18n.translation import lazy_ugettext as _ +from sqlalchemy.ext.hybrid import hybrid_property + +from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin +from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase +from rhodecode.authentication.routes import AuthnPluginResourceBase +from rhodecode.lib.ext_json import formatted_json +from rhodecode.lib.utils2 import safe_unicode +from rhodecode.model.db import User + +log = logging.getLogger(__name__) + + +def plugin_factory(plugin_id, *args, **kwds): + """ + Factory function that is called during plugin discovery. + It returns the plugin instance. + """ + plugin = RhodeCodeAuthPlugin(plugin_id) + return plugin + + +class JasigCasAuthnResource(AuthnPluginResourceBase): + pass + + +class JasigCasSettingsSchema(AuthnPluginSettingsSchemaBase): + service_url = colander.SchemaNode( + colander.String(), + default='https://domain.com/cas/v1/tickets', + description=_('The url of the Jasig CAS REST service'), + title=_('URL'), + widget='string') + + +class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): + + def includeme(self, config): + config.add_authn_plugin(self) + config.add_authn_resource(self.get_id(), JasigCasAuthnResource(self)) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_get', + request_method='GET', + route_name='auth_home', + context=JasigCasAuthnResource) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_post', + request_method='POST', + route_name='auth_home', + context=JasigCasAuthnResource) + + def get_settings_schema(self): + return JasigCasSettingsSchema() + + def get_display_name(self): + return _('Jasig-CAS') + + @hybrid_property + def name(self): + return "jasig-cas" + + @hybrid_property + def is_container_auth(self): + return True + + def use_fake_password(self): + return True + + def user_activation_state(self): + def_user_perms = User.get_default_user().AuthUser.permissions['global'] + return 'hg.extern_activate.auto' in def_user_perms + + def auth(self, userobj, username, password, settings, **kwargs): + """ + Given a user object (which may be null), username, a plaintext password, + and a settings object (containing all the keys needed as listed in settings()), + authenticate this user's login attempt. + + Return None on failure. On success, return a dictionary of the form: + + see: RhodeCodeAuthPluginBase.auth_func_attrs + This is later validated for correctness + """ + if not username or not password: + log.debug('Empty username or password skipping...') + return None + + log.debug("Jasig CAS settings: \n%s" % (formatted_json(settings))) + params = urllib.urlencode({'username': username, 'password': password}) + headers = {"Content-type": "application/x-www-form-urlencoded", + "Accept": "text/plain", + "User-Agent": "RhodeCode-auth-%s" % rhodecode.__version__} + url = settings["service_url"] + + log.debug("Sent Jasig CAS: \n%s" + % (formatted_json({"url": url, + "body": params, + "headers": headers}))) + request = urllib2.Request(url, params, headers) + try: + response = urllib2.urlopen(request) + except urllib2.HTTPError as e: + log.debug("HTTPError when requesting Jasig CAS (status code: %d)" % e.code) + return None + except urllib2.URLError as e: + log.debug("URLError when requesting Jasig CAS url: %s " % url) + return None + + # old attrs fetched from RhodeCode database + admin = getattr(userobj, 'admin', False) + active = getattr(userobj, 'active', True) + email = getattr(userobj, 'email', '') + username = getattr(userobj, 'username', username) + firstname = getattr(userobj, 'firstname', '') + lastname = getattr(userobj, 'lastname', '') + extern_type = getattr(userobj, 'extern_type', '') + + user_attrs = { + 'username': username, + 'firstname': safe_unicode(firstname or username), + 'lastname': safe_unicode(lastname or ''), + 'groups': [], + 'email': email or '', + 'admin': admin or False, + 'active': active, + 'active_from_extern': True, + 'extern_name': username, + 'extern_type': extern_type, + } + + log.info('user %s authenticated correctly' % user_attrs['username']) + return user_attrs diff --git a/rhodecode/authentication/plugins/auth_ldap.py b/rhodecode/authentication/plugins/auth_ldap.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/plugins/auth_ldap.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode authentication plugin for LDAP +""" + + +import colander +import logging +import traceback + +from pylons.i18n.translation import lazy_ugettext as _ +from sqlalchemy.ext.hybrid import hybrid_property + +from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin +from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase +from rhodecode.authentication.routes import AuthnPluginResourceBase +from rhodecode.lib.exceptions import ( + LdapConnectionError, LdapUsernameError, LdapPasswordError, LdapImportError +) +from rhodecode.lib.ext_json import formatted_json +from rhodecode.lib.utils2 import safe_unicode, safe_str +from rhodecode.model.db import User +from rhodecode.model.validators import Missing + +log = logging.getLogger(__name__) + +try: + import ldap +except ImportError: + # means that python-ldap is not installed + ldap = Missing() + + +def plugin_factory(plugin_id, *args, **kwds): + """ + Factory function that is called during plugin discovery. + It returns the plugin instance. + """ + plugin = RhodeCodeAuthPlugin(plugin_id) + return plugin + + +class LdapAuthnResource(AuthnPluginResourceBase): + pass + + +class LdapSettingsSchema(AuthnPluginSettingsSchemaBase): + tls_kind_choices = ['PLAIN', 'LDAPS', 'START_TLS'] + tls_reqcert_choices = ['NEVER', 'ALLOW', 'TRY', 'DEMAND', 'HARD'] + search_scope_choices = ['BASE', 'ONELEVEL', 'SUBTREE'] + + host = colander.SchemaNode( + colander.String(), + default='', + description=_('Host of the LDAP Server'), + title=_('LDAP Host'), + widget='string') + port = colander.SchemaNode( + colander.Int(), + default=389, + description=_('Port that the LDAP server is listening on'), + title=_('Port'), + validator=colander.Range(min=0, max=65536), + widget='int') + dn_user = colander.SchemaNode( + colander.String(), + default='', + description=_('User to connect to LDAP'), + missing='', + title=_('Account'), + widget='string') + dn_pass = colander.SchemaNode( + colander.String(), + default='', + description=_('Password to connect to LDAP'), + missing='', + title=_('Password'), + widget='password') + tls_kind = colander.SchemaNode( + colander.String(), + default=tls_kind_choices[0], + description=_('TLS Type'), + title=_('Connection Security'), + validator=colander.OneOf(tls_kind_choices), + widget='select') + tls_reqcert = colander.SchemaNode( + colander.String(), + default=tls_reqcert_choices[0], + description=_('Require Cert over TLS?'), + title=_('Certificate Checks'), + validator=colander.OneOf(tls_reqcert_choices), + widget='select') + base_dn = colander.SchemaNode( + colander.String(), + default='', + description=_('Base DN to search (e.g., dc=mydomain,dc=com)'), + missing='', + title=_('Base DN'), + widget='string') + filter = colander.SchemaNode( + colander.String(), + default='', + description=_('Filter to narrow results (e.g., ou=Users, etc)'), + missing='', + title=_('LDAP Search Filter'), + widget='string') + search_scope = colander.SchemaNode( + colander.String(), + default=search_scope_choices[0], + description=_('How deep to search LDAP'), + title=_('LDAP Search Scope'), + validator=colander.OneOf(search_scope_choices), + widget='select') + attr_login = colander.SchemaNode( + colander.String(), + default='', + description=_('LDAP Attribute to map to user name'), + title=_('Login Attribute'), + missing_msg=_('The LDAP Login attribute of the CN must be specified'), + widget='string') + attr_firstname = colander.SchemaNode( + colander.String(), + default='', + description=_('LDAP Attribute to map to first name'), + missing='', + title=_('First Name Attribute'), + widget='string') + attr_lastname = colander.SchemaNode( + colander.String(), + default='', + description=_('LDAP Attribute to map to last name'), + missing='', + title=_('Last Name Attribute'), + widget='string') + attr_email = colander.SchemaNode( + colander.String(), + default='', + description=_('LDAP Attribute to map to email address'), + missing='', + title=_('Email Attribute'), + widget='string') + + +class AuthLdap(object): + + def _build_servers(self): + return ', '.join( + ["{}://{}:{}".format( + self.ldap_server_type, host.strip(), self.LDAP_SERVER_PORT) + for host in self.SERVER_ADDRESSES]) + + def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='', + tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3, + search_scope='SUBTREE', attr_login='uid', + ldap_filter='(&(objectClass=user)(!(objectClass=computer)))'): + if isinstance(ldap, Missing): + raise LdapImportError("Missing or incompatible ldap library") + + self.ldap_version = ldap_version + self.ldap_server_type = 'ldap' + + self.TLS_KIND = tls_kind + + if self.TLS_KIND == 'LDAPS': + port = port or 689 + self.ldap_server_type += 's' + + OPT_X_TLS_DEMAND = 2 + self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert, + OPT_X_TLS_DEMAND) + # split server into list + self.SERVER_ADDRESSES = server.split(',') + self.LDAP_SERVER_PORT = port + + # USE FOR READ ONLY BIND TO LDAP SERVER + self.attr_login = attr_login + + self.LDAP_BIND_DN = safe_str(bind_dn) + self.LDAP_BIND_PASS = safe_str(bind_pass) + self.LDAP_SERVER = self._build_servers() + self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope) + self.BASE_DN = safe_str(base_dn) + self.LDAP_FILTER = safe_str(ldap_filter) + + def _get_ldap_server(self): + if hasattr(ldap, 'OPT_X_TLS_CACERTDIR'): + ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, + '/etc/openldap/cacerts') + ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF) + ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON) + ldap.set_option(ldap.OPT_TIMEOUT, 20) + ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10) + ldap.set_option(ldap.OPT_TIMELIMIT, 15) + if self.TLS_KIND != 'PLAIN': + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT) + server = ldap.initialize(self.LDAP_SERVER) + if self.ldap_version == 2: + server.protocol = ldap.VERSION2 + else: + server.protocol = ldap.VERSION3 + + if self.TLS_KIND == 'START_TLS': + server.start_tls_s() + + if self.LDAP_BIND_DN and self.LDAP_BIND_PASS: + log.debug('Trying simple_bind with password and given DN: %s', + self.LDAP_BIND_DN) + server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) + + return server + + def get_uid(self, username): + from rhodecode.lib.helpers import chop_at + uid = username + for server_addr in self.SERVER_ADDRESSES: + uid = chop_at(username, "@%s" % server_addr) + return uid + + def fetch_attrs_from_simple_bind(self, server, dn, username, password): + try: + log.debug('Trying simple bind with %s', dn) + server.simple_bind_s(dn, safe_str(password)) + user = server.search_ext_s( + dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0] + _, attrs = user + return attrs + + except ldap.INVALID_CREDENTIALS: + log.debug( + "LDAP rejected password for user '%s': %s, org_exc:", + username, dn, exc_info=True) + + def authenticate_ldap(self, username, password): + """ + Authenticate a user via LDAP and return his/her LDAP properties. + + Raises AuthenticationError if the credentials are rejected, or + EnvironmentError if the LDAP server can't be reached. + + :param username: username + :param password: password + """ + + uid = self.get_uid(username) + + if not password: + msg = "Authenticating user %s with blank password not allowed" + log.warning(msg, username) + raise LdapPasswordError(msg) + if "," in username: + raise LdapUsernameError("invalid character in username: ,") + try: + server = self._get_ldap_server() + filter_ = '(&%s(%s=%s))' % ( + self.LDAP_FILTER, self.attr_login, username) + log.debug("Authenticating %r filter %s at %s", self.BASE_DN, + filter_, self.LDAP_SERVER) + lobjects = server.search_ext_s( + self.BASE_DN, self.SEARCH_SCOPE, filter_) + + if not lobjects: + raise ldap.NO_SUCH_OBJECT() + + for (dn, _attrs) in lobjects: + if dn is None: + continue + + user_attrs = self.fetch_attrs_from_simple_bind( + server, dn, username, password) + if user_attrs: + break + + else: + log.debug("No matching LDAP objects for authentication " + "of '%s' (%s)", uid, username) + raise LdapPasswordError('Failed to authenticate user ' + 'with given password') + + except ldap.NO_SUCH_OBJECT: + log.debug("LDAP says no such user '%s' (%s), org_exc:", + uid, username, exc_info=True) + raise LdapUsernameError() + except ldap.SERVER_DOWN: + org_exc = traceback.format_exc() + raise LdapConnectionError( + "LDAP can't access authentication " + "server, org_exc:%s" % org_exc) + + return dn, user_attrs + + +class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): + # used to define dynamic binding in the + DYNAMIC_BIND_VAR = '$login' + + def includeme(self, config): + config.add_authn_plugin(self) + config.add_authn_resource(self.get_id(), LdapAuthnResource(self)) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_get', + request_method='GET', + route_name='auth_home', + context=LdapAuthnResource) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_post', + request_method='POST', + route_name='auth_home', + context=LdapAuthnResource) + + def get_settings_schema(self): + return LdapSettingsSchema() + + def get_display_name(self): + return _('LDAP') + + @hybrid_property + def name(self): + return "ldap" + + def use_fake_password(self): + return True + + def user_activation_state(self): + def_user_perms = User.get_default_user().AuthUser.permissions['global'] + return 'hg.extern_activate.auto' in def_user_perms + + def try_dynamic_binding(self, username, password, current_args): + """ + Detects marker inside our original bind, and uses dynamic auth if + present + """ + + org_bind = current_args['bind_dn'] + passwd = current_args['bind_pass'] + + def has_bind_marker(username): + if self.DYNAMIC_BIND_VAR in username: + return True + + # we only passed in user with "special" variable + if org_bind and has_bind_marker(org_bind) and not passwd: + log.debug('Using dynamic user/password binding for ldap ' + 'authentication. Replacing `%s` with username', + self.DYNAMIC_BIND_VAR) + current_args['bind_dn'] = org_bind.replace( + self.DYNAMIC_BIND_VAR, username) + current_args['bind_pass'] = password + + return current_args + + def auth(self, userobj, username, password, settings, **kwargs): + """ + Given a user object (which may be null), username, a plaintext password, + and a settings object (containing all the keys needed as listed in + settings()), authenticate this user's login attempt. + + Return None on failure. On success, return a dictionary of the form: + + see: RhodeCodeAuthPluginBase.auth_func_attrs + This is later validated for correctness + """ + + if not username or not password: + log.debug('Empty username or password skipping...') + return None + + ldap_args = { + 'server': settings.get('host', ''), + 'base_dn': settings.get('base_dn', ''), + 'port': settings.get('port'), + 'bind_dn': settings.get('dn_user'), + 'bind_pass': settings.get('dn_pass'), + 'tls_kind': settings.get('tls_kind'), + 'tls_reqcert': settings.get('tls_reqcert'), + 'search_scope': settings.get('search_scope'), + 'attr_login': settings.get('attr_login'), + 'ldap_version': 3, + 'ldap_filter': settings.get('filter'), + } + + ldap_attrs = self.try_dynamic_binding(username, password, ldap_args) + + log.debug('Checking for ldap authentication.') + + try: + aldap = AuthLdap(**ldap_args) + (user_dn, ldap_attrs) = aldap.authenticate_ldap(username, password) + log.debug('Got ldap DN response %s', user_dn) + + def get_ldap_attr(k): + return ldap_attrs.get(settings.get(k), [''])[0] + + # old attrs fetched from RhodeCode database + admin = getattr(userobj, 'admin', False) + active = getattr(userobj, 'active', True) + email = getattr(userobj, 'email', '') + username = getattr(userobj, 'username', username) + firstname = getattr(userobj, 'firstname', '') + lastname = getattr(userobj, 'lastname', '') + extern_type = getattr(userobj, 'extern_type', '') + + groups = [] + user_attrs = { + 'username': username, + 'firstname': safe_unicode( + get_ldap_attr('attr_firstname') or firstname), + 'lastname': safe_unicode( + get_ldap_attr('attr_lastname') or lastname), + 'groups': groups, + 'email': get_ldap_attr('attr_email' or email), + 'admin': admin, + 'active': active, + "active_from_extern": None, + 'extern_name': user_dn, + 'extern_type': extern_type, + } + log.debug('ldap user: \n%s', formatted_json(user_attrs)) + log.info('user %s authenticated correctly', user_attrs['username']) + + return user_attrs + + except (LdapUsernameError, LdapPasswordError, LdapImportError): + log.exception("LDAP related exception") + return None + except (Exception,): + log.exception("Other exception") + return None diff --git a/rhodecode/authentication/plugins/auth_pam.py b/rhodecode/authentication/plugins/auth_pam.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/plugins/auth_pam.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ +""" +RhodeCode authentication library for PAM +""" + +import colander +import grp +import logging +import pam +import pwd +import re +import socket + +from pylons.i18n.translation import lazy_ugettext as _ +from sqlalchemy.ext.hybrid import hybrid_property + +from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin +from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase +from rhodecode.authentication.routes import AuthnPluginResourceBase +from rhodecode.lib.ext_json import formatted_json + +log = logging.getLogger(__name__) + + +def plugin_factory(plugin_id, *args, **kwds): + """ + Factory function that is called during plugin discovery. + It returns the plugin instance. + """ + plugin = RhodeCodeAuthPlugin(plugin_id) + return plugin + + +class PamAuthnResource(AuthnPluginResourceBase): + pass + + +class PamSettingsSchema(AuthnPluginSettingsSchemaBase): + service = colander.SchemaNode( + colander.String(), + default='login', + description=_('PAM service name to use for authentication.'), + title=_('PAM service name'), + widget='string') + gecos = colander.SchemaNode( + colander.String(), + default='(?P<last_name>.+),\s*(?P<first_name>\w+)', + description=_('Regular expression for extracting user name/email etc. ' + 'from Unix userinfo.'), + title=_('Gecos Regex'), + widget='string') + + +class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): + # PAM authentication can be slow. Repository operations involve a lot of + # auth calls. Little caching helps speedup push/pull operations significantly + AUTH_CACHE_TTL = 4 + + def includeme(self, config): + config.add_authn_plugin(self) + config.add_authn_resource(self.get_id(), PamAuthnResource(self)) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_get', + request_method='GET', + route_name='auth_home', + context=PamAuthnResource) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_post', + request_method='POST', + route_name='auth_home', + context=PamAuthnResource) + + def get_display_name(self): + return _('PAM') + + @hybrid_property + def name(self): + return "pam" + + def get_settings_schema(self): + return PamSettingsSchema() + + def use_fake_password(self): + return True + + def auth(self, userobj, username, password, settings, **kwargs): + if not username or not password: + log.debug('Empty username or password skipping...') + return None + + auth_result = pam.authenticate(username, password, settings["service"]) + + if not auth_result: + log.error("PAM was unable to authenticate user: %s" % (username, )) + return None + + log.debug('Got PAM response %s' % (auth_result, )) + + # old attrs fetched from RhodeCode database + default_email = "%s@%s" % (username, socket.gethostname()) + admin = getattr(userobj, 'admin', False) + active = getattr(userobj, 'active', True) + email = getattr(userobj, 'email', '') or default_email + username = getattr(userobj, 'username', username) + firstname = getattr(userobj, 'firstname', '') + lastname = getattr(userobj, 'lastname', '') + extern_type = getattr(userobj, 'extern_type', '') + + user_attrs = { + 'username': username, + 'firstname': firstname, + 'lastname': lastname, + 'groups': [g.gr_name for g in grp.getgrall() + if username in g.gr_mem], + 'email': email, + 'admin': admin, + 'active': active, + 'active_from_extern': None, + 'extern_name': username, + 'extern_type': extern_type, + } + + try: + user_data = pwd.getpwnam(username) + regex = settings["gecos"] + match = re.search(regex, user_data.pw_gecos) + if match: + user_attrs["firstname"] = match.group('first_name') + user_attrs["lastname"] = match.group('last_name') + except Exception: + log.warning("Cannot extract additional info for PAM user") + pass + + log.debug("pamuser: \n%s" % formatted_json(user_attrs)) + log.info('user %s authenticated correctly' % user_attrs['username']) + return user_attrs diff --git a/rhodecode/authentication/plugins/auth_rhodecode.py b/rhodecode/authentication/plugins/auth_rhodecode.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/plugins/auth_rhodecode.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode authentication plugin for built in internal auth +""" + +import logging + +from pylons.i18n.translation import lazy_ugettext as _ +from sqlalchemy.ext.hybrid import hybrid_property + +from rhodecode.authentication.base import RhodeCodeAuthPluginBase +from rhodecode.authentication.routes import AuthnPluginResourceBase +from rhodecode.lib.utils2 import safe_str +from rhodecode.model.db import User + +log = logging.getLogger(__name__) + + +def plugin_factory(plugin_id, *args, **kwds): + plugin = RhodeCodeAuthPlugin(plugin_id) + return plugin + + +class RhodecodeAuthnResource(AuthnPluginResourceBase): + pass + + +class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase): + + def includeme(self, config): + config.add_authn_plugin(self) + config.add_authn_resource(self.get_id(), RhodecodeAuthnResource(self)) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_get', + request_method='GET', + route_name='auth_home', + context=RhodecodeAuthnResource) + config.add_view( + 'rhodecode.authentication.views.AuthnPluginViewBase', + attr='settings_post', + request_method='POST', + route_name='auth_home', + context=RhodecodeAuthnResource) + + def get_display_name(self): + return _('Rhodecode') + + @hybrid_property + def name(self): + return "rhodecode" + + def user_activation_state(self): + def_user_perms = User.get_default_user().AuthUser.permissions['global'] + return 'hg.register.auto_activate' in def_user_perms + + def allows_authentication_from( + self, user, allows_non_existing_user=True, + allowed_auth_plugins=None, allowed_auth_sources=None): + """ + Custom method for this auth that doesn't accept non existing users. + We know that user exists in our database. + """ + allows_non_existing_user = False + return super(RhodeCodeAuthPlugin, self).allows_authentication_from( + user, allows_non_existing_user=allows_non_existing_user) + + def auth(self, userobj, username, password, settings, **kwargs): + if not userobj: + log.debug('userobj was:%s skipping' % (userobj, )) + return None + if userobj.extern_type != self.name: + log.warning( + "userobj:%s extern_type mismatch got:`%s` expected:`%s`" % + (userobj, userobj.extern_type, self.name)) + return None + + user_attrs = { + "username": userobj.username, + "firstname": userobj.firstname, + "lastname": userobj.lastname, + "groups": [], + "email": userobj.email, + "admin": userobj.admin, + "active": userobj.active, + "active_from_extern": userobj.active, + "extern_name": userobj.user_id, + "extern_type": userobj.extern_type, + } + + log.debug("User attributes:%s" % (user_attrs, )) + if userobj.active: + from rhodecode.lib import auth + crypto_backend = auth.crypto_backend() + password_encoded = safe_str(password) + password_match, new_hash = crypto_backend.hash_check_with_upgrade( + password_encoded, userobj.password) + + if password_match and new_hash: + log.debug('user %s properly authenticated, but ' + 'requires hash change to bcrypt', userobj) + # if password match, and we use OLD deprecated hash, + # we should migrate this user hash password to the new hash + # we store the new returned by hash_check_with_upgrade function + user_attrs['_hash_migrate'] = new_hash + + if userobj.username == User.DEFAULT_USER and userobj.active: + log.info( + 'user %s authenticated correctly as anonymous user', userobj) + return user_attrs + + elif userobj.username == username and password_match: + log.info('user %s authenticated correctly', userobj) + return user_attrs + log.info("user %s had a bad password when " + "authenticating on this plugin", userobj) + return None + else: + log.warning('user %s tried auth but is disabled', userobj) + return None diff --git a/rhodecode/authentication/registry.py b/rhodecode/authentication/registry.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/registry.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pyramid.exceptions import ConfigurationError +from zope.interface import implementer + +from rhodecode.authentication.interface import IAuthnPluginRegistry +from rhodecode.lib.utils2 import safe_str + +log = logging.getLogger(__name__) + + +@implementer(IAuthnPluginRegistry) +class AuthenticationPluginRegistry(object): + def __init__(self): + self._plugins = {} + + def add_authn_plugin(self, config, plugin): + plugin_id = plugin.get_id() + if plugin_id in self._plugins.keys(): + raise ConfigurationError( + 'Cannot register authentication plugin twice: "%s"', plugin_id) + else: + log.debug('Register authentication plugin: "%s"', plugin_id) + self._plugins[plugin_id] = plugin + + def get_plugins(self): + def sort_key(plugin): + return str.lower(safe_str(plugin.get_display_name())) + + return sorted(self._plugins.values(), key=sort_key) + + def get_plugin(self, plugin_id): + return self._plugins.get(plugin_id, None) diff --git a/rhodecode/authentication/routes.py b/rhodecode/authentication/routes.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/routes.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pyramid.exceptions import ConfigurationError +from pyramid.i18n import TranslationStringFactory + +from rhodecode.lib.utils2 import safe_str +from rhodecode.model.settings import SettingsModel + +_ = TranslationStringFactory('rhodecode-enterprise') + +log = logging.getLogger(__name__) + + +class AuthnResourceBase(object): + __name__ = None + __parent__ = None + + def get_root(self): + current = self + while current.__parent__ is not None: + current = current.__parent__ + return current + + +class AuthnPluginResourceBase(AuthnResourceBase): + + def __init__(self, plugin): + self.plugin = plugin + self.__name__ = plugin.name + self.display_name = plugin.get_display_name() + + +class AuthnRootResource(AuthnResourceBase): + """ + This is the root traversal resource object for the authentication settings. + """ + + def __init__(self): + self._store = {} + self._resource_name_map = {} + self.display_name = _('Global') + + def __getitem__(self, key): + """ + Customized get item function to return only items (plugins) that are + activated. + """ + if self._is_item_active(key): + return self._store[key] + else: + raise KeyError('Authentication plugin "{}" is not active.'.format( + key)) + + def __iter__(self): + for key in self._store.keys(): + if self._is_item_active(key): + yield self._store[key] + + def _is_item_active(self, key): + activated_plugins = SettingsModel().get_auth_plugins() + plugin_id = self.get_plugin_id(key) + return plugin_id in activated_plugins + + def get_plugin_id(self, resource_name): + """ + Return the plugin id for the given traversal resource name. + """ + # TODO: Store this info in the resource element. + return self._resource_name_map[resource_name] + + def get_sorted_list(self): + """ + Returns a sorted list of sub resources for displaying purposes. + """ + def sort_key(resource): + return str.lower(safe_str(resource.display_name)) + + active = [item for item in self] + return sorted(active, key=sort_key) + + def get_nav_list(self): + """ + Returns a sorted list of resources for displaying the navigation. + """ + list = self.get_sorted_list() + list.insert(0, self) + return list + + def add_authn_resource(self, config, plugin_id, resource): + """ + Register a traversal resource as a sub element to the authentication + settings. This method is registered as a directive on the pyramid + configurator object and called by plugins. + """ + + def _ensure_unique_name(name, limit=100): + counter = 1 + current = name + while current in self._store.keys(): + current = '{}{}'.format(name, counter) + counter += 1 + if counter > limit: + raise ConfigurationError( + 'Cannot build unique name for traversal resource "%s" ' + 'registered by plugin "%s"', name, plugin_id) + return current + + # Allow plugin resources with identical names by rename duplicates. + unique_name = _ensure_unique_name(resource.__name__) + if unique_name != resource.__name__: + log.warn('Name collision for traversal resource "%s" registered', + 'by authentication plugin "%s"', resource.__name__, + plugin_id) + resource.__name__ = unique_name + + log.debug('Register traversal resource "%s" for plugin "%s"', + unique_name, plugin_id) + self._resource_name_map[unique_name] = plugin_id + resource.__parent__ = self + self._store[unique_name] = resource + + +root = AuthnRootResource() + + +def root_factory(request=None): + """ + Returns the root traversal resource instance used for the authentication + settings route. + """ + return root diff --git a/rhodecode/authentication/schema.py b/rhodecode/authentication/schema.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/schema.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import colander + +from pyramid.i18n import TranslationStringFactory + +_ = TranslationStringFactory('rhodecode-enterprise') + + +class AuthnPluginSettingsSchemaBase(colander.MappingSchema): + """ + This base schema is intended for use in authentication plugins. + It adds a few default settings (e.g., "enabled"), so that plugin + authors don't have to maintain a bunch of boilerplate. + """ + enabled = colander.SchemaNode( + colander.Bool(), + default=False, + description=_('Enable or disable this authentication plugin.'), + missing=False, + title=_('Enabled'), + widget='bool', + ) + cache_ttl = colander.SchemaNode( + colander.Int(), + default=0, + description=_('Amount of seconds to cache the authentication ' + 'call for this plugin. Useful for long calls like ' + 'LDAP to improve the responsiveness of the ' + 'authentication system (0 means disabled).'), + missing=0, + title=_('Auth Cache TTL'), + validator=colander.Range(min=0, max=None), + widget='int', + ) diff --git a/rhodecode/authentication/views.py b/rhodecode/authentication/views.py new file mode 100644 --- /dev/null +++ b/rhodecode/authentication/views.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import colander +import formencode.htmlfill +import logging + +from pyramid.httpexceptions import HTTPFound +from pyramid.i18n import TranslationStringFactory +from pyramid.renderers import render +from pyramid.response import Response + +from rhodecode.authentication.base import get_auth_cache_manager +from rhodecode.authentication.interface import IAuthnPluginRegistry +from rhodecode.lib import auth +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.model.forms import AuthSettingsForm +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + +_ = TranslationStringFactory('rhodecode-enterprise') + + +class AuthnPluginViewBase(object): + + def __init__(self, context, request): + self.request = request + self.context = context + self.plugin = context.plugin + + # TODO: Think about replacing the htmlfill stuff. + def _render_and_fill(self, template, template_context, request, + form_defaults, validation_errors): + """ + Helper to render a template and fill the HTML form fields with + defaults. Also displays the form errors. + """ + # Render template to string. + html = render(template, template_context, request=request) + + # Fill the HTML form fields with default values and add error messages. + html = formencode.htmlfill.render( + html, + defaults=form_defaults, + errors=validation_errors, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + return html + + def settings_get(self): + """ + View that displays the plugin settings as a form. + """ + form_defaults = {} + validation_errors = None + schema = self.plugin.get_settings_schema() + + # Get default values for the form. + for node in schema.children: + value = self.plugin.get_setting_by_name(node.name) or node.default + form_defaults[node.name] = value + + template_context = { + 'resource': self.context, + 'plugin': self.context.plugin + } + + return Response(self._render_and_fill( + 'rhodecode:templates/admin/auth/plugin_settings.html', + template_context, + self.request, + form_defaults, + validation_errors)) + + def settings_post(self): + """ + View that validates and stores the plugin settings. + """ + schema = self.plugin.get_settings_schema() + try: + valid_data = schema.deserialize(self.request.params) + except colander.Invalid, e: + # Display error message and display form again. + form_defaults = self.request.params + validation_errors = e.asdict() + self.request.session.flash( + _('Errors exist when saving plugin settings. ' + 'Please check the form inputs.'), + queue='error') + + template_context = { + 'resource': self.context, + 'plugin': self.context.plugin + } + + return Response(self._render_and_fill( + 'rhodecode:templates/admin/auth/plugin_settings.html', + template_context, + self.request, + form_defaults, + validation_errors)) + + # Store validated data. + for name, value in valid_data.items(): + self.plugin.create_or_update_setting(name, value) + Session.commit() + + # Display success message and redirect. + self.request.session.flash( + _('Auth settings updated successfully.'), + queue='success') + redirect_to = self.request.resource_path( + self.context, route_name='auth_home') + return HTTPFound(redirect_to) + + +# TODO: Ongoing migration in these views. +# - Maybe we should also use a colander schema for these views. +class AuthSettingsView(object): + def __init__(self, context, request): + self.context = context + self.request = request + + # TODO: Move this into a utility function. It is needed in all view + # classes during migration. Maybe a mixin? + + # Some of the decorators rely on this attribute to be present on the + # class of the decorated method. + self._rhodecode_user = request.user + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + def index(self, defaults={}, errors=None, prefix_error=False): + authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry) + default_plugins = ['egg:rhodecode-enterprise-ce#rhodecode'] + enabled_plugins = SettingsModel().get_auth_plugins() or default_plugins + + # Create template context and render it. + template_context = { + 'resource': self.context, + 'available_plugins': authn_registry.get_plugins(), + 'enabled_plugins': enabled_plugins, + } + html = render('rhodecode:templates/admin/auth/auth_settings.html', + template_context, + request=self.request) + + # Create form default values and fill the form. + form_defaults = { + 'auth_plugins': ','.join(enabled_plugins) + } + form_defaults.update(defaults) + html = formencode.htmlfill.render( + html, + defaults=form_defaults, + errors=errors, + prefix_error=prefix_error, + encoding="UTF-8", + force_defaults=False) + + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def auth_settings(self): + try: + form = AuthSettingsForm()() + form_result = form.to_python(self.request.params) + plugins = ','.join(form_result['auth_plugins']) + setting = SettingsModel().create_or_update_setting( + 'auth_plugins', plugins) + Session().add(setting) + Session().commit() + + cache_manager = get_auth_cache_manager() + cache_manager.clear() + self.request.session.flash( + _('Auth settings updated successfully.'), + queue='success') + except formencode.Invalid as errors: + e = errors.error_dict or {} + self.request.session.flash( + _('Errors exist when saving plugin setting. ' + 'Please check the form inputs.'), + queue='error') + return self.index( + defaults=errors.value, + errors=e, + prefix_error=False) + except Exception: + log.exception('Exception in auth_settings') + self.request.session.flash( + _('Error occurred during update of auth settings.'), + queue='error') + + redirect_to = self.request.resource_path( + self.context, route_name='auth_home') + return HTTPFound(redirect_to) diff --git a/rhodecode/config/__init__.py b/rhodecode/config/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + diff --git a/rhodecode/config/conf.py b/rhodecode/config/conf.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/conf.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Various config settings for RhodeCode +""" +from rhodecode import EXTENSIONS + +from rhodecode.lib.utils2 import __get_lem + + +# language map is also used by whoosh indexer, which for those specified +# extensions will index it's content +LANGUAGES_EXTENSIONS_MAP = __get_lem() + +# list of readme files to search in file tree and display in summary +# attached weights defines the search order lower is first +ALL_READMES = [ + ('readme', 0), ('README', 0), ('Readme', 0), + ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), + ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), + ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), + ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), +] + +# extension together with weights to search lower is first +RST_EXTS = [ + ('', 0), ('.rst', 1), ('.rest', 1), + ('.RST', 2), ('.REST', 2) +] + +MARKDOWN_EXTS = [ + ('.md', 1), ('.MD', 1), + ('.mkdn', 2), ('.MKDN', 2), + ('.mdown', 3), ('.MDOWN', 3), + ('.markdown', 4), ('.MARKDOWN', 4) +] + +PLAIN_EXTS = [ + ('.text', 2), ('.TEXT', 2), + ('.txt', 3), ('.TXT', 3) +] + +ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS + +DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" + +DATE_FORMAT = "%Y-%m-%d" diff --git a/rhodecode/config/deployment.ini_tmpl b/rhodecode/config/deployment.ini_tmpl new file mode 100644 --- /dev/null +++ b/rhodecode/config/deployment.ini_tmpl @@ -0,0 +1,4 @@ +Usage of make-config is deprecated. +Please use rhodecode-config to generate RhodeCode .ini config file. +rhodecode-config is a part of RhodeCode Tools package. Install it via +pip install https://rhodecode.com/dl/tools/latest diff --git a/rhodecode/config/environment.py b/rhodecode/config/environment.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/environment.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Pylons environment configuration +""" + +import os +import logging +import rhodecode +import platform +import re + +from mako.lookup import TemplateLookup +from pylons.configuration import PylonsConfig +from pylons.error import handle_mako_error + +# don't remove this import it does magic for celery +from rhodecode.lib import celerypylons # noqa + +import rhodecode.lib.app_globals as app_globals + +from rhodecode.config import utils +from rhodecode.config.routing import make_map + +from rhodecode.lib import helpers +from rhodecode.lib.auth import set_available_permissions +from rhodecode.lib.utils import ( + repo2db_mapper, make_db_config, set_rhodecode_config, + load_rcextensions) +from rhodecode.lib.utils2 import str2bool, aslist +from rhodecode.lib.vcs import connect_vcs, start_vcs_server +from rhodecode.model.scm import ScmModel + +log = logging.getLogger(__name__) + + +def load_environment(global_conf, app_conf, initial=False, + test_env=None, test_index=None): + """ + Configure the Pylons environment via the ``pylons.config`` + object + """ + config = PylonsConfig() + + rhodecode.is_test = str2bool(app_conf.get('is_test', 'False')) + + # Pylons paths + root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + paths = { + 'root': root, + 'controllers': os.path.join(root, 'controllers'), + 'static_files': os.path.join(root, 'public'), + 'templates': [os.path.join(root, 'templates')], + } + + # Initialize config with the basic options + config.init_app(global_conf, app_conf, package='rhodecode', paths=paths) + + # store some globals into rhodecode + rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery')) + rhodecode.CELERY_EAGER = str2bool( + config['app_conf'].get('celery.always.eager')) + + config['routes.map'] = make_map(config) + config['pylons.app_globals'] = app_globals.Globals(config) + config['pylons.h'] = helpers + rhodecode.CONFIG = config + + load_rcextensions(root_path=config['here']) + + # Setup cache object as early as possible + import pylons + pylons.cache._push_object(config['pylons.app_globals'].cache) + + # Create the Mako TemplateLookup, with the default auto-escaping + config['pylons.app_globals'].mako_lookup = TemplateLookup( + directories=paths['templates'], + error_handler=handle_mako_error, + module_directory=os.path.join(app_conf['cache_dir'], 'templates'), + input_encoding='utf-8', default_filters=['escape'], + imports=['from webhelpers.html import escape']) + + # sets the c attribute access when don't existing attribute are accessed + config['pylons.strict_tmpl_context'] = True + config_file_name = os.path.split(config['__file__'])[-1] + test = re.match('^test[\w_]*\.ini$', config_file_name) is not None + if test: + if test_env is None: + test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0)) + + from rhodecode.lib.utils import create_test_env, create_test_index + from rhodecode.tests import TESTS_TMP_PATH + # test repos + if test_env: + create_test_env(TESTS_TMP_PATH, config) + create_test_index(TESTS_TMP_PATH, config, True) + + # Limit backends to "vcs.backends" from configuration + backends = config['vcs.backends'] = aslist( + config.get('vcs.backends', 'hg,git'), sep=',') + for alias in rhodecode.BACKENDS.keys(): + if alias not in backends: + del rhodecode.BACKENDS[alias] + log.info("Enabled backends: %s", backends) + + # initialize vcs client and optionally run the server if enabled + vcs_server_uri = config.get('vcs.server', '') + vcs_server_enabled = str2bool(config.get('vcs.server.enable', 'true')) + start_server = ( + str2bool(config.get('vcs.start_server', 'false')) and + not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0'))) + if vcs_server_enabled and start_server: + log.info("Starting vcsserver") + start_vcs_server(server_and_port=vcs_server_uri, + protocol=utils.get_vcs_server_protocol(config), + log_level=config['vcs.server.log_level']) + + # MULTIPLE DB configs + # Setup the SQLAlchemy database engine + utils.initialize_database(config) + + set_available_permissions(config) + db_cfg = make_db_config(clear_session=True) + + repos_path = list(db_cfg.items('paths'))[0][1] + config['base_path'] = repos_path + + config['vcs.hooks.direct_calls'] = _use_direct_hook_calls(config) + config['vcs.hooks.protocol'] = _get_vcs_hooks_protocol(config) + + # store db config also in main global CONFIG + set_rhodecode_config(config) + + # configure instance id + utils.set_instance_id(config) + + # CONFIGURATION OPTIONS HERE (note: all config options will override + # any Pylons config options) + + # store config reference into our module to skip import magic of pylons + rhodecode.CONFIG.update(config) + + utils.configure_pyro4(config) + utils.configure_vcs(config) + if vcs_server_enabled: + connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(config)) + + import_on_startup = str2bool(config.get('startup.import_repos', False)) + if vcs_server_enabled and import_on_startup: + repo2db_mapper(ScmModel().repo_scan(repos_path), remove_obsolete=False) + return config + + +def _use_direct_hook_calls(config): + default_direct_hook_calls = 'false' + direct_hook_calls = str2bool( + config.get('vcs.hooks.direct_calls', default_direct_hook_calls)) + return direct_hook_calls + + +def _get_vcs_hooks_protocol(config): + protocol = config.get('vcs.hooks.protocol', 'pyro4').lower() + return protocol diff --git a/rhodecode/config/hook_templates/git_post_receive.py.tmpl b/rhodecode/config/hook_templates/git_post_receive.py.tmpl new file mode 100644 --- /dev/null +++ b/rhodecode/config/hook_templates/git_post_receive.py.tmpl @@ -0,0 +1,46 @@ +#!_ENV_ +import os +import sys + +try: + from vcsserver import hooks +except ImportError: + if os.environ.get('RC_DEBUG_GIT_HOOK'): + import traceback + print traceback.format_exc() + hooks = None + + +RC_HOOK_VER = '_TMPL_' + + +def main(): + if hooks is None: + # exit with success if we cannot import rhodecode.lib.hooks !! + # this allows simply push to this repo even without rhodecode + sys.exit(0) + + if os.environ.get('RC_SKIP_HOOKS'): + sys.exit(0) + + repo_path = os.getcwd() + push_data = sys.stdin.readlines() + os.environ['RC_HOOK_VER'] = RC_HOOK_VER + # os.environ is modified here by a subprocess call that + # runs git and later git executes this hook. + # Environ gets some additional info from rhodecode system + # like IP or username from basic-auth + try: + result = hooks.git_post_receive(repo_path, push_data, os.environ) + sys.exit(result) + except Exception as error: + # TODO: johbo: Improve handling of this special case + if not getattr(error, '_vcs_kind', None) == 'repo_locked': + raise + print 'ERROR:', error + sys.exit(1) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/rhodecode/config/hook_templates/git_pre_receive.py.tmpl b/rhodecode/config/hook_templates/git_pre_receive.py.tmpl new file mode 100644 --- /dev/null +++ b/rhodecode/config/hook_templates/git_pre_receive.py.tmpl @@ -0,0 +1,46 @@ +#!_ENV_ +import os +import sys + +try: + from vcsserver import hooks +except ImportError: + if os.environ.get('RC_DEBUG_GIT_HOOK'): + import traceback + print traceback.format_exc() + hooks = None + + +RC_HOOK_VER = '_TMPL_' + + +def main(): + if hooks is None: + # exit with success if we cannot import rhodecode.lib.hooks !! + # this allows simply push to this repo even without rhodecode + sys.exit(0) + + if os.environ.get('RC_SKIP_HOOKS'): + sys.exit(0) + + repo_path = os.getcwd() + push_data = sys.stdin.readlines() + os.environ['RC_HOOK_VER'] = RC_HOOK_VER + # os.environ is modified here by a subprocess call that + # runs git and later git executes this hook. + # Environ gets some additional info from rhodecode system + # like IP or username from basic-auth + try: + result = hooks.git_pre_receive(repo_path, push_data, os.environ) + sys.exit(result) + except Exception as error: + # TODO: johbo: Improve handling of this special case + if not getattr(error, '_vcs_kind', None) == 'repo_locked': + raise + print 'ERROR:', error + sys.exit(1) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/rhodecode/config/hook_templates/svn_post_commit_hook.py.tmpl b/rhodecode/config/hook_templates/svn_post_commit_hook.py.tmpl new file mode 100644 --- /dev/null +++ b/rhodecode/config/hook_templates/svn_post_commit_hook.py.tmpl @@ -0,0 +1,14 @@ +#!_ENV_ + +import sys + + +RC_HOOK_VER = '_TMPL_' + + +def main(): + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/rhodecode/config/hook_templates/svn_pre_commit_hook.py.tmpl b/rhodecode/config/hook_templates/svn_pre_commit_hook.py.tmpl new file mode 100644 --- /dev/null +++ b/rhodecode/config/hook_templates/svn_pre_commit_hook.py.tmpl @@ -0,0 +1,19 @@ +#!_ENV_ + +import os +import sys + + +RC_HOOK_VER = '_TMPL_' + + +def main(): + if os.environ.get('SSH_READ_ONLY') == '1': + sys.stderr.write('Only read-only access is allowed') + sys.exit(1) + + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/rhodecode/config/licenses.json b/rhodecode/config/licenses.json new file mode 100644 --- /dev/null +++ b/rhodecode/config/licenses.json @@ -0,0 +1,217 @@ +{ + "cyrus-sasl-2.1.26": { + "cyrus": "http://cyrusimap.web.cmu.edu/mediawiki/index.php/Downloads#Licensing" + }, + "openldap-2.4.41": { + "OLDAP-2.8": "http://spdx.org/licenses/OLDAP-2.8" + }, + "openssl-1.0.1p": { + "OpenSSL": "http://spdx.org/licenses/OpenSSL" + }, + "python-2.7.10": { + "Python-2.0": "http://spdx.org/licenses/Python-2.0" + }, + "python2.7-Babel-1.3": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-Beaker-1.7.0": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-FormEncode-1.2.4": { + "Python-2.0": "http://spdx.org/licenses/Python-2.0" + }, + "python2.7-Mako-1.0.1": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-Markdown-2.6.2": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-MarkupSafe-0.23": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-Paste-2.0.2": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-PasteDeploy-1.5.2": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-PasteScript-1.7.5": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-Pygments-2.0.2": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-Pylons-1.0.2-patch1": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-Pyro4-4.35": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-Routes-1.13": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-SQLAlchemy-0.9.9": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-Tempita-0.5.2": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-URLObject-2.4.0": { + "Unlicense": "http://spdx.org/licenses/Unlicense" + }, + "python2.7-WebError-0.10.3": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-WebHelpers-1.3-cust1": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-WebHelpers2-2.0": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-WebOb-1.3.1": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-Whoosh-2.7.0-patch1": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-alembic-0.8.4": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-amqplib-1.0.2": { + "LGPL-3.0": "http://spdx.org/licenses/LGPL-3.0" + }, + "python2.7-anyjson-0.3.3": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-appenlight_client-0.6.14": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-backport_ipaddress-0.1": { + "Python-2.0": "http://spdx.org/licenses/Python-2.0" + }, + "python2.7-celery-2.2.10": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-click-4.0": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-configobj-5.0.6": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-cssselect-0.9.1": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-decorator-3.4.2": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-docutils-0.12": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-future-0.14.3": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-futures-3.0.2": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-greenlet-0.4.7": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-gunicorn-19.3.0": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-ipython-3.1.0": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-kombu-1.5.1-patch1": { + "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" + }, + "python2.7-mccabe-0.3": { + "expat": "http://directory.fsf.org/wiki/License:Expat" + }, + "python2.7-meld3-1.0.2": { + "repoze": "http://repoze.org/license.html" + }, + "python2.7-msgpack-python-0.4.6": { + "Apache-2.0": "http://spdx.org/licenses/Apache-2.0" + }, + "python2.7-objgraph-2.0.0": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-packaging-15.2": { + "Apache-2.0": "http://spdx.org/licenses/Apache-2.0" + }, + "python2.7-psutil-2.2.1": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-psycopg2-2.6": { + "LGPL-3.0+": "http://spdx.org/licenses/LGPL-3.0+" + }, + "python2.7-py-1.4.29": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-py-bcrypt-0.4": { + "BSD-4-Clause": "http://spdx.org/licenses/BSD-4-Clause" + }, + "python2.7-pycrypto-2.6.1": { + "publicDomain": null + }, + "python2.7-pyparsing-1.5.7": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-pysqlite-2.6.3": { + "Libpng": "http://spdx.org/licenses/Libpng", + "Zlib": "http://spdx.org/licenses/Zlib" + }, + "python2.7-pytest-2.8.5": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-python-dateutil-1.5": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-python-ldap-2.4.19": { + "Python-2.0": "http://spdx.org/licenses/Python-2.0" + }, + "python2.7-pytz-2015.4": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-recaptcha-client-1.0.6": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-repoze.lru-0.6": { + "repoze": "http://repoze.org/license.html" + }, + "python2.7-requests-2.5.1": { + "APSL-2.0": "http://spdx.org/licenses/APSL-2.0" + }, + "python2.7-serpent-1.11": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-setproctitle-1.1.8": { + "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" + }, + "python2.7-setuptools-18.0.1": { + "PSF": null, + "ZPL": null + }, + "python2.7-simplejson-3.7.2": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-six-1.9.0": { + "MIT": "http://spdx.org/licenses/MIT" + }, + "python2.7-subprocess32-3.2.6": { + "Python-2.0": "http://spdx.org/licenses/Python-2.0" + }, + "python2.7-supervisor-3.1.3": { + "repoze": "http://repoze.org/license.html" + }, + "python2.7-trollius-1.0.4": { + "APSL-2.0": "http://spdx.org/licenses/APSL-2.0" + }, + "python2.7-waitress-0.8.9": { + "ZPL-2.1": "http://spdx.org/licenses/ZPL-2.1" + }, + "python2.7-zope.cachedescriptors-4.0.0": { + "ZPL-2.1": "http://spdx.org/licenses/ZPL-2.1" + } +} diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/middleware.py @@ -0,0 +1,309 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Pylons middleware initialization +""" +import logging + +from paste.registry import RegistryManager +from paste.gzipper import make_gzip_middleware +from pylons.middleware import ErrorHandler, StatusCodeRedirect +from pylons.wsgiapp import PylonsApp +from pyramid.authorization import ACLAuthorizationPolicy +from pyramid.config import Configurator +from pyramid.static import static_view +from pyramid.settings import asbool, aslist +from pyramid.wsgi import wsgiapp +from routes.middleware import RoutesMiddleware +import routes.util + +import rhodecode +from rhodecode.config import patches +from rhodecode.config.environment import load_environment +from rhodecode.lib.middleware import csrf +from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled +from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper +from rhodecode.lib.middleware.https_fixup import HttpsFixup +from rhodecode.lib.middleware.vcs import VCSMiddleware +from rhodecode.lib.plugins.utils import register_rhodecode_plugin + + +log = logging.getLogger(__name__) + + +def make_app(global_conf, full_stack=True, static_files=True, **app_conf): + """Create a Pylons WSGI application and return it + + ``global_conf`` + The inherited configuration for this application. Normally from + the [DEFAULT] section of the Paste ini file. + + ``full_stack`` + Whether or not this application provides a full WSGI stack (by + default, meaning it handles its own exceptions and errors). + Disable full_stack when this application is "managed" by + another WSGI middleware. + + ``app_conf`` + The application's local configuration. Normally specified in + the [app:<name>] section of the Paste ini file (where <name> + defaults to main). + + """ + # Apply compatibility patches + patches.kombu_1_5_1_python_2_7_11() + patches.inspect_getargspec() + + # Configure the Pylons environment + config = load_environment(global_conf, app_conf) + + # The Pylons WSGI app + app = PylonsApp(config=config) + if rhodecode.is_test: + app = csrf.CSRFDetector(app) + + expected_origin = config.get('expected_origin') + if expected_origin: + # The API can be accessed from other Origins. + app = csrf.OriginChecker(app, expected_origin, + skip_urls=[routes.util.url_for('api')]) + + # Add RoutesMiddleware. Currently we have two instances in the stack. This + # is the lower one to make the StatusCodeRedirect middleware happy. + # TODO: johbo: This is not optimal, search for a better solution. + app = RoutesMiddleware(app, config['routes.map']) + + # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) + if asbool(config['pdebug']): + from rhodecode.lib.profiler import ProfilingMiddleware + app = ProfilingMiddleware(app) + + # Protect from VCS Server error related pages when server is not available + vcs_server_enabled = asbool(config.get('vcs.server.enable', 'true')) + if not vcs_server_enabled: + app = DisableVCSPagesWrapper(app) + + if asbool(full_stack): + + # Appenlight monitoring and error handler + app, appenlight_client = wrap_in_appenlight_if_enabled(app, config) + + # Handle Python exceptions + app = ErrorHandler(app, global_conf, **config['pylons.errorware']) + + # we want our low level middleware to get to the request ASAP. We don't + # need any pylons stack middleware in them + app = VCSMiddleware(app, config, appenlight_client) + # Display error documents for 401, 403, 404 status codes (and + # 500 when debug is disabled) + if asbool(config['debug']): + app = StatusCodeRedirect(app) + else: + app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) + + # enable https redirects based on HTTP_X_URL_SCHEME set by proxy + app = HttpsFixup(app, config) + + # Establish the Registry for this application + app = RegistryManager(app) + + app.config = config + + return app + + +def make_pyramid_app(global_config, **settings): + """ + Constructs the WSGI application based on Pyramid and wraps the Pylons based + application. + + Specials: + + * We migrate from Pylons to Pyramid. While doing this, we keep both + frameworks functional. This involves moving some WSGI middlewares around + and providing access to some data internals, so that the old code is + still functional. + + * The application can also be integrated like a plugin via the call to + `includeme`. This is accompanied with the other utility functions which + are called. Changing this should be done with great care to not break + cases when these fragments are assembled from another place. + + """ + # The edition string should be available in pylons too, so we add it here + # before copying the settings. + settings.setdefault('rhodecode.edition', 'Community Edition') + + # As long as our Pylons application does expect "unprepared" settings, make + # sure that we keep an unmodified copy. This avoids unintentional change of + # behavior in the old application. + settings_pylons = settings.copy() + + sanitize_settings_and_apply_defaults(settings) + config = Configurator(settings=settings) + add_pylons_compat_data(config.registry, global_config, settings_pylons) + includeme(config) + includeme_last(config) + pyramid_app = config.make_wsgi_app() + pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config) + return pyramid_app + + +def add_pylons_compat_data(registry, global_config, settings): + """ + Attach data to the registry to support the Pylons integration. + """ + registry._pylons_compat_global_config = global_config + registry._pylons_compat_settings = settings + + +def includeme(config): + settings = config.registry.settings + + # Includes which are required. The application would fail without them. + config.include('pyramid_mako') + config.include('pyramid_beaker') + config.include('rhodecode.authentication') + config.include('rhodecode.tweens') + config.include('rhodecode.api') + + # Set the authorization policy. + authz_policy = ACLAuthorizationPolicy() + config.set_authorization_policy(authz_policy) + + # Set the default renderer for HTML templates to mako. + config.add_mako_renderer('.html') + + # plugin information + config.registry.rhodecode_plugins = {} + + config.add_directive( + 'register_rhodecode_plugin', register_rhodecode_plugin) + # include RhodeCode plugins + includes = aslist(settings.get('rhodecode.includes', [])) + for inc in includes: + config.include(inc) + + # This is the glue which allows us to migrate in chunks. By registering the + # pylons based application as the "Not Found" view in Pyramid, we will + # fallback to the old application each time the new one does not yet know + # how to handle a request. + pylons_app = make_app( + config.registry._pylons_compat_global_config, + **config.registry._pylons_compat_settings) + config.registry._pylons_compat_config = pylons_app.config + pylons_app_as_view = wsgiapp(pylons_app) + config.add_notfound_view(pylons_app_as_view) + + +def includeme_last(config): + """ + The static file catchall needs to be last in the view configuration. + """ + settings = config.registry.settings + + # Note: johbo: I would prefer to register a prefix for static files at some + # point, e.g. move them under '_static/'. This would fully avoid that we + # can have name clashes with a repository name. Imaging someone calling his + # repo "css" ;-) Also having an external web server to serve out the static + # files seems to be easier to set up if they have a common prefix. + # + # Example: config.add_static_view('_static', path='rhodecode:public') + # + # It might be an option to register both paths for a while and then migrate + # over to the new location. + + # Serving static files with a catchall. + if settings['static_files']: + config.add_route('catchall_static', '/*subpath') + config.add_view( + static_view('rhodecode:public'), route_name='catchall_static') + + +def wrap_app_in_wsgi_middlewares(pyramid_app, config): + """ + Apply outer WSGI middlewares around the application. + + Part of this has been moved up from the Pylons layer, so that the + data is also available if old Pylons code is hit through an already ported + view. + """ + settings = config.registry.settings + + # Add RoutesMiddleware. Currently we have two instances in the stack. This + # is the upper one to support the pylons compatibility tween during + # migration to pyramid. + pyramid_app = RoutesMiddleware( + pyramid_app, config.registry._pylons_compat_config['routes.map']) + + # TODO: johbo: Don't really see why we enable the gzip middleware when + # serving static files, might be something that should have its own setting + # as well? + if settings['static_files']: + pyramid_app = make_gzip_middleware( + pyramid_app, settings, compress_level=1) + + return pyramid_app + + +def sanitize_settings_and_apply_defaults(settings): + """ + Applies settings defaults and does all type conversion. + + We would move all settings parsing and preparation into this place, so that + we have only one place left which deals with this part. The remaining parts + of the application would start to rely fully on well prepared settings. + + This piece would later be split up per topic to avoid a big fat monster + function. + """ + + # Pyramid's mako renderer has to search in the templates folder so that the + # old templates still work. Ported and new templates are expected to use + # real asset specifications for the includes. + mako_directories = settings.setdefault('mako.directories', [ + # Base templates of the original Pylons application + 'rhodecode:templates', + ]) + log.debug( + "Using the following Mako template directories: %s", + mako_directories) + + # Default includes, possible to change as a user + pyramid_includes = settings.setdefault('pyramid.includes', [ + 'rhodecode.lib.middleware.request_wrapper', + ]) + log.debug( + "Using the following pyramid.includes: %s", + pyramid_includes) + + # TODO: johbo: Re-think this, usually the call to config.include + # should allow to pass in a prefix. + settings.setdefault('rhodecode.api.url', '/_admin/api') + + _bool_setting(settings, 'vcs.server.enable', 'true') + _bool_setting(settings, 'static_files', 'true') + + return settings + + +def _bool_setting(settings, name, default): + settings[name] = asbool(settings.get(name, default)) diff --git a/rhodecode/config/patches.py b/rhodecode/config/patches.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/patches.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Compatibility patches. + +Please keep the following principles in mind: + +* Keep imports local, so that importing this module does not cause too many + side effects by itself. + +* Try to make patches idempotent, calling them multiple times should not do + harm. If that is not possible, ensure that the second call explodes. + +""" + + +def kombu_1_5_1_python_2_7_11(): + """ + Kombu 1.5.1 relies on a private method which got removed in Python 2.7.11. + + This patch adds the symbol to the module :mod:`uuid` and assigns the value + ``None`` to it. This causes kombu to fall back to the public API of + :mod:`uuid`. + + This patch can most probably be removed once celery and kombu are updated + to more recent versions. + """ + import uuid + + if not hasattr(uuid, '_uuid_generate_random'): + uuid._uuid_generate_random = None + + +def inspect_getargspec(): + """ + Pyramid and Pylons rely on inspect.getargspec to lookup the signature of + view functions. This is not compatible with cython, therefore we replace + getargspec with a custom version. + Code is inspired by the inspect module from Python-3.4 + """ + import inspect + + def _isCython(func): + """ + Private helper that checks if a function is a cython function. + """ + return func.__class__.__name__ == 'cython_function_or_method' + + def unwrap(func): + """ + Get the object wrapped by *func*. + + Follows the chain of :attr:`__wrapped__` attributes returning the last + object in the chain. + + *stop* is an optional callback accepting an object in the wrapper chain + as its sole argument that allows the unwrapping to be terminated early + if the callback returns a true value. If the callback never returns a + true value, the last object in the chain is returned as usual. For + example, :func:`signature` uses this to stop unwrapping if any object + in the chain has a ``__signature__`` attribute defined. + + :exc:`ValueError` is raised if a cycle is encountered. + """ + f = func # remember the original func for error reporting + memo = {id(f)} # Memoise by id to tolerate non-hashable objects + while hasattr(func, '__wrapped__'): + func = func.__wrapped__ + id_func = id(func) + if id_func in memo: + raise ValueError('wrapper loop when unwrapping {!r}'.format(f)) + memo.add(id_func) + return func + + def custom_getargspec(func): + """ + Get the names and default values of a function's arguments. + + A tuple of four things is returned: (args, varargs, varkw, defaults). + 'args' is a list of the argument names (it may contain nested lists). + 'varargs' and 'varkw' are the names of the * and ** arguments or None. + 'defaults' is an n-tuple of the default values of the last n arguments. + """ + + func = unwrap(func) + + if inspect.ismethod(func): + func = func.im_func + if not inspect.isfunction(func): + if not _isCython(func): + raise TypeError('{!r} is not a Python or Cython function' + .format(func)) + args, varargs, varkw = inspect.getargs(func.func_code) + return inspect.ArgSpec(args, varargs, varkw, func.func_defaults) + + inspect.getargspec = custom_getargspec diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/routing.py @@ -0,0 +1,1112 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Routes configuration + +The more specific and detailed routes should be defined first so they +may take precedent over the more generic routes. For more information +refer to the routes manual at http://routes.groovie.org/docs/ + +IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py +and _route_name variable which uses some of stored naming here to do redirects. +""" +import os +from routes import Mapper + +from rhodecode.config import routing_links + +# prefix for non repository related links needs to be prefixed with `/` +ADMIN_PREFIX = '/_admin' + +# Default requirements for URL parts +URL_NAME_REQUIREMENTS = { + # group name can have a slash in them, but they must not end with a slash + 'group_name': r'.*?[^/]', + # repo names can have a slash in them, but they must not end with a slash + 'repo_name': r'.*?[^/]', + # file path eats up everything at the end + 'f_path': r'.*', + # reference types + 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)', + 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)', +} + + +def make_map(config): + """Create, configure and return the routes Mapper""" + rmap = Mapper(directory=config['pylons.paths']['controllers'], + always_scan=config['debug']) + rmap.minimization = False + rmap.explicit = False + + from rhodecode.lib.utils2 import str2bool + from rhodecode.model import repo, repo_group + + def check_repo(environ, match_dict): + """ + check for valid repository for proper 404 handling + + :param environ: + :param match_dict: + """ + repo_name = match_dict.get('repo_name') + + if match_dict.get('f_path'): + # fix for multiple initial slashes that causes errors + match_dict['f_path'] = match_dict['f_path'].lstrip('/') + repo_model = repo.RepoModel() + by_name_match = repo_model.get_by_repo_name(repo_name) + # if we match quickly from database, short circuit the operation, + # and validate repo based on the type. + if by_name_match: + return True + + by_id_match = repo_model.get_repo_by_id(repo_name) + if by_id_match: + repo_name = by_id_match.repo_name + match_dict['repo_name'] = repo_name + return True + + return False + + def check_group(environ, match_dict): + """ + check for valid repository group path for proper 404 handling + + :param environ: + :param match_dict: + """ + repo_group_name = match_dict.get('group_name') + repo_group_model = repo_group.RepoGroupModel() + by_name_match = repo_group_model.get_by_group_name(repo_group_name) + if by_name_match: + return True + + return False + + def check_user_group(environ, match_dict): + """ + check for valid user group for proper 404 handling + + :param environ: + :param match_dict: + """ + return True + + def check_int(environ, match_dict): + return match_dict.get('id').isdigit() + + # The ErrorController route (handles 404/500 error pages); it should + # likely stay at the top, ensuring it can always be resolved + rmap.connect('/error/{action}', controller='error') + rmap.connect('/error/{action}/{id}', controller='error') + + #========================================================================== + # CUSTOM ROUTES HERE + #========================================================================== + + # MAIN PAGE + rmap.connect('home', '/', controller='home', action='index') + rmap.connect('repo_switcher_data', '/_repos_and_groups', controller='home', + action='repo_switcher_data') + rmap.connect('repo_list_data', '/_repos', controller='home', + action='repo_list_data') + + rmap.connect('user_autocomplete_data', '/_users', controller='home', + action='user_autocomplete_data') + rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home', + action='user_group_autocomplete_data') + + rmap.connect( + 'user_profile', '/_profiles/{username}', controller='users', + action='user_profile') + + # TODO: johbo: Static links, to be replaced by our redirection mechanism + rmap.connect('rst_help', + 'http://docutils.sourceforge.net/docs/user/rst/quickref.html', + _static=True) + rmap.connect('markdown_help', + 'http://daringfireball.net/projects/markdown/syntax', + _static=True) + rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True) + rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True) + rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True) + # TODO: anderson - making this a static link since redirect won't play + # nice with POST requests + rmap.connect('enterprise_license_convert_from_old', + 'https://rhodecode.com/u/license-upgrade', + _static=True) + + routing_links.connect_redirection_links(rmap) + + rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping') + rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test') + + # ADMIN REPOSITORY ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/repos') as m: + m.connect('repos', '/repos', + action='create', conditions={'method': ['POST']}) + m.connect('repos', '/repos', + action='index', conditions={'method': ['GET']}) + m.connect('new_repo', '/create_repository', + action='create_repository', conditions={'method': ['GET']}) + m.connect('/repos/{repo_name}', + action='update', conditions={'method': ['PUT'], + 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + m.connect('delete_repo', '/repos/{repo_name}', + action='delete', conditions={'method': ['DELETE']}, + requirements=URL_NAME_REQUIREMENTS) + m.connect('repo', '/repos/{repo_name}', + action='show', conditions={'method': ['GET'], + 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # ADMIN REPOSITORY GROUPS ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/repo_groups') as m: + m.connect('repo_groups', '/repo_groups', + action='create', conditions={'method': ['POST']}) + m.connect('repo_groups', '/repo_groups', + action='index', conditions={'method': ['GET']}) + m.connect('new_repo_group', '/repo_groups/new', + action='new', conditions={'method': ['GET']}) + m.connect('update_repo_group', '/repo_groups/{group_name}', + action='update', conditions={'method': ['PUT'], + 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + # EXTRAS REPO GROUP ROUTES + m.connect('edit_repo_group', '/repo_groups/{group_name}/edit', + action='edit', + conditions={'method': ['GET'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + m.connect('edit_repo_group', '/repo_groups/{group_name}/edit', + action='edit', + conditions={'method': ['PUT'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced', + action='edit_repo_group_advanced', + conditions={'method': ['GET'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced', + action='edit_repo_group_advanced', + conditions={'method': ['PUT'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions', + action='edit_repo_group_perms', + conditions={'method': ['GET'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions', + action='update_perms', + conditions={'method': ['PUT'], 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + m.connect('delete_repo_group', '/repo_groups/{group_name}', + action='delete', conditions={'method': ['DELETE'], + 'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + # ADMIN USER ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/users') as m: + m.connect('users', '/users', + action='create', conditions={'method': ['POST']}) + m.connect('users', '/users', + action='index', conditions={'method': ['GET']}) + m.connect('new_user', '/users/new', + action='new', conditions={'method': ['GET']}) + m.connect('update_user', '/users/{user_id}', + action='update', conditions={'method': ['PUT']}) + m.connect('delete_user', '/users/{user_id}', + action='delete', conditions={'method': ['DELETE']}) + m.connect('edit_user', '/users/{user_id}/edit', + action='edit', conditions={'method': ['GET']}) + m.connect('user', '/users/{user_id}', + action='show', conditions={'method': ['GET']}) + m.connect('force_password_reset_user', '/users/{user_id}/password_reset', + action='reset_password', conditions={'method': ['POST']}) + m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group', + action='create_personal_repo_group', conditions={'method': ['POST']}) + + # EXTRAS USER ROUTES + m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced', + action='edit_advanced', conditions={'method': ['GET']}) + m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced', + action='update_advanced', conditions={'method': ['PUT']}) + + m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', + action='edit_auth_tokens', conditions={'method': ['GET']}) + m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', + action='add_auth_token', conditions={'method': ['PUT']}) + m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', + action='delete_auth_token', conditions={'method': ['DELETE']}) + + m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions', + action='edit_global_perms', conditions={'method': ['GET']}) + m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions', + action='update_global_perms', conditions={'method': ['PUT']}) + + m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary', + action='edit_perms_summary', conditions={'method': ['GET']}) + + m.connect('edit_user_emails', '/users/{user_id}/edit/emails', + action='edit_emails', conditions={'method': ['GET']}) + m.connect('edit_user_emails', '/users/{user_id}/edit/emails', + action='add_email', conditions={'method': ['PUT']}) + m.connect('edit_user_emails', '/users/{user_id}/edit/emails', + action='delete_email', conditions={'method': ['DELETE']}) + + m.connect('edit_user_ips', '/users/{user_id}/edit/ips', + action='edit_ips', conditions={'method': ['GET']}) + m.connect('edit_user_ips', '/users/{user_id}/edit/ips', + action='add_ip', conditions={'method': ['PUT']}) + m.connect('edit_user_ips', '/users/{user_id}/edit/ips', + action='delete_ip', conditions={'method': ['DELETE']}) + + # ADMIN USER GROUPS REST ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/user_groups') as m: + m.connect('users_groups', '/user_groups', + action='create', conditions={'method': ['POST']}) + m.connect('users_groups', '/user_groups', + action='index', conditions={'method': ['GET']}) + m.connect('new_users_group', '/user_groups/new', + action='new', conditions={'method': ['GET']}) + m.connect('update_users_group', '/user_groups/{user_group_id}', + action='update', conditions={'method': ['PUT']}) + m.connect('delete_users_group', '/user_groups/{user_group_id}', + action='delete', conditions={'method': ['DELETE']}) + m.connect('edit_users_group', '/user_groups/{user_group_id}/edit', + action='edit', conditions={'method': ['GET']}, + function=check_user_group) + + # EXTRAS USER GROUP ROUTES + m.connect('edit_user_group_global_perms', '/user_groups/{user_group_id}/edit/global_permissions', + action='edit_global_perms', conditions={'method': ['GET']}) + m.connect('edit_user_group_global_perms', '/user_groups/{user_group_id}/edit/global_permissions', + action='update_global_perms', conditions={'method': ['PUT']}) + m.connect('edit_user_group_perms_summary', '/user_groups/{user_group_id}/edit/permissions_summary', + action='edit_perms_summary', conditions={'method': ['GET']}) + + m.connect('edit_user_group_perms', '/user_groups/{user_group_id}/edit/permissions', + action='edit_perms', conditions={'method': ['GET']}) + m.connect('edit_user_group_perms', '/user_groups/{user_group_id}/edit/permissions', + action='update_perms', conditions={'method': ['PUT']}) + + m.connect('edit_user_group_advanced', '/user_groups/{user_group_id}/edit/advanced', + action='edit_advanced', conditions={'method': ['GET']}) + + m.connect('edit_user_group_members', '/user_groups/{user_group_id}/edit/members', + action='edit_members', conditions={'method': ['GET']}) + + # ADMIN PERMISSIONS ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/permissions') as m: + m.connect('admin_permissions_application', '/permissions/application', + action='permission_application_update', conditions={'method': ['POST']}) + m.connect('admin_permissions_application', '/permissions/application', + action='permission_application', conditions={'method': ['GET']}) + + m.connect('admin_permissions_global', '/permissions/global', + action='permission_global_update', conditions={'method': ['POST']}) + m.connect('admin_permissions_global', '/permissions/global', + action='permission_global', conditions={'method': ['GET']}) + + m.connect('admin_permissions_object', '/permissions/object', + action='permission_objects_update', conditions={'method': ['POST']}) + m.connect('admin_permissions_object', '/permissions/object', + action='permission_objects', conditions={'method': ['GET']}) + + m.connect('admin_permissions_ips', '/permissions/ips', + action='permission_ips', conditions={'method': ['POST']}) + m.connect('admin_permissions_ips', '/permissions/ips', + action='permission_ips', conditions={'method': ['GET']}) + + m.connect('admin_permissions_overview', '/permissions/overview', + action='permission_perms', conditions={'method': ['GET']}) + + # ADMIN DEFAULTS REST ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/defaults') as m: + m.connect('admin_defaults_repositories', '/defaults/repositories', + action='update_repository_defaults', conditions={'method': ['POST']}) + m.connect('admin_defaults_repositories', '/defaults/repositories', + action='index', conditions={'method': ['GET']}) + + # ADMIN DEBUG STYLE ROUTES + if str2bool(config.get('debug_style')): + with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style', + controller='debug_style') as m: + m.connect('debug_style_home', '', + action='index', conditions={'method': ['GET']}) + m.connect('debug_style_template', '/t/{t_path}', + action='template', conditions={'method': ['GET']}) + + # ADMIN SETTINGS ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/settings') as m: + + # default + m.connect('admin_settings', '/settings', + action='settings_global_update', + conditions={'method': ['POST']}) + m.connect('admin_settings', '/settings', + action='settings_global', conditions={'method': ['GET']}) + + m.connect('admin_settings_vcs', '/settings/vcs', + action='settings_vcs_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_vcs', '/settings/vcs', + action='settings_vcs', + conditions={'method': ['GET']}) + m.connect('admin_settings_vcs', '/settings/vcs', + action='delete_svn_pattern', + conditions={'method': ['DELETE']}) + + m.connect('admin_settings_mapping', '/settings/mapping', + action='settings_mapping_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_mapping', '/settings/mapping', + action='settings_mapping', conditions={'method': ['GET']}) + + m.connect('admin_settings_global', '/settings/global', + action='settings_global_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_global', '/settings/global', + action='settings_global', conditions={'method': ['GET']}) + + m.connect('admin_settings_visual', '/settings/visual', + action='settings_visual_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_visual', '/settings/visual', + action='settings_visual', conditions={'method': ['GET']}) + + m.connect('admin_settings_issuetracker', + '/settings/issue-tracker', action='settings_issuetracker', + conditions={'method': ['GET']}) + m.connect('admin_settings_issuetracker_save', + '/settings/issue-tracker/save', + action='settings_issuetracker_save', + conditions={'method': ['POST']}) + m.connect('admin_issuetracker_test', '/settings/issue-tracker/test', + action='settings_issuetracker_test', + conditions={'method': ['POST']}) + m.connect('admin_issuetracker_delete', + '/settings/issue-tracker/delete', + action='settings_issuetracker_delete', + conditions={'method': ['DELETE']}) + + m.connect('admin_settings_email', '/settings/email', + action='settings_email_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_email', '/settings/email', + action='settings_email', conditions={'method': ['GET']}) + + m.connect('admin_settings_hooks', '/settings/hooks', + action='settings_hooks_update', + conditions={'method': ['POST', 'DELETE']}) + m.connect('admin_settings_hooks', '/settings/hooks', + action='settings_hooks', conditions={'method': ['GET']}) + + m.connect('admin_settings_search', '/settings/search', + action='settings_search', conditions={'method': ['GET']}) + + m.connect('admin_settings_system', '/settings/system', + action='settings_system', conditions={'method': ['GET']}) + + m.connect('admin_settings_system_update', '/settings/system/updates', + action='settings_system_update', conditions={'method': ['GET']}) + + m.connect('admin_settings_supervisor', '/settings/supervisor', + action='settings_supervisor', conditions={'method': ['GET']}) + m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log', + action='settings_supervisor_log', conditions={'method': ['GET']}) + + m.connect('admin_settings_labs', '/settings/labs', + action='settings_labs_update', + conditions={'method': ['POST']}) + m.connect('admin_settings_labs', '/settings/labs', + action='settings_labs', conditions={'method': ['GET']}) + + m.connect('admin_settings_open_source', '/settings/open_source', + action='settings_open_source', + conditions={'method': ['GET']}) + + # ADMIN MY ACCOUNT + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/my_account') as m: + + m.connect('my_account', '/my_account', + action='my_account', conditions={'method': ['GET']}) + m.connect('my_account_edit', '/my_account/edit', + action='my_account_edit', conditions={'method': ['GET']}) + m.connect('my_account', '/my_account', + action='my_account_update', conditions={'method': ['POST']}) + + m.connect('my_account_password', '/my_account/password', + action='my_account_password', conditions={'method': ['GET']}) + m.connect('my_account_password', '/my_account/password', + action='my_account_password_update', conditions={'method': ['POST']}) + + m.connect('my_account_repos', '/my_account/repos', + action='my_account_repos', conditions={'method': ['GET']}) + + m.connect('my_account_watched', '/my_account/watched', + action='my_account_watched', conditions={'method': ['GET']}) + + m.connect('my_account_pullrequests', '/my_account/pull_requests', + action='my_account_pullrequests', conditions={'method': ['GET']}) + + m.connect('my_account_perms', '/my_account/perms', + action='my_account_perms', conditions={'method': ['GET']}) + + m.connect('my_account_emails', '/my_account/emails', + action='my_account_emails', conditions={'method': ['GET']}) + m.connect('my_account_emails', '/my_account/emails', + action='my_account_emails_add', conditions={'method': ['POST']}) + m.connect('my_account_emails', '/my_account/emails', + action='my_account_emails_delete', conditions={'method': ['DELETE']}) + + m.connect('my_account_auth_tokens', '/my_account/auth_tokens', + action='my_account_auth_tokens', conditions={'method': ['GET']}) + m.connect('my_account_auth_tokens', '/my_account/auth_tokens', + action='my_account_auth_tokens_add', conditions={'method': ['POST']}) + m.connect('my_account_auth_tokens', '/my_account/auth_tokens', + action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']}) + + m.connect('my_account_oauth', '/my_account/oauth', + action='my_account_oauth', conditions={'method': ['GET']}) + m.connect('my_account_oauth', '/my_account/oauth', + action='my_account_oauth_delete', + conditions={'method': ['DELETE']}) + + # NOTIFICATION REST ROUTES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/notifications') as m: + m.connect('notifications', '/notifications', + action='index', conditions={'method': ['GET']}) + m.connect('notifications_mark_all_read', '/notifications/mark_all_read', + action='mark_all_read', conditions={'method': ['POST']}) + + m.connect('/notifications/{notification_id}', + action='update', conditions={'method': ['PUT']}) + m.connect('/notifications/{notification_id}', + action='delete', conditions={'method': ['DELETE']}) + m.connect('notification', '/notifications/{notification_id}', + action='show', conditions={'method': ['GET']}) + + # ADMIN GIST + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/gists') as m: + m.connect('gists', '/gists', + action='create', conditions={'method': ['POST']}) + m.connect('gists', '/gists', + action='index', conditions={'method': ['GET']}) + m.connect('new_gist', '/gists/new', + action='new', conditions={'method': ['GET']}) + + m.connect('/gists/{gist_id}', + action='delete', conditions={'method': ['DELETE']}) + m.connect('edit_gist', '/gists/{gist_id}/edit', + action='edit_form', conditions={'method': ['GET']}) + m.connect('edit_gist', '/gists/{gist_id}/edit', + action='edit', conditions={'method': ['POST']}) + m.connect( + 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision', + action='check_revision', conditions={'method': ['GET']}) + + m.connect('gist', '/gists/{gist_id}', + action='show', conditions={'method': ['GET']}) + m.connect('gist_rev', '/gists/{gist_id}/{revision}', + revision='tip', + action='show', conditions={'method': ['GET']}) + m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}', + revision='tip', + action='show', conditions={'method': ['GET']}) + m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}', + revision='tip', + action='show', conditions={'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + # ADMIN MAIN PAGES + with rmap.submapper(path_prefix=ADMIN_PREFIX, + controller='admin/admin') as m: + m.connect('admin_home', '', action='index') + m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', + action='add_repo') + m.connect( + 'pull_requests_global', '/pull_requests/{pull_request_id:[0-9]+}', + action='pull_requests') + + # USER JOURNAL + rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,), + controller='journal', action='index') + rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,), + controller='journal', action='journal_rss') + rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,), + controller='journal', action='journal_atom') + + rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,), + controller='journal', action='public_journal') + + rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,), + controller='journal', action='public_journal_rss') + + rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,), + controller='journal', action='public_journal_rss') + + rmap.connect('public_journal_atom', + '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal', + action='public_journal_atom') + + rmap.connect('public_journal_atom_old', + '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal', + action='public_journal_atom') + + rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,), + controller='journal', action='toggle_following', + conditions={'method': ['POST']}) + + # FULL TEXT SEARCH + rmap.connect('search', '%s/search' % (ADMIN_PREFIX,), + controller='search') + rmap.connect('search_repo_home', '/{repo_name}/search', + controller='search', + action='index', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # LOGIN/LOGOUT/REGISTER/SIGN IN + rmap.connect('login_home', '%s/login' % (ADMIN_PREFIX,), controller='login', + action='index') + + rmap.connect('logout_home', '%s/logout' % (ADMIN_PREFIX,), controller='login', + action='logout', conditions={'method': ['POST']}) + + rmap.connect('register', '%s/register' % (ADMIN_PREFIX,), controller='login', + action='register') + + rmap.connect('reset_password', '%s/password_reset' % (ADMIN_PREFIX,), + controller='login', action='password_reset') + + rmap.connect('reset_password_confirmation', + '%s/password_reset_confirmation' % (ADMIN_PREFIX,), + controller='login', action='password_reset_confirmation') + + rmap.connect('social_auth', + '%s/social_auth/{provider_name}' % (ADMIN_PREFIX,), + controller='login', action='social_auth') + + # FEEDS + rmap.connect('rss_feed_home', '/{repo_name}/feed/rss', + controller='feed', action='rss', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('atom_feed_home', '/{repo_name}/feed/atom', + controller='feed', action='atom', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + #========================================================================== + # REPOSITORY ROUTES + #========================================================================== + + rmap.connect('repo_creating_home', '/{repo_name}/repo_creating', + controller='admin/repos', action='repo_creating', + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_check_home', '/{repo_name}/crepo_check', + controller='admin/repos', action='repo_check', + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}', + controller='summary', action='repo_stats', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_refs_data', '/{repo_name}/refs-data', + controller='summary', action='repo_refs_data', + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog', + controller='summary', action='repo_refs_changelog_data', + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}', + controller='changeset', revision='tip', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}', + controller='changeset', revision='tip', action='changeset_children', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}', + controller='changeset', revision='tip', action='changeset_parents', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # repo edit options + rmap.connect('edit_repo', '/{repo_name}/settings', + controller='admin/repos', action='edit', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions', + controller='admin/repos', action='edit_permissions', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions', + controller='admin/repos', action='edit_permissions_update', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', + controller='admin/repos', action='edit_fields', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new', + controller='admin/repos', action='create_repo_field', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}', + controller='admin/repos', action='delete_repo_field', + conditions={'method': ['DELETE'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced', + controller='admin/repos', action='edit_advanced', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking', + controller='admin/repos', action='edit_advanced_locking', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle', + controller='admin/repos', action='toggle_locking', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal', + controller='admin/repos', action='edit_advanced_journal', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork', + controller='admin/repos', action='edit_advanced_fork', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', + controller='admin/repos', action='edit_caches_form', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', + controller='admin/repos', action='edit_caches', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', + controller='admin/repos', action='edit_remote_form', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', + controller='admin/repos', action='edit_remote', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', + controller='admin/repos', action='edit_statistics_form', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', + controller='admin/repos', action='edit_statistics', + conditions={'method': ['PUT'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_settings_issuetracker', + '/{repo_name}/settings/issue-tracker', + controller='admin/repos', action='repo_issuetracker', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_issuetracker_test', + '/{repo_name}/settings/issue-tracker/test', + controller='admin/repos', action='repo_issuetracker_test', + conditions={'method': ['POST'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_issuetracker_delete', + '/{repo_name}/settings/issue-tracker/delete', + controller='admin/repos', action='repo_issuetracker_delete', + conditions={'method': ['DELETE'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_issuetracker_save', + '/{repo_name}/settings/issue-tracker/save', + controller='admin/repos', action='repo_issuetracker_save', + conditions={'method': ['POST'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', + controller='admin/repos', action='repo_settings_vcs_update', + conditions={'method': ['POST'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', + controller='admin/repos', action='repo_settings_vcs', + conditions={'method': ['GET'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', + controller='admin/repos', action='repo_delete_svn_pattern', + conditions={'method': ['DELETE'], 'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # still working url for backward compat. + rmap.connect('raw_changeset_home_depraced', + '/{repo_name}/raw-changeset/{revision}', + controller='changeset', action='changeset_raw', + revision='tip', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # new URLs + rmap.connect('changeset_raw_home', + '/{repo_name}/changeset-diff/{revision}', + controller='changeset', action='changeset_raw', + revision='tip', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_patch_home', + '/{repo_name}/changeset-patch/{revision}', + controller='changeset', action='changeset_patch', + revision='tip', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_download_home', + '/{repo_name}/changeset-download/{revision}', + controller='changeset', action='changeset_download', + revision='tip', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_comment', + '/{repo_name}/changeset/{revision}/comment', + controller='changeset', revision='tip', action='comment', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_comment_preview', + '/{repo_name}/changeset/comment/preview', + controller='changeset', action='preview_comment', + conditions={'function': check_repo, 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_comment_delete', + '/{repo_name}/changeset/comment/{comment_id}/delete', + controller='changeset', action='delete_comment', + conditions={'function': check_repo, 'method': ['DELETE']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changeset_info', '/changeset_info/{repo_name}/{revision}', + controller='changeset', action='changeset_info', + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('compare_home', + '/{repo_name}/compare', + controller='compare', action='index', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('compare_url', + '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', + controller='compare', action='compare', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_home', + '/{repo_name}/pull-request/new', controller='pullrequests', + action='index', conditions={'function': check_repo, + 'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest', + '/{repo_name}/pull-request/new', controller='pullrequests', + action='create', conditions={'function': check_repo, + 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_repo_refs', + '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}', + controller='pullrequests', + action='get_repo_refs', + conditions={'function': check_repo, 'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_repo_destinations', + '/{repo_name}/pull-request/repo-destinations', + controller='pullrequests', + action='get_repo_destinations', + conditions={'function': check_repo, 'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_show', + '/{repo_name}/pull-request/{pull_request_id}', + controller='pullrequests', + action='show', conditions={'function': check_repo, + 'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_update', + '/{repo_name}/pull-request/{pull_request_id}', + controller='pullrequests', + action='update', conditions={'function': check_repo, + 'method': ['PUT']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_merge', + '/{repo_name}/pull-request/{pull_request_id}', + controller='pullrequests', + action='merge', conditions={'function': check_repo, + 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_delete', + '/{repo_name}/pull-request/{pull_request_id}', + controller='pullrequests', + action='delete', conditions={'function': check_repo, + 'method': ['DELETE']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_show_all', + '/{repo_name}/pull-request', + controller='pullrequests', + action='show_all', conditions={'function': check_repo, + 'method': ['GET']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_comment', + '/{repo_name}/pull-request-comment/{pull_request_id}', + controller='pullrequests', + action='comment', conditions={'function': check_repo, + 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('pullrequest_comment_delete', + '/{repo_name}/pull-request-comment/{comment_id}/delete', + controller='pullrequests', action='delete_comment', + conditions={'function': check_repo, 'method': ['DELETE']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('summary_home_explicit', '/{repo_name}/summary', + controller='summary', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('branches_home', '/{repo_name}/branches', + controller='branches', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('tags_home', '/{repo_name}/tags', + controller='tags', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('bookmarks_home', '/{repo_name}/bookmarks', + controller='bookmarks', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changelog_home', '/{repo_name}/changelog', + controller='changelog', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary', + controller='changelog', action='changelog_summary', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changelog_file_home', '/{repo_name}/changelog/{revision}/{f_path}', + controller='changelog', f_path=None, + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}', + controller='changelog', action='changelog_details', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_home', + '/{repo_name}/files/{revision}/{f_path}', + controller='files', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_home_simple_catchrev', + '/{repo_name}/files/{revision}', + controller='files', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_home_simple_catchall', + '/{repo_name}/files', + controller='files', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_history_home', + '/{repo_name}/history/{revision}/{f_path}', + controller='files', action='history', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_authors_home', + '/{repo_name}/authors/{revision}/{f_path}', + controller='files', action='authors', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}', + controller='files', action='diff', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_diff_2way_home', + '/{repo_name}/diff-2way/{f_path}', + controller='files', action='diff_2way', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_rawfile_home', + '/{repo_name}/rawfile/{revision}/{f_path}', + controller='files', action='rawfile', revision='tip', + f_path='', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_raw_home', + '/{repo_name}/raw/{revision}/{f_path}', + controller='files', action='raw', revision='tip', f_path='', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_render_home', + '/{repo_name}/render/{revision}/{f_path}', + controller='files', action='index', revision='tip', f_path='', + rendered=True, conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_annotate_home', + '/{repo_name}/annotate/{revision}/{f_path}', + controller='files', action='index', revision='tip', + f_path='', annotate=True, conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_edit', + '/{repo_name}/edit/{revision}/{f_path}', + controller='files', action='edit', revision='tip', + f_path='', + conditions={'function': check_repo, 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_edit_home', + '/{repo_name}/edit/{revision}/{f_path}', + controller='files', action='edit_home', revision='tip', + f_path='', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_add', + '/{repo_name}/add/{revision}/{f_path}', + controller='files', action='add', revision='tip', + f_path='', + conditions={'function': check_repo, 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_add_home', + '/{repo_name}/add/{revision}/{f_path}', + controller='files', action='add_home', revision='tip', + f_path='', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_delete', + '/{repo_name}/delete/{revision}/{f_path}', + controller='files', action='delete', revision='tip', + f_path='', + conditions={'function': check_repo, 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_delete_home', + '/{repo_name}/delete/{revision}/{f_path}', + controller='files', action='delete_home', revision='tip', + f_path='', conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}', + controller='files', action='archivefile', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_nodelist_home', + '/{repo_name}/nodelist/{revision}/{f_path}', + controller='files', action='nodelist', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('files_metadata_list_home', + '/{repo_name}/metadata_list/{revision}/{f_path}', + controller='files', action='metadata_list', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_fork_create_home', '/{repo_name}/fork', + controller='forks', action='fork_create', + conditions={'function': check_repo, 'method': ['POST']}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_fork_home', '/{repo_name}/fork', + controller='forks', action='fork', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_forks_home', '/{repo_name}/forks', + controller='forks', action='forks', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + rmap.connect('repo_followers_home', '/{repo_name}/followers', + controller='followers', action='followers', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + # must be here for proper group/repo catching pattern + _connect_with_slash( + rmap, 'repo_group_home', '/{group_name}', + controller='home', action='index_repo_group', + conditions={'function': check_group}, + requirements=URL_NAME_REQUIREMENTS) + + # catch all, at the end + _connect_with_slash( + rmap, 'summary_home', '/{repo_name}', + controller='summary', action='index', + conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS) + + return rmap + + +def _connect_with_slash(mapper, name, path, *args, **kwargs): + """ + Connect a route with an optional trailing slash in `path`. + """ + mapper.connect(name + '_slash', path + '/', *args, **kwargs) + mapper.connect(name, path, *args, **kwargs) diff --git a/rhodecode/config/routing_links.py b/rhodecode/config/routing_links.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/routing_links.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Single source for redirection links. + +Goal of this module is to provide a single source of truth regarding external +links. The data inside this module is used to configure the routing +system of Enterprise and it is used also as a base to check if this data +and our server configuration are in sync. + +.. py:data:: link_config + + Contains the configuration for external links. Each item is supposed to be + a `dict` like this example:: + + {"name": "url_name", + "target": "https://rhodecode.com/r1/enterprise/keyword/", + "external_target": "https://example.com/some-page.html", + } + +then you can retrieve the url by simply calling the URL function: + +`h.url('url_name')` + +The redirection must be first implemented in our servers before +you can see it working. +""" +# flake8: noqa +from __future__ import unicode_literals + + +link_config = [ + {"name": "enterprise_docs", + "target": "https://rhodecode.com/r1/enterprise/docs/", + "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/", + }, + {"name": "enterprise_log_file_locations", + "target": "https://rhodecode.com/r1/enterprise/docs/admin-system-overview/", + "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/system-overview.html#log-files", + }, + {"name": "enterprise_issue_tracker_settings", + "target": "https://rhodecode.com/r1/enterprise/docs/issue-trackers-overview/", + "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/issue-trackers/issue-trackers.html", + }, + {"name": "enterprise_svn_setup", + "target": "https://rhodecode.com/r1/enterprise/docs/svn-setup/", + "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/svn-http.html", + }, +] + + +def connect_redirection_links(rmap): + for link in link_config: + rmap.connect(link['name'], link['target'], _static=True) diff --git a/rhodecode/config/utils.py b/rhodecode/config/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/config/utils.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import shlex +import Pyro4 +import platform + +from rhodecode.model import init_model + + +def configure_pyro4(config): + """ + Configure Pyro4 based on `config`. + + This will mainly set the different configuration parameters of the Pyro4 + library based on the settings in our INI files. The Pyro4 documentation + lists more details about the specific settings and their meaning. + """ + Pyro4.config.COMMTIMEOUT = float(config['vcs.connection_timeout']) + Pyro4.config.SERIALIZER = 'pickle' + Pyro4.config.SERIALIZERS_ACCEPTED.add('pickle') + + # Note: We need server configuration in the WSGI processes + # because we provide a callback server in certain vcs operations. + Pyro4.config.SERVERTYPE = "multiplex" + Pyro4.config.POLLTIMEOUT = 0.01 + + +def configure_vcs(config): + """ + Patch VCS config with some RhodeCode specific stuff + """ + from rhodecode.lib.vcs import conf + from rhodecode.lib.utils2 import aslist + conf.settings.BACKENDS = { + 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository', + 'git': 'rhodecode.lib.vcs.backends.git.GitRepository', + 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository', + } + + conf.settings.HG_USE_REBASE_FOR_MERGING = config.get( + 'rhodecode_hg_use_rebase_for_merging', False) + conf.settings.GIT_REV_FILTER = shlex.split( + config.get('git_rev_filter', '--all').strip()) + conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding', + 'UTF-8'), sep=',') + conf.settings.ALIASES[:] = config.get('vcs.backends') + conf.settings.SVN_COMPATIBLE_VERSION = config.get( + 'vcs.svn.compatible_version') + + +def initialize_database(config): + from rhodecode.lib.utils2 import engine_from_config + engine = engine_from_config(config, 'sqlalchemy.db1.') + init_model(engine, encryption_key=config['beaker.session.secret']) + + +def get_vcs_server_protocol(config): + protocol = config.get('vcs.server.protocol', 'pyro4') + return protocol + + +def set_instance_id(config): + """ Sets a dynamic generated config['instance_id'] if missing or '*' """ + + config['instance_id'] = config.get('instance_id') or '' + if config['instance_id'] == '*' or not config['instance_id']: + _platform_id = platform.uname()[1] or 'instance' + config['instance_id'] = '%s-%s' % (_platform_id, os.getpid()) diff --git a/rhodecode/controllers/__init__.py b/rhodecode/controllers/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/controllers/admin/__init__.py b/rhodecode/controllers/admin/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/controllers/admin/admin.py b/rhodecode/controllers/admin/admin.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/admin.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Controller for Admin panel of RhodeCode Enterprise +""" + + +import logging + +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from sqlalchemy.orm import joinedload +from whoosh.qparser.default import QueryParser, query +from whoosh.qparser.dateparse import DateParserPlugin +from whoosh.fields import (TEXT, Schema, DATETIME) +from sqlalchemy.sql.expression import or_, and_, func + +from rhodecode.model.db import UserLog, PullRequest +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.utils2 import safe_int, remove_prefix, remove_suffix +from rhodecode.lib.helpers import Page + + +log = logging.getLogger(__name__) + +# JOURNAL SCHEMA used only to generate queries in journal. We use whoosh +# querylang to build sql queries and filter journals +JOURNAL_SCHEMA = Schema( + username=TEXT(), + date=DATETIME(), + action=TEXT(), + repository=TEXT(), + ip=TEXT(), +) + + +def _journal_filter(user_log, search_term): + """ + Filters sqlalchemy user_log based on search_term with whoosh Query language + http://packages.python.org/Whoosh/querylang.html + + :param user_log: + :param search_term: + """ + log.debug('Initial search term: %r' % search_term) + qry = None + if search_term: + qp = QueryParser('repository', schema=JOURNAL_SCHEMA) + qp.add_plugin(DateParserPlugin()) + qry = qp.parse(unicode(search_term)) + log.debug('Filtering using parsed query %r' % qry) + + def wildcard_handler(col, wc_term): + if wc_term.startswith('*') and not wc_term.endswith('*'): + # postfix == endswith + wc_term = remove_prefix(wc_term, prefix='*') + return func.lower(col).endswith(wc_term) + elif wc_term.startswith('*') and wc_term.endswith('*'): + # wildcard == ilike + wc_term = remove_prefix(wc_term, prefix='*') + wc_term = remove_suffix(wc_term, suffix='*') + return func.lower(col).contains(wc_term) + + def get_filterion(field, val, term): + + if field == 'repository': + field = getattr(UserLog, 'repository_name') + elif field == 'ip': + field = getattr(UserLog, 'user_ip') + elif field == 'date': + field = getattr(UserLog, 'action_date') + elif field == 'username': + field = getattr(UserLog, 'username') + else: + field = getattr(UserLog, field) + log.debug('filter field: %s val=>%s' % (field, val)) + + # sql filtering + if isinstance(term, query.Wildcard): + return wildcard_handler(field, val) + elif isinstance(term, query.Prefix): + return func.lower(field).startswith(func.lower(val)) + elif isinstance(term, query.DateRange): + return and_(field >= val[0], field <= val[1]) + return func.lower(field) == func.lower(val) + + if isinstance(qry, (query.And, query.Term, query.Prefix, query.Wildcard, + query.DateRange)): + if not isinstance(qry, query.And): + qry = [qry] + for term in qry: + field = term.fieldname + val = (term.text if not isinstance(term, query.DateRange) + else [term.startdate, term.enddate]) + user_log = user_log.filter(get_filterion(field, val, term)) + elif isinstance(qry, query.Or): + filters = [] + for term in qry: + field = term.fieldname + val = (term.text if not isinstance(term, query.DateRange) + else [term.startdate, term.enddate]) + filters.append(get_filterion(field, val, term)) + user_log = user_log.filter(or_(*filters)) + + return user_log + + +class AdminController(BaseController): + + @LoginRequired() + def __before__(self): + super(AdminController, self).__before__() + + @HasPermissionAllDecorator('hg.admin') + def index(self): + users_log = UserLog.query()\ + .options(joinedload(UserLog.user))\ + .options(joinedload(UserLog.repository)) + + # FILTERING + c.search_term = request.GET.get('filter') + try: + users_log = _journal_filter(users_log, c.search_term) + except Exception: + # we want this to crash for now + raise + + users_log = users_log.order_by(UserLog.action_date.desc()) + + p = safe_int(request.GET.get('page', 1), 1) + + def url_generator(**kw): + return url.current(filter=c.search_term, **kw) + + c.users_log = Page(users_log, page=p, items_per_page=10, + url=url_generator) + c.log_data = render('admin/admin_log.html') + + if request.is_xhr: + return c.log_data + return render('admin/admin.html') + + # global redirect doesn't need permissions + def pull_requests(self, pull_request_id): + """ + Global redirect for Pull Requests + + :param pull_request_id: id of pull requests in the system + """ + pull_request = PullRequest.get_or_404(pull_request_id) + repo_name = pull_request.target_repo.repo_name + return redirect(url( + 'pullrequest_show', repo_name=repo_name, + pull_request_id=pull_request_id)) diff --git a/rhodecode/controllers/admin/defaults.py b/rhodecode/controllers/admin/defaults.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/defaults.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +default settings controller for RhodeCode Enterprise +""" + +import logging +import formencode +from formencode import htmlfill + +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +from rhodecode.lib import auth +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib.base import BaseController, render +from rhodecode.model.forms import DefaultsForm +from rhodecode.model.meta import Session +from rhodecode import BACKENDS +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +class DefaultsController(BaseController): + + @LoginRequired() + def __before__(self): + super(DefaultsController, self).__before__() + + @HasPermissionAllDecorator('hg.admin') + def index(self): + """GET /defaults: All items in the collection""" + # url('admin_defaults_repositories') + c.backends = BACKENDS.keys() + c.active = 'repositories' + defaults = SettingsModel().get_default_repo_settings() + + return htmlfill.render( + render('admin/defaults/defaults.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def update_repository_defaults(self): + """PUT /defaults/repositories: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # Or using helpers: + # h.form(url('admin_defaults_repositories'), + # method='post') + # url('admin_defaults_repositories') + c.active = 'repositories' + _form = DefaultsForm()() + + try: + form_result = _form.to_python(dict(request.POST)) + for k, v in form_result.iteritems(): + setting = SettingsModel().create_or_update_setting(k, v) + Session().add(setting) + Session().commit() + h.flash(_('Default settings updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + + return htmlfill.render( + render('admin/defaults/defaults.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception('Exception in update action') + h.flash(_('Error occurred during update of default values'), + category='error') + + return redirect(url('admin_defaults_repositories')) diff --git a/rhodecode/controllers/admin/gists.py b/rhodecode/controllers/admin/gists.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/gists.py @@ -0,0 +1,339 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +gist controller for RhodeCode +""" + +import time +import logging +import traceback +import formencode +from formencode import htmlfill + +from pylons import request, response, tmpl_context as c, url +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _ + +from rhodecode.model.forms import GistForm +from rhodecode.model.gist import GistModel +from rhodecode.model.meta import Session +from rhodecode.model.db import Gist, User +from rhodecode.lib import auth +from rhodecode.lib import helpers as h +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.auth import LoginRequired, NotAnonymous +from rhodecode.lib.utils import jsonify +from rhodecode.lib.utils2 import safe_str, safe_int, time_to_datetime +from rhodecode.lib.ext_json import json +from webob.exc import HTTPNotFound, HTTPForbidden +from sqlalchemy.sql.expression import or_ +from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError + +log = logging.getLogger(__name__) + + +class GistsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + + def __load_defaults(self, extra_values=None): + c.lifetime_values = [ + (str(-1), _('forever')), + (str(5), _('5 minutes')), + (str(60), _('1 hour')), + (str(60 * 24), _('1 day')), + (str(60 * 24 * 30), _('1 month')), + ] + if extra_values: + c.lifetime_values.append(extra_values) + c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] + c.acl_options = [ + (Gist.ACL_LEVEL_PRIVATE, _("Requires registered account")), + (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users")) + ] + + @LoginRequired() + def index(self): + """GET /admin/gists: All items in the collection""" + # url('gists') + not_default_user = c.rhodecode_user.username != User.DEFAULT_USER + c.show_private = request.GET.get('private') and not_default_user + c.show_public = request.GET.get('public') and not_default_user + c.show_all = request.GET.get('all') and c.rhodecode_user.admin + + gists = _gists = Gist().query()\ + .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\ + .order_by(Gist.created_on.desc()) + + c.active = 'public' + # MY private + if c.show_private and not c.show_public: + gists = _gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\ + .filter(Gist.gist_owner == c.rhodecode_user.user_id) + c.active = 'my_private' + # MY public + elif c.show_public and not c.show_private: + gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\ + .filter(Gist.gist_owner == c.rhodecode_user.user_id) + c.active = 'my_public' + # MY public+private + elif c.show_private and c.show_public: + gists = _gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC, + Gist.gist_type == Gist.GIST_PRIVATE))\ + .filter(Gist.gist_owner == c.rhodecode_user.user_id) + c.active = 'my_all' + # Show all by super-admin + elif c.show_all: + c.active = 'all' + gists = _gists + + # default show ALL public gists + if not c.show_public and not c.show_private and not c.show_all: + gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) + c.active = 'public' + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + + data = [] + + for gist in gists: + data.append({ + 'created_on': _render('gist_created', gist.created_on), + 'created_on_raw': gist.created_on, + 'type': _render('gist_type', gist.gist_type), + 'access_id': _render('gist_access_id', gist.gist_access_id, gist.owner.full_contact), + 'author': _render('gist_author', gist.owner.full_contact, gist.created_on, gist.gist_expires), + 'author_raw': h.escape(gist.owner.full_contact), + 'expires': _render('gist_expires', gist.gist_expires), + 'description': _render('gist_description', gist.gist_description) + }) + c.data = json.dumps(data) + return render('admin/gists/index.html') + + @LoginRequired() + @NotAnonymous() + @auth.CSRFRequired() + def create(self): + """POST /admin/gists: Create a new item""" + # url('gists') + self.__load_defaults() + gist_form = GistForm([x[0] for x in c.lifetime_values], + [x[0] for x in c.acl_options])() + try: + form_result = gist_form.to_python(dict(request.POST)) + # TODO: multiple files support, from the form + filename = form_result['filename'] or Gist.DEFAULT_FILENAME + nodes = { + filename: { + 'content': form_result['content'], + 'lexer': form_result['mimetype'] # None is autodetect + } + } + _public = form_result['public'] + gist_type = Gist.GIST_PUBLIC if _public else Gist.GIST_PRIVATE + gist_acl_level = form_result.get( + 'acl_level', Gist.ACL_LEVEL_PRIVATE) + gist = GistModel().create( + description=form_result['description'], + owner=c.rhodecode_user.user_id, + gist_mapping=nodes, + gist_type=gist_type, + lifetime=form_result['lifetime'], + gist_id=form_result['gistid'], + gist_acl_level=gist_acl_level + ) + Session().commit() + new_gist_id = gist.gist_access_id + except formencode.Invalid as errors: + defaults = errors.value + + return formencode.htmlfill.render( + render('admin/gists/new.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + + except Exception: + log.exception("Exception while trying to create a gist") + h.flash(_('Error occurred during gist creation'), category='error') + return redirect(url('new_gist')) + return redirect(url('gist', gist_id=new_gist_id)) + + @LoginRequired() + @NotAnonymous() + def new(self, format='html'): + """GET /admin/gists/new: Form to create a new item""" + # url('new_gist') + self.__load_defaults() + return render('admin/gists/new.html') + + @LoginRequired() + @NotAnonymous() + @auth.CSRFRequired() + def delete(self, gist_id): + """DELETE /admin/gists/gist_id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('gist', gist_id=ID), + # method='delete') + # url('gist', gist_id=ID) + c.gist = Gist.get_or_404(gist_id) + + owner = c.gist.gist_owner == c.rhodecode_user.user_id + if not (h.HasPermissionAny('hg.admin')() or owner): + raise HTTPForbidden() + + GistModel().delete(c.gist) + Session().commit() + h.flash(_('Deleted gist %s') % c.gist.gist_access_id, category='success') + + return redirect(url('gists')) + + def _add_gist_to_context(self, gist_id): + c.gist = Gist.get_or_404(gist_id) + + # Check if this gist is expired + if c.gist.gist_expires != -1: + if time.time() > c.gist.gist_expires: + log.error( + 'Gist expired at %s', time_to_datetime(c.gist.gist_expires)) + raise HTTPNotFound() + + # check if this gist requires a login + is_default_user = c.rhodecode_user.username == User.DEFAULT_USER + if c.gist.acl_level == Gist.ACL_LEVEL_PRIVATE and is_default_user: + log.error("Anonymous user %s tried to access protected gist `%s`", + c.rhodecode_user, gist_id) + raise HTTPNotFound() + + @LoginRequired() + def show(self, gist_id, revision='tip', format='html', f_path=None): + """GET /admin/gists/gist_id: Show a specific item""" + # url('gist', gist_id=ID) + self._add_gist_to_context(gist_id) + c.render = not request.GET.get('no-render', False) + + try: + c.file_last_commit, c.files = GistModel().get_gist_files( + gist_id, revision=revision) + except VCSError: + log.exception("Exception in gist show") + raise HTTPNotFound() + if format == 'raw': + content = '\n\n'.join([f.content for f in c.files if (f_path is None or f.path == f_path)]) + response.content_type = 'text/plain' + return content + return render('admin/gists/show.html') + + @LoginRequired() + @NotAnonymous() + @auth.CSRFRequired() + def edit(self, gist_id): + self._add_gist_to_context(gist_id) + + owner = c.gist.gist_owner == c.rhodecode_user.user_id + if not (h.HasPermissionAny('hg.admin')() or owner): + raise HTTPForbidden() + + rpost = request.POST + nodes = {} + _file_data = zip(rpost.getall('org_files'), rpost.getall('files'), + rpost.getall('mimetypes'), rpost.getall('contents')) + for org_filename, filename, mimetype, content in _file_data: + nodes[org_filename] = { + 'org_filename': org_filename, + 'filename': filename, + 'content': content, + 'lexer': mimetype, + } + try: + GistModel().update( + gist=c.gist, + description=rpost['description'], + owner=c.gist.owner, + gist_mapping=nodes, + gist_type=c.gist.gist_type, + lifetime=rpost['lifetime'], + gist_acl_level=rpost['acl_level'] + ) + + Session().commit() + h.flash(_('Successfully updated gist content'), category='success') + except NodeNotChangedError: + # raised if nothing was changed in repo itself. We anyway then + # store only DB stuff for gist + Session().commit() + h.flash(_('Successfully updated gist data'), category='success') + except Exception: + log.exception("Exception in gist edit") + h.flash(_('Error occurred during update of gist %s') % gist_id, + category='error') + + return redirect(url('gist', gist_id=gist_id)) + + @LoginRequired() + @NotAnonymous() + def edit_form(self, gist_id, format='html'): + """GET /admin/gists/gist_id/edit: Form to edit an existing item""" + # url('edit_gist', gist_id=ID) + self._add_gist_to_context(gist_id) + + owner = c.gist.gist_owner == c.rhodecode_user.user_id + if not (h.HasPermissionAny('hg.admin')() or owner): + raise HTTPForbidden() + + try: + c.file_last_commit, c.files = GistModel().get_gist_files(gist_id) + except VCSError: + log.exception("Exception in gist edit") + raise HTTPNotFound() + + if c.gist.gist_expires == -1: + expiry = _('never') + else: + # this cannot use timeago, since it's used in select2 as a value + expiry = h.age(h.time_to_datetime(c.gist.gist_expires)) + self.__load_defaults( + extra_values=('0', _('%(expiry)s - current value') % {'expiry': expiry})) + return render('admin/gists/edit.html') + + @LoginRequired() + @NotAnonymous() + @jsonify + def check_revision(self, gist_id): + c.gist = Gist.get_or_404(gist_id) + last_rev = c.gist.scm_instance().get_commit() + success = True + revision = request.GET.get('revision') + + ##TODO: maybe move this to model ? + if revision != last_rev.raw_id: + log.error('Last revision %s is different then submitted %s' + % (revision, last_rev)) + # our gist has newer version than we + success = False + + return {'success': success} diff --git a/rhodecode/controllers/admin/my_account.py b/rhodecode/controllers/admin/my_account.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/my_account.py @@ -0,0 +1,373 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +my account controller for RhodeCode admin +""" + +import logging + +import formencode +from formencode import htmlfill +from pylons import request, tmpl_context as c, url, session +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ +from sqlalchemy.orm import joinedload + +from rhodecode.lib import helpers as h +from rhodecode.lib import auth +from rhodecode.lib.auth import ( + LoginRequired, NotAnonymous, AuthUser, generate_auth_token) +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.utils2 import safe_int, md5 +from rhodecode.lib.ext_json import json +from rhodecode.model.db import (Repository, PullRequest, PullRequestReviewers, + UserEmailMap, User, UserFollowing, + ExternalIdentity) +from rhodecode.model.forms import UserForm, PasswordChangeForm +from rhodecode.model.scm import RepoList +from rhodecode.model.user import UserModel +from rhodecode.model.repo import RepoModel +from rhodecode.model.auth_token import AuthTokenModel +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +class MyAccountController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('setting', 'settings', controller='admin/settings', + # path_prefix='/admin', name_prefix='admin_') + + @LoginRequired() + @NotAnonymous() + def __before__(self): + super(MyAccountController, self).__before__() + + def __load_data(self): + c.user = User.get(c.rhodecode_user.user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user since it's" + " crucial for entire application"), category='warning') + return redirect(url('users')) + + def _load_my_repos_data(self, watched=False): + if watched: + admin = False + follows_repos = Session().query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + repo_list = [x.follows_repository for x in follows_repos] + else: + admin = True + repo_list = Repository.get_all_repos( + user_id=c.rhodecode_user.user_id) + repo_list = RepoList(repo_list, perm_set=[ + 'repository.read', 'repository.write', 'repository.admin']) + + repos_data = RepoModel().get_repos_as_dict( + repo_list=repo_list, admin=admin) + # json used to render the grid + return json.dumps(repos_data) + + @auth.CSRFRequired() + def my_account_update(self): + """ + POST /_admin/my_account Updates info of my account + """ + # url('my_account') + c.active = 'profile_edit' + self.__load_data() + c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id, + ip_addr=self.ip_addr) + c.extern_type = c.user.extern_type + c.extern_name = c.user.extern_name + + defaults = c.user.get_dict() + update = False + _form = UserForm(edit=True, + old_data={'user_id': c.rhodecode_user.user_id, + 'email': c.rhodecode_user.email})() + form_result = {} + try: + post_data = dict(request.POST) + post_data['new_password'] = '' + post_data['password_confirmation'] = '' + form_result = _form.to_python(post_data) + # skip updating those attrs for my account + skip_attrs = ['admin', 'active', 'extern_type', 'extern_name', + 'new_password', 'password_confirmation'] + # TODO: plugin should define if username can be updated + if c.extern_type != "rhodecode": + # forbid updating username for external accounts + skip_attrs.append('username') + + UserModel().update_user( + c.rhodecode_user.user_id, skip_attrs=skip_attrs, **form_result) + h.flash(_('Your account was updated successfully'), + category='success') + Session().commit() + update = True + + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/my_account/my_account.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception updating user") + h.flash(_('Error occurred during update of user %s') + % form_result.get('username'), category='error') + + if update: + return redirect('my_account') + + return htmlfill.render( + render('admin/my_account/my_account.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + def my_account(self): + """ + GET /_admin/my_account Displays info about my account + """ + # url('my_account') + c.active = 'profile' + self.__load_data() + + defaults = c.user.get_dict() + return htmlfill.render( + render('admin/my_account/my_account.html'), + defaults=defaults, encoding="UTF-8", force_defaults=False) + + def my_account_edit(self): + """ + GET /_admin/my_account/edit Displays edit form of my account + """ + c.active = 'profile_edit' + self.__load_data() + c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id, + ip_addr=self.ip_addr) + c.extern_type = c.user.extern_type + c.extern_name = c.user.extern_name + + defaults = c.user.get_dict() + return htmlfill.render( + render('admin/my_account/my_account.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @auth.CSRFRequired() + def my_account_password_update(self): + c.active = 'password' + self.__load_data() + _form = PasswordChangeForm(c.rhodecode_user.username)() + try: + form_result = _form.to_python(request.POST) + UserModel().update_user(c.rhodecode_user.user_id, **form_result) + instance = c.rhodecode_user.get_instance() + instance.update_userdata(force_password_change=False) + Session().commit() + session.setdefault('rhodecode_user', {}).update( + {'password': md5(instance.password)}) + session.save() + h.flash(_("Successfully updated password"), category='success') + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/my_account/my_account.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception updating password") + h.flash(_('Error occurred during update of user password'), + category='error') + return render('admin/my_account/my_account.html') + + def my_account_password(self): + c.active = 'password' + self.__load_data() + return render('admin/my_account/my_account.html') + + def my_account_repos(self): + c.active = 'repos' + self.__load_data() + + # json used to render the grid + c.data = self._load_my_repos_data() + return render('admin/my_account/my_account.html') + + def my_account_watched(self): + c.active = 'watched' + self.__load_data() + + # json used to render the grid + c.data = self._load_my_repos_data(watched=True) + return render('admin/my_account/my_account.html') + + def my_account_perms(self): + c.active = 'perms' + self.__load_data() + c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id, + ip_addr=self.ip_addr) + + return render('admin/my_account/my_account.html') + + def my_account_emails(self): + c.active = 'emails' + self.__load_data() + + c.user_email_map = UserEmailMap.query()\ + .filter(UserEmailMap.user == c.user).all() + return render('admin/my_account/my_account.html') + + @auth.CSRFRequired() + def my_account_emails_add(self): + email = request.POST.get('new_email') + + try: + UserModel().add_extra_email(c.rhodecode_user.user_id, email) + Session().commit() + h.flash(_("Added new email address `%s` for user account") % email, + category='success') + except formencode.Invalid as error: + msg = error.error_dict['email'] + h.flash(msg, category='error') + except Exception: + log.exception("Exception in my_account_emails") + h.flash(_('An error occurred during email saving'), + category='error') + return redirect(url('my_account_emails')) + + @auth.CSRFRequired() + def my_account_emails_delete(self): + email_id = request.POST.get('del_email_id') + user_model = UserModel() + user_model.delete_extra_email(c.rhodecode_user.user_id, email_id) + Session().commit() + h.flash(_("Removed email address from user account"), + category='success') + return redirect(url('my_account_emails')) + + def my_account_pullrequests(self): + c.active = 'pullrequests' + self.__load_data() + c.show_closed = request.GET.get('pr_show_closed') + + def _filter(pr): + s = sorted(pr, key=lambda o: o.created_on, reverse=True) + if not c.show_closed: + s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s) + return s + + c.my_pull_requests = _filter( + PullRequest.query().filter( + PullRequest.user_id == c.rhodecode_user.user_id).all()) + my_prs = [ + x.pull_request for x in PullRequestReviewers.query().filter( + PullRequestReviewers.user_id == c.rhodecode_user.user_id).all()] + c.participate_in_pull_requests = _filter(my_prs) + return render('admin/my_account/my_account.html') + + def my_account_auth_tokens(self): + c.active = 'auth_tokens' + self.__load_data() + show_expired = True + c.lifetime_values = [ + (str(-1), _('forever')), + (str(5), _('5 minutes')), + (str(60), _('1 hour')), + (str(60 * 24), _('1 day')), + (str(60 * 24 * 30), _('1 month')), + ] + c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] + c.role_values = [(x, AuthTokenModel.cls._get_role_name(x)) + for x in AuthTokenModel.cls.ROLES] + c.role_options = [(c.role_values, _("Role"))] + c.user_auth_tokens = AuthTokenModel().get_auth_tokens( + c.rhodecode_user.user_id, show_expired=show_expired) + return render('admin/my_account/my_account.html') + + @auth.CSRFRequired() + def my_account_auth_tokens_add(self): + lifetime = safe_int(request.POST.get('lifetime'), -1) + description = request.POST.get('description') + role = request.POST.get('role') + AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime, + role) + Session().commit() + h.flash(_("Auth token successfully created"), category='success') + return redirect(url('my_account_auth_tokens')) + + @auth.CSRFRequired() + def my_account_auth_tokens_delete(self): + auth_token = request.POST.get('del_auth_token') + user_id = c.rhodecode_user.user_id + if request.POST.get('del_auth_token_builtin'): + user = User.get(user_id) + if user: + user.api_key = generate_auth_token(user.username) + Session().add(user) + Session().commit() + h.flash(_("Auth token successfully reset"), category='success') + elif auth_token: + AuthTokenModel().delete(auth_token, c.rhodecode_user.user_id) + Session().commit() + h.flash(_("Auth token successfully deleted"), category='success') + + return redirect(url('my_account_auth_tokens')) + + def my_account_oauth(self): + c.active = 'oauth' + self.__load_data() + c.user_oauth_tokens = ExternalIdentity().by_local_user_id( + c.rhodecode_user.user_id).all() + settings = SettingsModel().get_all_settings() + c.social_plugins = SettingsModel().list_enabled_social_plugins( + settings) + return render('admin/my_account/my_account.html') + + @auth.CSRFRequired() + def my_account_oauth_delete(self): + token = ExternalIdentity.by_external_id_and_provider( + request.params.get('external_id'), + request.params.get('provider_name'), + local_user_id=c.rhodecode_user.user_id + ) + if token: + Session().delete(token) + Session().commit() + h.flash(_("OAuth token successfully deleted"), category='success') + + return redirect(url('my_account_oauth')) diff --git a/rhodecode/controllers/admin/notifications.py b/rhodecode/controllers/admin/notifications.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/notifications.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +notifications controller for RhodeCode +""" + +import logging +import traceback + +from pylons import request +from pylons import tmpl_context as c, url +from pylons.controllers.util import redirect, abort +import webhelpers.paginate +from webob.exc import HTTPBadRequest + +from rhodecode.lib import auth +from rhodecode.lib.auth import LoginRequired, NotAnonymous +from rhodecode.lib.base import BaseController, render +from rhodecode.lib import helpers as h +from rhodecode.lib.helpers import Page +from rhodecode.lib.utils2 import safe_int +from rhodecode.model.db import Notification +from rhodecode.model.notification import NotificationModel +from rhodecode.model.meta import Session + + +log = logging.getLogger(__name__) + + +class NotificationsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('notification', 'notifications', controller='_admin/notifications', + # path_prefix='/_admin', name_prefix='_admin_') + + @LoginRequired() + @NotAnonymous() + def __before__(self): + super(NotificationsController, self).__before__() + + def index(self): + """GET /_admin/notifications: All items in the collection""" + # url('notifications') + c.user = c.rhodecode_user + notif = NotificationModel().get_for_user(c.rhodecode_user.user_id, + filter_=request.GET.getall('type')) + + p = safe_int(request.GET.get('page', 1), 1) + notifications_url = webhelpers.paginate.PageURL( + url('notifications'), request.GET) + c.notifications = Page(notif, page=p, items_per_page=10, + url=notifications_url) + c.pull_request_type = Notification.TYPE_PULL_REQUEST + c.comment_type = [Notification.TYPE_CHANGESET_COMMENT, + Notification.TYPE_PULL_REQUEST_COMMENT] + + _current_filter = request.GET.getall('type') + c.current_filter = 'all' + if _current_filter == [c.pull_request_type]: + c.current_filter = 'pull_request' + elif _current_filter == c.comment_type: + c.current_filter = 'comment' + + if request.is_xhr: + return render('admin/notifications/notifications_data.html') + + return render('admin/notifications/notifications.html') + + @auth.CSRFRequired() + def mark_all_read(self): + if request.is_xhr: + nm = NotificationModel() + # mark all read + nm.mark_all_read_for_user(c.rhodecode_user.user_id, + filter_=request.GET.getall('type')) + Session().commit() + c.user = c.rhodecode_user + notif = nm.get_for_user(c.rhodecode_user.user_id, + filter_=request.GET.getall('type')) + notifications_url = webhelpers.paginate.PageURL( + url('notifications'), request.GET) + c.notifications = Page(notif, page=1, items_per_page=10, + url=notifications_url) + return render('admin/notifications/notifications_data.html') + + def _has_permissions(self, notification): + def is_owner(): + user_id = c.rhodecode_user.user_id + for user_notification in notification.notifications_to_users: + if user_notification.user.user_id == user_id: + return True + return False + return h.HasPermissionAny('hg.admin')() or is_owner() + + @auth.CSRFRequired() + def update(self, notification_id): + """PUT /_admin/notifications/id: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('notification', notification_id=ID), + # method='put') + # url('notification', notification_id=ID) + try: + no = Notification.get(notification_id) + if self._has_permissions(no): + # deletes only notification2user + NotificationModel().mark_read(c.rhodecode_user.user_id, no) + Session().commit() + return 'ok' + except Exception: + Session().rollback() + log.exception("Exception updating a notification item") + raise HTTPBadRequest() + + @auth.CSRFRequired() + def delete(self, notification_id): + """DELETE /_admin/notifications/id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('notification', notification_id=ID), + # method='delete') + # url('notification', notification_id=ID) + try: + no = Notification.get(notification_id) + if self._has_permissions(no): + # deletes only notification2user + NotificationModel().delete(c.rhodecode_user.user_id, no) + Session().commit() + return 'ok' + except Exception: + Session().rollback() + log.exception("Exception deleting a notification item") + raise HTTPBadRequest() + + def show(self, notification_id): + """GET /_admin/notifications/id: Show a specific item""" + # url('notification', notification_id=ID) + c.user = c.rhodecode_user + no = Notification.get(notification_id) + + if no and self._has_permissions(no): + unotification = NotificationModel()\ + .get_user_notification(c.user.user_id, no) + + # if this association to user is not valid, we don't want to show + # this message + if unotification: + if not unotification.read: + unotification.mark_as_read() + Session().commit() + c.notification = no + + return render('admin/notifications/show_notification.html') + + return abort(403) diff --git a/rhodecode/controllers/admin/permissions.py b/rhodecode/controllers/admin/permissions.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/permissions.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +permissions controller for RhodeCode Enterprise +""" + + +import logging + +import formencode +from formencode import htmlfill +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +from rhodecode.lib import helpers as h +from rhodecode.lib import auth +from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator) +from rhodecode.lib.base import BaseController, render +from rhodecode.model.db import User, UserIpMap +from rhodecode.model.forms import ( + ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm) +from rhodecode.model.meta import Session +from rhodecode.model.permission import PermissionModel +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +class PermissionsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('permission', 'permissions') + + @LoginRequired() + def __before__(self): + super(PermissionsController, self).__before__() + + def __load_data(self): + PermissionModel().set_global_permission_choices(c, translator=_) + + @HasPermissionAllDecorator('hg.admin') + def permission_application(self): + c.active = 'application' + self.__load_data() + + c.user = User.get_default_user() + + # TODO: johbo: The default user might be based on outdated state which + # has been loaded from the cache. A call to refresh() ensures that the + # latest state from the database is used. + Session().refresh(c.user) + + app_settings = SettingsModel().get_all_settings() + defaults = { + 'anonymous': c.user.active, + 'default_register_message': app_settings.get( + 'rhodecode_register_message') + } + defaults.update(c.user.get_default_perms()) + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def permission_application_update(self): + c.active = 'application' + self.__load_data() + _form = ApplicationPermissionsForm( + [x[0] for x in c.register_choices], + [x[0] for x in c.extern_activate_choices])() + + try: + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_name': User.DEFAULT_USER}) + PermissionModel().update_application_permissions(form_result) + + settings = [ + ('register_message', 'default_register_message'), + ] + for setting, form_key in settings: + sett = SettingsModel().create_or_update_setting( + setting, form_result[form_key]) + Session().add(sett) + + Session().commit() + h.flash(_('Application permissions updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during update of permissions") + h.flash(_('Error occurred during update of permissions'), + category='error') + + return redirect(url('admin_permissions_application')) + + @HasPermissionAllDecorator('hg.admin') + def permission_objects(self): + c.active = 'objects' + self.__load_data() + c.user = User.get_default_user() + defaults = {} + defaults.update(c.user.get_default_perms()) + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def permission_objects_update(self): + c.active = 'objects' + self.__load_data() + _form = ObjectPermissionsForm( + [x[0] for x in c.repo_perms_choices], + [x[0] for x in c.group_perms_choices], + [x[0] for x in c.user_group_perms_choices])() + + try: + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_name': User.DEFAULT_USER}) + PermissionModel().update_object_permissions(form_result) + + Session().commit() + h.flash(_('Object permissions updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during update of permissions") + h.flash(_('Error occurred during update of permissions'), + category='error') + + return redirect(url('admin_permissions_object')) + + @HasPermissionAllDecorator('hg.admin') + def permission_global(self): + c.active = 'global' + self.__load_data() + + c.user = User.get_default_user() + defaults = {} + defaults.update(c.user.get_default_perms()) + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def permission_global_update(self): + c.active = 'global' + self.__load_data() + _form = UserPermissionsForm( + [x[0] for x in c.repo_create_choices], + [x[0] for x in c.repo_create_on_write_choices], + [x[0] for x in c.repo_group_create_choices], + [x[0] for x in c.user_group_create_choices], + [x[0] for x in c.fork_choices], + [x[0] for x in c.inherit_default_permission_choices])() + + try: + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_name': User.DEFAULT_USER}) + PermissionModel().update_user_permissions(form_result) + + Session().commit() + h.flash(_('Global permissions updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during update of permissions") + h.flash(_('Error occurred during update of permissions'), + category='error') + + return redirect(url('admin_permissions_global')) + + @HasPermissionAllDecorator('hg.admin') + def permission_ips(self): + c.active = 'ips' + c.user = User.get_default_user() + c.user_ip_map = ( + UserIpMap.query().filter(UserIpMap.user == c.user).all()) + + return render('admin/permissions/permissions.html') + + @HasPermissionAllDecorator('hg.admin') + def permission_perms(self): + c.active = 'perms' + c.user = User.get_default_user() + c.perm_user = c.user.AuthUser + return render('admin/permissions/permissions.html') diff --git a/rhodecode/controllers/admin/repo_groups.py b/rhodecode/controllers/admin/repo_groups.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/repo_groups.py @@ -0,0 +1,407 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Repository groups controller for RhodeCode +""" + +import logging +import formencode + +from formencode import htmlfill + +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _, ungettext + +from rhodecode.lib import auth +from rhodecode.lib import helpers as h +from rhodecode.lib.ext_json import json +from rhodecode.lib.auth import ( + LoginRequired, NotAnonymous, HasPermissionAll, + HasRepoGroupPermissionAll, HasRepoGroupPermissionAnyDecorator) +from rhodecode.lib.base import BaseController, render +from rhodecode.model.db import RepoGroup, User +from rhodecode.model.scm import RepoGroupList +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.forms import RepoGroupForm, RepoGroupPermsForm +from rhodecode.model.meta import Session +from rhodecode.lib.utils2 import safe_int + + +log = logging.getLogger(__name__) + + +class RepoGroupsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + + @LoginRequired() + def __before__(self): + super(RepoGroupsController, self).__before__() + + def __load_defaults(self, allow_empty_group=False, repo_group=None): + if self._can_create_repo_group(): + # we're global admin, we're ok and we can create TOP level groups + allow_empty_group = True + + # override the choices for this form, we need to filter choices + # and display only those we have ADMIN right + groups_with_admin_rights = RepoGroupList( + RepoGroup.query().all(), + perm_set=['group.admin']) + c.repo_groups = RepoGroup.groups_choices( + groups=groups_with_admin_rights, + show_empty_group=allow_empty_group) + + if repo_group: + # exclude filtered ids + exclude_group_ids = [repo_group.group_id] + c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids, + c.repo_groups) + c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) + parent_group = repo_group.parent_group + + add_parent_group = (parent_group and ( + unicode(parent_group.group_id) not in c.repo_groups_choices)) + if add_parent_group: + c.repo_groups_choices.append(unicode(parent_group.group_id)) + c.repo_groups.append(RepoGroup._generate_choice(parent_group)) + + def __load_data(self, group_id): + """ + Load defaults settings for edit, and update + + :param group_id: + """ + repo_group = RepoGroup.get_or_404(group_id) + data = repo_group.get_dict() + data['group_name'] = repo_group.name + + # fill owner + if repo_group.user: + data.update({'user': repo_group.user.username}) + else: + replacement_user = User.get_first_admin().username + data.update({'user': replacement_user}) + + # fill repository group users + for p in repo_group.repo_group_to_perm: + data.update({ + 'u_perm_%s' % p.user.user_id: p.permission.permission_name}) + + # fill repository group user groups + for p in repo_group.users_group_to_perm: + data.update({ + 'g_perm_%s' % p.users_group.users_group_id: + p.permission.permission_name}) + # html and form expects -1 as empty parent group + data['group_parent_id'] = data['group_parent_id'] or -1 + return data + + def _revoke_perms_on_yourself(self, form_result): + _updates = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_updates']) + _additions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_additions']) + _deletions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_deletions']) + admin_perm = 'group.admin' + if _updates and _updates[0][1] != admin_perm or \ + _additions and _additions[0][1] != admin_perm or \ + _deletions and _deletions[0][1] != admin_perm: + return True + return False + + def _can_create_repo_group(self, parent_group_id=None): + is_admin = HasPermissionAll('hg.admin')('group create controller') + create_repo_group = HasPermissionAll( + 'hg.repogroup.create.true')('group create controller') + if is_admin or (create_repo_group and not parent_group_id): + # we're global admin, or we have global repo group create + # permission + # we're ok and we can create TOP level groups + return True + elif parent_group_id: + # we check the permission if we can write to parent group + group = RepoGroup.get(parent_group_id) + group_name = group.group_name if group else None + if HasRepoGroupPermissionAll('group.admin')( + group_name, 'check if user is an admin of group'): + # we're an admin of passed in group, we're ok. + return True + else: + return False + return False + + @NotAnonymous() + def index(self): + """GET /repo_groups: All items in the collection""" + # url('repo_groups') + + repo_group_list = RepoGroup.get_all_repo_groups() + _perms = ['group.admin'] + repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms) + repo_group_data = RepoGroupModel().get_repo_groups_as_dict( + repo_group_list=repo_group_list_acl, admin=True) + c.data = json.dumps(repo_group_data) + return render('admin/repo_groups/repo_groups.html') + + # perm checks inside + @NotAnonymous() + @auth.CSRFRequired() + def create(self): + """POST /repo_groups: Create a new item""" + # url('repo_groups') + + parent_group_id = safe_int(request.POST.get('group_parent_id')) + can_create = self._can_create_repo_group(parent_group_id) + + self.__load_defaults() + # permissions for can create group based on parent_id are checked + # here in the Form + available_groups = map(lambda k: unicode(k[0]), c.repo_groups) + repo_group_form = RepoGroupForm(available_groups=available_groups, + can_create_in_root=can_create)() + try: + owner = c.rhodecode_user + form_result = repo_group_form.to_python(dict(request.POST)) + RepoGroupModel().create( + group_name=form_result['group_name_full'], + group_description=form_result['group_description'], + owner=owner.user_id, + copy_permissions=form_result['group_copy_permissions'] + ) + Session().commit() + _new_group_name = form_result['group_name_full'] + repo_group_url = h.link_to( + _new_group_name, + h.url('repo_group_home', group_name=_new_group_name)) + h.flash(h.literal(_('Created repository group %s') + % repo_group_url), category='success') + # TODO: in futureaction_logger(, '', '', '', self.sa) + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/repo_groups/repo_group_add.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during creation of repository group") + h.flash(_('Error occurred during creation of repository group %s') + % request.POST.get('group_name'), category='error') + + # TODO: maybe we should get back to the main view, not the admin one + return redirect(url('repo_groups', parent_group=parent_group_id)) + + # perm checks inside + @NotAnonymous() + def new(self): + """GET /repo_groups/new: Form to create a new item""" + # url('new_repo_group') + # perm check for admin, create_group perm or admin of parent_group + parent_group_id = safe_int(request.GET.get('parent_group')) + if not self._can_create_repo_group(parent_group_id): + return abort(403) + + self.__load_defaults() + return render('admin/repo_groups/repo_group_add.html') + + @HasRepoGroupPermissionAnyDecorator('group.admin') + @auth.CSRFRequired() + def update(self, group_name): + """PUT /repo_groups/group_name: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('repos_group', group_name=GROUP_NAME), method='put') + # url('repo_group_home', group_name=GROUP_NAME) + + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + can_create_in_root = self._can_create_repo_group() + show_root_location = can_create_in_root + if not c.repo_group.parent_group: + # this group don't have a parrent so we should show empty value + show_root_location = True + self.__load_defaults(allow_empty_group=show_root_location, + repo_group=c.repo_group) + + repo_group_form = RepoGroupForm( + edit=True, + old_data=c.repo_group.get_dict(), + available_groups=c.repo_groups_choices, + can_create_in_root=can_create_in_root, + )() + try: + form_result = repo_group_form.to_python(dict(request.POST)) + gr_name = form_result['group_name'] + new_gr = RepoGroupModel().update(group_name, form_result) + Session().commit() + h.flash(_('Updated repository group %s') % (gr_name,), + category='success') + # we now have new name ! + group_name = new_gr.group_name + # TODO: in future action_logger(, '', '', '', self.sa) + except formencode.Invalid as errors: + c.active = 'settings' + return htmlfill.render( + render('admin/repo_groups/repo_group_edit.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during update or repository group") + h.flash(_('Error occurred during update of repository group %s') + % request.POST.get('group_name'), category='error') + + return redirect(url('edit_repo_group', group_name=group_name)) + + @HasRepoGroupPermissionAnyDecorator('group.admin') + @auth.CSRFRequired() + def delete(self, group_name): + """DELETE /repo_groups/group_name: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('repos_group', group_name=GROUP_NAME), method='delete') + # url('repo_group_home', group_name=GROUP_NAME) + + gr = c.repo_group = RepoGroupModel()._get_repo_group(group_name) + repos = gr.repositories.all() + if repos: + msg = ungettext( + 'This group contains %(num)d repository and cannot be deleted', + 'This group contains %(num)d repositories and cannot be' + ' deleted', + len(repos)) % {'num': len(repos)} + h.flash(msg, category='warning') + return redirect(url('repo_groups')) + + children = gr.children.all() + if children: + msg = ungettext( + 'This group contains %(num)d subgroup and cannot be deleted', + 'This group contains %(num)d subgroups and cannot be deleted', + len(children)) % {'num': len(children)} + h.flash(msg, category='warning') + return redirect(url('repo_groups')) + + try: + RepoGroupModel().delete(group_name) + Session().commit() + h.flash(_('Removed repository group %s') % group_name, + category='success') + # TODO: in future action_logger(, '', '', '', self.sa) + except Exception: + log.exception("Exception during deletion of repository group") + h.flash(_('Error occurred during deletion of repository group %s') + % group_name, category='error') + + return redirect(url('repo_groups')) + + @HasRepoGroupPermissionAnyDecorator('group.admin') + def edit(self, group_name): + """GET /repo_groups/group_name/edit: Form to edit an existing item""" + # url('edit_repo_group', group_name=GROUP_NAME) + c.active = 'settings' + + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + # we can only allow moving empty group if it's already a top-level + # group, ie has no parents, or we're admin + can_create_in_root = self._can_create_repo_group() + show_root_location = can_create_in_root + if not c.repo_group.parent_group: + # this group don't have a parrent so we should show empty value + show_root_location = True + self.__load_defaults(allow_empty_group=show_root_location, + repo_group=c.repo_group) + defaults = self.__load_data(c.repo_group.group_id) + + return htmlfill.render( + render('admin/repo_groups/repo_group_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasRepoGroupPermissionAnyDecorator('group.admin') + def edit_repo_group_advanced(self, group_name): + """GET /repo_groups/group_name/edit: Form to edit an existing item""" + # url('edit_repo_group', group_name=GROUP_NAME) + c.active = 'advanced' + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + + return render('admin/repo_groups/repo_group_edit.html') + + @HasRepoGroupPermissionAnyDecorator('group.admin') + def edit_repo_group_perms(self, group_name): + """GET /repo_groups/group_name/edit: Form to edit an existing item""" + # url('edit_repo_group', group_name=GROUP_NAME) + c.active = 'perms' + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + self.__load_defaults() + defaults = self.__load_data(c.repo_group.group_id) + + return htmlfill.render( + render('admin/repo_groups/repo_group_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasRepoGroupPermissionAnyDecorator('group.admin') + @auth.CSRFRequired() + def update_perms(self, group_name): + """ + Update permissions for given repository group + + :param group_name: + """ + + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + valid_recursive_choices = ['none', 'repos', 'groups', 'all'] + form = RepoGroupPermsForm(valid_recursive_choices)().to_python( + request.POST) + + if not c.rhodecode_user.is_admin: + if self._revoke_perms_on_yourself(form): + msg = _('Cannot change permission for yourself as admin') + h.flash(msg, category='warning') + return redirect( + url('edit_repo_group_perms', group_name=group_name)) + + # iterate over all members(if in recursive mode) of this groups and + # set the permissions ! + # this can be potentially heavy operation + RepoGroupModel().update_permissions( + c.repo_group, + form['perm_additions'], form['perm_updates'], + form['perm_deletions'], form['recursive']) + + # TODO: implement this + # action_logger(c.rhodecode_user, 'admin_changed_repo_permissions', + # repo_name, self.ip_addr, self.sa) + Session().commit() + h.flash(_('Repository Group permissions updated'), category='success') + return redirect(url('edit_repo_group_perms', group_name=group_name)) diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/repos.py @@ -0,0 +1,878 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Repositories controller for RhodeCode +""" + +import logging +import traceback + +import formencode +from formencode import htmlfill +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ +from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest + +from rhodecode.lib import auth, helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasPermissionAllDecorator, + HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny, + HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator) +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.ext_json import json +from rhodecode.lib.exceptions import AttachedForksError +from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify +from rhodecode.lib.utils2 import safe_int +from rhodecode.lib.vcs import RepositoryError +from rhodecode.model.db import ( + User, Repository, UserFollowing, RepoGroup, RepositoryField) +from rhodecode.model.forms import ( + RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm, + IssueTrackerPatternsForm) +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList +from rhodecode.model.settings import ( + SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel, + SettingNotFound) + +log = logging.getLogger(__name__) + + +class ReposController(BaseRepoController): + """ + REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('repo', 'repos') + + @LoginRequired() + def __before__(self): + super(ReposController, self).__before__() + + def _load_repo(self, repo_name): + repo_obj = Repository.get_by_repo_name(repo_name) + + if repo_obj is None: + h.not_mapped_error(repo_name) + return redirect(url('repos')) + + return repo_obj + + def __load_defaults(self, repo=None): + acl_groups = RepoGroupList(RepoGroup.query().all(), + perm_set=['group.write', 'group.admin']) + c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) + c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) + + # in case someone no longer have a group.write access to a repository + # pre fill the list with this entry, we don't care if this is the same + # but it will allow saving repo data properly. + + repo_group = None + if repo: + repo_group = repo.group + if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices: + c.repo_groups_choices.append(unicode(repo_group.group_id)) + c.repo_groups.append(RepoGroup._generate_choice(repo_group)) + + choices, c.landing_revs = ScmModel().get_repo_landing_revs() + c.landing_revs_choices = choices + + def __load_data(self, repo_name=None): + """ + Load defaults settings for edit, and update + + :param repo_name: + """ + c.repo_info = self._load_repo(repo_name) + self.__load_defaults(c.repo_info) + + # override defaults for exact repo info here git/hg etc + if not c.repository_requirements_missing: + choices, c.landing_revs = ScmModel().get_repo_landing_revs( + c.repo_info) + c.landing_revs_choices = choices + defaults = RepoModel()._get_defaults(repo_name) + + return defaults + + def _log_creation_exception(self, e, repo_name): + reason = None + if len(e.args) == 2: + reason = e.args[1] + + if reason == 'INVALID_CERTIFICATE': + log.exception( + 'Exception creating a repository: invalid certificate') + msg = (_('Error creating repository %s: invalid certificate') + % repo_name) + else: + log.exception("Exception creating a repository") + msg = (_('Error creating repository %s') + % repo_name) + + return msg + + @NotAnonymous() + def index(self, format='html'): + """GET /repos: All items in the collection""" + # url('repos') + + repo_list = Repository.get_all_repos() + c.repo_list = RepoList(repo_list, perm_set=['repository.admin']) + repos_data = RepoModel().get_repos_as_dict( + repo_list=c.repo_list, admin=True, super_user_actions=True) + # json used to render the grid + c.data = json.dumps(repos_data) + + return render('admin/repos/repos.html') + + # perms check inside + @NotAnonymous() + @auth.CSRFRequired() + def create(self): + """ + POST /repos: Create a new item""" + # url('repos') + + self.__load_defaults() + form_result = {} + task_id = None + try: + # CanWriteToGroup validators checks permissions of this POST + form_result = RepoForm(repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)()\ + .to_python(dict(request.POST)) + + # create is done sometimes async on celery, db transaction + # management is handled there. + task = RepoModel().create(form_result, c.rhodecode_user.user_id) + from celery.result import BaseAsyncResult + if isinstance(task, BaseAsyncResult): + task_id = task.task_id + except formencode.Invalid as errors: + c.personal_repo_group = RepoGroup.get_by_group_name( + c.rhodecode_user.username) + return htmlfill.render( + render('admin/repos/repo_add.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + except Exception as e: + msg = self._log_creation_exception(e, form_result.get('repo_name')) + h.flash(msg, category='error') + return redirect(url('home')) + + return redirect(h.url('repo_creating_home', + repo_name=form_result['repo_name_full'], + task_id=task_id)) + + # perms check inside + @NotAnonymous() + def create_repository(self): + """GET /_admin/create_repository: Form to create a new item""" + new_repo = request.GET.get('repo', '') + parent_group = request.GET.get('parent_group') + if not HasPermissionAny('hg.admin', 'hg.create.repository')(): + # you're not super admin nor have global create permissions, + # but maybe you have at least write permission to a parent group ? + _gr = RepoGroup.get(parent_group) + gr_name = _gr.group_name if _gr else None + # create repositories with write permission on group is set to true + create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() + group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name) + group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name) + if not (group_admin or (group_write and create_on_write)): + raise HTTPForbidden + + acl_groups = RepoGroupList(RepoGroup.query().all(), + perm_set=['group.write', 'group.admin']) + c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) + c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) + choices, c.landing_revs = ScmModel().get_repo_landing_revs() + c.personal_repo_group = RepoGroup.get_by_group_name(c.rhodecode_user.username) + c.new_repo = repo_name_slug(new_repo) + + ## apply the defaults from defaults page + defaults = SettingsModel().get_default_repo_settings(strip_prefix=True) + # set checkbox to autochecked + defaults['repo_copy_permissions'] = True + if parent_group: + defaults.update({'repo_group': parent_group}) + + return htmlfill.render( + render('admin/repos/repo_add.html'), + defaults=defaults, + errors={}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + + @NotAnonymous() + def repo_creating(self, repo_name): + c.repo = repo_name + c.task_id = request.GET.get('task_id') + if not c.repo: + raise HTTPNotFound() + return render('admin/repos/repo_creating.html') + + @NotAnonymous() + @jsonify + def repo_check(self, repo_name): + c.repo = repo_name + task_id = request.GET.get('task_id') + + if task_id and task_id not in ['None']: + from rhodecode import CELERY_ENABLED + from celery.result import AsyncResult + if CELERY_ENABLED: + task = AsyncResult(task_id) + if task.failed(): + msg = self._log_creation_exception(task.result, c.repo) + h.flash(msg, category='error') + return redirect(url('home'), code=501) + + repo = Repository.get_by_repo_name(repo_name) + if repo and repo.repo_state == Repository.STATE_CREATED: + if repo.clone_uri: + clone_uri = repo.clone_uri_hidden + h.flash(_('Created repository %s from %s') + % (repo.repo_name, clone_uri), category='success') + else: + repo_url = h.link_to(repo.repo_name, + h.url('summary_home', + repo_name=repo.repo_name)) + fork = repo.fork + if fork: + fork_name = fork.repo_name + h.flash(h.literal(_('Forked repository %s as %s') + % (fork_name, repo_url)), category='success') + else: + h.flash(h.literal(_('Created repository %s') % repo_url), + category='success') + return {'result': True} + return {'result': False} + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def update(self, repo_name): + """ + PUT /repos/repo_name: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('repo', repo_name=ID), + # method='put') + # url('repo', repo_name=ID) + + self.__load_data(repo_name) + c.active = 'settings' + c.repo_fields = RepositoryField.query()\ + .filter(RepositoryField.repository == c.repo_info).all() + + repo_model = RepoModel() + changed_name = repo_name + + # override the choices with extracted revisions ! + c.personal_repo_group = RepoGroup.get_by_group_name( + c.rhodecode_user.username) + repo = Repository.get_by_repo_name(repo_name) + old_data = { + 'repo_name': repo_name, + 'repo_group': repo.group.get_dict() if repo.group else {}, + 'repo_type': repo.repo_type, + } + _form = RepoForm(edit=True, old_data=old_data, + repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)() + + try: + form_result = _form.to_python(dict(request.POST)) + repo = repo_model.update(repo_name, **form_result) + ScmModel().mark_for_invalidation(repo_name) + h.flash(_('Repository %s updated successfully') % repo_name, + category='success') + changed_name = repo.repo_name + action_logger(c.rhodecode_user, 'admin_updated_repo', + changed_name, self.ip_addr, self.sa) + Session().commit() + except formencode.Invalid as errors: + defaults = self.__load_data(repo_name) + defaults.update(errors.value) + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + except Exception: + log.exception("Exception during update of repository") + h.flash(_('Error occurred during update of repository %s') \ + % repo_name, category='error') + return redirect(url('edit_repo', repo_name=changed_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def delete(self, repo_name): + """ + DELETE /repos/repo_name: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('repo', repo_name=ID), + # method='delete') + # url('repo', repo_name=ID) + + repo_model = RepoModel() + repo = repo_model.get_by_repo_name(repo_name) + if not repo: + h.not_mapped_error(repo_name) + return redirect(url('repos')) + try: + _forks = repo.forks.count() + handle_forks = None + if _forks and request.POST.get('forks'): + do = request.POST['forks'] + if do == 'detach_forks': + handle_forks = 'detach' + h.flash(_('Detached %s forks') % _forks, category='success') + elif do == 'delete_forks': + handle_forks = 'delete' + h.flash(_('Deleted %s forks') % _forks, category='success') + repo_model.delete(repo, forks=handle_forks) + action_logger(c.rhodecode_user, 'admin_deleted_repo', + repo_name, self.ip_addr, self.sa) + ScmModel().mark_for_invalidation(repo_name) + h.flash(_('Deleted repository %s') % repo_name, category='success') + Session().commit() + except AttachedForksError: + h.flash(_('Cannot delete %s it still contains attached forks') + % repo_name, category='warning') + + except Exception: + log.exception("Exception during deletion of repository") + h.flash(_('An error occurred during deletion of %s') % repo_name, + category='error') + + return redirect(url('repos')) + + @HasPermissionAllDecorator('hg.admin') + def show(self, repo_name, format='html'): + """GET /repos/repo_name: Show a specific item""" + # url('repo', repo_name=ID) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + defaults = self.__load_data(repo_name) + if 'clone_uri' in defaults: + del defaults['clone_uri'] + + c.repo_fields = RepositoryField.query()\ + .filter(RepositoryField.repository == c.repo_info).all() + c.personal_repo_group = RepoGroup.get_by_group_name( + c.rhodecode_user.username) + c.active = 'settings' + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_permissions(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + c.active = 'permissions' + defaults = RepoModel()._get_defaults(repo_name) + + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_permissions_update(self, repo_name): + form = RepoPermsForm()().to_python(request.POST) + RepoModel().update_permissions(repo_name, + form['perm_additions'], form['perm_updates'], form['perm_deletions']) + + #TODO: implement this + #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions', + # repo_name, self.ip_addr, self.sa) + Session().commit() + h.flash(_('Repository permissions updated'), category='success') + return redirect(url('edit_repo_perms', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_fields(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + c.repo_fields = RepositoryField.query()\ + .filter(RepositoryField.repository == c.repo_info).all() + c.active = 'fields' + if request.POST: + + return redirect(url('repo_edit_fields')) + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def create_repo_field(self, repo_name): + try: + form_result = RepoFieldForm()().to_python(dict(request.POST)) + RepoModel().add_repo_field( + repo_name, form_result['new_field_key'], + field_type=form_result['new_field_type'], + field_value=form_result['new_field_value'], + field_label=form_result['new_field_label'], + field_desc=form_result['new_field_desc']) + + Session().commit() + except Exception as e: + log.exception("Exception creating field") + msg = _('An error occurred during creation of field') + if isinstance(e, formencode.Invalid): + msg += ". " + e.msg + h.flash(msg, category='error') + return redirect(url('edit_repo_fields', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def delete_repo_field(self, repo_name, field_id): + field = RepositoryField.get_or_404(field_id) + try: + RepoModel().delete_repo_field(repo_name, field.field_key) + Session().commit() + except Exception as e: + log.exception("Exception during removal of field") + msg = _('An error occurred during removal of field') + h.flash(msg, category='error') + return redirect(url('edit_repo_fields', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_advanced(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + c.default_user_id = User.get_default_user().user_id + c.in_public_journal = UserFollowing.query()\ + .filter(UserFollowing.user_id == c.default_user_id)\ + .filter(UserFollowing.follows_repository == c.repo_info).scalar() + + c.active = 'advanced' + c.has_origin_repo_read_perm = False + if c.repo_info.fork: + c.has_origin_repo_read_perm = h.HasRepoPermissionAny( + 'repository.write', 'repository.read', 'repository.admin')( + c.repo_info.fork.repo_name, 'repo set as fork page') + + if request.POST: + return redirect(url('repo_edit_advanced')) + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_advanced_journal(self, repo_name): + """ + Set's this repository to be visible in public journal, + in other words assing default user to follow this repo + + :param repo_name: + """ + + try: + repo_id = Repository.get_by_repo_name(repo_name).repo_id + user_id = User.get_default_user().user_id + self.scm_model.toggle_following_repo(repo_id, user_id) + h.flash(_('Updated repository visibility in public journal'), + category='success') + Session().commit() + except Exception: + h.flash(_('An error occurred during setting this' + ' repository in public journal'), + category='error') + + return redirect(url('edit_repo_advanced', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_advanced_fork(self, repo_name): + """ + Mark given repository as a fork of another + + :param repo_name: + """ + + new_fork_id = request.POST.get('id_fork_of') + try: + + if new_fork_id and not new_fork_id.isdigit(): + log.error('Given fork id %s is not an INT', new_fork_id) + + fork_id = safe_int(new_fork_id) + repo = ScmModel().mark_as_fork(repo_name, fork_id, + c.rhodecode_user.username) + fork = repo.fork.repo_name if repo.fork else _('Nothing') + Session().commit() + h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork), + category='success') + except RepositoryError as e: + log.exception("Repository Error occurred") + h.flash(str(e), category='error') + except Exception as e: + log.exception("Exception while editing fork") + h.flash(_('An error occurred during this operation'), + category='error') + + return redirect(url('edit_repo_advanced', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_advanced_locking(self, repo_name): + """ + Unlock repository when it is locked ! + + :param repo_name: + """ + try: + repo = Repository.get_by_repo_name(repo_name) + if request.POST.get('set_lock'): + Repository.lock(repo, c.rhodecode_user.user_id, + lock_reason=Repository.LOCK_WEB) + h.flash(_('Locked repository'), category='success') + elif request.POST.get('set_unlock'): + Repository.unlock(repo) + h.flash(_('Unlocked repository'), category='success') + except Exception as e: + log.exception("Exception during unlocking") + h.flash(_('An error occurred during unlocking'), + category='error') + return redirect(url('edit_repo_advanced', repo_name=repo_name)) + + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @auth.CSRFRequired() + def toggle_locking(self, repo_name): + """ + Toggle locking of repository by simple GET call to url + + :param repo_name: + """ + + try: + repo = Repository.get_by_repo_name(repo_name) + + if repo.enable_locking: + if repo.locked[0]: + Repository.unlock(repo) + action = _('Unlocked') + else: + Repository.lock(repo, c.rhodecode_user.user_id, + lock_reason=Repository.LOCK_WEB) + action = _('Locked') + + h.flash(_('Repository has been %s') % action, + category='success') + except Exception: + log.exception("Exception during unlocking") + h.flash(_('An error occurred during unlocking'), + category='error') + return redirect(url('summary_home', repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_caches(self, repo_name): + """PUT /{repo_name}/settings/caches: invalidate the repo caches.""" + try: + ScmModel().mark_for_invalidation(repo_name, delete=True) + Session().commit() + h.flash(_('Cache invalidation successful'), + category='success') + except Exception: + log.exception("Exception during cache invalidation") + h.flash(_('An error occurred during cache invalidation'), + category='error') + + return redirect(url('edit_repo_caches', repo_name=c.repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_caches_form(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + c.active = 'caches' + + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_remote(self, repo_name): + """PUT /{repo_name}/settings/remote: edit the repo remote.""" + try: + ScmModel().pull_changes(repo_name, c.rhodecode_user.username) + h.flash(_('Pulled from remote location'), category='success') + except Exception: + log.exception("Exception during pull from remote") + h.flash(_('An error occurred during pull from remote location'), + category='error') + return redirect(url('edit_repo_remote', repo_name=c.repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_remote_form(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + c.active = 'remote' + + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def edit_statistics(self, repo_name): + """PUT /{repo_name}/settings/statistics: reset the repo statistics.""" + try: + RepoModel().delete_stats(repo_name) + Session().commit() + except Exception as e: + log.error(traceback.format_exc()) + h.flash(_('An error occurred during deletion of repository stats'), + category='error') + return redirect(url('edit_repo_statistics', repo_name=c.repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def edit_statistics_form(self, repo_name): + """GET /repo_name/settings: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + c.repo_info = self._load_repo(repo_name) + repo = c.repo_info.scm_instance() + + if c.repo_info.stats: + # this is on what revision we ended up so we add +1 for count + last_rev = c.repo_info.stats.stat_on_revision + 1 + else: + last_rev = 0 + c.stats_revision = last_rev + + c.repo_last_rev = repo.count() + + if last_rev == 0 or c.repo_last_rev == 0: + c.stats_percentage = 0 + else: + c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) + + c.active = 'statistics' + + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def repo_issuetracker_test(self, repo_name): + if request.is_xhr: + return h.urlify_commit_message( + request.POST.get('test_text', ''), + repo_name) + else: + raise HTTPBadRequest() + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def repo_issuetracker_delete(self, repo_name): + uid = request.POST.get('uid') + repo_settings = IssueTrackerSettingsModel(repo=repo_name) + try: + repo_settings.delete_entries(uid) + except Exception: + h.flash(_('Error occurred during deleting issue tracker entry'), + category='error') + else: + h.flash(_('Removed issue tracker entry'), category='success') + return redirect(url('repo_settings_issuetracker', + repo_name=repo_name)) + + def _update_patterns(self, form, repo_settings): + for uid in form['delete_patterns']: + repo_settings.delete_entries(uid) + + for pattern in form['patterns']: + for setting, value, type_ in pattern: + sett = repo_settings.create_or_update_setting( + setting, value, type_) + Session().add(sett) + + Session().commit() + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def repo_issuetracker_save(self, repo_name): + # Save inheritance + repo_settings = IssueTrackerSettingsModel(repo=repo_name) + inherited = (request.POST.get('inherit_global_issuetracker') + == "inherited") + repo_settings.inherit_global_settings = inherited + Session().commit() + + form = IssueTrackerPatternsForm()().to_python(request.POST) + if form: + self._update_patterns(form, repo_settings) + + h.flash(_('Updated issue tracker entries'), category='success') + return redirect(url('repo_settings_issuetracker', + repo_name=repo_name)) + + @HasRepoPermissionAllDecorator('repository.admin') + def repo_issuetracker(self, repo_name): + """GET /admin/settings/issue-tracker: All items in the collection""" + c.active = 'issuetracker' + c.data = 'data' + c.repo_info = self._load_repo(repo_name) + + repo = Repository.get_by_repo_name(repo_name) + c.settings_model = IssueTrackerSettingsModel(repo=repo) + c.global_patterns = c.settings_model.get_global_settings() + c.repo_patterns = c.settings_model.get_repo_settings() + + return render('admin/repos/repo_edit.html') + + @HasRepoPermissionAllDecorator('repository.admin') + def repo_settings_vcs(self, repo_name): + """GET /{repo_name}/settings/vcs/: All items in the collection""" + + model = VcsSettingsModel(repo=repo_name) + + c.active = 'vcs' + c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() + c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() + c.svn_branch_patterns = model.get_repo_svn_branch_patterns() + c.svn_tag_patterns = model.get_repo_svn_tag_patterns() + c.repo_info = self._load_repo(repo_name) + defaults = self._vcs_form_defaults(repo_name) + c.inherit_global_settings = defaults['inherit_global_settings'] + + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + def repo_settings_vcs_update(self, repo_name): + """POST /{repo_name}/settings/vcs/: All items in the collection""" + c.active = 'vcs' + + model = VcsSettingsModel(repo=repo_name) + c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() + c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() + c.svn_branch_patterns = model.get_repo_svn_branch_patterns() + c.svn_tag_patterns = model.get_repo_svn_tag_patterns() + c.repo_info = self._load_repo(repo_name) + defaults = self._vcs_form_defaults(repo_name) + c.inherit_global_settings = defaults['inherit_global_settings'] + + application_form = RepoVcsSettingsForm(repo_name)() + try: + form_result = application_form.to_python(dict(request.POST)) + except formencode.Invalid as errors: + h.flash( + _("Some form inputs contain invalid data."), + category='error') + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + + try: + inherit_global_settings = form_result['inherit_global_settings'] + model.create_or_update_repo_settings( + form_result, inherit_global_settings=inherit_global_settings) + except Exception: + log.exception("Exception while updating settings") + h.flash( + _('Error occurred during updating repository VCS settings'), + category='error') + else: + Session().commit() + h.flash(_('Updated VCS settings'), category='success') + return redirect(url('repo_vcs_settings', repo_name=repo_name)) + + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=self._vcs_form_defaults(repo_name), + encoding="UTF-8", + force_defaults=False) + + @HasRepoPermissionAllDecorator('repository.admin') + @auth.CSRFRequired() + @jsonify + def repo_delete_svn_pattern(self, repo_name): + if not request.is_xhr: + return False + + delete_pattern_id = request.POST.get('delete_svn_pattern') + model = VcsSettingsModel(repo=repo_name) + try: + model.delete_repo_svn_pattern(delete_pattern_id) + except SettingNotFound: + raise HTTPBadRequest() + + Session().commit() + return True + + def _vcs_form_defaults(self, repo_name): + model = VcsSettingsModel(repo=repo_name) + global_defaults = model.get_global_settings() + + repo_defaults = {} + repo_defaults.update(global_defaults) + repo_defaults.update(model.get_repo_settings()) + + global_defaults = { + '{}_inherited'.format(k): global_defaults[k] + for k in global_defaults} + + defaults = { + 'inherit_global_settings': model.inherit_global_settings + } + defaults.update(global_defaults) + defaults.update(repo_defaults) + defaults.update({ + 'new_svn_branch': '', + 'new_svn_tag': '', + }) + return defaults diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/settings.py @@ -0,0 +1,866 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +settings controller for rhodecode admin +""" + +import collections +import logging +import urllib2 + +import datetime +import formencode +from formencode import htmlfill +import packaging.version +from pylons import request, tmpl_context as c, url, config +from pylons.controllers.util import redirect +from pylons.i18n.translation import _, lazy_ugettext +from webob.exc import HTTPBadRequest + +import rhodecode +from rhodecode.lib import auth +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.celerylib import tasks, run_task +from rhodecode.lib.utils import repo2db_mapper +from rhodecode.lib.utils2 import ( + str2bool, safe_unicode, AttributeDict, safe_int) +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils import jsonify, read_opensource_licenses + +from rhodecode.model.db import RhodeCodeUi, Repository +from rhodecode.model.forms import ApplicationSettingsForm, \ + ApplicationUiSettingsForm, ApplicationVisualisationForm, \ + LabsSettingsForm, IssueTrackerPatternsForm + +from rhodecode.model.scm import ScmModel +from rhodecode.model.notification import EmailNotificationModel +from rhodecode.model.meta import Session +from rhodecode.model.settings import ( + IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, + SettingsModel) +from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER +from rhodecode.model.user import UserModel + +log = logging.getLogger(__name__) + + +class SettingsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('setting', 'settings', controller='admin/settings', + # path_prefix='/admin', name_prefix='admin_') + + @LoginRequired() + def __before__(self): + super(SettingsController, self).__before__() + c.labs_active = str2bool( + rhodecode.CONFIG.get('labs_settings_active', 'false')) + c.navlist = navigation.get_navlist(request) + + def _get_hg_ui_settings(self): + ret = RhodeCodeUi.query().all() + + if not ret: + raise Exception('Could not get application ui settings !') + settings = {} + for each in ret: + k = each.ui_key + v = each.ui_value + if k == '/': + k = 'root_path' + + if k in ['push_ssl', 'publish']: + v = str2bool(v) + + if k.find('.') != -1: + k = k.replace('.', '_') + + if each.ui_section in ['hooks', 'extensions']: + v = each.ui_active + + settings[each.ui_section + '_' + k] = v + return settings + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + @jsonify + def delete_svn_pattern(self): + if not request.is_xhr: + raise HTTPBadRequest() + + delete_pattern_id = request.POST.get('delete_svn_pattern') + model = VcsSettingsModel() + try: + model.delete_global_svn_pattern(delete_pattern_id) + except SettingNotFound: + raise HTTPBadRequest() + + Session().commit() + return True + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_vcs_update(self): + """POST /admin/settings: All items in the collection""" + # url('admin_settings_vcs') + c.active = 'vcs' + + model = VcsSettingsModel() + c.svn_branch_patterns = model.get_global_svn_branch_patterns() + c.svn_tag_patterns = model.get_global_svn_tag_patterns() + + application_form = ApplicationUiSettingsForm()() + try: + form_result = application_form.to_python(dict(request.POST)) + except formencode.Invalid as errors: + h.flash( + _("Some form inputs contain invalid data."), + category='error') + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + + try: + model.update_global_ssl_setting(form_result['web_push_ssl']) + if c.visual.allow_repo_location_change: + model.update_global_path_setting( + form_result['paths_root_path']) + model.update_global_hook_settings(form_result) + model.create_global_svn_settings(form_result) + model.create_or_update_global_hg_settings(form_result) + model.create_or_update_global_pr_settings(form_result) + except Exception: + log.exception("Exception while updating settings") + h.flash(_('Error occurred during updating ' + 'application settings'), category='error') + else: + Session().commit() + h.flash(_('Updated VCS settings'), category='success') + return redirect(url('admin_settings_vcs')) + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def settings_vcs(self): + """GET /admin/settings: All items in the collection""" + # url('admin_settings_vcs') + c.active = 'vcs' + model = VcsSettingsModel() + c.svn_branch_patterns = model.get_global_svn_branch_patterns() + c.svn_tag_patterns = model.get_global_svn_tag_patterns() + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_mapping_update(self): + """POST /admin/settings/mapping: All items in the collection""" + # url('admin_settings_mapping') + c.active = 'mapping' + rm_obsolete = request.POST.get('destroy', False) + invalidate_cache = request.POST.get('invalidate', False) + log.debug( + 'rescanning repo location with destroy obsolete=%s', rm_obsolete) + + if invalidate_cache: + log.debug('invalidating all repositories cache') + for repo in Repository.get_all(): + ScmModel().mark_for_invalidation(repo.repo_name, delete=True) + + filesystem_repos = ScmModel().repo_scan() + added, removed = repo2db_mapper(filesystem_repos, rm_obsolete) + _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' + h.flash(_('Repositories successfully ' + 'rescanned added: %s ; removed: %s') % + (_repr(added), _repr(removed)), + category='success') + return redirect(url('admin_settings_mapping')) + + @HasPermissionAllDecorator('hg.admin') + def settings_mapping(self): + """GET /admin/settings/mapping: All items in the collection""" + # url('admin_settings_mapping') + c.active = 'mapping' + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_global_update(self): + """POST /admin/settings/global: All items in the collection""" + # url('admin_settings_global') + c.active = 'global' + application_form = ApplicationSettingsForm()() + try: + form_result = application_form.to_python(dict(request.POST)) + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + try: + settings = [ + ('title', 'rhodecode_title'), + ('realm', 'rhodecode_realm'), + ('pre_code', 'rhodecode_pre_code'), + ('post_code', 'rhodecode_post_code'), + ('captcha_public_key', 'rhodecode_captcha_public_key'), + ('captcha_private_key', 'rhodecode_captcha_private_key'), + ] + for setting, form_key in settings: + sett = SettingsModel().create_or_update_setting( + setting, form_result[form_key]) + Session().add(sett) + + Session().commit() + h.flash(_('Updated application settings'), category='success') + + except Exception: + log.exception("Exception while updating application settings") + h.flash( + _('Error occurred during updating application settings'), + category='error') + + return redirect(url('admin_settings_global')) + + @HasPermissionAllDecorator('hg.admin') + def settings_global(self): + """GET /admin/settings/global: All items in the collection""" + # url('admin_settings_global') + c.active = 'global' + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_visual_update(self): + """POST /admin/settings/visual: All items in the collection""" + # url('admin_settings_visual') + c.active = 'visual' + application_form = ApplicationVisualisationForm()() + try: + form_result = application_form.to_python(dict(request.POST)) + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + + try: + settings = [ + ('show_public_icon', 'rhodecode_show_public_icon', 'bool'), + ('show_private_icon', 'rhodecode_show_private_icon', 'bool'), + ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'), + ('repository_fields', 'rhodecode_repository_fields', 'bool'), + ('dashboard_items', 'rhodecode_dashboard_items', 'int'), + ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'), + ('show_version', 'rhodecode_show_version', 'bool'), + ('use_gravatar', 'rhodecode_use_gravatar', 'bool'), + ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'), + ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'), + ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'), + ('support_url', 'rhodecode_support_url', 'unicode'), + ('show_revision_number', 'rhodecode_show_revision_number', 'bool'), + ('show_sha_length', 'rhodecode_show_sha_length', 'int'), + ] + for setting, form_key, type_ in settings: + sett = SettingsModel().create_or_update_setting( + setting, form_result[form_key], type_) + Session().add(sett) + + Session().commit() + + h.flash(_('Updated visualisation settings'), category='success') + except Exception: + log.exception("Exception updating visualization settings") + h.flash(_('Error occurred during updating ' + 'visualisation settings'), + category='error') + + return redirect(url('admin_settings_visual')) + + @HasPermissionAllDecorator('hg.admin') + def settings_visual(self): + """GET /admin/settings/visual: All items in the collection""" + # url('admin_settings_visual') + c.active = 'visual' + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_issuetracker_test(self): + if request.is_xhr: + return h.urlify_commit_message( + request.POST.get('test_text', ''), + 'repo_group/test_repo1') + else: + raise HTTPBadRequest() + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_issuetracker_delete(self): + uid = request.POST.get('uid') + IssueTrackerSettingsModel().delete_entries(uid) + h.flash(_('Removed issue tracker entry'), category='success') + return redirect(url('admin_settings_issuetracker')) + + @HasPermissionAllDecorator('hg.admin') + def settings_issuetracker(self): + """GET /admin/settings/issue-tracker: All items in the collection""" + # url('admin_settings_issuetracker') + c.active = 'issuetracker' + defaults = SettingsModel().get_all_settings() + + entry_key = 'rhodecode_issuetracker_pat_' + + c.issuetracker_entries = {} + for k, v in defaults.items(): + if k.startswith(entry_key): + uid = k[len(entry_key):] + c.issuetracker_entries[uid] = None + + for uid in c.issuetracker_entries: + c.issuetracker_entries[uid] = AttributeDict({ + 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid), + 'url': defaults.get('rhodecode_issuetracker_url_' + uid), + 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid), + 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid), + }) + + return render('admin/settings/settings.html') + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_issuetracker_save(self): + settings_model = IssueTrackerSettingsModel() + + form = IssueTrackerPatternsForm()().to_python(request.POST) + for uid in form['delete_patterns']: + settings_model.delete_entries(uid) + + for pattern in form['patterns']: + for setting, value, type_ in pattern: + sett = settings_model.create_or_update_setting( + setting, value, type_) + Session().add(sett) + + Session().commit() + + h.flash(_('Updated issue tracker entries'), category='success') + return redirect(url('admin_settings_issuetracker')) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_email_update(self): + """POST /admin/settings/email: All items in the collection""" + # url('admin_settings_email') + c.active = 'email' + + test_email = request.POST.get('test_email') + + if not test_email: + h.flash(_('Please enter email address'), category='error') + return redirect(url('admin_settings_email')) + + email_kwargs = { + 'date': datetime.datetime.now(), + 'user': c.rhodecode_user, + 'rhodecode_version': c.rhodecode_version + } + + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs) + + recipients = [test_email] if test_email else None + + run_task(tasks.send_email, recipients, subject, + email_body_plaintext, email_body) + + h.flash(_('Send email task created'), category='success') + return redirect(url('admin_settings_email')) + + @HasPermissionAllDecorator('hg.admin') + def settings_email(self): + """GET /admin/settings/email: All items in the collection""" + # url('admin_settings_email') + c.active = 'email' + c.rhodecode_ini = rhodecode.CONFIG + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_hooks_update(self): + """POST or DELETE /admin/settings/hooks: All items in the collection""" + # url('admin_settings_hooks') + c.active = 'hooks' + if c.visual.allow_custom_hooks_settings: + ui_key = request.POST.get('new_hook_ui_key') + ui_value = request.POST.get('new_hook_ui_value') + + hook_id = request.POST.get('hook_id') + new_hook = False + + model = SettingsModel() + try: + if ui_value and ui_key: + model.create_or_update_hook(ui_key, ui_value) + h.flash(_('Added new hook'), category='success') + new_hook = True + elif hook_id: + RhodeCodeUi.delete(hook_id) + Session().commit() + + # check for edits + update = False + _d = request.POST.dict_of_lists() + for k, v in zip(_d.get('hook_ui_key', []), + _d.get('hook_ui_value_new', [])): + model.create_or_update_hook(k, v) + update = True + + if update and not new_hook: + h.flash(_('Updated hooks'), category='success') + Session().commit() + except Exception: + log.exception("Exception during hook creation") + h.flash(_('Error occurred during hook creation'), + category='error') + + return redirect(url('admin_settings_hooks')) + + @HasPermissionAllDecorator('hg.admin') + def settings_hooks(self): + """GET /admin/settings/hooks: All items in the collection""" + # url('admin_settings_hooks') + c.active = 'hooks' + + model = SettingsModel() + c.hooks = model.get_builtin_hooks() + c.custom_hooks = model.get_custom_hooks() + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def settings_search(self): + """GET /admin/settings/search: All items in the collection""" + # url('admin_settings_search') + c.active = 'search' + + from rhodecode.lib.index import searcher_from_config + searcher = searcher_from_config(config) + c.statistics = searcher.statistics() + + return render('admin/settings/settings.html') + + @HasPermissionAllDecorator('hg.admin') + def settings_system(self): + """GET /admin/settings/system: All items in the collection""" + # url('admin_settings_system') + c.active = 'system' + + defaults = self._form_defaults() + c.rhodecode_ini = rhodecode.CONFIG + c.rhodecode_update_url = defaults.get('rhodecode_update_url') + server_info = ScmModel().get_server_info(request.environ) + for key, val in server_info.iteritems(): + setattr(c, key, val) + + if c.disk['percent'] > 90: + h.flash(h.literal(_( + 'Critical: your disk space is very low <b>%s%%</b> used' % + c.disk['percent'])), 'error') + elif c.disk['percent'] > 70: + h.flash(h.literal(_( + 'Warning: your disk space is running low <b>%s%%</b> used' % + c.disk['percent'])), 'warning') + + try: + c.uptime_age = h._age( + h.time_to_datetime(c.boot_time), False, show_suffix=False) + except TypeError: + c.uptime_age = c.boot_time + + try: + c.system_memory = '%s/%s, %s%% (%s%%) used%s' % ( + h.format_byte_size_binary(c.memory['used']), + h.format_byte_size_binary(c.memory['total']), + c.memory['percent2'], + c.memory['percent'], + ' %s' % c.memory['error'] if 'error' in c.memory else '') + except TypeError: + c.system_memory = 'NOT AVAILABLE' + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @staticmethod + def get_update_data(update_url): + """Return the JSON update data.""" + ver = rhodecode.__version__ + log.debug('Checking for upgrade on `%s` server', update_url) + opener = urllib2.build_opener() + opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)] + response = opener.open(update_url) + response_data = response.read() + data = json.loads(response_data) + + return data + + @HasPermissionAllDecorator('hg.admin') + def settings_system_update(self): + """GET /admin/settings/system/updates: All items in the collection""" + # url('admin_settings_system_update') + defaults = self._form_defaults() + update_url = defaults.get('rhodecode_update_url', '') + + _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s) + try: + data = self.get_update_data(update_url) + except urllib2.URLError as e: + log.exception("Exception contacting upgrade server") + return _err('Failed to contact upgrade server: %r' % e) + except ValueError as e: + log.exception("Bad data sent from update server") + return _err('Bad data sent from update server') + + latest = data['versions'][0] + + c.update_url = update_url + c.latest_data = latest + c.latest_ver = latest['version'] + c.cur_ver = rhodecode.__version__ + c.should_upgrade = False + + if (packaging.version.Version(c.latest_ver) > + packaging.version.Version(c.cur_ver)): + c.should_upgrade = True + c.important_notices = latest['general'] + + return render('admin/settings/settings_system_update.html') + + @HasPermissionAllDecorator('hg.admin') + def settings_supervisor(self): + c.rhodecode_ini = rhodecode.CONFIG + c.active = 'supervisor' + + c.supervisor_procs = OrderedDict([ + (SUPERVISOR_MASTER, {}), + ]) + + c.log_size = 10240 + supervisor = SupervisorModel() + + _connection = supervisor.get_connection( + c.rhodecode_ini.get('supervisor.uri')) + c.connection_error = None + try: + _connection.supervisor.getAllProcessInfo() + except Exception as e: + c.connection_error = str(e) + log.exception("Exception reading supervisor data") + return render('admin/settings/settings.html') + + groupid = c.rhodecode_ini.get('supervisor.group_id') + + # feed our group processes to the main + for proc in supervisor.get_group_processes(_connection, groupid): + c.supervisor_procs[proc['name']] = {} + + for k in c.supervisor_procs.keys(): + try: + # master process info + if k == SUPERVISOR_MASTER: + _data = supervisor.get_master_state(_connection) + _data['name'] = 'supervisor master' + _data['description'] = 'pid %s, id: %s, ver: %s' % ( + _data['pid'], _data['id'], _data['ver']) + c.supervisor_procs[k] = _data + else: + procid = groupid + ":" + k + c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid) + except Exception as e: + log.exception("Exception reading supervisor data") + c.supervisor_procs[k] = {'_rhodecode_error': str(e)} + + return render('admin/settings/settings.html') + + @HasPermissionAllDecorator('hg.admin') + def settings_supervisor_log(self, procid): + import rhodecode + c.rhodecode_ini = rhodecode.CONFIG + c.active = 'supervisor_tail' + + supervisor = SupervisorModel() + _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri')) + groupid = c.rhodecode_ini.get('supervisor.group_id') + procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid + + c.log_size = 10240 + offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1 + c.log = supervisor.read_process_log(_connection, procid, offset, 0) + + return render('admin/settings/settings.html') + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def settings_labs_update(self): + """POST /admin/settings/labs: All items in the collection""" + # url('admin_settings/labs', method={'POST'}) + c.active = 'labs' + + application_form = LabsSettingsForm()() + try: + form_result = application_form.to_python(dict(request.POST)) + except formencode.Invalid as errors: + h.flash( + _('Some form inputs contain invalid data.'), + category='error') + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding='UTF-8', + force_defaults=False + ) + + try: + session = Session() + for setting in _LAB_SETTINGS: + setting_name = setting.key[len('rhodecode_'):] + sett = SettingsModel().create_or_update_setting( + setting_name, form_result[setting.key], setting.type) + session.add(sett) + + except Exception: + log.exception('Exception while updating lab settings') + h.flash(_('Error occurred during updating labs settings'), + category='error') + else: + Session().commit() + h.flash(_('Updated Labs settings'), category='success') + return redirect(url('admin_settings_labs')) + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding='UTF-8', + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def settings_labs(self): + """GET /admin/settings/labs: All items in the collection""" + # url('admin_settings_labs') + if not c.labs_active: + redirect(url('admin_settings')) + + c.active = 'labs' + c.lab_settings = _LAB_SETTINGS + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding='UTF-8', + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def settings_open_source(self): + # url('admin_settings_open_source') + + c.active = 'open_source' + c.opensource_licenses = collections.OrderedDict( + sorted(read_opensource_licenses().items(), key=lambda t: t[0])) + + return htmlfill.render( + render('admin/settings/settings.html'), + defaults=self._form_defaults(), + encoding='UTF-8', + force_defaults=False) + + def _form_defaults(self): + defaults = SettingsModel().get_all_settings() + defaults.update(self._get_hg_ui_settings()) + defaults.update({ + 'new_svn_branch': '', + 'new_svn_tag': '', + }) + return defaults + + +# :param key: name of the setting including the 'rhodecode_' prefix +# :param type: the RhodeCodeSetting type to use. +# :param group: the i18ned group in which we should dispaly this setting +# :param label: the i18ned label we should display for this setting +# :param help: the i18ned help we should dispaly for this setting +LabSetting = collections.namedtuple( + 'LabSetting', ('key', 'type', 'group', 'label', 'help')) + + +# This list has to be kept in sync with the form +# rhodecode.model.forms.LabsSettingsForm. +_LAB_SETTINGS = [ + LabSetting( + key='rhodecode_hg_use_rebase_for_merging', + type='bool', + group=lazy_ugettext('Mercurial server-side merge'), + label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'), + help='' # Do not translate the empty string! + ), + LabSetting( + key='rhodecode_proxy_subversion_http_requests', + type='bool', + group=lazy_ugettext('Subversion HTTP Support'), + label=lazy_ugettext('Proxy subversion HTTP requests'), + help='' # Do not translate the empty string! + ), + LabSetting( + key='rhodecode_subversion_http_server_url', + type='str', + group=lazy_ugettext('Subversion HTTP Server URL'), + label='', # Do not translate the empty string! + help=lazy_ugettext('e.g. http://localhost:8080/') + ), +] + + +NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url']) + + +class NavEntry(object): + + def __init__(self, key, name, view_name, pyramid=False): + self.key = key + self.name = name + self.view_name = view_name + self.pyramid = pyramid + + def generate_url(self, request): + if self.pyramid: + if hasattr(request, 'route_path'): + return request.route_path(self.view_name) + else: + # TODO: johbo: Remove this after migrating to pyramid. + # We need the pyramid request here to generate URLs to pyramid + # views from within pylons views. + from pyramid.threadlocal import get_current_request + pyramid_request = get_current_request() + return pyramid_request.route_path(self.view_name) + else: + return url(self.view_name) + + +class NavigationRegistry(object): + + _base_entries = [ + NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'), + NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'), + NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'), + NavEntry('mapping', lazy_ugettext('Remap and Rescan'), + 'admin_settings_mapping'), + NavEntry('issuetracker', lazy_ugettext('Issue Tracker'), + 'admin_settings_issuetracker'), + NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'), + NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'), + NavEntry('search', lazy_ugettext('Full Text Search'), + 'admin_settings_search'), + NavEntry('system', lazy_ugettext('System Info'), + 'admin_settings_system'), + NavEntry('open_source', lazy_ugettext('Open Source Licenses'), + 'admin_settings_open_source'), + # TODO: marcink: we disable supervisor now until the supervisor stats + # page is fixed in the nix configuration + # NavEntry('supervisor', lazy_ugettext('Supervisor'), + # 'admin_settings_supervisor'), + ] + + def __init__(self): + self._registered_entries = collections.OrderedDict([ + (item.key, item) for item in self.__class__._base_entries + ]) + + # Add the labs entry when it's activated. + labs_active = str2bool( + rhodecode.CONFIG.get('labs_settings_active', 'false')) + if labs_active: + self.add_entry( + NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs')) + + def add_entry(self, entry): + self._registered_entries[entry.key] = entry + + def get_navlist(self, request): + navlist = [NavListEntry(i.key, i.name, i.generate_url(request)) + for i in self._registered_entries.values()] + return navlist + +navigation = NavigationRegistry() diff --git a/rhodecode/controllers/admin/user_groups.py b/rhodecode/controllers/admin/user_groups.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/user_groups.py @@ -0,0 +1,471 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +User Groups crud controller for pylons +""" + +import logging +import formencode + +from formencode import htmlfill +from pylons import request, tmpl_context as c, url, config +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +from sqlalchemy.orm import joinedload + +from rhodecode.lib import auth +from rhodecode.lib import helpers as h +from rhodecode.lib.exceptions import UserGroupAssignedException,\ + RepoGroupAssignmentError +from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int +from rhodecode.lib.auth import ( + LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, + HasPermissionAnyDecorator) +from rhodecode.lib.base import BaseController, render +from rhodecode.model.permission import PermissionModel +from rhodecode.model.scm import UserGroupList +from rhodecode.model.user_group import UserGroupModel +from rhodecode.model.db import ( + User, UserGroup, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) +from rhodecode.model.forms import ( + UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm, + UserPermissionsForm) +from rhodecode.model.meta import Session +from rhodecode.lib.utils import action_logger +from rhodecode.lib.ext_json import json + +log = logging.getLogger(__name__) + + +class UserGroupsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + + @LoginRequired() + def __before__(self): + super(UserGroupsController, self).__before__() + c.available_permissions = config['available_permissions'] + PermissionModel().set_global_permission_choices(c, translator=_) + + def __load_data(self, user_group_id): + c.group_members_obj = [x.user for x in c.user_group.members] + c.group_members_obj.sort(key=lambda u: u.username.lower()) + + c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] + + c.available_members = [(x.user_id, x.username) + for x in User.query().all()] + c.available_members.sort(key=lambda u: u[1].lower()) + + def __load_defaults(self, user_group_id): + """ + Load defaults settings for edit, and update + + :param user_group_id: + """ + user_group = UserGroup.get_or_404(user_group_id) + data = user_group.get_dict() + # fill owner + if user_group.user: + data.update({'user': user_group.user.username}) + else: + replacement_user = User.get_first_admin().username + data.update({'user': replacement_user}) + return data + + def _revoke_perms_on_yourself(self, form_result): + _updates = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_updates']) + _additions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_additions']) + _deletions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), + form_result['perm_deletions']) + admin_perm = 'usergroup.admin' + if _updates and _updates[0][1] != admin_perm or \ + _additions and _additions[0][1] != admin_perm or \ + _deletions and _deletions[0][1] != admin_perm: + return True + return False + + # permission check inside + @NotAnonymous() + def index(self): + """GET /users_groups: All items in the collection""" + # url('users_groups') + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + + def user_group_name(user_group_id, user_group_name): + return _render("user_group_name", user_group_id, user_group_name) + + def user_group_actions(user_group_id, user_group_name): + return _render("user_group_actions", user_group_id, user_group_name) + + ## json generate + group_iter = UserGroupList(UserGroup.query().all(), + perm_set=['usergroup.admin']) + + user_groups_data = [] + for user_gr in group_iter: + user_groups_data.append({ + "group_name": user_group_name( + user_gr.users_group_id, h.escape(user_gr.users_group_name)), + "group_name_raw": user_gr.users_group_name, + "desc": h.escape(user_gr.user_group_description), + "members": len(user_gr.members), + "active": h.bool2icon(user_gr.users_group_active), + "owner": h.escape(h.link_to_user(user_gr.user.username)), + "action": user_group_actions( + user_gr.users_group_id, user_gr.users_group_name) + }) + + c.data = json.dumps(user_groups_data) + return render('admin/user_groups/user_groups.html') + + @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') + @auth.CSRFRequired() + def create(self): + """POST /users_groups: Create a new item""" + # url('users_groups') + + users_group_form = UserGroupForm()() + try: + form_result = users_group_form.to_python(dict(request.POST)) + user_group = UserGroupModel().create( + name=form_result['users_group_name'], + description=form_result['user_group_description'], + owner=c.rhodecode_user.user_id, + active=form_result['users_group_active']) + Session().flush() + + user_group_name = form_result['users_group_name'] + action_logger(c.rhodecode_user, + 'admin_created_users_group:%s' % user_group_name, + None, self.ip_addr, self.sa) + user_group_link = h.link_to(h.escape(user_group_name), + url('edit_users_group', + user_group_id=user_group.users_group_id)) + h.flash(h.literal(_('Created user group %(user_group_link)s') + % {'user_group_link': user_group_link}), + category='success') + Session().commit() + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/user_groups/user_group_add.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception creating user group") + h.flash(_('Error occurred during creation of user group %s') \ + % request.POST.get('users_group_name'), category='error') + + return redirect(url('users_groups')) + + @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') + def new(self): + """GET /user_groups/new: Form to create a new item""" + # url('new_users_group') + return render('admin/user_groups/user_group_add.html') + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @auth.CSRFRequired() + def update(self, user_group_id): + """PUT /user_groups/user_group_id: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('users_group', user_group_id=ID), + # method='put') + # url('users_group', user_group_id=ID) + + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'settings' + self.__load_data(user_group_id) + + available_members = [safe_unicode(x[0]) for x in c.available_members] + + users_group_form = UserGroupForm(edit=True, + old_data=c.user_group.get_dict(), + available_members=available_members)() + + try: + form_result = users_group_form.to_python(request.POST) + UserGroupModel().update(c.user_group, form_result) + gr = form_result['users_group_name'] + action_logger(c.rhodecode_user, + 'admin_updated_users_group:%s' % gr, + None, self.ip_addr, self.sa) + h.flash(_('Updated user group %s') % gr, category='success') + Session().commit() + except formencode.Invalid as errors: + defaults = errors.value + e = errors.error_dict or {} + + return htmlfill.render( + render('admin/user_groups/user_group_edit.html'), + defaults=defaults, + errors=e, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during update of user group") + h.flash(_('Error occurred during update of user group %s') + % request.POST.get('users_group_name'), category='error') + + return redirect(url('edit_users_group', user_group_id=user_group_id)) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @auth.CSRFRequired() + def delete(self, user_group_id): + """DELETE /user_groups/user_group_id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('users_group', user_group_id=ID), + # method='delete') + # url('users_group', user_group_id=ID) + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + force = str2bool(request.POST.get('force')) + + try: + UserGroupModel().delete(c.user_group, force=force) + Session().commit() + h.flash(_('Successfully deleted user group'), category='success') + except UserGroupAssignedException as e: + h.flash(str(e), category='error') + except Exception: + log.exception("Exception during deletion of user group") + h.flash(_('An error occurred during deletion of user group'), + category='error') + return redirect(url('users_groups')) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit(self, user_group_id): + """GET /user_groups/user_group_id/edit: Form to edit an existing item""" + # url('edit_users_group', user_group_id=ID) + + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'settings' + self.__load_data(user_group_id) + + defaults = self.__load_defaults(user_group_id) + + return htmlfill.render( + render('admin/user_groups/user_group_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit_perms(self, user_group_id): + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'perms' + + defaults = {} + # fill user group users + for p in c.user_group.user_user_group_to_perm: + defaults.update({'u_perm_%s' % p.user.user_id: + p.permission.permission_name}) + + for p in c.user_group.user_group_user_group_to_perm: + defaults.update({'g_perm_%s' % p.user_group.users_group_id: + p.permission.permission_name}) + + return htmlfill.render( + render('admin/user_groups/user_group_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @auth.CSRFRequired() + def update_perms(self, user_group_id): + """ + grant permission for given usergroup + + :param user_group_id: + """ + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + form = UserGroupPermsForm()().to_python(request.POST) + + if not c.rhodecode_user.is_admin: + if self._revoke_perms_on_yourself(form): + msg = _('Cannot change permission for yourself as admin') + h.flash(msg, category='warning') + return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) + + try: + UserGroupModel().update_permissions(user_group_id, + form['perm_additions'], form['perm_updates'], form['perm_deletions']) + except RepoGroupAssignmentError: + h.flash(_('Target group cannot be the same'), category='error') + return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) + #TODO: implement this + #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions', + # repo_name, self.ip_addr, self.sa) + Session().commit() + h.flash(_('User Group permissions updated'), category='success') + return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit_perms_summary(self, user_group_id): + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'perms_summary' + permissions = { + 'repositories': {}, + 'repositories_groups': {}, + } + ugroup_repo_perms = UserGroupRepoToPerm.query()\ + .options(joinedload(UserGroupRepoToPerm.permission))\ + .options(joinedload(UserGroupRepoToPerm.repository))\ + .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\ + .all() + + for gr in ugroup_repo_perms: + permissions['repositories'][gr.repository.repo_name] \ + = gr.permission.permission_name + + ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ + .options(joinedload(UserGroupRepoGroupToPerm.permission))\ + .options(joinedload(UserGroupRepoGroupToPerm.group))\ + .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\ + .all() + + for gr in ugroup_group_perms: + permissions['repositories_groups'][gr.group.group_name] \ + = gr.permission.permission_name + c.permissions = permissions + return render('admin/user_groups/user_group_edit.html') + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit_global_perms(self, user_group_id): + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'global_perms' + + c.default_user = User.get_default_user() + defaults = c.user_group.get_dict() + defaults.update(c.default_user.get_default_perms(suffix='_inherited')) + defaults.update(c.user_group.get_default_perms()) + + return htmlfill.render( + render('admin/user_groups/user_group_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @auth.CSRFRequired() + def update_global_perms(self, user_group_id): + """PUT /users_perm/user_group_id: Update an existing item""" + # url('users_group_perm', user_group_id=ID, method='put') + user_group_id = safe_int(user_group_id) + user_group = UserGroup.get_or_404(user_group_id) + c.active = 'global_perms' + + try: + # first stage that verifies the checkbox + _form = UserIndividualPermissionsForm() + form_result = _form.to_python(dict(request.POST)) + inherit_perms = form_result['inherit_default_permissions'] + user_group.inherit_default_permissions = inherit_perms + Session().add(user_group) + + if not inherit_perms: + # only update the individual ones if we un check the flag + _form = UserPermissionsForm( + [x[0] for x in c.repo_create_choices], + [x[0] for x in c.repo_create_on_write_choices], + [x[0] for x in c.repo_group_create_choices], + [x[0] for x in c.user_group_create_choices], + [x[0] for x in c.fork_choices], + [x[0] for x in c.inherit_default_permission_choices])() + + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_group_id': user_group.users_group_id}) + + PermissionModel().update_user_group_permissions(form_result) + + Session().commit() + h.flash(_('User Group global permissions updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + c.user_group = user_group + return htmlfill.render( + render('admin/user_groups/user_group_edit.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + except Exception: + log.exception("Exception during permissions saving") + h.flash(_('An error occurred during permissions saving'), + category='error') + + return redirect(url('edit_user_group_global_perms', user_group_id=user_group_id)) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit_advanced(self, user_group_id): + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'advanced' + c.group_members_obj = sorted( + (x.user for x in c.user_group.members), + key=lambda u: u.username.lower()) + + c.group_to_repos = sorted( + (x.repository for x in c.user_group.users_group_repo_to_perm), + key=lambda u: u.repo_name.lower()) + + c.group_to_repo_groups = sorted( + (x.group for x in c.user_group.users_group_repo_group_to_perm), + key=lambda u: u.group_name.lower()) + + return render('admin/user_groups/user_group_edit.html') + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def edit_members(self, user_group_id): + user_group_id = safe_int(user_group_id) + c.user_group = UserGroup.get_or_404(user_group_id) + c.active = 'members' + c.group_members_obj = sorted((x.user for x in c.user_group.members), + key=lambda u: u.username.lower()) + + c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] + return render('admin/user_groups/user_group_edit.html') diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/admin/users.py @@ -0,0 +1,717 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Users crud controller for pylons +""" + +import logging +import formencode + +from formencode import htmlfill +from pylons import request, tmpl_context as c, url, config +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +from rhodecode.authentication.plugins import auth_rhodecode +from rhodecode.lib.exceptions import ( + DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException, + UserOwnsUserGroupsException, UserCreationError) +from rhodecode.lib import helpers as h +from rhodecode.lib import auth +from rhodecode.lib.auth import ( + LoginRequired, HasPermissionAllDecorator, AuthUser, generate_auth_token) +from rhodecode.lib.base import BaseController, render +from rhodecode.model.auth_token import AuthTokenModel + +from rhodecode.model.db import ( + PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup) +from rhodecode.model.forms import ( + UserForm, UserPermissionsForm, UserIndividualPermissionsForm) +from rhodecode.model.user import UserModel +from rhodecode.model.meta import Session +from rhodecode.model.permission import PermissionModel +from rhodecode.lib.utils import action_logger +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils2 import datetime_to_time, safe_int + +log = logging.getLogger(__name__) + + +class UsersController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + + @LoginRequired() + def __before__(self): + super(UsersController, self).__before__() + c.available_permissions = config['available_permissions'] + c.allowed_languages = [ + ('en', 'English (en)'), + ('de', 'German (de)'), + ('fr', 'French (fr)'), + ('it', 'Italian (it)'), + ('ja', 'Japanese (ja)'), + ('pl', 'Polish (pl)'), + ('pt', 'Portuguese (pt)'), + ('ru', 'Russian (ru)'), + ('zh', 'Chinese (zh)'), + ] + PermissionModel().set_global_permission_choices(c, translator=_) + + @HasPermissionAllDecorator('hg.admin') + def index(self): + """GET /users: All items in the collection""" + # url('users') + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + + def grav_tmpl(user_email, size): + return _render("user_gravatar", user_email, size) + + def username(user_id, username): + return _render("user_name", user_id, username) + + def user_actions(user_id, username): + return _render("user_actions", user_id, username) + + # json generate + c.users_list = User.query()\ + .filter(User.username != User.DEFAULT_USER) \ + .all() + + users_data = [] + for user in c.users_list: + users_data.append({ + "gravatar": grav_tmpl(user.email, 20), + "username": h.link_to( + user.username, h.url('user_profile', username=user.username)), + "username_raw": user.username, + "email": user.email, + "first_name": h.escape(user.name), + "last_name": h.escape(user.lastname), + "last_login": h.format_date(user.last_login), + "last_login_raw": datetime_to_time(user.last_login), + "last_activity": h.format_date( + h.time_to_datetime(user.user_data.get('last_activity', 0))), + "last_activity_raw": user.user_data.get('last_activity', 0), + "active": h.bool2icon(user.active), + "active_raw": user.active, + "admin": h.bool2icon(user.admin), + "admin_raw": user.admin, + "extern_type": user.extern_type, + "extern_name": user.extern_name, + "action": user_actions(user.user_id, user.username), + }) + + + c.data = json.dumps(users_data) + return render('admin/users/users.html') + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def create(self): + """POST /users: Create a new item""" + # url('users') + c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name + user_model = UserModel() + user_form = UserForm()() + try: + form_result = user_form.to_python(dict(request.POST)) + user = user_model.create(form_result) + Session().flush() + username = form_result['username'] + action_logger(c.rhodecode_user, 'admin_created_user:%s' % username, + None, self.ip_addr, self.sa) + + user_link = h.link_to(h.escape(username), + url('edit_user', + user_id=user.user_id)) + h.flash(h.literal(_('Created user %(user_link)s') + % {'user_link': user_link}), category='success') + Session().commit() + except formencode.Invalid as errors: + return htmlfill.render( + render('admin/users/user_add.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except UserCreationError as e: + h.flash(e, 'error') + except Exception: + log.exception("Exception creation of user") + h.flash(_('Error occurred during creation of user %s') + % request.POST.get('username'), category='error') + return redirect(url('users')) + + @HasPermissionAllDecorator('hg.admin') + def new(self): + """GET /users/new: Form to create a new item""" + # url('new_user') + c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name + return render('admin/users/user_add.html') + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def update(self, user_id): + """PUT /users/user_id: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('update_user', user_id=ID), + # method='put') + # url('user', user_id=ID) + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + c.active = 'profile' + c.extern_type = c.user.extern_type + c.extern_name = c.user.extern_name + c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) + available_languages = [x[0] for x in c.allowed_languages] + _form = UserForm(edit=True, available_languages=available_languages, + old_data={'user_id': user_id, + 'email': c.user.email})() + form_result = {} + try: + form_result = _form.to_python(dict(request.POST)) + skip_attrs = ['extern_type', 'extern_name'] + # TODO: plugin should define if username can be updated + if c.extern_type != "rhodecode": + # forbid updating username for external accounts + skip_attrs.append('username') + + UserModel().update_user(user_id, skip_attrs=skip_attrs, **form_result) + usr = form_result['username'] + action_logger(c.rhodecode_user, 'admin_updated_user:%s' % usr, + None, self.ip_addr, self.sa) + h.flash(_('User updated successfully'), category='success') + Session().commit() + except formencode.Invalid as errors: + defaults = errors.value + e = errors.error_dict or {} + + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + errors=e, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception updating user") + h.flash(_('Error occurred during update of user %s') + % form_result.get('username'), category='error') + return redirect(url('edit_user', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def delete(self, user_id): + """DELETE /users/user_id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('delete_user', user_id=ID), + # method='delete') + # url('user', user_id=ID) + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + + _repos = c.user.repositories + _repo_groups = c.user.repository_groups + _user_groups = c.user.user_groups + + handle_repos = None + handle_repo_groups = None + handle_user_groups = None + # dummy call for flash of handle + set_handle_flash_repos = lambda: None + set_handle_flash_repo_groups = lambda: None + set_handle_flash_user_groups = lambda: None + + if _repos and request.POST.get('user_repos'): + do = request.POST['user_repos'] + if do == 'detach': + handle_repos = 'detach' + set_handle_flash_repos = lambda: h.flash( + _('Detached %s repositories') % len(_repos), + category='success') + elif do == 'delete': + handle_repos = 'delete' + set_handle_flash_repos = lambda: h.flash( + _('Deleted %s repositories') % len(_repos), + category='success') + + if _repo_groups and request.POST.get('user_repo_groups'): + do = request.POST['user_repo_groups'] + if do == 'detach': + handle_repo_groups = 'detach' + set_handle_flash_repo_groups = lambda: h.flash( + _('Detached %s repository groups') % len(_repo_groups), + category='success') + elif do == 'delete': + handle_repo_groups = 'delete' + set_handle_flash_repo_groups = lambda: h.flash( + _('Deleted %s repository groups') % len(_repo_groups), + category='success') + + if _user_groups and request.POST.get('user_user_groups'): + do = request.POST['user_user_groups'] + if do == 'detach': + handle_user_groups = 'detach' + set_handle_flash_user_groups = lambda: h.flash( + _('Detached %s user groups') % len(_user_groups), + category='success') + elif do == 'delete': + handle_user_groups = 'delete' + set_handle_flash_user_groups = lambda: h.flash( + _('Deleted %s user groups') % len(_user_groups), + category='success') + + try: + UserModel().delete(c.user, handle_repos=handle_repos, + handle_repo_groups=handle_repo_groups, + handle_user_groups=handle_user_groups) + Session().commit() + set_handle_flash_repos() + set_handle_flash_repo_groups() + set_handle_flash_user_groups() + h.flash(_('Successfully deleted user'), category='success') + except (UserOwnsReposException, UserOwnsRepoGroupsException, + UserOwnsUserGroupsException, DefaultUserException) as e: + h.flash(e, category='warning') + except Exception: + log.exception("Exception during deletion of user") + h.flash(_('An error occurred during deletion of user'), + category='error') + return redirect(url('users')) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def reset_password(self, user_id): + """ + toggle reset password flag for this user + + :param user_id: + """ + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + try: + old_value = c.user.user_data.get('force_password_change') + c.user.update_userdata(force_password_change=not old_value) + Session().commit() + if old_value: + msg = _('Force password change disabled for user') + else: + msg = _('Force password change enabled for user') + h.flash(msg, category='success') + except Exception: + log.exception("Exception during password reset for user") + h.flash(_('An error occurred during password reset for user'), + category='error') + + return redirect(url('edit_user_advanced', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def create_personal_repo_group(self, user_id): + """ + Create personal repository group for this user + + :param user_id: + """ + from rhodecode.model.repo_group import RepoGroupModel + + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + + try: + desc = RepoGroupModel.PERSONAL_GROUP_DESC % { + 'username': c.user.username} + if not RepoGroup.get_by_group_name(c.user.username): + RepoGroupModel().create(group_name=c.user.username, + group_description=desc, + owner=c.user.username) + + msg = _('Created repository group `%s`' % (c.user.username,)) + h.flash(msg, category='success') + except Exception: + log.exception("Exception during repository group creation") + msg = _( + 'An error occurred during repository group creation for user') + h.flash(msg, category='error') + + return redirect(url('edit_user_advanced', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + def show(self, user_id): + """GET /users/user_id: Show a specific item""" + # url('user', user_id=ID) + User.get_or_404(-1) + + @HasPermissionAllDecorator('hg.admin') + def edit(self, user_id): + """GET /users/user_id/edit: Form to edit an existing item""" + # url('edit_user', user_id=ID) + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'profile' + c.extern_type = c.user.extern_type + c.extern_name = c.user.extern_name + c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) + + defaults = c.user.get_dict() + defaults.update({'language': c.user.user_data.get('language')}) + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def edit_advanced(self, user_id): + user_id = safe_int(user_id) + user = c.user = User.get_or_404(user_id) + if user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'advanced' + c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) + c.personal_repo_group = RepoGroup.get_by_group_name(user.username) + c.first_admin = User.get_first_admin() + defaults = user.get_dict() + + # Interim workaround if the user participated on any pull requests as a + # reviewer. + has_review = bool(PullRequestReviewers.query().filter( + PullRequestReviewers.user_id == user_id).first()) + c.can_delete_user = not has_review + c.can_delete_user_message = _( + 'The user participates as reviewer in pull requests and ' + 'cannot be deleted. You can set the user to ' + '"inactive" instead of deleting it.') if has_review else '' + + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + def edit_auth_tokens(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'auth_tokens' + show_expired = True + c.lifetime_values = [ + (str(-1), _('forever')), + (str(5), _('5 minutes')), + (str(60), _('1 hour')), + (str(60 * 24), _('1 day')), + (str(60 * 24 * 30), _('1 month')), + ] + c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] + c.role_values = [(x, AuthTokenModel.cls._get_role_name(x)) + for x in AuthTokenModel.cls.ROLES] + c.role_options = [(c.role_values, _("Role"))] + c.user_auth_tokens = AuthTokenModel().get_auth_tokens( + c.user.user_id, show_expired=show_expired) + defaults = c.user.get_dict() + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def add_auth_token(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + lifetime = safe_int(request.POST.get('lifetime'), -1) + description = request.POST.get('description') + role = request.POST.get('role') + AuthTokenModel().create(c.user.user_id, description, lifetime, role) + Session().commit() + h.flash(_("Auth token successfully created"), category='success') + return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id)) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def delete_auth_token(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + auth_token = request.POST.get('del_auth_token') + if request.POST.get('del_auth_token_builtin'): + user = User.get(c.user.user_id) + if user: + user.api_key = generate_auth_token(user.username) + Session().add(user) + Session().commit() + h.flash(_("Auth token successfully reset"), category='success') + elif auth_token: + AuthTokenModel().delete(auth_token, c.user.user_id) + Session().commit() + h.flash(_("Auth token successfully deleted"), category='success') + + return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id)) + + @HasPermissionAllDecorator('hg.admin') + def edit_global_perms(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'global_perms' + + c.default_user = User.get_default_user() + defaults = c.user.get_dict() + defaults.update(c.default_user.get_default_perms(suffix='_inherited')) + defaults.update(c.default_user.get_default_perms()) + defaults.update(c.user.get_default_perms()) + + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def update_global_perms(self, user_id): + """PUT /users_perm/user_id: Update an existing item""" + # url('user_perm', user_id=ID, method='put') + user_id = safe_int(user_id) + user = User.get_or_404(user_id) + c.active = 'global_perms' + try: + # first stage that verifies the checkbox + _form = UserIndividualPermissionsForm() + form_result = _form.to_python(dict(request.POST)) + inherit_perms = form_result['inherit_default_permissions'] + user.inherit_default_permissions = inherit_perms + Session().add(user) + + if not inherit_perms: + # only update the individual ones if we un check the flag + _form = UserPermissionsForm( + [x[0] for x in c.repo_create_choices], + [x[0] for x in c.repo_create_on_write_choices], + [x[0] for x in c.repo_group_create_choices], + [x[0] for x in c.user_group_create_choices], + [x[0] for x in c.fork_choices], + [x[0] for x in c.inherit_default_permission_choices])() + + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_id': user.user_id}) + + PermissionModel().update_user_permissions(form_result) + + Session().commit() + h.flash(_('User global permissions updated successfully'), + category='success') + + Session().commit() + except formencode.Invalid as errors: + defaults = errors.value + c.user = user + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception("Exception during permissions saving") + h.flash(_('An error occurred during permissions saving'), + category='error') + return redirect(url('edit_user_global_perms', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + def edit_perms_summary(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'perms_summary' + c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) + + return render('admin/users/user_edit.html') + + @HasPermissionAllDecorator('hg.admin') + def edit_emails(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'emails' + c.user_email_map = UserEmailMap.query() \ + .filter(UserEmailMap.user == c.user).all() + + defaults = c.user.get_dict() + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def add_email(self, user_id): + """POST /user_emails:Add an existing item""" + # url('user_emails', user_id=ID, method='put') + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + + email = request.POST.get('new_email') + user_model = UserModel() + + try: + user_model.add_extra_email(user_id, email) + Session().commit() + h.flash(_("Added new email address `%s` for user account") % email, + category='success') + except formencode.Invalid as error: + msg = error.error_dict['email'] + h.flash(msg, category='error') + except Exception: + log.exception("Exception during email saving") + h.flash(_('An error occurred during email saving'), + category='error') + return redirect(url('edit_user_emails', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def delete_email(self, user_id): + """DELETE /user_emails_delete/user_id: Delete an existing item""" + # url('user_emails_delete', user_id=ID, method='delete') + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + email_id = request.POST.get('del_email_id') + user_model = UserModel() + user_model.delete_extra_email(user_id, email_id) + Session().commit() + h.flash(_("Removed email address from user account"), category='success') + return redirect(url('edit_user_emails', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + def edit_ips(self, user_id): + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + if c.user.username == User.DEFAULT_USER: + h.flash(_("You can't edit this user"), category='warning') + return redirect(url('users')) + + c.active = 'ips' + c.user_ip_map = UserIpMap.query() \ + .filter(UserIpMap.user == c.user).all() + + c.inherit_default_ips = c.user.inherit_default_permissions + c.default_user_ip_map = UserIpMap.query() \ + .filter(UserIpMap.user == User.get_default_user()).all() + + defaults = c.user.get_dict() + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def add_ip(self, user_id): + """POST /user_ips:Add an existing item""" + # url('user_ips', user_id=ID, method='put') + + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + user_model = UserModel() + try: + ip_list = user_model.parse_ip_range(request.POST.get('new_ip')) + except Exception as e: + ip_list = [] + log.exception("Exception during ip saving") + h.flash(_('An error occurred during ip saving:%s' % (e,)), + category='error') + + desc = request.POST.get('description') + added = [] + for ip in ip_list: + try: + user_model.add_extra_ip(user_id, ip, desc) + Session().commit() + added.append(ip) + except formencode.Invalid as error: + msg = error.error_dict['ip'] + h.flash(msg, category='error') + except Exception: + log.exception("Exception during ip saving") + h.flash(_('An error occurred during ip saving'), + category='error') + if added: + h.flash( + _("Added ips %s to user whitelist") % (', '.join(ip_list), ), + category='success') + if 'default_user' in request.POST: + return redirect(url('admin_permissions_ips')) + return redirect(url('edit_user_ips', user_id=user_id)) + + @HasPermissionAllDecorator('hg.admin') + @auth.CSRFRequired() + def delete_ip(self, user_id): + """DELETE /user_ips_delete/user_id: Delete an existing item""" + # url('user_ips_delete', user_id=ID, method='delete') + user_id = safe_int(user_id) + c.user = User.get_or_404(user_id) + + ip_id = request.POST.get('del_ip_id') + user_model = UserModel() + user_model.delete_extra_ip(user_id, ip_id) + Session().commit() + h.flash(_("Removed ip address from user whitelist"), category='success') + + if 'default_user' in request.POST: + return redirect(url('admin_permissions_ips')) + return redirect(url('edit_user_ips', user_id=user_id)) diff --git a/rhodecode/controllers/base_references.py b/rhodecode/controllers/base_references.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/base_references.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from pylons import tmpl_context as c + +from rhodecode.controllers import utils +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils import PartialRenderer +from rhodecode.lib.utils2 import datetime_to_time + + +class BaseReferencesController(BaseRepoController): + """ + Base for reference controllers for branches, tags and bookmarks. + + Implement and set the following things: + + - `partials_template` is the source for the partials to use. + + - `template` is the template to render in the end. + + - `_get_reference_items(repo)` should return a sequence of tuples which + map from `name` to `commit_id`. + + """ + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def index(self): + _render = PartialRenderer(self.partials_template) + _data = [] + pre_load = ["author", "date", "message"] + repo = c.rhodecode_repo + is_svn = h.is_svn(repo) + format_ref_id = utils.get_format_ref_id(repo) + + for ref_name, commit_id in self._get_reference_items(repo): + commit = repo.get_commit( + commit_id=commit_id, pre_load=pre_load) + + # TODO: johbo: Unify generation of reference links + use_commit_id = '/' in ref_name or is_svn + files_url = h.url( + 'files_home', + repo_name=c.repo_name, + f_path=ref_name if is_svn else '', + revision=commit_id if use_commit_id else ref_name, + at=ref_name) + + _data.append({ + "name": _render('name', ref_name, files_url), + "name_raw": ref_name, + "date": _render('date', commit.date), + "date_raw": datetime_to_time(commit.date), + "author": _render('author', commit.author), + "commit": _render( + 'commit', commit.message, commit.raw_id, commit.idx), + "commit_raw": commit.idx, + "compare": _render( + 'compare', format_ref_id(ref_name, commit.raw_id)), + }) + c.has_references = bool(_data) + c.data = json.dumps(_data) + return render(self.template) diff --git a/rhodecode/controllers/bookmarks.py b/rhodecode/controllers/bookmarks.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/bookmarks.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ +""" +Bookmarks controller for rhodecode +""" + +import logging + +from pylons import tmpl_context as c +from webob.exc import HTTPNotFound + +from rhodecode.controllers.base_references import BaseReferencesController +from rhodecode.lib import helpers as h + +log = logging.getLogger(__name__) + + +class BookmarksController(BaseReferencesController): + + partials_template = 'bookmarks/bookmarks_data.html' + template = 'bookmarks/bookmarks.html' + + def __before__(self): + super(BookmarksController, self).__before__() + if not h.is_hg(c.rhodecode_repo): + raise HTTPNotFound() + + def _get_reference_items(self, repo): + return repo.bookmarks.items() diff --git a/rhodecode/controllers/branches.py b/rhodecode/controllers/branches.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/branches.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +branches controller for rhodecode +""" + +import logging + +from pylons import tmpl_context as c + +from rhodecode.controllers.base_references import BaseReferencesController + + +log = logging.getLogger(__name__) + + +class BranchesController(BaseReferencesController): + + partials_template = 'branches/branches_data.html' + template = 'branches/branches.html' + + def __before__(self): + super(BranchesController, self).__before__() + c.closed_branches = c.rhodecode_repo.branches_closed + + def _get_reference_items(self, repo): + return repo.branches_all.items() diff --git a/rhodecode/controllers/changelog.py b/rhodecode/controllers/changelog.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/changelog.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +changelog controller for rhodecode +""" + +import logging + +from pylons import request, url, session, tmpl_context as c +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ +from webob.exc import HTTPNotFound, HTTPBadRequest + +import rhodecode.lib.helpers as h +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.ext_json import json +from rhodecode.lib.graphmod import _colored, _dagwalker +from rhodecode.lib.helpers import RepoPage +from rhodecode.lib.utils2 import safe_int, safe_str +from rhodecode.lib.vcs.exceptions import ( + RepositoryError, CommitDoesNotExistError, + CommitError, NodeDoesNotExistError, EmptyRepositoryError) + +log = logging.getLogger(__name__) + +DEFAULT_CHANGELOG_SIZE = 20 + + +def _load_changelog_summary(): + p = safe_int(request.GET.get('page'), 1) + size = safe_int(request.GET.get('size'), 10) + + def url_generator(**kw): + return url('summary_home', + repo_name=c.rhodecode_db_repo.repo_name, size=size, **kw) + + pre_load = ['author', 'branch', 'date', 'message'] + try: + collection = c.rhodecode_repo.get_commits(pre_load=pre_load) + except EmptyRepositoryError: + collection = c.rhodecode_repo + + c.repo_commits = RepoPage( + collection, page=p, items_per_page=size, url=url_generator) + page_ids = [x.raw_id for x in c.repo_commits] + c.comments = c.rhodecode_db_repo.get_comments(page_ids) + c.statuses = c.rhodecode_db_repo.statuses(page_ids) + + +class ChangelogController(BaseRepoController): + + def __before__(self): + super(ChangelogController, self).__before__() + c.affected_files_cut_off = 60 + + def __get_commit_or_redirect( + self, commit_id, repo, redirect_after=True, partial=False): + """ + This is a safe way to get a commit. If an error occurs it + redirects to a commit with a proper message. If partial is set + then it does not do redirect raise and throws an exception instead. + + :param commit_id: commit to fetch + :param repo: repo instance + """ + try: + return c.rhodecode_repo.get_commit(commit_id) + except EmptyRepositoryError: + if not redirect_after: + return None + h.flash(h.literal(_('There are no commits yet')), + category='warning') + redirect(url('changelog_home', repo_name=repo.repo_name)) + except RepositoryError as e: + msg = safe_str(e) + log.exception(msg) + h.flash(msg, category='warning') + if not partial: + redirect(h.url('changelog_home', repo_name=repo.repo_name)) + raise HTTPBadRequest() + + def _graph(self, repo, commits): + """ + Generates a DAG graph for repo + + :param repo: repo instance + :param commits: list of commits + """ + if not commits: + c.jsdata = json.dumps([]) + return + + dag = _dagwalker(repo, commits) + data = [['', vtx, edges] for vtx, edges in _colored(dag)] + c.jsdata = json.dumps(data) + + def _check_if_valid_branch(self, branch_name, repo_name, f_path): + if branch_name not in c.rhodecode_repo.branches_all: + h.flash('Branch {} is not found.'.format(branch_name), + category='warning') + redirect(url('changelog_file_home', repo_name=repo_name, + revision=branch_name, f_path=f_path or '')) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def index(self, repo_name, revision=None, f_path=None): + commit_id = revision + limit = 100 + hist_limit = safe_int(request.GET.get('limit')) or None + if request.GET.get('size'): + c.size = safe_int(request.GET.get('size'), 1) + session['changelog_size'] = c.size + session.save() + else: + c.size = int(session.get('changelog_size', DEFAULT_CHANGELOG_SIZE)) + + # min size must be 1 and less than limit + c.size = max(c.size, 1) if c.size <= limit else limit + + p = safe_int(request.GET.get('page', 1), 1) + c.branch_name = branch_name = request.GET.get('branch', None) + c.book_name = book_name = request.GET.get('bookmark', None) + + c.selected_name = branch_name or book_name + if not commit_id and branch_name: + self._check_if_valid_branch(branch_name, repo_name, f_path) + + c.changelog_for_path = f_path + pre_load = ['author', 'branch', 'date', 'message', 'parents'] + try: + if f_path: + log.debug('generating changelog for path %s', f_path) + # get the history for the file ! + base_commit = c.rhodecode_repo.get_commit(revision) + try: + collection = base_commit.get_file_history( + f_path, limit=hist_limit, pre_load=pre_load) + if (collection + and request.environ.get('HTTP_X_PARTIAL_XHR')): + # for ajax call we remove first one since we're looking + # at it right now in the context of a file commit + collection.pop(0) + except (NodeDoesNotExistError, CommitError): + # this node is not present at tip! + try: + commit = self.__get_commit_or_redirect( + commit_id, repo_name) + collection = commit.get_file_history(f_path) + except RepositoryError as e: + h.flash(safe_str(e), category='warning') + redirect(h.url('changelog_home', repo_name=repo_name)) + collection = list(reversed(collection)) + else: + collection = c.rhodecode_repo.get_commits( + branch_name=branch_name, pre_load=pre_load) + + c.total_cs = len(collection) + c.showing_commits = min(c.size, c.total_cs) + c.pagination = RepoPage(collection, page=p, item_count=c.total_cs, + items_per_page=c.size, branch=branch_name) + page_commit_ids = [x.raw_id for x in c.pagination] + c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids) + c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids) + except EmptyRepositoryError as e: + h.flash(safe_str(e), category='warning') + return redirect(url('summary_home', repo_name=repo_name)) + except (RepositoryError, CommitDoesNotExistError, Exception) as e: + msg = safe_str(e) + log.exception(msg) + h.flash(msg, category='error') + return redirect(url('changelog_home', repo_name=repo_name)) + + if (request.environ.get('HTTP_X_PARTIAL_XHR') + or request.environ.get('HTTP_X_PJAX')): + # loading from ajax, we don't want the first result, it's popped + return render('changelog/changelog_file_history.html') + + if f_path: + revs = [] + else: + revs = c.pagination + self._graph(c.rhodecode_repo, revs) + + return render('changelog/changelog.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def changelog_details(self, commit_id): + if request.environ.get('HTTP_X_PARTIAL_XHR'): + c.commit = c.rhodecode_repo.get_commit(commit_id=commit_id) + return render('changelog/changelog_details.html') + raise HTTPNotFound() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def changelog_summary(self, repo_name): + if request.environ.get('HTTP_X_PJAX'): + _load_changelog_summary() + return render('changelog/changelog_summary_data.html') + raise HTTPNotFound() diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/changeset.py @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +commit controller for RhodeCode showing changes between commits +""" + +import logging + +from collections import defaultdict +from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound + +from pylons import tmpl_context as c, request, response +from pylons.i18n.translation import _ +from pylons.controllers.util import redirect + +from rhodecode.lib import auth +from rhodecode.lib import diffs +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous) +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError +import rhodecode.lib.helpers as h +from rhodecode.lib.utils import action_logger, jsonify +from rhodecode.lib.utils2 import safe_unicode +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib.vcs.exceptions import ( + RepositoryError, CommitDoesNotExistError) +from rhodecode.model.db import ChangesetComment, ChangesetStatus +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel + + +log = logging.getLogger(__name__) + + +def _update_with_GET(params, GET): + for k in ['diff1', 'diff2', 'diff']: + params[k] += GET.getall(k) + + +def get_ignore_ws(fid, GET): + ig_ws_global = GET.get('ignorews') + ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid)) + if ig_ws: + try: + return int(ig_ws[0].split(':')[-1]) + except Exception: + pass + return ig_ws_global + + +def _ignorews_url(GET, fileid=None): + fileid = str(fileid) if fileid else None + params = defaultdict(list) + _update_with_GET(params, GET) + label = _('Show whitespace') + tooltiplbl = _('Show whitespace for all diffs') + ig_ws = get_ignore_ws(fileid, GET) + ln_ctx = get_line_ctx(fileid, GET) + + if ig_ws is None: + params['ignorews'] += [1] + label = _('Ignore whitespace') + tooltiplbl = _('Ignore whitespace for all diffs') + ctx_key = 'context' + ctx_val = ln_ctx + + # if we have passed in ln_ctx pass it along to our params + if ln_ctx: + params[ctx_key] += [ctx_val] + + if fileid: + params['anchor'] = 'a_' + fileid + return h.link_to(label, h.url.current(**params), title=tooltiplbl, class_='tooltip') + + +def get_line_ctx(fid, GET): + ln_ctx_global = GET.get('context') + if fid: + ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid)) + else: + _ln_ctx = filter(lambda k: k.startswith('C'), GET) + ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global + if ln_ctx: + ln_ctx = [ln_ctx] + + if ln_ctx: + retval = ln_ctx[0].split(':')[-1] + else: + retval = ln_ctx_global + + try: + return int(retval) + except Exception: + return 3 + + +def _context_url(GET, fileid=None): + """ + Generates a url for context lines. + + :param fileid: + """ + + fileid = str(fileid) if fileid else None + ig_ws = get_ignore_ws(fileid, GET) + ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2 + + params = defaultdict(list) + _update_with_GET(params, GET) + + if ln_ctx > 0: + params['context'] += [ln_ctx] + + if ig_ws: + ig_ws_key = 'ignorews' + ig_ws_val = 1 + params[ig_ws_key] += [ig_ws_val] + + lbl = _('Increase context') + tooltiplbl = _('Increase context for all diffs') + + if fileid: + params['anchor'] = 'a_' + fileid + return h.link_to(lbl, h.url.current(**params), title=tooltiplbl, class_='tooltip') + + +class ChangesetController(BaseRepoController): + + def __before__(self): + super(ChangesetController, self).__before__() + c.affected_files_cut_off = 60 + + def _index(self, commit_id_range, method): + c.ignorews_url = _ignorews_url + c.context_url = _context_url + c.fulldiff = fulldiff = request.GET.get('fulldiff') + # get ranges of commit ids if preset + commit_range = commit_id_range.split('...')[:2] + enable_comments = True + try: + pre_load = ['affected_files', 'author', 'branch', 'date', + 'message', 'parents'] + + if len(commit_range) == 2: + enable_comments = False + commits = c.rhodecode_repo.get_commits( + start_id=commit_range[0], end_id=commit_range[1], + pre_load=pre_load) + commits = list(commits) + else: + commits = [c.rhodecode_repo.get_commit( + commit_id=commit_id_range, pre_load=pre_load)] + + c.commit_ranges = commits + if not c.commit_ranges: + raise RepositoryError( + 'The commit range returned an empty result') + except CommitDoesNotExistError: + msg = _('No such commit exists for this repository') + h.flash(msg, category='error') + raise HTTPNotFound() + except Exception: + log.exception("General failure") + raise HTTPNotFound() + + c.changes = OrderedDict() + c.lines_added = 0 + c.lines_deleted = 0 + + c.commit_statuses = ChangesetStatus.STATUSES + c.comments = [] + c.statuses = [] + c.inline_comments = [] + c.inline_cnt = 0 + c.files = [] + + # Iterate over ranges (default commit view is always one commit) + for commit in c.commit_ranges: + if method == 'show': + c.statuses.extend([ChangesetStatusModel().get_status( + c.rhodecode_db_repo.repo_id, commit.raw_id)]) + + c.comments.extend(ChangesetCommentsModel().get_comments( + c.rhodecode_db_repo.repo_id, + revision=commit.raw_id)) + + # comments from PR + st = ChangesetStatusModel().get_statuses( + c.rhodecode_db_repo.repo_id, commit.raw_id, + with_revisions=True) + + # from associated statuses, check the pull requests, and + # show comments from them + + prs = set(x.pull_request for x in + filter(lambda x: x.pull_request is not None, st)) + for pr in prs: + c.comments.extend(pr.comments) + + inlines = ChangesetCommentsModel().get_inline_comments( + c.rhodecode_db_repo.repo_id, revision=commit.raw_id) + c.inline_comments.extend(inlines.iteritems()) + + c.changes[commit.raw_id] = [] + + commit2 = commit + commit1 = commit.parents[0] if commit.parents else EmptyCommit() + + # fetch global flags of ignore ws or context lines + context_lcl = get_line_ctx('', request.GET) + ign_whitespace_lcl = get_ignore_ws('', request.GET) + + _diff = c.rhodecode_repo.get_diff( + commit1, commit2, + ignore_whitespace=ign_whitespace_lcl, context=context_lcl) + + # diff_limit will cut off the whole diff if the limit is applied + # otherwise it will just hide the big files from the front-end + diff_limit = self.cut_off_limit_diff + file_limit = self.cut_off_limit_file + + diff_processor = diffs.DiffProcessor( + _diff, format='gitdiff', diff_limit=diff_limit, + file_limit=file_limit, show_full_diff=fulldiff) + commit_changes = OrderedDict() + if method == 'show': + _parsed = diff_processor.prepare() + c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) + for f in _parsed: + c.files.append(f) + st = f['stats'] + c.lines_added += st['added'] + c.lines_deleted += st['deleted'] + fid = h.FID(commit.raw_id, f['filename']) + diff = diff_processor.as_html(enable_comments=enable_comments, + parsed_lines=[f]) + commit_changes[fid] = [ + commit1.raw_id, commit2.raw_id, + f['operation'], f['filename'], diff, st, f] + else: + # downloads/raw we only need RAW diff nothing else + diff = diff_processor.as_raw() + commit_changes[''] = [None, None, None, None, diff, None, None] + c.changes[commit.raw_id] = commit_changes + + # sort comments by how they were generated + c.comments = sorted(c.comments, key=lambda x: x.comment_id) + + # count inline comments + for __, lines in c.inline_comments: + for comments in lines.values(): + c.inline_cnt += len(comments) + + if len(c.commit_ranges) == 1: + c.commit = c.commit_ranges[0] + c.parent_tmpl = ''.join( + '# Parent %s\n' % x.raw_id for x in c.commit.parents) + if method == 'download': + response.content_type = 'text/plain' + response.content_disposition = ( + 'attachment; filename=%s.diff' % commit_id_range[:12]) + return diff + elif method == 'patch': + response.content_type = 'text/plain' + c.diff = safe_unicode(diff) + return render('changeset/patch_changeset.html') + elif method == 'raw': + response.content_type = 'text/plain' + return diff + elif method == 'show': + if len(c.commit_ranges) == 1: + return render('changeset/changeset.html') + else: + c.ancestor = None + c.target_repo = c.rhodecode_db_repo + return render('changeset/changeset_range.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def index(self, revision, method='show'): + return self._index(revision, method=method) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def changeset_raw(self, revision): + return self._index(revision, method='raw') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def changeset_patch(self, revision): + return self._index(revision, method='patch') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def changeset_download(self, revision): + return self._index(revision, method='download') + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def comment(self, repo_name, revision): + commit_id = revision + status = request.POST.get('changeset_status', None) + text = request.POST.get('text') + if status: + text = text or (_('Status change %(transition_icon)s %(status)s') + % {'transition_icon': '>', + 'status': ChangesetStatus.get_status_lbl(status)}) + + multi_commit_ids = filter( + lambda s: s not in ['', None], + request.POST.get('commit_ids', '').split(','),) + + commit_ids = multi_commit_ids or [commit_id] + comment = None + for current_id in filter(None, commit_ids): + c.co = comment = ChangesetCommentsModel().create( + text=text, + repo=c.rhodecode_db_repo.repo_id, + user=c.rhodecode_user.user_id, + revision=current_id, + f_path=request.POST.get('f_path'), + line_no=request.POST.get('line'), + status_change=(ChangesetStatus.get_status_lbl(status) + if status else None) + ) + # get status if set ! + if status: + # if latest status was from pull request and it's closed + # disallow changing status ! + # dont_allow_on_closed_pull_request = True ! + + try: + ChangesetStatusModel().set_status( + c.rhodecode_db_repo.repo_id, + status, + c.rhodecode_user.user_id, + comment, + revision=current_id, + dont_allow_on_closed_pull_request=True + ) + except StatusChangeOnClosedPullRequestError: + msg = _('Changing the status of a commit associated with ' + 'a closed pull request is not allowed') + log.exception(msg) + h.flash(msg, category='warning') + return redirect(h.url( + 'changeset_home', repo_name=repo_name, + revision=current_id)) + + # finalize, commit and redirect + Session().commit() + + data = { + 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), + } + if comment: + data.update(comment.get_dict()) + data.update({'rendered_text': + render('changeset/changeset_comment_block.html')}) + + return data + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + def preview_comment(self): + # Technically a CSRF token is not needed as no state changes with this + # call. However, as this is a POST is better to have it, so automated + # tools don't flag it as potential CSRF. + # Post is required because the payload could be bigger than the maximum + # allowed by GET. + if not request.environ.get('HTTP_X_PARTIAL_XHR'): + raise HTTPBadRequest() + text = request.POST.get('text') + renderer = request.POST.get('renderer') or 'rst' + if text: + return h.render(text, renderer=renderer, mentions=True) + return '' + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def delete_comment(self, repo_name, comment_id): + comment = ChangesetComment.get(comment_id) + owner = (comment.author.user_id == c.rhodecode_user.user_id) + is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) + if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: + ChangesetCommentsModel().delete(comment=comment) + Session().commit() + return True + else: + raise HTTPForbidden() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def changeset_info(self, repo_name, revision): + if request.is_xhr: + try: + return c.rhodecode_repo.get_commit(commit_id=revision) + except CommitDoesNotExistError as e: + return EmptyCommit(message=str(e)) + else: + raise HTTPBadRequest() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def changeset_children(self, repo_name, revision): + if request.is_xhr: + commit = c.rhodecode_repo.get_commit(commit_id=revision) + result = {"results": commit.children} + return result + else: + raise HTTPBadRequest() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def changeset_parents(self, repo_name, revision): + if request.is_xhr: + commit = c.rhodecode_repo.get_commit(commit_id=revision) + result = {"results": commit.parents} + return result + else: + raise HTTPBadRequest() diff --git a/rhodecode/controllers/compare.py b/rhodecode/controllers/compare.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/compare.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Compare controller for showing differences between two commits/refs/tags etc. +""" + +import logging + +from webob.exc import HTTPBadRequest +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name +from rhodecode.lib import helpers as h +from rhodecode.lib import diffs +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.utils import safe_str +from rhodecode.lib.utils2 import safe_unicode, str2bool +from rhodecode.lib.vcs.exceptions import ( + EmptyRepositoryError, RepositoryError, RepositoryRequirementError) +from rhodecode.model.db import Repository, ChangesetStatus + +log = logging.getLogger(__name__) + + +class CompareController(BaseRepoController): + + def __before__(self): + super(CompareController, self).__before__() + + def _get_commit_or_redirect( + self, ref, ref_type, repo, redirect_after=True, partial=False): + """ + This is a safe way to get a commit. If an error occurs it + redirects to a commit with a proper message. If partial is set + then it does not do redirect raise and throws an exception instead. + """ + try: + return get_commit_from_ref_name(repo, safe_str(ref), ref_type) + except EmptyRepositoryError: + if not redirect_after: + return repo.scm_instance().EMPTY_COMMIT + h.flash(h.literal(_('There are no commits yet')), + category='warning') + redirect(url('summary_home', repo_name=repo.repo_name)) + + except RepositoryError as e: + msg = safe_str(e) + log.exception(msg) + h.flash(msg, category='warning') + if not partial: + redirect(h.url('summary_home', repo_name=repo.repo_name)) + raise HTTPBadRequest() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def index(self, repo_name): + c.compare_home = True + c.commit_ranges = [] + c.files = [] + c.limited_diff = False + source_repo = c.rhodecode_db_repo.repo_name + target_repo = request.GET.get('target_repo', source_repo) + c.source_repo = Repository.get_by_repo_name(source_repo) + c.target_repo = Repository.get_by_repo_name(target_repo) + c.source_ref = c.target_ref = _('Select commit') + c.source_ref_type = "" + c.target_ref_type = "" + c.commit_statuses = ChangesetStatus.STATUSES + c.preview_mode = False + return render('compare/compare_diff.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def compare(self, repo_name, source_ref_type, source_ref, + target_ref_type, target_ref): + # source_ref will be evaluated in source_repo + source_repo_name = c.rhodecode_db_repo.repo_name + source_path, source_id = parse_path_ref(source_ref) + + # target_ref will be evaluated in target_repo + target_repo_name = request.GET.get('target_repo', source_repo_name) + target_path, target_id = parse_path_ref(target_ref) + + c.commit_statuses = ChangesetStatus.STATUSES + + # if merge is True + # Show what changes since the shared ancestor commit of target/source + # the source would get if it was merged with target. Only commits + # which are in target but not in source will be shown. + merge = str2bool(request.GET.get('merge')) + # if merge is False + # Show a raw diff of source/target refs even if no ancestor exists + + + # c.fulldiff disables cut_off_limit + c.fulldiff = str2bool(request.GET.get('fulldiff')) + + # if partial, returns just compare_commits.html (commits log) + partial = request.is_xhr + + # swap url for compare_diff page + c.swap_url = h.url( + 'compare_url', + repo_name=target_repo_name, + source_ref_type=target_ref_type, + source_ref=target_ref, + target_repo=source_repo_name, + target_ref_type=source_ref_type, + target_ref=source_ref, + merge=merge and '1' or '') + + source_repo = Repository.get_by_repo_name(source_repo_name) + target_repo = Repository.get_by_repo_name(target_repo_name) + + if source_repo is None: + msg = _('Could not find the original repo: %(repo)s') % { + 'repo': source_repo} + + log.error(msg) + h.flash(msg, category='error') + return redirect(url('compare_home', repo_name=c.repo_name)) + + if target_repo is None: + msg = _('Could not find the other repo: %(repo)s') % { + 'repo': target_repo_name} + log.error(msg) + h.flash(msg, category='error') + return redirect(url('compare_home', repo_name=c.repo_name)) + + source_alias = source_repo.scm_instance().alias + target_alias = target_repo.scm_instance().alias + if source_alias != target_alias: + msg = _('The comparison of two different kinds of remote repos ' + 'is not available') + log.error(msg) + h.flash(msg, category='error') + return redirect(url('compare_home', repo_name=c.repo_name)) + + source_commit = self._get_commit_or_redirect( + ref=source_id, ref_type=source_ref_type, repo=source_repo, + partial=partial) + target_commit = self._get_commit_or_redirect( + ref=target_id, ref_type=target_ref_type, repo=target_repo, + partial=partial) + + c.compare_home = False + c.source_repo = source_repo + c.target_repo = target_repo + c.source_ref = source_ref + c.target_ref = target_ref + c.source_ref_type = source_ref_type + c.target_ref_type = target_ref_type + + source_scm = source_repo.scm_instance() + target_scm = target_repo.scm_instance() + + pre_load = ["author", "branch", "date", "message"] + c.ancestor = None + try: + c.commit_ranges = source_scm.compare( + source_commit.raw_id, target_commit.raw_id, + target_scm, merge, pre_load=pre_load) + if merge: + c.ancestor = source_scm.get_common_ancestor( + source_commit.raw_id, target_commit.raw_id, target_scm) + except RepositoryRequirementError: + msg = _('Could not compare repos with different ' + 'large file settings') + log.error(msg) + if partial: + return msg + h.flash(msg, category='error') + return redirect(url('compare_home', repo_name=c.repo_name)) + + c.statuses = c.rhodecode_db_repo.statuses( + [x.raw_id for x in c.commit_ranges]) + + if partial: + return render('compare/compare_commits.html') + + if c.ancestor: + # case we want a simple diff without incoming commits, + # previewing what will be merged. + # Make the diff on target repo (which is known to have target_ref) + log.debug('Using ancestor %s as source_ref instead of %s' + % (c.ancestor, source_ref)) + source_repo = target_repo + source_commit = target_repo.get_commit(commit_id=c.ancestor) + + # diff_limit will cut off the whole diff if the limit is applied + # otherwise it will just hide the big files from the front-end + diff_limit = self.cut_off_limit_diff + file_limit = self.cut_off_limit_file + + log.debug('calculating diff between ' + 'source_ref:%s and target_ref:%s for repo `%s`', + source_commit, target_commit, + safe_unicode(source_repo.scm_instance().path)) + + if source_commit.repository != target_commit.repository: + msg = _( + "Repositories unrelated. " + "Cannot compare commit %(commit1)s from repository %(repo1)s " + "with commit %(commit2)s from repository %(repo2)s.") % { + 'commit1': h.show_id(source_commit), + 'repo1': source_repo.repo_name, + 'commit2': h.show_id(target_commit), + 'repo2': target_repo.repo_name, + } + h.flash(msg, category='error') + raise HTTPBadRequest() + + txtdiff = source_repo.scm_instance().get_diff( + commit1=source_commit, commit2=target_commit, + path1=source_path, path=target_path) + diff_processor = diffs.DiffProcessor( + txtdiff, format='gitdiff', diff_limit=diff_limit, + file_limit=file_limit, show_full_diff=c.fulldiff) + _parsed = diff_processor.prepare() + + c.limited_diff = False + if isinstance(_parsed, diffs.LimitedDiffContainer): + c.limited_diff = True + + c.files = [] + c.changes = {} + c.lines_added = 0 + c.lines_deleted = 0 + for f in _parsed: + st = f['stats'] + if not st['binary']: + c.lines_added += st['added'] + c.lines_deleted += st['deleted'] + fid = h.FID('', f['filename']) + c.files.append([fid, f['operation'], f['filename'], f['stats'], f]) + htmldiff = diff_processor.as_html( + enable_comments=False, parsed_lines=[f]) + c.changes[fid] = [f['operation'], f['filename'], htmldiff, f] + + c.preview_mode = merge + + return render('compare/compare_diff.html') diff --git a/rhodecode/controllers/debug_style.py b/rhodecode/controllers/debug_style.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/debug_style.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Provides a few url endpoints that help understanding the styling concept. +""" +import os + +from pylons import tmpl_context as c + +from rhodecode.lib.base import BaseController, render + + +class DebugStyleController(BaseController): + + def index(self): + c.active = 'index' + return render('debug_style/index.html') + + def template(self, t_path): + c.active = os.path.splitext(t_path)[0] + return render('debug_style/' + t_path) diff --git a/rhodecode/controllers/error.py b/rhodecode/controllers/error.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/error.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode error controller +""" + +import cgi +import logging +import os +import paste.fileapp + +from pylons import tmpl_context as c, request, config, url +from pylons.i18n.translation import _ +from pylons.middleware import media_path +from webob.exc import HTTPNotFound + +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.utils2 import AttributeDict +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +class ErrorController(BaseController): + """Generates error documents as and when they are required. + + The ErrorDocuments middleware forwards to ErrorController when error + related status codes are returned from the application. + + This behavior can be altered by changing the parameters to the + ErrorDocuments middleware in your config/middleware.py file. + """ + + def __before__(self): + + try: + rc_config = SettingsModel().get_all_settings() + except Exception: + log.exception('failed to fetch settings') + rc_config = {} + + c.visual = AttributeDict({}) + c.visual.rhodecode_support_url = ( + rc_config.get('rhodecode_support_url') or url('rhodecode_support')) + return + + def document(self): + resp = request.environ.get('pylons.original_response', None) + if not resp: + raise HTTPNotFound() + + c.rhodecode_name = config.get('rhodecode_title') + + log.debug('### %s ###' % resp.status) + + e = request.environ + c.serv_p = r'%(protocol)s://%(host)s/' % { + 'protocol': e.get('wsgi.url_scheme'), + 'host': e.get('HTTP_HOST'), + } + + c.error_message = cgi.escape(request.GET.get('code', str(resp.status))) + c.error_explanation = self.get_error_explanation(resp.status_int) + + # redirect to when error with given seconds + c.redirect_time = 0 + c.redirect_module = _('Home page') + c.url_redirect = "/" + + return render('/errors/error_document.html') + + def img(self, id): + """Serve Pylons' stock images""" + return self._serve_file(os.path.join(media_path, 'img', id)) + + def style(self, id): + """Serve Pylons' stock stylesheets""" + return self._serve_file(os.path.join(media_path, 'style', id)) + + def _serve_file(self, path): + """Call Paste's FileApp (a WSGI application) to serve the file + at the specified path + """ + fapp = paste.fileapp.FileApp(path) + return fapp(request.environ, self.start_response) + + def get_error_explanation(self, code): + """ get the error explanations of int codes + [400, 401, 403, 404, 500]""" + try: + code = int(code) + except Exception: + code = 500 + + if code == 400: + return _('The request could not be understood by the server' + ' due to malformed syntax.') + if code == 401: + return _('Unauthorized access to resource') + if code == 403: + return _("You don't have permission to view this page") + if code == 404: + return _('The resource could not be found') + if code == 500: + return _('The server encountered an unexpected condition' + ' which prevented it from fulfilling the request.') + + def vcs_unavailable(self): + c.rhodecode_name = config.get('rhodecode_title') + c.error_message = _('VCS Server Required') + c.error_explanation = _( + 'A VCS Server is required for this action. ' + 'There is currently no VCS Server configured.') + c.error_docs_link = 'https://docs.rhodecode.com/RhodeCode-Control/'\ + 'tasks/upgrade-from-cli.html#manually-changing-vcs-server-settings' + # redirect to when error with given seconds + c.redirect_time = 0 + c.redirect_module = _('Home page') + c.url_redirect = "/" + return render('/errors/error_document.html') diff --git a/rhodecode/controllers/feed.py b/rhodecode/controllers/feed.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/feed.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Feed controller for RhodeCode +""" + +import logging + +import pytz +from pylons import url, response, tmpl_context as c +from pylons.i18n.translation import _ + +from beaker.cache import cache_region, region_invalidate +from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed + +from rhodecode.model.db import CacheKey +from rhodecode.lib import helpers as h +from rhodecode.lib import caches +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.base import BaseRepoController +from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer +from rhodecode.lib.utils2 import safe_int, str2bool +from rhodecode.lib.utils import PartialRenderer + +log = logging.getLogger(__name__) + + +class FeedController(BaseRepoController): + + def _get_config(self): + import rhodecode + config = rhodecode.CONFIG + + return { + 'language': 'en-us', + 'feed_ttl': '5', # TTL of feed, + 'feed_include_diff': + str2bool(config.get('rss_include_diff', False)), + 'feed_items_per_page': + safe_int(config.get('rss_items_per_page', 20)), + 'feed_diff_limit': + # we need to protect from parsing huge diffs here other way + # we can kill the server + safe_int(config.get('rss_cut_off_limit', 32 * 1024)), + } + + @LoginRequired(auth_token_access=True) + def __before__(self): + super(FeedController, self).__before__() + config = self._get_config() + # common values for feeds + self.description = _('Changes on %s repository') + self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s') + self.language = config["language"] + self.ttl = config["feed_ttl"] + self.feed_include_diff = config['feed_include_diff'] + self.feed_diff_limit = config['feed_diff_limit'] + self.feed_items_per_page = config['feed_items_per_page'] + + def __changes(self, commit): + diff_processor = DiffProcessor( + commit.diff(), diff_limit=self.feed_diff_limit) + _parsed = diff_processor.prepare(inline_diff=False) + limited_diff = isinstance(_parsed, LimitedDiffContainer) + + return _parsed, limited_diff + + def _get_title(self, commit): + return h.shorter(commit.message, 160) + + def _get_description(self, commit): + _renderer = PartialRenderer('feed/atom_feed_entry.mako') + parsed_diff, limited_diff = self.__changes(commit) + return _renderer( + 'body', + commit=commit, + parsed_diff=parsed_diff, + limited_diff=limited_diff, + feed_include_diff=self.feed_include_diff, + ) + + def _set_timezone(self, date, tzinfo=pytz.utc): + if not getattr(date, "tzinfo", None): + date.replace(tzinfo=tzinfo) + return date + + def _get_commits(self): + return list(c.rhodecode_repo[-self.feed_items_per_page:]) + + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + def atom(self, repo_name): + """Produce an atom-1.0 feed via feedgenerator module""" + + @cache_region('long_term') + def _generate_feed(cache_key): + feed = Atom1Feed( + title=self.title % repo_name, + link=url('summary_home', repo_name=repo_name, qualified=True), + description=self.description % repo_name, + language=self.language, + ttl=self.ttl + ) + + for commit in reversed(self._get_commits()): + date = self._set_timezone(commit.date) + feed.add_item( + title=self._get_title(commit), + author_name=commit.author, + description=self._get_description(commit), + link=url('changeset_home', repo_name=repo_name, + revision=commit.raw_id, qualified=True), + pubdate=date,) + + return feed.mime_type, feed.writeString('utf-8') + + invalidator_context = CacheKey.repo_context_cache( + _generate_feed, repo_name, CacheKey.CACHE_TYPE_ATOM) + + with invalidator_context as context: + context.invalidate() + mime_type, feed = context.compute() + + response.content_type = mime_type + return feed + + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + def rss(self, repo_name): + """Produce an rss2 feed via feedgenerator module""" + + @cache_region('long_term') + def _generate_feed(cache_key): + feed = Rss201rev2Feed( + title=self.title % repo_name, + link=url('summary_home', repo_name=repo_name, + qualified=True), + description=self.description % repo_name, + language=self.language, + ttl=self.ttl + ) + + for commit in reversed(self._get_commits()): + date = self._set_timezone(commit.date) + feed.add_item( + title=self._get_title(commit), + author_name=commit.author, + description=self._get_description(commit), + link=url('changeset_home', repo_name=repo_name, + revision=commit.raw_id, qualified=True), + pubdate=date,) + + return feed.mime_type, feed.writeString('utf-8') + + invalidator_context = CacheKey.repo_context_cache( + _generate_feed, repo_name, CacheKey.CACHE_TYPE_RSS) + + with invalidator_context as context: + context.invalidate() + mime_type, feed = context.compute() + + response.content_type = mime_type + return feed diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/files.py @@ -0,0 +1,1114 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Files controller for RhodeCode Enterprise +""" + +import itertools +import logging +import os +import shutil +import tempfile + +from pylons import request, response, tmpl_context as c, url +from pylons.i18n.translation import _ +from pylons.controllers.util import redirect +from webob.exc import HTTPNotFound, HTTPBadRequest + +from rhodecode.controllers.utils import parse_path_ref +from rhodecode.lib import diffs, helpers as h, caches +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.utils import jsonify, action_logger +from rhodecode.lib.utils2 import ( + convert_line_endings, detect_mode, safe_str, str2bool) +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired, XHRRequired) +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.vcs import path as vcspath +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import ( + RepositoryError, CommitDoesNotExistError, EmptyRepositoryError, + ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError, + NodeDoesNotExistError, CommitError, NodeError) +from rhodecode.lib.vcs.nodes import FileNode + +from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import ScmModel +from rhodecode.model.db import Repository + +from rhodecode.controllers.changeset import ( + _ignorews_url, _context_url, get_line_ctx, get_ignore_ws) +from rhodecode.lib.exceptions import NonRelativePathError + +log = logging.getLogger(__name__) + + +class FilesController(BaseRepoController): + + def __before__(self): + super(FilesController, self).__before__() + c.cut_off_limit = self.cut_off_limit_file + + def _get_default_encoding(self): + enc_list = getattr(c, 'default_encodings', []) + return enc_list[0] if enc_list else 'UTF-8' + + def __get_commit_or_redirect(self, commit_id, repo_name, + redirect_after=True): + """ + This is a safe way to get commit. If an error occurs it redirects to + tip with proper message + + :param commit_id: id of commit to fetch + :param repo_name: repo name to redirect after + :param redirect_after: toggle redirection + """ + try: + return c.rhodecode_repo.get_commit(commit_id) + except EmptyRepositoryError: + if not redirect_after: + return None + url_ = url('files_add_home', + repo_name=c.repo_name, + revision=0, f_path='', anchor='edit') + if h.HasRepoPermissionAny( + 'repository.write', 'repository.admin')(c.repo_name): + add_new = h.link_to( + _('Click here to add a new file.'), + url_, class_="alert-link") + else: + add_new = "" + h.flash(h.literal( + _('There are no files yet. %s') % add_new), category='warning') + redirect(h.url('summary_home', repo_name=repo_name)) + except (CommitDoesNotExistError, LookupError): + msg = _('No such commit exists for this repository') + h.flash(msg, category='error') + raise HTTPNotFound() + except RepositoryError as e: + h.flash(safe_str(e), category='error') + raise HTTPNotFound() + + def __get_filenode_or_redirect(self, repo_name, commit, path): + """ + Returns file_node, if error occurs or given path is directory, + it'll redirect to top level path + + :param repo_name: repo_name + :param commit: given commit + :param path: path to lookup + """ + try: + file_node = commit.get_node(path) + if file_node.is_dir(): + raise RepositoryError('The given path is a directory') + except CommitDoesNotExistError: + msg = _('No such commit exists for this repository') + log.exception(msg) + h.flash(msg, category='error') + raise HTTPNotFound() + except RepositoryError as e: + h.flash(safe_str(e), category='error') + raise HTTPNotFound() + + return file_node + + def __get_tree_cache_manager(self, repo_name, namespace_type): + _namespace = caches.get_repo_namespace_key(namespace_type, repo_name) + return caches.get_cache_manager('repo_cache_long', _namespace) + + def _get_tree_at_commit(self, repo_name, commit_id, f_path): + def _cached_tree(): + log.debug('Generating cached file tree for %s, %s, %s', + repo_name, commit_id, f_path) + return render('files/files_browser.html') + + cache_manager = self.__get_tree_cache_manager( + repo_name, caches.FILE_TREE) + + cache_key = caches.compute_key_from_params( + repo_name, commit_id, f_path) + + return cache_manager.get(cache_key, createfunc=_cached_tree) + + def _get_nodelist_at_commit(self, repo_name, commit_id, f_path): + def _cached_nodes(): + log.debug('Generating cached nodelist for %s, %s, %s', + repo_name, commit_id, f_path) + _d, _f = ScmModel().get_nodes( + repo_name, commit_id, f_path, flat=False) + return _d + _f + + cache_manager = self.__get_tree_cache_manager( + repo_name, caches.FILE_SEARCH_TREE_META) + + cache_key = caches.compute_key_from_params( + repo_name, commit_id, f_path) + return cache_manager.get(cache_key, createfunc=_cached_nodes) + + def _get_metadata_at_commit(self, repo_name, commit, dir_node): + def _cached_metadata(): + log.debug('Generating cached metadata for %s, %s, %s', + repo_name, commit.raw_id, safe_str(dir_node.path)) + + data = ScmModel().get_dirnode_metadata(commit, dir_node) + return data + + cache_manager = self.__get_tree_cache_manager( + repo_name, caches.FILE_TREE_META) + + cache_key = caches.compute_key_from_params( + repo_name, commit.raw_id, safe_str(dir_node.path)) + + return cache_manager.get(cache_key, createfunc=_cached_metadata) + + @LoginRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + def index( + self, repo_name, revision, f_path, annotate=False, rendered=False): + commit_id = revision + + # redirect to given commit_id from form if given + get_commit_id = request.GET.get('at_rev', None) + if get_commit_id: + self.__get_commit_or_redirect(get_commit_id, repo_name) + + c.commit = self.__get_commit_or_redirect(commit_id, repo_name) + c.branch = request.GET.get('branch', None) + c.f_path = f_path + c.annotate = annotate + # default is false, but .rst/.md files later are autorendered, we can + # overwrite autorendering by setting this GET flag + c.renderer = rendered or not request.GET.get('no-render', False) + + # prev link + try: + prev_commit = c.commit.prev(c.branch) + c.prev_commit = prev_commit + c.url_prev = url('files_home', repo_name=c.repo_name, + revision=prev_commit.raw_id, f_path=f_path) + if c.branch: + c.url_prev += '?branch=%s' % c.branch + except (CommitDoesNotExistError, VCSError): + c.url_prev = '#' + c.prev_commit = EmptyCommit() + + # next link + try: + next_commit = c.commit.next(c.branch) + c.next_commit = next_commit + c.url_next = url('files_home', repo_name=c.repo_name, + revision=next_commit.raw_id, f_path=f_path) + if c.branch: + c.url_next += '?branch=%s' % c.branch + except (CommitDoesNotExistError, VCSError): + c.url_next = '#' + c.next_commit = EmptyCommit() + + # files or dirs + try: + c.file = c.commit.get_node(f_path) + c.file_author = True + c.file_tree = '' + if c.file.is_file(): + c.renderer = ( + c.renderer and h.renderer_from_filename(c.file.path)) + c.file_last_commit = c.file.last_commit + + c.on_branch_head = self._is_valid_head( + commit_id, c.rhodecode_repo) + c.branch_or_raw_id = c.commit.branch or c.commit.raw_id + + author = c.file_last_commit.author + c.authors = [(h.email(author), + h.person(author, 'username_or_name_or_email'))] + else: + c.authors = [] + c.file_tree = self._get_tree_at_commit( + repo_name, c.commit.raw_id, f_path) + except RepositoryError as e: + h.flash(safe_str(e), category='error') + raise HTTPNotFound() + + if request.environ.get('HTTP_X_PJAX'): + return render('files/files_pjax.html') + + return render('files/files.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def history(self, repo_name, revision, f_path): + commit = self.__get_commit_or_redirect(revision, repo_name) + f_path = f_path + _file = commit.get_node(f_path) + if _file.is_file(): + file_history, _hist = self._get_node_history(commit, f_path) + + res = [] + for obj in file_history: + res.append({ + 'text': obj[1], + 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]] + }) + + data = { + 'more': False, + 'results': res + } + return data + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def authors(self, repo_name, revision, f_path): + commit = self.__get_commit_or_redirect(revision, repo_name) + file_node = commit.get_node(f_path) + if file_node.is_file(): + c.file_last_commit = file_node.last_commit + if request.GET.get('annotate') == '1': + # use _hist from annotation if annotation mode is on + commit_ids = set(x[1] for x in file_node.annotate) + _hist = ( + c.rhodecode_repo.get_commit(commit_id) + for commit_id in commit_ids) + else: + _f_history, _hist = self._get_node_history(commit, f_path) + c.file_author = False + c.authors = [] + for author in set(commit.author for commit in _hist): + c.authors.append(( + h.email(author), + h.person(author, 'username_or_name_or_email'))) + return render('files/file_authors_box.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def rawfile(self, repo_name, revision, f_path): + """ + Action for download as raw + """ + commit = self.__get_commit_or_redirect(revision, repo_name) + file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path) + + response.content_disposition = 'attachment; filename=%s' % \ + safe_str(f_path.split(Repository.NAME_SEP)[-1]) + + response.content_type = file_node.mimetype + charset = self._get_default_encoding() + if charset: + response.charset = charset + + return file_node.content + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def raw(self, repo_name, revision, f_path): + """ + Action for show as raw, some mimetypes are "rendered", + those include images, icons. + """ + commit = self.__get_commit_or_redirect(revision, repo_name) + file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path) + + raw_mimetype_mapping = { + # map original mimetype to a mimetype used for "show as raw" + # you can also provide a content-disposition to override the + # default "attachment" disposition. + # orig_type: (new_type, new_dispo) + + # show images inline: + # Do not re-add SVG: it is unsafe and permits XSS attacks. One can + # for example render an SVG with javascript inside or even render + # HTML. + 'image/x-icon': ('image/x-icon', 'inline'), + 'image/png': ('image/png', 'inline'), + 'image/gif': ('image/gif', 'inline'), + 'image/jpeg': ('image/jpeg', 'inline'), + } + + mimetype = file_node.mimetype + try: + mimetype, dispo = raw_mimetype_mapping[mimetype] + except KeyError: + # we don't know anything special about this, handle it safely + if file_node.is_binary: + # do same as download raw for binary files + mimetype, dispo = 'application/octet-stream', 'attachment' + else: + # do not just use the original mimetype, but force text/plain, + # otherwise it would serve text/html and that might be unsafe. + # Note: underlying vcs library fakes text/plain mimetype if the + # mimetype can not be determined and it thinks it is not + # binary.This might lead to erroneous text display in some + # cases, but helps in other cases, like with text files + # without extension. + mimetype, dispo = 'text/plain', 'inline' + + if dispo == 'attachment': + dispo = 'attachment; filename=%s' % safe_str( + f_path.split(os.sep)[-1]) + + response.content_disposition = dispo + response.content_type = mimetype + charset = self._get_default_encoding() + if charset: + response.charset = charset + return file_node.content + + @CSRFRequired() + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def delete(self, repo_name, revision, f_path): + commit_id = revision + + repo = c.rhodecode_db_repo + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + if not self._is_valid_head(commit_id, repo.scm_instance()): + h.flash(_('You can only delete files with revision ' + 'being a valid branch '), category='warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip', + f_path=f_path)) + + c.commit = self.__get_commit_or_redirect(commit_id, repo_name) + c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) + + c.default_message = _( + 'Deleted file %s via RhodeCode Enterprise') % (f_path) + c.f_path = f_path + node_path = f_path + author = c.rhodecode_user.full_contact + message = request.POST.get('message') or c.default_message + try: + nodes = { + node_path: { + 'content': '' + } + } + self.scm_model.delete_nodes( + user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo, + message=message, + nodes=nodes, + parent_commit=c.commit, + author=author, + ) + + h.flash(_('Successfully deleted file %s') % f_path, + category='success') + except Exception: + msg = _('Error occurred during commit') + log.exception(msg) + h.flash(msg, category='error') + return redirect(url('changeset_home', + repo_name=c.repo_name, revision='tip')) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def delete_home(self, repo_name, revision, f_path): + commit_id = revision + + repo = c.rhodecode_db_repo + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + if not self._is_valid_head(commit_id, repo.scm_instance()): + h.flash(_('You can only delete files with revision ' + 'being a valid branch '), category='warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip', + f_path=f_path)) + + c.commit = self.__get_commit_or_redirect(commit_id, repo_name) + c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) + + c.default_message = _( + 'Deleted file %s via RhodeCode Enterprise') % (f_path) + c.f_path = f_path + + return render('files/files_delete.html') + + @CSRFRequired() + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def edit(self, repo_name, revision, f_path): + commit_id = revision + + repo = c.rhodecode_db_repo + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + if not self._is_valid_head(commit_id, repo.scm_instance()): + h.flash(_('You can only edit files with revision ' + 'being a valid branch '), category='warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip', + f_path=f_path)) + + c.commit = self.__get_commit_or_redirect(commit_id, repo_name) + c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) + + if c.file.is_binary: + return redirect(url('files_home', repo_name=c.repo_name, + revision=c.commit.raw_id, f_path=f_path)) + c.default_message = _( + 'Edited file %s via RhodeCode Enterprise') % (f_path) + c.f_path = f_path + old_content = c.file.content + sl = old_content.splitlines(1) + first_line = sl[0] if sl else '' + + # modes: 0 - Unix, 1 - Mac, 2 - DOS + mode = detect_mode(first_line, 0) + content = convert_line_endings(request.POST.get('content', ''), mode) + + message = request.POST.get('message') or c.default_message + org_f_path = c.file.unicode_path + filename = request.POST['filename'] + org_filename = c.file.name + + if content == old_content and filename == org_filename: + h.flash(_('No changes'), category='warning') + return redirect(url('changeset_home', repo_name=c.repo_name, + revision='tip')) + try: + mapping = { + org_f_path: { + 'org_filename': org_f_path, + 'filename': os.path.join(c.file.dir_path, filename), + 'content': content, + 'lexer': '', + 'op': 'mod', + } + } + + ScmModel().update_nodes( + user=c.rhodecode_user.user_id, + repo=c.rhodecode_db_repo, + message=message, + nodes=mapping, + parent_commit=c.commit, + ) + + h.flash(_('Successfully committed to %s') % f_path, + category='success') + except Exception: + msg = _('Error occurred during commit') + log.exception(msg) + h.flash(msg, category='error') + return redirect(url('changeset_home', + repo_name=c.repo_name, revision='tip')) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def edit_home(self, repo_name, revision, f_path): + commit_id = revision + + repo = c.rhodecode_db_repo + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + if not self._is_valid_head(commit_id, repo.scm_instance()): + h.flash(_('You can only edit files with revision ' + 'being a valid branch '), category='warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip', + f_path=f_path)) + + c.commit = self.__get_commit_or_redirect(commit_id, repo_name) + c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) + + if c.file.is_binary: + return redirect(url('files_home', repo_name=c.repo_name, + revision=c.commit.raw_id, f_path=f_path)) + c.default_message = _( + 'Edited file %s via RhodeCode Enterprise') % (f_path) + c.f_path = f_path + + return render('files/files_edit.html') + + def _is_valid_head(self, commit_id, repo): + # check if commit is a branch identifier- basically we cannot + # create multiple heads via file editing + valid_heads = repo.branches.keys() + repo.branches.values() + + if h.is_svn(repo) and not repo.is_empty(): + # Note: Subversion only has one head, we add it here in case there + # is no branch matched. + valid_heads.append(repo.get_commit(commit_idx=-1).raw_id) + + # check if commit is a branch name or branch hash + return commit_id in valid_heads + + @CSRFRequired() + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def add(self, repo_name, revision, f_path): + repo = Repository.get_by_repo_name(repo_name) + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + r_post = request.POST + + c.commit = self.__get_commit_or_redirect( + revision, repo_name, redirect_after=False) + if c.commit is None: + c.commit = EmptyCommit(alias=c.rhodecode_repo.alias) + c.default_message = (_('Added file via RhodeCode Enterprise')) + c.f_path = f_path + unix_mode = 0 + content = convert_line_endings(r_post.get('content', ''), unix_mode) + + message = r_post.get('message') or c.default_message + filename = r_post.get('filename') + location = r_post.get('location', '') # dir location + file_obj = r_post.get('upload_file', None) + + if file_obj is not None and hasattr(file_obj, 'filename'): + filename = file_obj.filename + content = file_obj.file + + if hasattr(content, 'file'): + # non posix systems store real file under file attr + content = content.file + + # If there's no commit, redirect to repo summary + if type(c.commit) is EmptyCommit: + redirect_url = "summary_home" + else: + redirect_url = "changeset_home" + + if not filename: + h.flash(_('No filename'), category='warning') + return redirect(url(redirect_url, repo_name=c.repo_name, + revision='tip')) + + # extract the location from filename, + # allows using foo/bar.txt syntax to create subdirectories + subdir_loc = filename.rsplit('/', 1) + if len(subdir_loc) == 2: + location = os.path.join(location, subdir_loc[0]) + + # strip all crap out of file, just leave the basename + filename = os.path.basename(filename) + node_path = os.path.join(location, filename) + author = c.rhodecode_user.full_contact + + try: + nodes = { + node_path: { + 'content': content + } + } + self.scm_model.create_nodes( + user=c.rhodecode_user.user_id, + repo=c.rhodecode_db_repo, + message=message, + nodes=nodes, + parent_commit=c.commit, + author=author, + ) + + h.flash(_('Successfully committed to %s') % node_path, + category='success') + except NonRelativePathError as e: + h.flash(_( + 'The location specified must be a relative path and must not ' + 'contain .. in the path'), category='warning') + return redirect(url('changeset_home', repo_name=c.repo_name, + revision='tip')) + except (NodeError, NodeAlreadyExistsError) as e: + h.flash(_(e), category='error') + except Exception: + msg = _('Error occurred during commit') + log.exception(msg) + h.flash(msg, category='error') + return redirect(url('changeset_home', + repo_name=c.repo_name, revision='tip')) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + def add_home(self, repo_name, revision, f_path): + + repo = Repository.get_by_repo_name(repo_name) + if repo.enable_locking and repo.locked[0]: + h.flash(_('This repository has been locked by %s on %s') + % (h.person_by_id(repo.locked[0]), + h.format_date(h.time_to_datetime(repo.locked[1]))), + 'warning') + return redirect(h.url('files_home', + repo_name=repo_name, revision='tip')) + + c.commit = self.__get_commit_or_redirect( + revision, repo_name, redirect_after=False) + if c.commit is None: + c.commit = EmptyCommit(alias=c.rhodecode_repo.alias) + c.default_message = (_('Added file via RhodeCode Enterprise')) + c.f_path = f_path + + return render('files/files_add.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def archivefile(self, repo_name, fname): + fileformat = None + commit_id = None + ext = None + subrepos = request.GET.get('subrepos') == 'true' + + for a_type, ext_data in settings.ARCHIVE_SPECS.items(): + archive_spec = fname.split(ext_data[1]) + if len(archive_spec) == 2 and archive_spec[1] == '': + fileformat = a_type or ext_data[1] + commit_id = archive_spec[0] + ext = ext_data[1] + + dbrepo = RepoModel().get_by_repo_name(repo_name) + if not dbrepo.enable_downloads: + return _('Downloads disabled') + + try: + commit = c.rhodecode_repo.get_commit(commit_id) + content_type = settings.ARCHIVE_SPECS[fileformat][0] + except CommitDoesNotExistError: + return _('Unknown revision %s') % commit_id + except EmptyRepositoryError: + return _('Empty repository') + except KeyError: + return _('Unknown archive type') + + # archive cache + from rhodecode import CONFIG + + archive_name = '%s-%s%s%s' % ( + safe_str(repo_name.replace('/', '_')), + '-sub' if subrepos else '', + safe_str(commit.short_id), ext) + + use_cached_archive = False + archive_cache_enabled = CONFIG.get( + 'archive_cache_dir') and not request.GET.get('no_cache') + + if archive_cache_enabled: + # check if we it's ok to write + if not os.path.isdir(CONFIG['archive_cache_dir']): + os.makedirs(CONFIG['archive_cache_dir']) + cached_archive_path = os.path.join( + CONFIG['archive_cache_dir'], archive_name) + if os.path.isfile(cached_archive_path): + log.debug('Found cached archive in %s', cached_archive_path) + fd, archive = None, cached_archive_path + use_cached_archive = True + else: + log.debug('Archive %s is not yet cached', archive_name) + + if not use_cached_archive: + # generate new archive + fd, archive = tempfile.mkstemp() + log.debug('Creating new temp archive in %s' % (archive,)) + try: + commit.archive_repo(archive, kind=fileformat, subrepos=subrepos) + except ImproperArchiveTypeError: + return _('Unknown archive type') + if archive_cache_enabled: + # if we generated the archive and we have cache enabled + # let's use this for future + log.debug('Storing new archive in %s' % (cached_archive_path,)) + shutil.move(archive, cached_archive_path) + archive = cached_archive_path + + def get_chunked_archive(archive): + with open(archive, 'rb') as stream: + while True: + data = stream.read(16 * 1024) + if not data: + if fd: # fd means we used temporary file + os.close(fd) + if not archive_cache_enabled: + log.debug('Destroying temp archive %s', archive) + os.remove(archive) + break + yield data + + # store download action + action_logger(user=c.rhodecode_user, + action='user_downloaded_archive:%s' % archive_name, + repo=repo_name, ipaddr=self.ip_addr, commit=True) + response.content_disposition = str( + 'attachment; filename=%s' % archive_name) + response.content_type = str(content_type) + + return get_chunked_archive(archive) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def diff(self, repo_name, f_path): + ignore_whitespace = request.GET.get('ignorews') == '1' + line_context = request.GET.get('context', 3) + diff1 = request.GET.get('diff1', '') + + path1, diff1 = parse_path_ref(diff1, default_path=f_path) + + diff2 = request.GET.get('diff2', '') + c.action = request.GET.get('diff') + c.no_changes = diff1 == diff2 + c.f_path = f_path + c.big_diff = False + c.ignorews_url = _ignorews_url + c.context_url = _context_url + c.changes = OrderedDict() + c.changes[diff2] = [] + + if not any((diff1, diff2)): + h.flash( + 'Need query parameter "diff1" or "diff2" to generate a diff.', + category='error') + raise HTTPBadRequest() + + # special case if we want a show commit_id only, it's impl here + # to reduce JS and callbacks + + if request.GET.get('show_rev') and diff1: + if str2bool(request.GET.get('annotate', 'False')): + _url = url('files_annotate_home', repo_name=c.repo_name, + revision=diff1, f_path=path1) + else: + _url = url('files_home', repo_name=c.repo_name, + revision=diff1, f_path=path1) + + return redirect(_url) + + try: + node1 = self._get_file_node(diff1, path1) + node2 = self._get_file_node(diff2, f_path) + except (RepositoryError, NodeError): + log.exception("Exception while trying to get node from repository") + return redirect(url( + 'files_home', repo_name=c.repo_name, f_path=f_path)) + + if all(isinstance(node.commit, EmptyCommit) + for node in (node1, node2)): + raise HTTPNotFound + + c.commit_1 = node1.commit + c.commit_2 = node2.commit + + if c.action == 'download': + _diff = diffs.get_gitdiff(node1, node2, + ignore_whitespace=ignore_whitespace, + context=line_context) + diff = diffs.DiffProcessor(_diff, format='gitdiff') + + diff_name = '%s_vs_%s.diff' % (diff1, diff2) + response.content_type = 'text/plain' + response.content_disposition = ( + 'attachment; filename=%s' % (diff_name,) + ) + charset = self._get_default_encoding() + if charset: + response.charset = charset + return diff.as_raw() + + elif c.action == 'raw': + _diff = diffs.get_gitdiff(node1, node2, + ignore_whitespace=ignore_whitespace, + context=line_context) + diff = diffs.DiffProcessor(_diff, format='gitdiff') + response.content_type = 'text/plain' + charset = self._get_default_encoding() + if charset: + response.charset = charset + return diff.as_raw() + + else: + fid = h.FID(diff2, node2.path) + line_context_lcl = get_line_ctx(fid, request.GET) + ign_whitespace_lcl = get_ignore_ws(fid, request.GET) + + __, commit1, commit2, diff, st, data = diffs.wrapped_diff( + filenode_old=node1, + filenode_new=node2, + diff_limit=self.cut_off_limit_diff, + file_limit=self.cut_off_limit_file, + show_full_diff=request.GET.get('fulldiff'), + ignore_whitespace=ign_whitespace_lcl, + line_context=line_context_lcl,) + + c.lines_added = data['stats']['added'] if data else 0 + c.lines_deleted = data['stats']['deleted'] if data else 0 + c.files = [data] + c.commit_ranges = [c.commit_1, c.commit_2] + c.ancestor = None + c.statuses = [] + c.target_repo = c.rhodecode_db_repo + c.filename1 = node1.path + c.filename = node2.path + c.binary_file = node1.is_binary or node2.is_binary + operation = data['operation'] if data else '' + + commit_changes = { + # TODO: it's passing the old file to the diff to keep the + # standard but this is not being used for this template, + # but might need both files in the future or a more standard + # way to work with that + 'fid': [commit1, commit2, operation, + c.filename, diff, st, data] + } + + c.changes = commit_changes + + return render('files/file_diff.html') + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def diff_2way(self, repo_name, f_path): + diff1 = request.GET.get('diff1', '') + diff2 = request.GET.get('diff2', '') + + nodes = [] + unknown_commits = [] + for commit in [diff1, diff2]: + try: + nodes.append(self._get_file_node(commit, f_path)) + except (RepositoryError, NodeError): + log.exception('%(commit)s does not exist' % {'commit': commit}) + unknown_commits.append(commit) + h.flash(h.literal( + _('Commit %(commit)s does not exist.') % {'commit': commit} + ), category='error') + + if unknown_commits: + return redirect(url('files_home', repo_name=c.repo_name, + f_path=f_path)) + + if all(isinstance(node.commit, EmptyCommit) for node in nodes): + raise HTTPNotFound + + node1, node2 = nodes + + f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False) + diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff') + diff_data = diff_processor.prepare() + + if not diff_data or diff_data[0]['raw_diff'] == '': + h.flash(h.literal(_('%(file_path)s has not changed ' + 'between %(commit_1)s and %(commit_2)s.') % { + 'file_path': f_path, + 'commit_1': node1.commit.id, + 'commit_2': node2.commit.id + }), category='error') + return redirect(url('files_home', repo_name=c.repo_name, + f_path=f_path)) + + c.diff_data = diff_data[0] + c.FID = h.FID(diff2, node2.path) + # cleanup some unneeded data + del c.diff_data['raw_diff'] + del c.diff_data['chunks'] + + c.node1 = node1 + c.commit_1 = node1.commit + c.node2 = node2 + c.commit_2 = node2.commit + + return render('files/diff_2way.html') + + def _get_file_node(self, commit_id, f_path): + if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]: + commit = c.rhodecode_repo.get_commit(commit_id=commit_id) + try: + node = commit.get_node(f_path) + if node.is_dir(): + raise NodeError('%s path is a %s not a file' + % (node, type(node))) + except NodeDoesNotExistError: + commit = EmptyCommit( + commit_id=commit_id, + idx=commit.idx, + repo=commit.repository, + alias=commit.repository.alias, + message=commit.message, + author=commit.author, + date=commit.date) + node = FileNode(f_path, '', commit=commit) + else: + commit = EmptyCommit( + repo=c.rhodecode_repo, + alias=c.rhodecode_repo.alias) + node = FileNode(f_path, '', commit=commit) + return node + + def _get_node_history(self, commit, f_path, commits=None): + """ + get commit history for given node + + :param commit: commit to calculate history + :param f_path: path for node to calculate history for + :param commits: if passed don't calculate history and take + commits defined in this list + """ + # calculate history based on tip + tip = c.rhodecode_repo.get_commit() + if commits is None: + pre_load = ["author", "branch"] + try: + commits = tip.get_file_history(f_path, pre_load=pre_load) + except (NodeDoesNotExistError, CommitError): + # this node is not present at tip! + commits = commit.get_file_history(f_path, pre_load=pre_load) + + history = [] + commits_group = ([], _("Changesets")) + for commit in commits: + branch = ' (%s)' % commit.branch if commit.branch else '' + n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch) + commits_group[0].append((commit.raw_id, n_desc,)) + history.append(commits_group) + + symbolic_reference = self._symbolic_reference + + if c.rhodecode_repo.alias == 'svn': + adjusted_f_path = self._adjust_file_path_for_svn( + f_path, c.rhodecode_repo) + if adjusted_f_path != f_path: + log.debug( + 'Recognized svn tag or branch in file "%s", using svn ' + 'specific symbolic references', f_path) + f_path = adjusted_f_path + symbolic_reference = self._symbolic_reference_svn + + branches = self._create_references( + c.rhodecode_repo.branches, symbolic_reference, f_path) + branches_group = (branches, _("Branches")) + + tags = self._create_references( + c.rhodecode_repo.tags, symbolic_reference, f_path) + tags_group = (tags, _("Tags")) + + history.append(branches_group) + history.append(tags_group) + + return history, commits + + def _adjust_file_path_for_svn(self, f_path, repo): + """ + Computes the relative path of `f_path`. + + This is mainly based on prefix matching of the recognized tags and + branches in the underlying repository. + """ + tags_and_branches = itertools.chain( + repo.branches.iterkeys(), + repo.tags.iterkeys()) + tags_and_branches = sorted(tags_and_branches, key=len, reverse=True) + + for name in tags_and_branches: + if f_path.startswith(name + '/'): + f_path = vcspath.relpath(f_path, name) + break + return f_path + + def _create_references( + self, branches_or_tags, symbolic_reference, f_path): + items = [] + for name, commit_id in branches_or_tags.items(): + sym_ref = symbolic_reference(commit_id, name, f_path) + items.append((sym_ref, name)) + return items + + def _symbolic_reference(self, commit_id, name, f_path): + return commit_id + + def _symbolic_reference_svn(self, commit_id, name, f_path): + new_f_path = vcspath.join(name, f_path) + return u'%s@%s' % (new_f_path, commit_id) + + @LoginRequired() + @XHRRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + @jsonify + def nodelist(self, repo_name, revision, f_path): + commit = self.__get_commit_or_redirect(revision, repo_name) + + metadata = self._get_nodelist_at_commit( + repo_name, commit.raw_id, f_path) + return {'nodes': metadata} + + @LoginRequired() + @XHRRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + @jsonify + def metadata_list(self, repo_name, revision, f_path): + """ + Returns a json dict that contains commit date, author, revision + and id for the specified repo, revision and file path + + :param repo_name: name of the repository + :param revision: revision of files + :param f_path: file path of the requested directory + """ + + commit = self.__get_commit_or_redirect(revision, repo_name) + try: + file_node = commit.get_node(f_path) + except RepositoryError as e: + return {'error': safe_str(e)} + + metadata = self._get_metadata_at_commit( + repo_name, commit, file_node) + return {'metadata': metadata} diff --git a/rhodecode/controllers/followers.py b/rhodecode/controllers/followers.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/followers.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Followers controller for rhodecode +""" + +import logging + +from pylons import tmpl_context as c, request + +from rhodecode.lib.helpers import Page +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.model.db import UserFollowing +from rhodecode.lib.utils2 import safe_int + +log = logging.getLogger(__name__) + + +class FollowersController(BaseRepoController): + + def __before__(self): + super(FollowersController, self).__before__() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def followers(self, repo_name): + p = safe_int(request.GET.get('page', 1), 1) + repo_id = c.rhodecode_db_repo.repo_id + d = UserFollowing.get_repo_followers(repo_id)\ + .order_by(UserFollowing.follows_from) + c.followers_pager = Page(d, page=p, items_per_page=20) + + c.followers_data = render('/followers/followers_data.html') + + if request.environ.get('HTTP_X_PJAX'): + return c.followers_data + + return render('/followers/followers.html') diff --git a/rhodecode/controllers/forks.py b/rhodecode/controllers/forks.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/forks.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +forks controller for rhodecode +""" + +import formencode +import logging +from formencode import htmlfill + +from pylons import tmpl_context as c, request, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ + +import rhodecode.lib.helpers as h + +from rhodecode.lib import auth +from rhodecode.lib.helpers import Page +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, + HasRepoPermissionAny, HasPermissionAnyDecorator, HasAcceptedRepoType) +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User +from rhodecode.model.repo import RepoModel +from rhodecode.model.forms import RepoForkForm +from rhodecode.model.scm import ScmModel, RepoGroupList +from rhodecode.lib.utils2 import safe_int + +log = logging.getLogger(__name__) + + +class ForksController(BaseRepoController): + + def __before__(self): + super(ForksController, self).__before__() + + def __load_defaults(self): + acl_groups = RepoGroupList( + RepoGroup.query().all(), + perm_set=['group.write', 'group.admin']) + c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) + c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) + choices, c.landing_revs = ScmModel().get_repo_landing_revs() + c.landing_revs_choices = choices + c.personal_repo_group = RepoGroup.get_by_group_name( + c.rhodecode_user.username) + + def __load_data(self, repo_name=None): + """ + Load defaults settings for edit, and update + + :param repo_name: + """ + self.__load_defaults() + + c.repo_info = Repository.get_by_repo_name(repo_name) + repo = c.repo_info.scm_instance() + + if c.repo_info is None: + h.not_mapped_error(repo_name) + return redirect(url('repos')) + + c.default_user_id = User.get_default_user().user_id + c.in_public_journal = UserFollowing.query()\ + .filter(UserFollowing.user_id == c.default_user_id)\ + .filter(UserFollowing.follows_repository == c.repo_info).scalar() + + if c.repo_info.stats: + last_rev = c.repo_info.stats.stat_on_revision+1 + else: + last_rev = 0 + c.stats_revision = last_rev + + c.repo_last_rev = repo.count() + + if last_rev == 0 or c.repo_last_rev == 0: + c.stats_percentage = 0 + else: + c.stats_percentage = '%.2f' % ((float((last_rev)) / + c.repo_last_rev) * 100) + + defaults = RepoModel()._get_defaults(repo_name) + # alter the description to indicate a fork + defaults['description'] = ('fork of repository: %s \n%s' + % (defaults['repo_name'], + defaults['description'])) + # add suffix to fork + defaults['repo_name'] = '%s-fork' % defaults['repo_name'] + + return defaults + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + def forks(self, repo_name): + p = safe_int(request.GET.get('page', 1), 1) + repo_id = c.rhodecode_db_repo.repo_id + d = [] + for r in Repository.get_repo_forks(repo_id): + if not HasRepoPermissionAny( + 'repository.read', 'repository.write', 'repository.admin' + )(r.repo_name, 'get forks check'): + continue + d.append(r) + c.forks_pager = Page(d, page=p, items_per_page=20) + + c.forks_data = render('/forks/forks_data.html') + + if request.environ.get('HTTP_X_PJAX'): + return c.forks_data + + return render('/forks/forks.html') + + @LoginRequired() + @NotAnonymous() + @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + def fork(self, repo_name): + c.repo_info = Repository.get_by_repo_name(repo_name) + if not c.repo_info: + h.not_mapped_error(repo_name) + return redirect(url('home')) + + defaults = self.__load_data(repo_name) + + return htmlfill.render( + render('forks/fork.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + @LoginRequired() + @NotAnonymous() + @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + @auth.CSRFRequired() + def fork_create(self, repo_name): + self.__load_defaults() + c.repo_info = Repository.get_by_repo_name(repo_name) + _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type}, + repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)() + form_result = {} + task_id = None + try: + form_result = _form.to_python(dict(request.POST)) + # create fork is done sometimes async on celery, db transaction + # management is handled there. + task = RepoModel().create_fork( + form_result, c.rhodecode_user.user_id) + from celery.result import BaseAsyncResult + if isinstance(task, BaseAsyncResult): + task_id = task.task_id + except formencode.Invalid as errors: + c.new_repo = errors.value['repo_name'] + return htmlfill.render( + render('forks/fork.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except Exception: + log.exception( + u'Exception while trying to fork the repository %s', repo_name) + msg = ( + _('An error occurred during repository forking %s') % + (repo_name, )) + h.flash(msg, category='error') + + return redirect(h.url('repo_creating_home', + repo_name=form_result['repo_name_full'], + task_id=task_id)) diff --git a/rhodecode/controllers/home.py b/rhodecode/controllers/home.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/home.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Home controller for RhodeCode Enterprise +""" + +import logging +import time + + +from pylons import tmpl_context as c, request +from pylons.i18n.translation import _ +from sqlalchemy.sql import func + +from rhodecode.lib.auth import ( + LoginRequired, HasPermissionAllDecorator, + HasRepoGroupPermissionAnyDecorator, XHRRequired) +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.ext_json import json +from rhodecode.lib.utils import jsonify +from rhodecode.lib.utils2 import safe_unicode +from rhodecode.model.db import Repository, RepoGroup +from rhodecode.model.repo import RepoModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.scm import RepoList, RepoGroupList + + +log = logging.getLogger(__name__) + + +class HomeController(BaseController): + def __before__(self): + super(HomeController, self).__before__() + + def ping(self): + """ + Ping, doesn't require login, good for checking out the platform + """ + instance_id = getattr(c, 'rhodecode_instanceid', '') + return 'pong[%s] => %s' % (instance_id, self.ip_addr,) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + def error_test(self): + """ + Test exception handling and emails on errors + """ + class TestException(Exception): + pass + + msg = ('RhodeCode Enterprise %s test exception. Generation time: %s' + % (c.rhodecode_name, time.time())) + raise TestException(msg) + + def _get_groups_and_repos(self, repo_group_id=None): + # repo groups groups + repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id) + _perms = ['group.read', 'group.write', 'group.admin'] + repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms) + repo_group_data = RepoGroupModel().get_repo_groups_as_dict( + repo_group_list=repo_group_list_acl, admin=False) + + # repositories + repo_list = Repository.get_all_repos(group_id=repo_group_id) + _perms = ['repository.read', 'repository.write', 'repository.admin'] + repo_list_acl = RepoList(repo_list, perm_set=_perms) + repo_data = RepoModel().get_repos_as_dict( + repo_list=repo_list_acl, admin=False) + + return repo_data, repo_group_data + + @LoginRequired() + def index(self): + c.repo_group = None + + repo_data, repo_group_data = self._get_groups_and_repos() + # json used to render the grids + c.repos_data = json.dumps(repo_data) + c.repo_groups_data = json.dumps(repo_group_data) + + return render('/index.html') + + @LoginRequired() + @HasRepoGroupPermissionAnyDecorator('group.read', 'group.write', + 'group.admin') + def index_repo_group(self, group_name): + """GET /repo_group_name: Show a specific item""" + c.repo_group = RepoGroupModel()._get_repo_group(group_name) + repo_data, repo_group_data = self._get_groups_and_repos( + c.repo_group.group_id) + + # json used to render the grids + c.repos_data = json.dumps(repo_data) + c.repo_groups_data = json.dumps(repo_group_data) + + return render('index_repo_group.html') + + def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): + query = Repository.query()\ + .order_by(func.length(Repository.repo_name))\ + .order_by(Repository.repo_name) + + if repo_type: + query = query.filter(Repository.repo_type == repo_type) + + if name_contains: + ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) + query = query.filter( + Repository.repo_name.ilike(ilike_expression)) + query = query.limit(limit) + + all_repos = query.all() + repo_iter = self.scm_model.get_repos(all_repos) + return [ + { + 'id': obj['name'], + 'text': obj['name'], + 'type': 'repo', + 'obj': obj['dbrepo'] + } + for obj in repo_iter] + + def _get_repo_group_list(self, name_contains=None, limit=20): + query = RepoGroup.query()\ + .order_by(func.length(RepoGroup.group_name))\ + .order_by(RepoGroup.group_name) + + if name_contains: + ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) + query = query.filter( + RepoGroup.group_name.ilike(ilike_expression)) + query = query.limit(limit) + + all_groups = query.all() + repo_groups_iter = self.scm_model.get_repo_groups(all_groups) + return [ + { + 'id': obj.group_name, + 'text': obj.group_name, + 'type': 'group', + 'obj': {} + } + for obj in repo_groups_iter] + + @LoginRequired() + @XHRRequired() + @jsonify + def repo_switcher_data(self): + query = request.GET.get('query') + log.debug('generating switcher repo/groups list, query %s', query) + + res = [] + repo_groups = self._get_repo_group_list(query) + if repo_groups: + res.append({ + 'text': _('Groups'), + 'children': repo_groups + }) + + repos = self._get_repo_list(query) + if repos: + res.append({ + 'text': _('Repositories'), + 'children': repos + }) + + data = { + 'more': False, + 'results': res + } + return data + + @LoginRequired() + @XHRRequired() + @jsonify + def repo_list_data(self): + query = request.GET.get('query') + repo_type = request.GET.get('repo_type') + log.debug('generating repo list, query:%s', query) + + res = [] + repos = self._get_repo_list(query, repo_type=repo_type) + if repos: + res.append({ + 'text': _('Repositories'), + 'children': repos + }) + data = { + 'more': False, + 'results': res + } + return data + + @LoginRequired() + @XHRRequired() + @jsonify + def user_autocomplete_data(self): + query = request.GET.get('query') + + repo_model = RepoModel() + _users = repo_model.get_users(name_contains=query) + + if request.GET.get('user_groups'): + # extend with user groups + _user_groups = repo_model.get_user_groups(name_contains=query) + _users = _users + _user_groups + + return {'suggestions': _users} + + @LoginRequired() + @XHRRequired() + @jsonify + def user_group_autocomplete_data(self): + return {'suggestions': []} diff --git a/rhodecode/controllers/journal.py b/rhodecode/controllers/journal.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/journal.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Journal / user event log controller for rhodecode +""" + +import logging +from itertools import groupby + +from sqlalchemy import or_ +from sqlalchemy.orm import joinedload + +from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed + +from webob.exc import HTTPBadRequest +from pylons import request, tmpl_context as c, response, url +from pylons.i18n.translation import _ + +from rhodecode.controllers.admin.admin import _journal_filter +from rhodecode.model.db import UserLog, UserFollowing, User +from rhodecode.model.meta import Session +import rhodecode.lib.helpers as h +from rhodecode.lib.helpers import Page +from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.utils2 import safe_int, AttributeDict + +log = logging.getLogger(__name__) + + +class JournalController(BaseController): + + def __before__(self): + super(JournalController, self).__before__() + self.language = 'en-us' + self.ttl = "5" + self.feed_nr = 20 + c.search_term = request.GET.get('filter') + + def _get_daily_aggregate(self, journal): + groups = [] + for k, g in groupby(journal, lambda x: x.action_as_day): + user_group = [] + #groupby username if it's a present value, else fallback to journal username + for _, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username): + l = list(g2) + user_group.append((l[0].user, l)) + + groups.append((k, user_group,)) + + return groups + + def _get_journal_data(self, following_repos): + repo_ids = [x.follows_repository.repo_id for x in following_repos + if x.follows_repository is not None] + user_ids = [x.follows_user.user_id for x in following_repos + if x.follows_user is not None] + + filtering_criterion = None + + if repo_ids and user_ids: + filtering_criterion = or_(UserLog.repository_id.in_(repo_ids), + UserLog.user_id.in_(user_ids)) + if repo_ids and not user_ids: + filtering_criterion = UserLog.repository_id.in_(repo_ids) + if not repo_ids and user_ids: + filtering_criterion = UserLog.user_id.in_(user_ids) + if filtering_criterion is not None: + journal = self.sa.query(UserLog)\ + .options(joinedload(UserLog.user))\ + .options(joinedload(UserLog.repository)) + #filter + try: + journal = _journal_filter(journal, c.search_term) + except Exception: + # we want this to crash for now + raise + journal = journal.filter(filtering_criterion)\ + .order_by(UserLog.action_date.desc()) + else: + journal = [] + + return journal + + def _atom_feed(self, repos, public=True): + journal = self._get_journal_data(repos) + if public: + _link = url('public_journal_atom', qualified=True) + _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), + 'atom feed') + else: + _link = url('journal_atom', qualified=True) + _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'atom feed') + + feed = Atom1Feed(title=_desc, + link=_link, + description=_desc, + language=self.language, + ttl=self.ttl) + + for entry in journal[:self.feed_nr]: + user = entry.user + if user is None: + #fix deleted users + user = AttributeDict({'short_contact': entry.username, + 'email': '', + 'full_contact': ''}) + action, action_extra, ico = h.action_parser(entry, feed=True) + title = "%s - %s %s" % (user.short_contact, action(), + entry.repository.repo_name) + desc = action_extra() + _url = None + if entry.repository is not None: + _url = url('changelog_home', + repo_name=entry.repository.repo_name, + qualified=True) + + feed.add_item(title=title, + pubdate=entry.action_date, + link=_url or url('', qualified=True), + author_email=user.email, + author_name=user.full_contact, + description=desc) + + response.content_type = feed.mime_type + return feed.writeString('utf-8') + + def _rss_feed(self, repos, public=True): + journal = self._get_journal_data(repos) + if public: + _link = url('public_journal_atom', qualified=True) + _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), + 'rss feed') + else: + _link = url('journal_atom', qualified=True) + _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed') + + feed = Rss201rev2Feed(title=_desc, + link=_link, + description=_desc, + language=self.language, + ttl=self.ttl) + + for entry in journal[:self.feed_nr]: + user = entry.user + if user is None: + #fix deleted users + user = AttributeDict({'short_contact': entry.username, + 'email': '', + 'full_contact': ''}) + action, action_extra, ico = h.action_parser(entry, feed=True) + title = "%s - %s %s" % (user.short_contact, action(), + entry.repository.repo_name) + desc = action_extra() + _url = None + if entry.repository is not None: + _url = url('changelog_home', + repo_name=entry.repository.repo_name, + qualified=True) + + feed.add_item(title=title, + pubdate=entry.action_date, + link=_url or url('', qualified=True), + author_email=user.email, + author_name=user.full_contact, + description=desc) + + response.content_type = feed.mime_type + return feed.writeString('utf-8') + + @LoginRequired() + @NotAnonymous() + def index(self): + # Return a rendered template + p = safe_int(request.GET.get('page', 1), 1) + c.user = User.get(c.rhodecode_user.user_id) + following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + + journal = self._get_journal_data(following) + + def url_generator(**kw): + return url.current(filter=c.search_term, **kw) + + c.journal_pager = Page(journal, page=p, items_per_page=20, url=url_generator) + c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager) + + c.journal_data = render('journal/journal_data.html') + if request.is_xhr: + return c.journal_data + + return render('journal/journal.html') + + @LoginRequired(auth_token_access=True) + @NotAnonymous() + def journal_atom(self): + """ + Produce an atom-1.0 feed via feedgenerator module + """ + following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + return self._atom_feed(following, public=False) + + @LoginRequired(auth_token_access=True) + @NotAnonymous() + def journal_rss(self): + """ + Produce an rss feed via feedgenerator module + """ + following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + return self._rss_feed(following, public=False) + + @CSRFRequired() + @LoginRequired() + @NotAnonymous() + def toggle_following(self): + user_id = request.POST.get('follows_user_id') + if user_id: + try: + self.scm_model.toggle_following_user( + user_id, c.rhodecode_user.user_id) + Session.commit() + return 'ok' + except Exception: + raise HTTPBadRequest() + + repo_id = request.POST.get('follows_repo_id') + if repo_id: + try: + self.scm_model.toggle_following_repo( + repo_id, c.rhodecode_user.user_id) + Session.commit() + return 'ok' + except Exception: + raise HTTPBadRequest() + + + @LoginRequired() + def public_journal(self): + # Return a rendered template + p = safe_int(request.GET.get('page', 1), 1) + + c.following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + + journal = self._get_journal_data(c.following) + + c.journal_pager = Page(journal, page=p, items_per_page=20) + + c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager) + + c.journal_data = render('journal/journal_data.html') + if request.is_xhr: + return c.journal_data + return render('journal/public_journal.html') + + @LoginRequired(auth_token_access=True) + def public_journal_atom(self): + """ + Produce an atom-1.0 feed via feedgenerator module + """ + c.following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + + return self._atom_feed(c.following) + + @LoginRequired(auth_token_access=True) + def public_journal_rss(self): + """ + Produce an rss2 feed via feedgenerator module + """ + c.following = self.sa.query(UserFollowing)\ + .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\ + .options(joinedload(UserFollowing.follows_repository))\ + .all() + + return self._rss_feed(c.following) diff --git a/rhodecode/controllers/login.py b/rhodecode/controllers/login.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/login.py @@ -0,0 +1,409 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Login controller for rhodeocode +""" + +import datetime +import formencode +import logging +import urlparse +import uuid + +from formencode import htmlfill +from webob.exc import HTTPFound +from pylons.i18n.translation import _ +from pylons.controllers.util import redirect +from pylons import request, session, tmpl_context as c, url +from recaptcha.client.captcha import submit + +import rhodecode.lib.helpers as h +from rhodecode.lib.auth import ( + AuthUser, HasPermissionAnyDecorator, CSRFRequired) +from rhodecode.authentication.base import loadplugin +from rhodecode.lib.base import BaseController, render +from rhodecode.lib.exceptions import UserCreationError +from rhodecode.lib.utils2 import safe_str +from rhodecode.model.db import User, ExternalIdentity +from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm +from rhodecode.model.login_session import LoginSession +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel +from rhodecode.model.user import UserModel + +log = logging.getLogger(__name__) + + +class LoginController(BaseController): + + def __before__(self): + super(LoginController, self).__before__() + + def _store_user_in_session(self, username, remember=False): + user = User.get_by_username(username, case_insensitive=True) + auth_user = AuthUser(user.user_id) + auth_user.set_authenticated() + cs = auth_user.get_cookie_store() + session['rhodecode_user'] = cs + user.update_lastlogin() + Session().commit() + + # If they want to be remembered, update the cookie + if remember: + _year = (datetime.datetime.now() + + datetime.timedelta(seconds=60 * 60 * 24 * 365)) + session._set_cookie_expires(_year) + + session.save() + + log.info('user %s is now authenticated and stored in ' + 'session, session attrs %s', username, cs) + + # dumps session attrs back to cookie + session._update_cookie_out() + # we set new cookie + headers = None + if session.request['set_cookie']: + # send set-cookie headers back to response to update cookie + headers = [('Set-Cookie', session.request['cookie_out'])] + return headers + + def _validate_came_from(self, came_from): + if not came_from: + return came_from + + parsed = urlparse.urlparse(came_from) + server_parsed = urlparse.urlparse(url.current()) + allowed_schemes = ['http', 'https'] + if parsed.scheme and parsed.scheme not in allowed_schemes: + log.error('Suspicious URL scheme detected %s for url %s' % + (parsed.scheme, parsed)) + came_from = url('home') + elif server_parsed.netloc != parsed.netloc: + log.error('Suspicious NETLOC detected %s for url %s server url ' + 'is: %s' % (parsed.netloc, parsed, server_parsed)) + came_from = url('home') + if any(bad_str in parsed.path for bad_str in ('\r', '\n')): + log.error('Header injection detected `%s` for url %s server url ' % + (parsed.path, parsed)) + came_from = url('home') + return came_from + + def _redirect_to_origin(self, location, headers=None): + request.GET.pop('came_from', None) + raise HTTPFound(location=location, headers=headers) + + def _set_came_from(self): + _default_came_from = url('home') + came_from = self._validate_came_from( + safe_str(request.GET.get('came_from', ''))) + c.came_from = came_from or _default_came_from + + def index(self): + self._set_came_from() + + not_default = c.rhodecode_user.username != User.DEFAULT_USER + ip_allowed = c.rhodecode_user.ip_allowed + c.social_plugins = self._get_active_social_plugins() + + # redirect if already logged in + if c.rhodecode_user.is_authenticated and not_default and ip_allowed: + raise self._redirect_to_origin(location=c.came_from) + + if request.POST: + # import Login Form validator class + login_form = LoginForm()() + try: + session.invalidate() + c.form_result = login_form.to_python(dict(request.POST)) + # form checks for username/password, now we're authenticated + headers = self._store_user_in_session( + username=c.form_result['username'], + remember=c.form_result['remember']) + raise self._redirect_to_origin( + location=c.came_from, headers=headers) + except formencode.Invalid as errors: + defaults = errors.value + # remove password from filling in form again + del defaults['password'] + return htmlfill.render( + render('/login.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except UserCreationError as e: + # container auth or other auth functions that create users on + # the fly can throw this exception signaling that there's issue + # with user creation, explanation should be provided in + # Exception itself + h.flash(e, 'error') + + # check if we use container plugin, and try to login using it. + from rhodecode.authentication.base import authenticate, HTTP_TYPE + try: + log.debug('Running PRE-AUTH for container based authentication') + auth_info = authenticate( + '', '', request.environ, HTTP_TYPE, skip_missing=True) + except UserCreationError as e: + log.error(e) + h.flash(e, 'error') + # render login, with flash message about limit + return render('/login.html') + + if auth_info: + headers = self._store_user_in_session(auth_info.get('username')) + raise self._redirect_to_origin( + location=c.came_from, headers=headers) + return render('/login.html') + + # TODO: Move this to a better place. + def _get_active_social_plugins(self): + from rhodecode.authentication.base import AuthomaticBase + activated_plugins = SettingsModel().get_auth_plugins() + social_plugins = [] + for plugin_id in activated_plugins: + plugin = loadplugin(plugin_id) + if isinstance(plugin, AuthomaticBase) and plugin.is_active(): + social_plugins.append(plugin) + return social_plugins + + @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', + 'hg.register.manual_activate') + def register(self): + c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\ + .AuthUser.permissions['global'] + + settings = SettingsModel().get_all_settings() + captcha_private_key = settings.get('rhodecode_captcha_private_key') + c.captcha_active = bool(captcha_private_key) + c.captcha_public_key = settings.get('rhodecode_captcha_public_key') + c.register_message = settings.get('rhodecode_register_message') or '' + + c.social_plugins = self._get_active_social_plugins() + + social_data = session.get('rhodecode.social_auth') + c.form_data = {} + if social_data: + c.form_data = {'username': social_data['user'].get('user_name'), + 'password': str(uuid.uuid4()), + 'email': social_data['user'].get('email') + } + + if request.POST: + register_form = RegisterForm()() + try: + form_result = register_form.to_python(dict(request.POST)) + form_result['active'] = c.auto_active + + if c.captcha_active: + response = submit( + request.POST.get('recaptcha_challenge_field'), + request.POST.get('recaptcha_response_field'), + private_key=captcha_private_key, + remoteip=self.ip_addr) + if c.captcha_active and not response.is_valid: + _value = form_result + _msg = _('bad captcha') + error_dict = {'recaptcha_field': _msg} + raise formencode.Invalid(_msg, _value, None, + error_dict=error_dict) + + new_user = UserModel().create_registration(form_result) + if social_data: + plugin_name = 'egg:rhodecode-enterprise-ee#{}'.format( + social_data['credentials.provider'] + ) + auth_plugin = loadplugin(plugin_name) + if auth_plugin: + auth_plugin.handle_social_data( + session, new_user.user_id, social_data) + h.flash(_('You have successfully registered with RhodeCode'), + category='success') + Session().commit() + return redirect(url('login_home')) + + except formencode.Invalid as errors: + return htmlfill.render( + render('/register.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + except UserCreationError as e: + # container auth or other auth functions that create users on + # the fly can throw this exception signaling that there's issue + # with user creation, explanation should be provided in + # Exception itself + h.flash(e, 'error') + + return render('/register.html') + + def password_reset(self): + settings = SettingsModel().get_all_settings() + captcha_private_key = settings.get('rhodecode_captcha_private_key') + c.captcha_active = bool(captcha_private_key) + c.captcha_public_key = settings.get('rhodecode_captcha_public_key') + + if request.POST: + password_reset_form = PasswordResetForm()() + try: + form_result = password_reset_form.to_python(dict(request.POST)) + if c.captcha_active: + response = submit( + request.POST.get('recaptcha_challenge_field'), + request.POST.get('recaptcha_response_field'), + private_key=captcha_private_key, + remoteip=self.ip_addr) + if c.captcha_active and not response.is_valid: + _value = form_result + _msg = _('bad captcha') + error_dict = {'recaptcha_field': _msg} + raise formencode.Invalid(_msg, _value, None, + error_dict=error_dict) + UserModel().reset_password_link(form_result) + h.flash(_('Your password reset link was sent'), + category='success') + return redirect(url('login_home')) + + except formencode.Invalid as errors: + return htmlfill.render( + render('/password_reset.html'), + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False) + + return render('/password_reset.html') + + def password_reset_confirmation(self): + if request.GET and request.GET.get('key'): + try: + user = User.get_by_auth_token(request.GET.get('key')) + data = {'email': user.email} + UserModel().reset_password(data) + h.flash(_( + 'Your password reset was successful, ' + 'a new password has been sent to your email'), + category='success') + except Exception as e: + log.error(e) + return redirect(url('reset_password')) + + return redirect(url('login_home')) + + @CSRFRequired() + def logout(self): + LoginSession().destroy_user_session() + return redirect(url('home')) + + def social_auth(self, provider_name): + plugin_name = 'egg:rhodecode-enterprise-ee#{}'.format( + provider_name + ) + auth_plugin = loadplugin(plugin_name) + if not auth_plugin: + return self._handle_social_auth_error(request, 'No auth plugin') + + result, response = auth_plugin.get_provider_result(request) + if result: + if result.error: + return self._handle_social_auth_error(request, result.error) + elif result.user: + return self._handle_social_auth_success(request, result) + return response + + def _handle_social_auth_error(self, request, result): + log.error(result) + h.flash(_('There was an error during OAuth processing.'), + category='error') + return redirect(url('home')) + + def _normalize_social_data(self, result): + social_data = { + 'user': {'data': result.user.data}, + 'credentials.provider': result.user.credentials.provider_name, + 'credentials.token': result.user.credentials.token, + 'credentials.token_secret': result.user.credentials.token_secret, + 'credentials.refresh_token': result.user.credentials.refresh_token + } + # normalize data + social_data['user']['id'] = result.user.id + user_name = result.user.username or '' + # use email name as username for google + if (social_data['credentials.provider'] == 'google' and + result.user.email): + user_name = result.user.email + + social_data['user']['user_name'] = user_name + social_data['user']['email'] = result.user.email or '' + return social_data + + def _handle_social_auth_success(self, request, result): + self._set_came_from() + + # Hooray, we have the user! + # OAuth 2.0 and OAuth 1.0a provide only limited user data on login, + # We need to update the user to get more info. + if result.user: + result.user.update() + + social_data = self._normalize_social_data(result) + + session['rhodecode.social_auth'] = social_data + + plugin_name = 'egg:rhodecode-enterprise-ee#{}'.format( + social_data['credentials.provider'] + ) + auth_plugin = loadplugin(plugin_name) + + # user is logged so bind his external identity with account + if request.user and request.user.username != User.DEFAULT_USER: + if auth_plugin: + auth_plugin.handle_social_data( + session, request.user.user_id, social_data) + session.pop('rhodecode.social_auth', None) + Session().commit() + return redirect(url('my_account_oauth')) + else: + user = ExternalIdentity.user_by_external_id_and_provider( + social_data['user']['id'], + social_data['credentials.provider'] + ) + + # user tokens are already found in our db + if user: + if auth_plugin: + auth_plugin.handle_social_data( + session, user.user_id, social_data) + session.pop('rhodecode.social_auth', None) + headers = self._store_user_in_session(user.username) + raise self._redirect_to_origin( + location=c.came_from, headers=headers) + else: + msg = _('You need to finish registration ' + 'process to bind your external identity to your ' + 'account or sign in to existing account') + h.flash(msg, category='success') + return redirect(url('register')) diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/pullrequests.py @@ -0,0 +1,844 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +pull requests controller for rhodecode for initializing pull requests +""" + +import formencode +import logging + +from webob.exc import HTTPNotFound, HTTPForbidden, HTTPBadRequest +from pylons import request, tmpl_context as c, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ +from sqlalchemy.sql import func +from sqlalchemy.sql.expression import or_ + +from rhodecode.lib import auth, diffs, helpers as h +from rhodecode.lib.ext_json import json +from rhodecode.lib.base import ( + BaseRepoController, render, vcs_operation_context) +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, + HasAcceptedRepoType, XHRRequired) +from rhodecode.lib.utils import jsonify +from rhodecode.lib.utils2 import safe_int, safe_str, str2bool, safe_unicode +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib.vcs.exceptions import ( + EmptyRepositoryError, CommitDoesNotExistError, RepositoryRequirementError) +from rhodecode.lib.diffs import LimitedDiffContainer +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.db import PullRequest, ChangesetStatus, ChangesetComment, \ + Repository +from rhodecode.model.forms import PullRequestForm +from rhodecode.model.meta import Session +from rhodecode.model.pull_request import PullRequestModel + +log = logging.getLogger(__name__) + + +class PullrequestsController(BaseRepoController): + def __before__(self): + super(PullrequestsController, self).__before__() + + def _load_compare_data(self, pull_request, enable_comments=True): + """ + Load context data needed for generating compare diff + + :param pull_request: object related to the request + :param enable_comments: flag to determine if comments are included + """ + source_repo = pull_request.source_repo + source_ref_id = pull_request.source_ref_parts.commit_id + + target_repo = pull_request.target_repo + target_ref_id = pull_request.target_ref_parts.commit_id + + # despite opening commits for bookmarks/branches/tags, we always + # convert this to rev to prevent changes after bookmark or branch change + c.source_ref_type = 'rev' + c.source_ref = source_ref_id + + c.target_ref_type = 'rev' + c.target_ref = target_ref_id + + c.source_repo = source_repo + c.target_repo = target_repo + + c.fulldiff = bool(request.GET.get('fulldiff')) + + # diff_limit is the old behavior, will cut off the whole diff + # if the limit is applied otherwise will just hide the + # big files from the front-end + diff_limit = self.cut_off_limit_diff + file_limit = self.cut_off_limit_file + + pre_load = ["author", "branch", "date", "message"] + + c.commit_ranges = [] + source_commit = EmptyCommit() + target_commit = EmptyCommit() + c.missing_requirements = False + try: + c.commit_ranges = [ + source_repo.get_commit(commit_id=rev, pre_load=pre_load) + for rev in pull_request.revisions] + + c.statuses = source_repo.statuses( + [x.raw_id for x in c.commit_ranges]) + + target_commit = source_repo.get_commit( + commit_id=safe_str(target_ref_id)) + source_commit = source_repo.get_commit( + commit_id=safe_str(source_ref_id)) + except RepositoryRequirementError: + c.missing_requirements = True + + c.missing_commits = False + if (c.missing_requirements or + isinstance(source_commit, EmptyCommit) or + source_commit == target_commit): + _parsed = [] + c.missing_commits = True + else: + vcs_diff = PullRequestModel().get_diff(pull_request) + diff_processor = diffs.DiffProcessor( + vcs_diff, format='gitdiff', diff_limit=diff_limit, + file_limit=file_limit, show_full_diff=c.fulldiff) + _parsed = diff_processor.prepare() + + c.limited_diff = isinstance(_parsed, LimitedDiffContainer) + + c.files = [] + c.changes = {} + c.lines_added = 0 + c.lines_deleted = 0 + c.included_files = [] + c.deleted_files = [] + + for f in _parsed: + st = f['stats'] + c.lines_added += st['added'] + c.lines_deleted += st['deleted'] + + fid = h.FID('', f['filename']) + c.files.append([fid, f['operation'], f['filename'], f['stats']]) + c.included_files.append(f['filename']) + html_diff = diff_processor.as_html(enable_comments=enable_comments, + parsed_lines=[f]) + c.changes[fid] = [f['operation'], f['filename'], html_diff, f] + + def _extract_ordering(self, request): + column_index = safe_int(request.GET.get('order[0][column]')) + order_dir = request.GET.get('order[0][dir]', 'desc') + order_by = request.GET.get( + 'columns[%s][data][sort]' % column_index, 'name_raw') + return order_by, order_dir + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + def show_all(self, repo_name): + # filter types + c.active = 'open' + c.source = str2bool(request.GET.get('source')) + c.closed = str2bool(request.GET.get('closed')) + c.my = str2bool(request.GET.get('my')) + c.awaiting_review = str2bool(request.GET.get('awaiting_review')) + c.awaiting_my_review = str2bool(request.GET.get('awaiting_my_review')) + c.repo_name = repo_name + + opened_by = None + if c.my: + c.active = 'my' + opened_by = [c.rhodecode_user.user_id] + + statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] + if c.closed: + c.active = 'closed' + statuses = [PullRequest.STATUS_CLOSED] + + if c.awaiting_review and not c.source: + c.active = 'awaiting' + if c.source and not c.awaiting_review: + c.active = 'source' + if c.awaiting_my_review: + c.active = 'awaiting_my' + + data = self._get_pull_requests_list( + repo_name=repo_name, opened_by=opened_by, statuses=statuses) + if not request.is_xhr: + c.data = json.dumps(data['data']) + c.records_total = data['recordsTotal'] + return render('/pullrequests/pullrequests.html') + else: + return json.dumps(data) + + def _get_pull_requests_list(self, repo_name, opened_by, statuses): + # pagination + start = safe_int(request.GET.get('start'), 0) + length = safe_int(request.GET.get('length'), c.visual.dashboard_items) + order_by, order_dir = self._extract_ordering(request) + + if c.awaiting_review: + pull_requests = PullRequestModel().get_awaiting_review( + repo_name, source=c.source, opened_by=opened_by, + statuses=statuses, offset=start, length=length, + order_by=order_by, order_dir=order_dir) + pull_requests_total_count = PullRequestModel( + ).count_awaiting_review( + repo_name, source=c.source, statuses=statuses, + opened_by=opened_by) + elif c.awaiting_my_review: + pull_requests = PullRequestModel().get_awaiting_my_review( + repo_name, source=c.source, opened_by=opened_by, + user_id=c.rhodecode_user.user_id, statuses=statuses, + offset=start, length=length, order_by=order_by, + order_dir=order_dir) + pull_requests_total_count = PullRequestModel( + ).count_awaiting_my_review( + repo_name, source=c.source, user_id=c.rhodecode_user.user_id, + statuses=statuses, opened_by=opened_by) + else: + pull_requests = PullRequestModel().get_all( + repo_name, source=c.source, opened_by=opened_by, + statuses=statuses, offset=start, length=length, + order_by=order_by, order_dir=order_dir) + pull_requests_total_count = PullRequestModel().count_all( + repo_name, source=c.source, statuses=statuses, + opened_by=opened_by) + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + data = [] + for pr in pull_requests: + comments = ChangesetCommentsModel().get_all_comments( + c.rhodecode_db_repo.repo_id, pull_request=pr) + + data.append({ + 'name': _render('pullrequest_name', + pr.pull_request_id, pr.target_repo.repo_name), + 'name_raw': pr.pull_request_id, + 'status': _render('pullrequest_status', + pr.calculated_review_status()), + 'title': _render( + 'pullrequest_title', pr.title, pr.description), + 'description': h.escape(pr.description), + 'updated_on': _render('pullrequest_updated_on', + h.datetime_to_time(pr.updated_on)), + 'updated_on_raw': h.datetime_to_time(pr.updated_on), + 'created_on': _render('pullrequest_updated_on', + h.datetime_to_time(pr.created_on)), + 'created_on_raw': h.datetime_to_time(pr.created_on), + 'author': _render('pullrequest_author', + pr.author.full_contact, ), + 'author_raw': pr.author.full_name, + 'comments': _render('pullrequest_comments', len(comments)), + 'comments_raw': len(comments), + 'closed': pr.is_closed(), + }) + # json used to render the grid + data = ({ + 'data': data, + 'recordsTotal': pull_requests_total_count, + 'recordsFiltered': pull_requests_total_count, + }) + return data + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + def index(self): + source_repo = c.rhodecode_db_repo + + try: + source_repo.scm_instance().get_commit() + except EmptyRepositoryError: + h.flash(h.literal(_('There are no commits yet')), + category='warning') + redirect(url('summary_home', repo_name=source_repo.repo_name)) + + commit_id = request.GET.get('commit') + branch_ref = request.GET.get('branch') + bookmark_ref = request.GET.get('bookmark') + + try: + source_repo_data = PullRequestModel().generate_repo_data( + source_repo, commit_id=commit_id, + branch=branch_ref, bookmark=bookmark_ref) + except CommitDoesNotExistError as e: + log.exception(e) + h.flash(_('Commit does not exist'), 'error') + redirect(url('pullrequest_home', repo_name=source_repo.repo_name)) + + default_target_repo = source_repo + if (source_repo.parent and + not source_repo.parent.scm_instance().is_empty()): + # change default if we have a parent repo + default_target_repo = source_repo.parent + + target_repo_data = PullRequestModel().generate_repo_data( + default_target_repo) + + selected_source_ref = source_repo_data['refs']['selected_ref'] + + title_source_ref = selected_source_ref.split(':', 2)[1] + c.default_title = PullRequestModel().generate_pullrequest_title( + source=source_repo.repo_name, + source_ref=title_source_ref, + target=default_target_repo.repo_name + ) + + c.default_repo_data = { + 'source_repo_name': source_repo.repo_name, + 'source_refs_json': json.dumps(source_repo_data), + 'target_repo_name': default_target_repo.repo_name, + 'target_refs_json': json.dumps(target_repo_data), + } + c.default_source_ref = selected_source_ref + + return render('/pullrequests/pullrequest.html') + + @LoginRequired() + @NotAnonymous() + @XHRRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def get_repo_refs(self, repo_name, target_repo_name): + repo = Repository.get_by_repo_name(target_repo_name) + if not repo: + raise HTTPNotFound + return PullRequestModel().generate_repo_data(repo) + + @LoginRequired() + @NotAnonymous() + @XHRRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def get_repo_destinations(self, repo_name): + repo = Repository.get_by_repo_name(repo_name) + if not repo: + raise HTTPNotFound + filter_query = request.GET.get('query') + + query = Repository.query() \ + .order_by(func.length(Repository.repo_name)) \ + .filter(or_( + Repository.repo_name == repo.repo_name, + Repository.fork_id == repo.repo_id)) + + if filter_query: + ilike_expression = u'%{}%'.format(safe_unicode(filter_query)) + query = query.filter( + Repository.repo_name.ilike(ilike_expression)) + + add_parent = False + if repo.parent: + if filter_query in repo.parent.repo_name: + if not repo.parent.scm_instance().is_empty(): + add_parent = True + + limit = 20 - 1 if add_parent else 20 + all_repos = query.limit(limit).all() + if add_parent: + all_repos += [repo.parent] + + repos = [] + for obj in self.scm_model.get_repos(all_repos): + repos.append({ + 'id': obj['name'], + 'text': obj['name'], + 'type': 'repo', + 'obj': obj['dbrepo'] + }) + + data = { + 'more': False, + 'results': [{ + 'text': _('Repositories'), + 'children': repos + }] if repos else [] + } + return data + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @HasAcceptedRepoType('git', 'hg') + @auth.CSRFRequired() + def create(self, repo_name): + repo = Repository.get_by_repo_name(repo_name) + if not repo: + raise HTTPNotFound + + try: + _form = PullRequestForm(repo.repo_id)().to_python(request.POST) + except formencode.Invalid as errors: + if errors.error_dict.get('revisions'): + msg = 'Revisions: %s' % errors.error_dict['revisions'] + elif errors.error_dict.get('pullrequest_title'): + msg = _('Pull request requires a title with min. 3 chars') + else: + msg = _('Error creating pull request: {}').format(errors) + log.exception(msg) + h.flash(msg, 'error') + + # would rather just go back to form ... + return redirect(url('pullrequest_home', repo_name=repo_name)) + + source_repo = _form['source_repo'] + source_ref = _form['source_ref'] + target_repo = _form['target_repo'] + target_ref = _form['target_ref'] + commit_ids = _form['revisions'][::-1] + reviewers = _form['review_members'] + + # find the ancestor for this pr + source_db_repo = Repository.get_by_repo_name(_form['source_repo']) + target_db_repo = Repository.get_by_repo_name(_form['target_repo']) + + source_scm = source_db_repo.scm_instance() + target_scm = target_db_repo.scm_instance() + + source_commit = source_scm.get_commit(source_ref.split(':')[-1]) + target_commit = target_scm.get_commit(target_ref.split(':')[-1]) + + ancestor = source_scm.get_common_ancestor( + source_commit.raw_id, target_commit.raw_id, target_scm) + + target_ref_type, target_ref_name, __ = _form['target_ref'].split(':') + target_ref = ':'.join((target_ref_type, target_ref_name, ancestor)) + + pullrequest_title = _form['pullrequest_title'] + title_source_ref = source_ref.split(':', 2)[1] + if not pullrequest_title: + pullrequest_title = PullRequestModel().generate_pullrequest_title( + source=source_repo, + source_ref=title_source_ref, + target=target_repo + ) + + description = _form['pullrequest_desc'] + try: + pull_request = PullRequestModel().create( + c.rhodecode_user.user_id, source_repo, source_ref, target_repo, + target_ref, commit_ids, reviewers, pullrequest_title, + description + ) + Session().commit() + h.flash(_('Successfully opened new pull request'), + category='success') + except Exception as e: + msg = _('Error occurred during sending pull request') + log.exception(msg) + h.flash(msg, category='error') + return redirect(url('pullrequest_home', repo_name=repo_name)) + + return redirect(url('pullrequest_show', repo_name=target_repo, + pull_request_id=pull_request.pull_request_id)) + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def update(self, repo_name, pull_request_id): + pull_request_id = safe_int(pull_request_id) + pull_request = PullRequest.get_or_404(pull_request_id) + # only owner or admin can update it + allowed_to_update = PullRequestModel().check_user_update( + pull_request, c.rhodecode_user) + if allowed_to_update: + if 'reviewers_ids' in request.POST: + self._update_reviewers(pull_request_id) + elif str2bool(request.POST.get('update_commits', 'false')): + self._update_commits(pull_request) + elif str2bool(request.POST.get('close_pull_request', 'false')): + self._reject_close(pull_request) + elif str2bool(request.POST.get('edit_pull_request', 'false')): + self._edit_pull_request(pull_request) + else: + raise HTTPBadRequest() + return True + raise HTTPForbidden() + + def _edit_pull_request(self, pull_request): + try: + PullRequestModel().edit( + pull_request, request.POST.get('title'), + request.POST.get('description')) + except ValueError: + msg = _(u'Cannot update closed pull requests.') + h.flash(msg, category='error') + return + else: + Session().commit() + + msg = _(u'Pull request title & description updated.') + h.flash(msg, category='success') + return + + def _update_commits(self, pull_request): + try: + if PullRequestModel().has_valid_update_type(pull_request): + updated_version, changes = PullRequestModel().update_commits( + pull_request) + if updated_version: + msg = _( + u'Pull request updated to "{source_commit_id}" with ' + u'{count_added} added, {count_removed} removed ' + u'commits.' + ).format( + source_commit_id=pull_request.source_ref_parts.commit_id, + count_added=len(changes.added), + count_removed=len(changes.removed)) + h.flash(msg, category='success') + else: + h.flash(_("Nothing changed in pull request."), + category='warning') + else: + msg = _( + u"Skipping update of pull request due to reference " + u"type: {reference_type}" + ).format(reference_type=pull_request.source_ref_parts.type) + h.flash(msg, category='warning') + except CommitDoesNotExistError: + h.flash( + _(u'Update failed due to missing commits.'), category='error') + + @auth.CSRFRequired() + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def merge(self, repo_name, pull_request_id): + """ + POST /{repo_name}/pull-request/{pull_request_id} + + Merge will perform a server-side merge of the specified + pull request, if the pull request is approved and mergeable. + After succesfull merging, the pull request is automatically + closed, with a relevant comment. + """ + pull_request_id = safe_int(pull_request_id) + pull_request = PullRequest.get_or_404(pull_request_id) + user = c.rhodecode_user + + if self._meets_merge_pre_conditions(pull_request, user): + log.debug("Pre-conditions checked, trying to merge.") + extras = vcs_operation_context( + request.environ, repo_name=pull_request.target_repo.repo_name, + username=user.username, action='push', + scm=pull_request.target_repo.repo_type) + self._merge_pull_request(pull_request, user, extras) + + return redirect(url( + 'pullrequest_show', + repo_name=pull_request.target_repo.repo_name, + pull_request_id=pull_request.pull_request_id)) + + def _meets_merge_pre_conditions(self, pull_request, user): + if not PullRequestModel().check_user_merge(pull_request, user): + raise HTTPForbidden() + + merge_status, msg = PullRequestModel().merge_status(pull_request) + if not merge_status: + log.debug("Cannot merge, not mergeable.") + h.flash(msg, category='error') + return False + + if (pull_request.calculated_review_status() + is not ChangesetStatus.STATUS_APPROVED): + log.debug("Cannot merge, approval is pending.") + msg = _('Pull request reviewer approval is pending.') + h.flash(msg, category='error') + return False + return True + + def _merge_pull_request(self, pull_request, user, extras): + merge_resp = PullRequestModel().merge( + pull_request, user, extras=extras) + + if merge_resp.executed: + log.debug("The merge was successful, closing the pull request.") + PullRequestModel().close_pull_request( + pull_request.pull_request_id, user) + Session().commit() + else: + log.debug( + "The merge was not successful. Merge response: %s", + merge_resp) + msg = PullRequestModel().merge_status_message( + merge_resp.failure_reason) + h.flash(msg, category='error') + + def _update_reviewers(self, pull_request_id): + reviewers_ids = map(int, filter( + lambda v: v not in [None, ''], + request.POST.get('reviewers_ids', '').split(','))) + PullRequestModel().update_reviewers(pull_request_id, reviewers_ids) + Session().commit() + + def _reject_close(self, pull_request): + if pull_request.is_closed(): + raise HTTPForbidden() + + PullRequestModel().close_pull_request_with_comment( + pull_request, c.rhodecode_user, c.rhodecode_db_repo) + Session().commit() + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def delete(self, repo_name, pull_request_id): + pull_request_id = safe_int(pull_request_id) + pull_request = PullRequest.get_or_404(pull_request_id) + # only owner can delete it ! + if pull_request.author.user_id == c.rhodecode_user.user_id: + PullRequestModel().delete(pull_request) + Session().commit() + h.flash(_('Successfully deleted pull request'), + category='success') + return redirect(url('my_account_pullrequests')) + raise HTTPForbidden() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + def show(self, repo_name, pull_request_id): + pull_request_id = safe_int(pull_request_id) + c.pull_request = PullRequest.get_or_404(pull_request_id) + + # pull_requests repo_name we opened it against + # ie. target_repo must match + if repo_name != c.pull_request.target_repo.repo_name: + raise HTTPNotFound + + c.allowed_to_change_status = PullRequestModel(). \ + check_user_change_status(c.pull_request, c.rhodecode_user) + c.allowed_to_update = PullRequestModel().check_user_update( + c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() + c.allowed_to_merge = PullRequestModel().check_user_merge( + c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() + + cc_model = ChangesetCommentsModel() + + c.pull_request_reviewers = c.pull_request.reviewers_statuses() + + c.pull_request_review_status = c.pull_request.calculated_review_status() + c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( + c.pull_request) + c.approval_msg = None + if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: + c.approval_msg = _('Reviewer approval is pending.') + c.pr_merge_status = False + # load compare data into template context + enable_comments = not c.pull_request.is_closed() + self._load_compare_data(c.pull_request, enable_comments=enable_comments) + + # this is a hack to properly display links, when creating PR, the + # compare view and others uses different notation, and + # compare_commits.html renders links based on the target_repo. + # We need to swap that here to generate it properly on the html side + c.target_repo = c.source_repo + + # inline comments + c.inline_cnt = 0 + c.inline_comments = cc_model.get_inline_comments( + c.rhodecode_db_repo.repo_id, + pull_request=pull_request_id).items() + # count inline comments + for __, lines in c.inline_comments: + for comments in lines.values(): + c.inline_cnt += len(comments) + + # outdated comments + c.outdated_cnt = 0 + if ChangesetCommentsModel.use_outdated_comments(c.pull_request): + c.outdated_comments = cc_model.get_outdated_comments( + c.rhodecode_db_repo.repo_id, + pull_request=c.pull_request) + # Count outdated comments and check for deleted files + for file_name, lines in c.outdated_comments.iteritems(): + for comments in lines.values(): + c.outdated_cnt += len(comments) + if file_name not in c.included_files: + c.deleted_files.append(file_name) + else: + c.outdated_comments = {} + + # comments + c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, + pull_request=pull_request_id) + + if c.allowed_to_update: + force_close = ('forced_closed', _('Close Pull Request')) + statuses = ChangesetStatus.STATUSES + [force_close] + else: + statuses = ChangesetStatus.STATUSES + c.commit_statuses = statuses + + c.ancestor = None # TODO: add ancestor here + + return render('/pullrequests/pullrequest_show.html') + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def comment(self, repo_name, pull_request_id): + pull_request_id = safe_int(pull_request_id) + pull_request = PullRequest.get_or_404(pull_request_id) + if pull_request.is_closed(): + raise HTTPForbidden() + + # TODO: johbo: Re-think this bit, "approved_closed" does not exist + # as a changeset status, still we want to send it in one value. + status = request.POST.get('changeset_status', None) + text = request.POST.get('text') + if status and '_closed' in status: + close_pr = True + status = status.replace('_closed', '') + else: + close_pr = False + + forced = (status == 'forced') + if forced: + status = 'rejected' + + allowed_to_change_status = PullRequestModel().check_user_change_status( + pull_request, c.rhodecode_user) + + if status and allowed_to_change_status: + message = (_('Status change %(transition_icon)s %(status)s') + % {'transition_icon': '>', + 'status': ChangesetStatus.get_status_lbl(status)}) + if close_pr: + message = _('Closing with') + ' ' + message + text = text or message + comm = ChangesetCommentsModel().create( + text=text, + repo=c.rhodecode_db_repo.repo_id, + user=c.rhodecode_user.user_id, + pull_request=pull_request_id, + f_path=request.POST.get('f_path'), + line_no=request.POST.get('line'), + status_change=(ChangesetStatus.get_status_lbl(status) + if status and allowed_to_change_status else None), + closing_pr=close_pr + ) + + if allowed_to_change_status: + old_calculated_status = pull_request.calculated_review_status() + # get status if set ! + if status: + ChangesetStatusModel().set_status( + c.rhodecode_db_repo.repo_id, + status, + c.rhodecode_user.user_id, + comm, + pull_request=pull_request_id + ) + + Session().flush() + # we now calculate the status of pull request, and based on that + # calculation we set the commits status + calculated_status = pull_request.calculated_review_status() + if old_calculated_status != calculated_status: + PullRequestModel()._trigger_pull_request_hook( + pull_request, c.rhodecode_user, 'review_status_change') + + calculated_status_lbl = ChangesetStatus.get_status_lbl( + calculated_status) + + if close_pr: + status_completed = ( + calculated_status in [ChangesetStatus.STATUS_APPROVED, + ChangesetStatus.STATUS_REJECTED]) + if forced or status_completed: + PullRequestModel().close_pull_request( + pull_request_id, c.rhodecode_user) + else: + h.flash(_('Closing pull request on other statuses than ' + 'rejected or approved is forbidden. ' + 'Calculated status from all reviewers ' + 'is currently: %s') % calculated_status_lbl, + category='warning') + + Session().commit() + + if not request.is_xhr: + return redirect(h.url('pullrequest_show', repo_name=repo_name, + pull_request_id=pull_request_id)) + + data = { + 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), + } + if comm: + c.co = comm + data.update(comm.get_dict()) + data.update({'rendered_text': + render('changeset/changeset_comment_block.html')}) + + return data + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @auth.CSRFRequired() + @jsonify + def delete_comment(self, repo_name, comment_id): + return self._delete_comment(comment_id) + + def _delete_comment(self, comment_id): + comment_id = safe_int(comment_id) + co = ChangesetComment.get_or_404(comment_id) + if co.pull_request.is_closed(): + # don't allow deleting comments on closed pull request + raise HTTPForbidden() + + is_owner = co.author.user_id == c.rhodecode_user.user_id + is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) + if h.HasPermissionAny('hg.admin')() or is_repo_admin or is_owner: + old_calculated_status = co.pull_request.calculated_review_status() + ChangesetCommentsModel().delete(comment=co) + Session().commit() + calculated_status = co.pull_request.calculated_review_status() + if old_calculated_status != calculated_status: + PullRequestModel()._trigger_pull_request_hook( + co.pull_request, c.rhodecode_user, 'review_status_change') + return True + else: + raise HTTPForbidden() diff --git a/rhodecode/controllers/search.py b/rhodecode/controllers/search.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/search.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Search controller for RhodeCode +""" + +import logging +import urllib + +from pylons import request, config, tmpl_context as c + +from webhelpers.util import update_params + +from rhodecode.lib.auth import LoginRequired, AuthUser +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.helpers import Page +from rhodecode.lib.utils2 import safe_str, safe_int +from rhodecode.lib.index import searcher_from_config +from rhodecode.model import validation_schema + +log = logging.getLogger(__name__) + + +class SearchController(BaseRepoController): + + @LoginRequired() + def index(self, repo_name=None): + + searcher = searcher_from_config(config) + formatted_results = [] + execution_time = '' + + schema = validation_schema.SearchParamsSchema() + + search_params = {} + errors = [] + try: + search_params = schema.deserialize( + dict(search_query=request.GET.get('q'), + search_type=request.GET.get('type'), + page_limit=request.GET.get('page_limit'), + requested_page=request.GET.get('page')) + ) + except validation_schema.Invalid as e: + errors = e.children + + search_query = search_params.get('search_query') + search_type = search_params.get('search_type') + + if search_params.get('search_query'): + page_limit = search_params['page_limit'] + requested_page = search_params['requested_page'] + + def url_generator(**kw): + q = urllib.quote(safe_str(search_query)) + return update_params( + "?q=%s&type=%s" % (q, safe_str(search_type)), **kw) + + c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id, + ip_addr=self.ip_addr) + + try: + search_result = searcher.search( + search_query, search_type, c.perm_user, repo_name) + + formatted_results = Page( + search_result['results'], page=requested_page, + item_count=search_result['count'], + items_per_page=page_limit, url=url_generator) + finally: + searcher.cleanup() + + if not search_result['error']: + execution_time = '%s results (%.3f seconds)' % ( + search_result['count'], + search_result['runtime']) + elif not errors: + node = schema['search_query'] + errors = [ + validation_schema.Invalid(node, search_result['error'])] + + c.errors = errors + c.formatted_results = formatted_results + c.runtime = execution_time + c.cur_query = search_query + c.search_type = search_type + # Return a rendered template + return render('/search/search.html') diff --git a/rhodecode/controllers/summary.py b/rhodecode/controllers/summary.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/summary.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Summary controller for RhodeCode Enterprise +""" + +import logging +from string import lower +from itertools import product + +from pylons import tmpl_context as c, request +from pylons.i18n.translation import _ +from beaker.cache import cache_region, region_invalidate + +from rhodecode.config.conf import ( + ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP) +from rhodecode.controllers import utils +from rhodecode.controllers.changelog import _load_changelog_summary +from rhodecode.lib import caches, helpers as h +from rhodecode.lib.utils import jsonify +from rhodecode.lib.utils2 import safe_str +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, XHRRequired) +from rhodecode.lib.base import BaseRepoController, render +from rhodecode.lib.markup_renderer import MarkupRenderer +from rhodecode.lib.ext_json import json +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib.vcs.exceptions import ( + CommitError, EmptyRepositoryError, NodeDoesNotExistError) +from rhodecode.model.db import Statistics, CacheKey, User + +log = logging.getLogger(__name__) + +README_FILES = [''.join([x[0][0], x[1][0]]) + for x in sorted(list(product(ALL_READMES, ALL_EXTS)), + key=lambda y:y[0][1] + y[1][1])] + + +class SummaryController(BaseRepoController): + + def __before__(self): + super(SummaryController, self).__before__() + + def __get_readme_data(self, db_repo): + repo_name = db_repo.repo_name + log.debug('Looking for README file') + + @cache_region('long_term') + def _generate_readme(cache_key): + readme_data = None + readme_file = None + try: + # gets the landing revision or tip if fails + commit = db_repo.get_landing_commit() + if isinstance(commit, EmptyCommit): + raise EmptyRepositoryError() + renderer = MarkupRenderer() + for f in README_FILES: + try: + node = commit.get_node(f) + except NodeDoesNotExistError: + continue + + if not node.is_file(): + continue + + readme_file = f + log.debug('Found README file `%s` rendering...', + readme_file) + readme_data = renderer.render(node.content, + filename=f) + break + except CommitError: + log.exception("Problem getting commit") + pass + except EmptyRepositoryError: + pass + except Exception: + log.exception("General failure") + + return readme_data, readme_file + + invalidator_context = CacheKey.repo_context_cache( + _generate_readme, repo_name, CacheKey.CACHE_TYPE_README) + + with invalidator_context as context: + context.invalidate() + computed = context.compute() + + return computed + + + @LoginRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + def index(self, repo_name): + username = '' + if c.rhodecode_user.username != User.DEFAULT_USER: + username = safe_str(c.rhodecode_user.username) + + _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl + if '{repo}' in _def_clone_uri: + _def_clone_uri_by_id = _def_clone_uri.replace( + '{repo}', '_{repoid}') + elif '{repoid}' in _def_clone_uri: + _def_clone_uri_by_id = _def_clone_uri.replace( + '_{repoid}', '{repo}') + + c.clone_repo_url = c.rhodecode_db_repo.clone_url( + user=username, uri_tmpl=_def_clone_uri) + c.clone_repo_url_id = c.rhodecode_db_repo.clone_url( + user=username, uri_tmpl=_def_clone_uri_by_id) + + c.show_stats = bool(c.rhodecode_db_repo.enable_statistics) + + stats = self.sa.query(Statistics)\ + .filter(Statistics.repository == c.rhodecode_db_repo)\ + .scalar() + + c.stats_percentage = 0 + + if stats and stats.languages: + c.no_data = False is c.rhodecode_db_repo.enable_statistics + lang_stats_d = json.loads(stats.languages) + + # Sort first by decreasing count and second by the file extension, + # so we have a consistent output. + lang_stats_items = sorted(lang_stats_d.iteritems(), + key=lambda k: (-k[1], k[0]))[:10] + lang_stats = [(x, {"count": y, + "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) + for x, y in lang_stats_items] + + c.trending_languages = json.dumps(lang_stats) + else: + c.no_data = True + c.trending_languages = json.dumps({}) + + c.enable_downloads = c.rhodecode_db_repo.enable_downloads + c.repository_followers = self.scm_model.get_followers( + c.rhodecode_db_repo) + c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo) + c.repository_is_user_following = self.scm_model.is_following_repo( + c.repo_name, c.rhodecode_user.user_id) + + if c.repository_requirements_missing: + return render('summary/missing_requirements.html') + + c.readme_data, c.readme_file = \ + self.__get_readme_data(c.rhodecode_db_repo) + + _load_changelog_summary() + + if request.is_xhr: + return render('changelog/changelog_summary_data.html') + + return render('summary/summary.html') + + @LoginRequired() + @XHRRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + @jsonify + def repo_stats(self, repo_name, commit_id): + _namespace = caches.get_repo_namespace_key( + caches.SUMMARY_STATS, repo_name) + show_stats = bool(c.rhodecode_db_repo.enable_statistics) + cache_manager = caches.get_cache_manager('repo_cache_long', _namespace) + _cache_key = caches.compute_key_from_params( + repo_name, commit_id, show_stats) + + def compute_stats(): + code_stats = {} + size = 0 + try: + scm_instance = c.rhodecode_db_repo.scm_instance() + commit = scm_instance.get_commit(commit_id) + + for node in commit.get_filenodes_generator(): + size += node.size + if not show_stats: + continue + ext = lower(node.extension) + ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext) + if ext_info: + if ext in code_stats: + code_stats[ext]['count'] += 1 + else: + code_stats[ext] = {"count": 1, "desc": ext_info} + except EmptyRepositoryError: + pass + return {'size': h.format_byte_size_binary(size), + 'code_stats': code_stats} + + stats = cache_manager.get(_cache_key, createfunc=compute_stats) + return stats + + def _switcher_reference_data(self, repo_name, references, is_svn): + """Prepare reference data for given `references`""" + items = [] + for name, commit_id in references.items(): + use_commit_id = '/' in name or is_svn + items.append({ + 'name': name, + 'commit_id': commit_id, + 'files_url': h.url( + 'files_home', + repo_name=repo_name, + f_path=name if is_svn else '', + revision=commit_id if use_commit_id else name, + at=name) + }) + return items + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', + 'repository.admin') + @jsonify + def repo_refs_data(self, repo_name): + repo = c.rhodecode_repo + refs_to_create = [ + (_("Branch"), repo.branches, 'branch'), + (_("Tag"), repo.tags, 'tag'), + (_("Bookmark"), repo.bookmarks, 'book'), + ] + res = self._create_reference_data(repo, refs_to_create) + data = { + 'more': False, + 'results': res + } + return data + + @jsonify + def repo_refs_changelog_data(self, repo_name): + repo = c.rhodecode_repo + + refs_to_create = [ + (_("Branches"), repo.branches, 'branch'), + (_("Closed branches"), repo.branches_closed, 'branch_closed'), + # TODO: enable when vcs can handle bookmarks filters + # (_("Bookmarks"), repo.bookmarks, "book"), + ] + res = self._create_reference_data(repo, refs_to_create) + data = { + 'more': False, + 'results': res + } + return data + + def _create_reference_data(self, repo, refs_to_create): + format_ref_id = utils.get_format_ref_id(repo) + + result = [] + for title, refs, ref_type in refs_to_create: + if refs: + result.append({ + 'text': title, + 'children': self._create_reference_items( + repo, refs, ref_type, format_ref_id), + }) + return result + + def _create_reference_items(self, repo, refs, ref_type, format_ref_id): + result = [] + is_svn = h.is_svn(repo) + for name, raw_id in refs.iteritems(): + result.append({ + 'text': name, + 'id': format_ref_id(name, raw_id), + 'raw_id': raw_id, + 'type': ref_type, + 'files_url': self._create_files_url(repo, name, raw_id, is_svn) + }) + return result + + def _create_files_url(self, repo, name, raw_id, is_svn): + use_commit_id = '/' in name or is_svn + return h.url( + 'files_home', + repo_name=repo.name, + f_path=name if is_svn else '', + revision=raw_id if use_commit_id else name, + at=name) diff --git a/rhodecode/controllers/tags.py b/rhodecode/controllers/tags.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/tags.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Tags controller for rhodecode +""" + +import logging + +from rhodecode.controllers.base_references import BaseReferencesController + +log = logging.getLogger(__name__) + + +class TagsController(BaseReferencesController): + + partials_template = 'tags/tags_data.html' + template = 'tags/tags.html' + + def _get_reference_items(self, repo): + return repo.tags.items() diff --git a/rhodecode/controllers/users.py b/rhodecode/controllers/users.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/users.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Users profile controller +""" + +from pylons import tmpl_context as c +from webob.exc import HTTPNotFound + +from rhodecode.lib.auth import LoginRequired, NotAnonymous +from rhodecode.lib.base import BaseController, render +from rhodecode.model.db import User +from rhodecode.model.user import UserModel + + +class UsersController(BaseController): + @LoginRequired() + @NotAnonymous() + def user_profile(self, username): + c.user = UserModel().get_by_username(username) + if not c.user or c.user.username == User.DEFAULT_USER: + raise HTTPNotFound() + + c.active = 'user_profile' + return render('users/user.html') diff --git a/rhodecode/controllers/utils.py b/rhodecode/controllers/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/controllers/utils.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Utilities to be shared by multiple controllers. + +Should only contain utilities to be shared in the controller layer. +""" + +from rhodecode.lib import helpers as h +from rhodecode.lib.vcs.exceptions import RepositoryError + +def parse_path_ref(ref, default_path=None): + """ + Parse out a path and reference combination and return both parts of it. + + This is used to allow support of path based comparisons for Subversion + as an iterim solution in parameter handling. + """ + if '@' in ref: + return ref.rsplit('@', 1) + else: + return default_path, ref + + +def get_format_ref_id(repo): + """Returns a `repo` specific reference formatter function""" + if h.is_svn(repo): + return _format_ref_id_svn + else: + return _format_ref_id + + +def _format_ref_id(name, raw_id): + """Default formatting of a given reference `name`""" + return name + + +def _format_ref_id_svn(name, raw_id): + """Special way of formatting a reference for Subversion including path""" + return '%s@%s' % (name, raw_id) + + +def get_commit_from_ref_name(repo, ref_name, ref_type=None): + """ + Gets the commit for a `ref_name` taking into account `ref_type`. + Needed in case a bookmark / tag share the same name. + + :param repo: the repo instance + :param ref_name: the name of the ref to get + :param ref_type: optional, used to disambiguate colliding refs + """ + repo_scm = repo.scm_instance() + ref_type_mapping = { + 'book': repo_scm.bookmarks, + 'bookmark': repo_scm.bookmarks, + 'tag': repo_scm.tags, + 'branch': repo_scm.branches, + } + + commit_id = ref_name + if repo_scm.alias != 'svn': # pass svn refs straight to backend until + # the branch issue with svn is fixed + if ref_type and ref_type in ref_type_mapping: + try: + commit_id = ref_type_mapping[ref_type][ref_name] + except KeyError: + raise RepositoryError( + '%s "%s" does not exist' % (ref_type, ref_name)) + + return repo_scm.get_commit(commit_id) diff --git a/rhodecode/i18n/be/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/be/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..78c7290e6f1a8b17229ce5792ab11dad8e426efa GIT binary patch literal 124230 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%0A@6<1VOaw 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 diff --git a/rhodecode/i18n/be/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/be/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/be/LC_MESSAGES/rhodecode.po @@ -0,0 +1,8073 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:09+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Belarusian (http://www.transifex.com/rhodecode/RhodeCode/language/be/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: be\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "" + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "" + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "" + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "" + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" diff --git a/rhodecode/i18n/de/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/de/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..38f87237765b0978b0a1809ecdff6f201478bfa3 GIT binary patch literal 124653 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 diff --git a/rhodecode/i18n/de/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/de/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/de/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7993 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Johannes Bornhold <johannes.bornhold@gmail.com>, 2015 +# Stephan Jauernick <info@stephan-jauernick.de>, 2013,2015 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: German (http://www.transifex.com/rhodecode/RhodeCode/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Aktiviert" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "Es sind noch keine Commits vorhanden" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "Zeige Leerzeichen" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "Ignoriere Leerzeichen" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "Status Änderung %(transition_icon)s %(status)s" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Homepage" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "Die Anfrage konnte vom Server nicht ausgewertet werden weil sie eine ungültige Syntax nutzt" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Unauthorisierter Zugang zur Ressource" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Du hast keine Rechte um diese Seite zu betrachten" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "Die Ressource konnte nicht gefunden werden" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "Aufgrund einer unerwarteten Gegebenheit konnte der Server diese Anfrage nicht bearbeiten" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Änderungen im %s Repository" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s Feed" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "Es sind noch keine Dateien vorhanden. %s" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "Das Repository is vom %s seit %s gesperrt" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "Du kannst Dateien nur dann löschen, wenn die Revision ein gültiger Branch ist" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "Datei %s wurde über RhodeCode Enterprise gelöscht." + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "Datei %s erfolgreich gelöscht" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Während des Committens trat ein Fehler auf" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Du kannst Dateien nur dann bearbeiten, wenn die Revision ein gültiger Branch ist" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "Datei %s wurde über RhodeCode Enterprise editiert." + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Keine Änderungen" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Der Commit zu %s war erfolgreich" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "Eine Datei wurde über RhodeCode Enterprise hinzugefügt." + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Kein Dateiname" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "Die spezifizierte Adresse muss ein gültiger Pfad sein und .. darf nicht teil des Pfades sein" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Downloads deaktiviert" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Unbekannte Revision %s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Leeres Repository" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Unbekannter Archiv Typ" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Changesets" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Entwicklungszweige" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Tags" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Währen des Forken des Repositorys trat ein Fehler auf: %s" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Gruppen" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Repositories" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "Öffentliches Journal" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "Logbuch" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "Ungültiges Captcha" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "Du hast dich erfolgreich bei RhodeCode angemeldet" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Ihr Passwort Zurücksetzen Link wurde versendet" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "Ihr Passwort wurde zurückgesetzt, ein neues Passwort wurde and ihre E-Mail Adresse gesendet" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "Der Titel eines Pullrequests muss mindestens aus 3 Zeichen bestehen" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "Es wurde erfolgreich ein neuer Pullrequest eröffnet" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Es trat ein Fehler auf während der Pullrequest gesendet wurde" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "Reviewer Zustimmung fehlt." + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "Pullrequest erfolgreich gelöscht" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "Reviewer Zustimmung steht noch aus." + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Schließen mit" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "Ein Pullrequest kann nur in den Stati rejected oder approved geschlossen werden. Berechneter Status aus den Reviews ist: %s" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "Branch" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "Tag" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "Lesezeichen" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "Geschlossene Branches" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Standardeinstellungen erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "Fehler bei der Aktualisierung der Standardwerte aufgetreten" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "für immer" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 Minuten" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 Stunde" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 Tag" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 Monat" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "Lebensdauer" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Fehler bei der Erstellung des Gist aufgetreten" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "Gist %s gelöscht" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "Gist Inhalt erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "Gist Daten erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "Fehler beim Update des Gist %s aufgetreten" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Sie können diesen Benutzer nicht editieren, da er für die ganze Applikation von entscheidender bedeutung ist." + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Ihr Account wurde erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "Fehler bei der Aktualisierung des Benutzers %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "Passwort erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "Fehler bei der Aktualisierung des Benutzerpassworts aufgetreten" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Währen der Speicherung der E-Mail-Addresse trat ein Fehler auf" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "Rolle" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "Authentifizierungstoken erfolgreich erstellt" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "Authentifizierungstoken erfolgreich zurückgesetzt" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "Authentifizierungstoken erfolgreich gelöscht" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "Anwendungs-Berechtigungen erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Fehler bei der Aktualisierung der Berechtigungen aufgetreten" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "Objekt-Berechtigungen erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "Globale Berechtigungen erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Repository-Gruppe %s erstellt" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Fehler bei der Erstellung der Repository-Gruppe %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Repository-Gruppe %s aktualisiert" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Fehler bei der Aktualisierung der Repository-Gruppe %s aufgetreten" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "Diese Gruppe enthält %(num)d Repository und kann nicht gelöscht werden" +msgstr[1] "Diese Gruppe enthält %(num)d Repositories und kann nicht gelöscht werden" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "Diese Gruppe enthält %(num)d Untergruppe und kann nicht gelöscht werden" +msgstr[1] "Diese Gruppe enthält %(num)d Untergruppen und kann nicht gelöscht werden" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Repository-Gruppe %s gelöscht" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Fehler beim Löschen der Repository-Gruppe %s aufgetreten" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "Es ist nicht möglich als Administrator die eigenen Berechtigungen zu ändern" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Berechtigungen der Repository-Gruppe aktualisiert" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "Fehler beim Erstellen des Repositorys %s: Ungültiges Zertifikat" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "Fehler beim Erstellen des Repositorys %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "Repository %s von %s erstellt" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Repository %s als %s geforkt" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Repository %s erstellt" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Repository %s wurde erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Fehler bei der Aktualisierung des Repositorys %s aufgetreten" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "%s Forks abgetrennt" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "%s Forks gelöscht" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Repository %s gelöscht" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "%s konnte nicht gelöscht werden da es noch Forks enthält" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Fehler beim Löschen von %s aufgetreten" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Repository Berechtigungen aktualisiert" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Fehler bei der Erstellung des Feldes aufgetreten" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Fehler beim Löschen des Feldes aufgetreten" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Sichtbarkeit des Repositorys im öffentlichen Logbuch aktualisiert" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Es trat ein Fehler während der Aktualisierung der Sicherbarkeit dieses Repositorys im Öffentlichen Logbuch auf" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Nichts" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Markiere Repository %s als Abzweig von Repository %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Während dieser operation trat ein Fehler auf" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "Gesperrtes Respository" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "Entsperrtes Repository" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Fehler beim Entsperren des Repositorys aufgetreten" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Entsperrt" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Gesperrt" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "Repository wurde %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "Cache erfolgreich invalidiert" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Währen der Cache Invalidierung trat ein Fehler auf" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Von entferntem Ort übertragen" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Fehler während des Abrufens vom remote Speicherplatz aufgetreten" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Fehler während des Löschens der Repository-Statistik aufgetreten" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "Ein Eintrag wurde aus dem Issue Tracker gelöscht." + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "Einige Eingabefelder enthalten ungültige Daten." + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "VCS-Einstellungen aktualisiert" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Fehler während der Aktualisierung der Applikations-Einstellungen aufgetreten" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Repositories erfolgreich gescannt, hinzugefügt: %s; entfernt: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Applikations-Einstellungen aktualisiert" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Visualisierungs-Einstellungen aktualisiert" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Fehler bei der Aktualisierung der Visualisierungs-Einstellungen" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "Bitte E-Mail-Adresse eingeben" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "Aufgabe zum Senden der E-Mail erstellt" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Neuer Hook hinzugefügt" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Die Hooks wurden aktutalisiert" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "Kritisch: Ihr Plattenplatz ist sehr gering <b>%s%%</b> belegt" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "Warnung: Ihr Plattenplatz geht zur Neige <b>%s%%</b> belegt" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "Fehler bei der Aktualisierung der Labs-Einstellungen aufgetreten" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "Labs-Einstellungen aktualisiert" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "Mercurial merge auf der Serverseite" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "EMail" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "Benutzergruppe %(user_group_link)s erstellt" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Fehler bei der Erstellung der Benutzergruppe %s aufgetreten" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Benutzergruppe %s aktualisiert" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Fehler bei der Aktualisierung des Benutzers %s aufgetreten" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Benutzergruppe erfolgreich gelöscht" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Fehler beim Löschen der Benutzergruppe aufgetreten" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "Zielgruppe kann nicht die gleiche sein" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Berechtigungen der Benutzergruppe aktualisiert" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "Globale Berechtigungen der Benutzergruppe aktualisiert" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Fehler beim Speichern der Berechtigungen aufgetreten" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "Benutzer %(user_link)s erstellt" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Fehler beim Erstellen des Benutzers %s aufgetreten" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Der Benutzer wurde erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "%s Repositories abgetrennt" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "%s Repositories gelöscht" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "%s Repository-Gruppen abgetrennt" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "%s Repository-Gruppen gelöscht" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "%s Benutzergruppen abgetrennt" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "%s Benutzergruppen gelöscht" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Benutzer erfolgreich gelöscht" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Während der Löschen des Benutzers trat ein Fehler auf" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "Erzwungene Passwortänderung inaktiv für Benutzer" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "Erzwungene Passwortänderung aktiv für Benutzer" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "Fehler beim Zurücksetzen des Passworts für den Benutzer aufgetreten" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "Repository-Gruppe %s erstellt" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "Fehler bei der Erstellung der Repository-Gruppe aufgetreten" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Sie können diesen Benutzer nicht editieren" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "Globale Berechtigungen des Benutzers erfolgreich aktualisiert" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "Fehler beim Speichern der IP-Adresse aufgetreten: %s" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Fehler beim Speichern der IP-Adresse aufgetreten" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "IP-Adressen %s zur Whitelist des Benutzers hinzugefügt" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "IP-Adressen von der Whitelist des Benutzers entfernt" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[gelöscht] Repository" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[erstellt] Repository" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[erstellt] Repository als Fork" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[forked] Repository" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[aktualisiert] Repository" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[gelöscht] Repository" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[erstellt] Benutzer" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[akutalisiert] Benutzer" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "[erstellt] Benutzergruppe" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "[aktualisiert] Benutzergruppe" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[übermittelt] in" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[beginnt zu folgen] Repository" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[folgt nicht mehr] Repository" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "Fork Name %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Pullrequest #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "vergleichsansicht" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Gelöschter Branch: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "Tag erstellt: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IP-Adresse %s nicht erlaubt" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Sie müssen ein Registrierter Nutzer sein um diese Aktion durchzuführen" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "Aktion wird für %s nicht unterstützt." + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "Sie müssen angemeldet sein, um diese Seite zu betrachten" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "Binärdatei" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Der Änderungssatz war zu groß und wurde abgeschnitten, benutzen sie das Diff Menü um die Unterschiede anzuzeigen" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Keine Änderungen erkannt" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "und %s weitere" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Keine Dateien" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "neue Datei" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "moderieren" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "löschen" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "umbennen" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "Das %s Repository ist nicht in der Datenbank vorhanden, eventuell wurde es im Dateisystem erstellt oder umbenannt. Bitte starten sie die Applikation erneut um die Repositories neu zu Indizieren" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d Jahr" +msgstr[1] "%d Jahre" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d Monat" +msgstr[1] "%d Monate" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d Tag" +msgstr[1] "%d Tage" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d Stunde" +msgstr[1] "%d Stunden" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d Minute" +msgstr[1] "%d Minuten" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d Sekunde" +msgstr[1] "%d Sekunden" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "vor %s" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s und %s her" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "jetzt gerade" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Passwort" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Kein Zugriff auf Repository" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Lesender Zugriff auf Repository" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Schreibdender Zugriff auf Repository" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Administrativer Zugang zum Repository" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Repository Gruppe hat Keinen Zugriff" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Repository Gruppe hat lesenden Zugriff" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Repository Gruppe hat schreibenden Zugriff" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Repository Gruppe hat Administrativen Zugriff" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "RhodeCode Administrator" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Repository erstelllung deaktiviert" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Repository erstellung aktiviert" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Registrierung deaktiviert" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Registrierung neuer Benutzer in RhodeCode mit manueller Aktivierung" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Registrierung neuer Benutzer in RhodeCode mit Automatischer Aktivierung" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Nicht Begutachtet" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Akzeptiert" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Abgelehnt" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "In Begutachtung" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Ungültige Suchanfrage. Versuchen sie die Anfrage in Anführungszeichen zu setzen." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "Es gibt keinen durchsuchbaren Index. Bitte den Whoosh Indizierer ausführen" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Während dieser Suche trat ein Fehler auf" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Bitte einen Benutzernamen eingeben" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Bitte einen Wert mit mindestens %(min)i Zeichen eingeben" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Bitte ein Passwort eingeben" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Bitte mindestens %(min)i Zeichen eingeben" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "Pullrequest zusammengeführt und geschlossen" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Lesezeichen" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Sie können diesen User nicht editieren da er für die ganze Applikation von entscheidender bedeutung ist." + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Sie können diesen User nicht löschen da er für die ganze Applikation von entscheidender bedeutung ist." + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "Benutezrname \"%(username)s\" existiert bereits" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "Benutzername \"%(username)s\" ist verboten" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "Benutzername \"%(username)s\" ist ungültig" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Kann diese Gruppe nicht als vorgesetzt setzen" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "Gruppe \"%(group_name)s\" existiert bereits" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Es gibt bereits ein Repository mit \"%(group_name)s\"" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "Üngültige(nicht ASCII) Zeichen im Passwort" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Die Passwörter stimmen nicht überein" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "Ungültiges Passwort" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "Ungültiger Benutzername" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Ihr Account wurde Deaktiviert" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Schlüssel stimmt nicht überein" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "Repository Name \"%(repo)s\" ist verboten" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "Forke um den selben typ wie der Vorgesetze zu haben" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "Dies ist ein Ungültiger Pfad" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Diese EMail Addresse ist schon in Benutzung" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "EMail Addresse \"%(email)s\" existiert nicht." + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "Das LDAP Login Attribut des CN muss angeben werden - Es ist der Name des Attributes welches das Equivalent zum \"Benutzername\" ist" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Übersichtsseite" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "Schnellfilter..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Name" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Beschreibung" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Besitzer" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Letzte Änderung" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Einloggen" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Benutzername" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Login Speichern" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "Passwort vergessen?" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "Passwort zurücksetzen" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "E-Mail-Adresse" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "Captcha" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Der Passwort Reset LInk wird an die passende EMail Addresse gesendet" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Passwort erneut eingeben" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Vorname" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Nachname" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "Admin Logbuch" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "Logbuch filter..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Aktion" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Repository" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Datum" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "Von IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Es sind bisher keine Aktionen passiert" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Admin" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Speichern" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Typ" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Zurücksetzen" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Löschen" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "Mein Account" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "Mein Account" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Hinzufügen" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Meine Benachrichtigungen" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Alle" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Kommentare" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Bisher gibt es keine Benachrichtigungen" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Zeige Benachrichtigung" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Benachrichtigungen" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Rechte" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Registrierung" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "Benutzergruppen" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Einstellungen" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "Keine" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Lesen" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Schreiben" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Neues Repository" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Clone von" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Entfernt" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Statistiken" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Aktiv" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "privates Repository" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "bearbeiten" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Repository Gruppe" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Privates Repository" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Aktiviere Statistiken" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Aktiviere Downloads" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Einstellungen speichern" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "Repositories" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Senden" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "Parst Meta-Tags aus der Repository-Beschreibung und erstellt farbige Tags." + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Icons" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Icon für öffentliche Repositories anzeigen" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Icon für private Repositories anzeigen" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "Icons für öffentliche/private Repositories neben dem Namen anzeigen" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "Benutzergruppe hinzufügen" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "Benutzergruppen" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "Benutzergruppe hinzufügen" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Gruppen name" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "Kurze, optionale Beschreibung für diese Benutzergruppe" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "%s Benutzergruppen Einstellungen" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "Globale Berechtigungen" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "Berechtigungsübersicht" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Mitglieder" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "Zugewiesen zu Repositories" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "Zugewiesen zu Repository-Gruppen" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "Benutzergruppe: %s" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "Bestägigen dass die Benutzergrupe `%(ugroup)s` mit allen Berechtigungen gelöscht werden soll" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "Noch keine Mitglieder" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "entziehen" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "Besitzer dieser Benutzergruppe ändern" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "Ausgewählte Gruppenmitglieder" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Alle Elemente entfernen" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Verfügbare Mitglieder" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Alle Elemente hinzufügen" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "Verwaltung der Benutzergruppen" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "Benutzergruppen" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Benutzer hinzufügen" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Benutzer" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "Benutzer hinzufügen" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Passwort bestätigen" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "Passwort generieren" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "Passwort ändern" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "Benutzer zwingen das Passwort bei der nächsten Anmeldung zu ändern" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "Benutzergruppe mit dem Namen dieses Benutzers erstellen.\nDer Benutzer wird automatisch als Besitzer dieser Gruppe eingetragen." + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "Generiertes Passwort:" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "E-Mails" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "Quelle des Eintrags" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "Letzte Anmeldung" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "Letzte Aktivität" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "Mitglied in Benutzergruppen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "Erzwinge Passwortänderung" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "Benutzer: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "Erstelle persönliche Repository-Gruppe" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "Repositories abtrennen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "Repositories löschen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "Repository-Gruppen abtrennen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "Benutzergruppen abtrennen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Bestätigen den Benutzer %s zu löschen" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "Lösche diesen Benutzer" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "Keine zusätzlichen Authentifizierungstoken spezifiziert" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "Geerbt von %s" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Benutzerverwaltung" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "Autentifizierungstyp" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "Support" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "Authentifizierung" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "Standards" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Zusammenfassung" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "Dateien" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Vergleiche" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "Zeige Pullrequests für %s" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Optionen" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Vergleiche Fork" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Suche" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "Entsperren" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "Sperren" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "Pullrequest erstellen" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "Anmelden" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "(Kennwort vergessen?)" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Kein Account?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Logbuch" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Öffentliches Logbuch" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "keine" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "lesen" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "schreiben" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "admin" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Rechte" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "Super-Administrator" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Öffenentliches Repository" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "Abonniere den %s RSS Feed" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "Abonniere den %s ATOM Feed" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Lade..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "ATOM Logbuch Feed" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "RSS Logbuch Feed" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Öffentliches Logbuch" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "ATOM Feed für das Öffentliche Logbuch" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "RSS Feed für das Öffentliche Logbuch" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "Die Statistik ist für dieses Repository deaktiviert" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" diff --git a/rhodecode/i18n/en/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/en/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..7b6f795177fba816e1a4f207dfc8680f5df10df8 GIT binary patch literal 61436 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 diff --git a/rhodecode/i18n/en/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/en/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/en/LC_MESSAGES/rhodecode.po @@ -0,0 +1,4662 @@ +# English translations for rhodecode. +# Copyright (C) 2015 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: rhodecode 0.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2013-06-01 18:38+0200\n" +"PO-Revision-Date: 2011-02-25 19:13+0100\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: en <LL@li.org>\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + +#: rhodecode/controllers/changelog.py:149 +msgid "All Branches" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +msgid "Show white space" +msgstr "" + +#: rhodecode/controllers/changeset.py:91 rhodecode/controllers/changeset.py:98 +msgid "Ignore white space" +msgstr "" + +#: rhodecode/controllers/changeset.py:164 +#, python-format +msgid "%s line context" +msgstr "" + +#: rhodecode/controllers/changeset.py:345 +#: rhodecode/controllers/pullrequests.py:481 +#, python-format +msgid "Status change -> %s" +msgstr "" + +#: rhodecode/controllers/changeset.py:376 +msgid "" +"Changing status on a changeset associated with a closed pull request is " +"not allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:74 +#: rhodecode/controllers/pullrequests.py:259 +msgid "There are no changesets yet" +msgstr "" + +#: rhodecode/controllers/error.py:69 +msgid "Home page" +msgstr "" + +#: rhodecode/controllers/error.py:98 +msgid "The request could not be understood by the server due to malformed syntax." +msgstr "" + +#: rhodecode/controllers/error.py:101 +msgid "Unauthorized access to resource" +msgstr "" + +#: rhodecode/controllers/error.py:103 +msgid "You don't have permission to view this page" +msgstr "" + +#: rhodecode/controllers/error.py:105 +msgid "The resource could not be found" +msgstr "" + +#: rhodecode/controllers/error.py:107 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "" + +#: rhodecode/controllers/feed.py:52 +#, python-format +msgid "Changes on %s repository" +msgstr "" + +#: rhodecode/controllers/feed.py:53 +#, python-format +msgid "%s %s feed" +msgstr "" + +#: rhodecode/controllers/feed.py:86 +#: rhodecode/templates/changeset/changeset.html:141 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/compare/compare_diff.html:58 +#: rhodecode/templates/compare/compare_diff.html:69 +#: rhodecode/templates/pullrequests/pullrequest_show.html:131 +#: rhodecode/templates/pullrequests/pullrequest_show.html:195 +msgid "Changeset was too big and was cut off..." +msgstr "" + +#: rhodecode/controllers/feed.py:90 +#, python-format +msgid "%s committed on %s" +msgstr "" + +#: rhodecode/controllers/files.py:89 +msgid "Click here to add new file" +msgstr "" + +#: rhodecode/controllers/files.py:90 +#, python-format +msgid "There are no files yet %s" +msgstr "" + +#: rhodecode/controllers/files.py:271 rhodecode/controllers/files.py:339 +#, python-format +msgid "This repository is has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:283 +msgid "You can only edit files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:297 +#, python-format +msgid "Edited file %s via RhodeCode" +msgstr "" + +#: rhodecode/controllers/files.py:313 +msgid "No changes" +msgstr "" + +#: rhodecode/controllers/files.py:322 rhodecode/controllers/files.py:394 +#, python-format +msgid "Successfully committed to %s" +msgstr "" + +#: rhodecode/controllers/files.py:327 rhodecode/controllers/files.py:405 +msgid "Error occurred during commit" +msgstr "" + +#: rhodecode/controllers/files.py:351 +msgid "Added file via RhodeCode" +msgstr "" + +#: rhodecode/controllers/files.py:368 +msgid "No content" +msgstr "" + +#: rhodecode/controllers/files.py:372 +msgid "No filename" +msgstr "" + +#: rhodecode/controllers/files.py:397 +msgid "Location must be relative path and must not contain .. in path" +msgstr "" + +#: rhodecode/controllers/files.py:431 +msgid "Downloads disabled" +msgstr "" + +#: rhodecode/controllers/files.py:442 +#, python-format +msgid "Unknown revision %s" +msgstr "" + +#: rhodecode/controllers/files.py:444 +msgid "Empty repository" +msgstr "" + +#: rhodecode/controllers/files.py:446 +msgid "Unknown archive type" +msgstr "" + +#: rhodecode/controllers/files.py:631 +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/email_templates/pull_request.html:12 +#: rhodecode/templates/pullrequests/pullrequest.html:124 +msgid "Changesets" +msgstr "" + +#: rhodecode/controllers/files.py:632 rhodecode/controllers/pullrequests.py:152 +#: rhodecode/controllers/summary.py:76 rhodecode/model/scm.py:682 +#: rhodecode/templates/switch_to_list.html:3 +#: rhodecode/templates/branches/branches.html:10 +msgid "Branches" +msgstr "" + +#: rhodecode/controllers/files.py:633 rhodecode/controllers/pullrequests.py:153 +#: rhodecode/controllers/summary.py:77 rhodecode/model/scm.py:693 +#: rhodecode/templates/switch_to_list.html:15 +#: rhodecode/templates/tags/tags.html:10 +msgid "Tags" +msgstr "" + +#: rhodecode/controllers/forks.py:176 +#, python-format +msgid "Forked repository %s as %s" +msgstr "" + +#: rhodecode/controllers/forks.py:190 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "" + +#: rhodecode/controllers/journal.py:110 rhodecode/controllers/journal.py:153 +msgid "public journal" +msgstr "" + +#: rhodecode/controllers/journal.py:114 rhodecode/controllers/journal.py:157 +#: rhodecode/templates/journal/journal.html:12 +msgid "journal" +msgstr "" + +#: rhodecode/controllers/login.py:138 +msgid "You have successfully registered into RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:159 +msgid "Your password reset link was sent" +msgstr "" + +#: rhodecode/controllers/login.py:179 +msgid "" +"Your password reset was successful, new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:139 +#: rhodecode/templates/changeset/changeset.html:10 +#: rhodecode/templates/email_templates/changeset_comment.html:8 +msgid "Changeset" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:149 +msgid "Special" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:150 +msgid "Peer branches" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:151 rhodecode/model/scm.py:688 +#: rhodecode/templates/switch_to_list.html:28 +#: rhodecode/templates/bookmarks/bookmarks.html:10 +msgid "Bookmarks" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:324 +msgid "Pull request requires a title with min. 3 chars" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:326 +msgid "Error creating pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:346 +msgid "Successfully opened new pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:349 +msgid "Error occurred during sending pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:388 +msgid "Successfully deleted pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:484 +msgid "Closing with" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:521 +msgid "Closing pull request on other statuses than rejected or approved forbidden" +msgstr "" + +#: rhodecode/controllers/search.py:132 +msgid "Invalid search query. Try quoting it." +msgstr "" + +#: rhodecode/controllers/search.py:137 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "" + +#: rhodecode/controllers/search.py:141 +msgid "An error occurred during this search operation" +msgstr "" + +#: rhodecode/controllers/summary.py:182 +msgid "No data loaded yet" +msgstr "" + +#: rhodecode/controllers/summary.py:188 +#: rhodecode/templates/summary/summary.html:149 +msgid "Statistics are disabled for this repository" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:96 +msgid "Default settings updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:110 +msgid "Error occurred during update of defaults" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:56 +msgid "forever" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:57 +#, fuzzy +msgid "5 minutes" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:58 +#, fuzzy +msgid "1 hour" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#, fuzzy +msgid "1 day" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:60 +#, fuzzy +msgid "1 month" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:62 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:127 +msgid "Error occurred during gist creation" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:165 +#, python-format +msgid "Deleted gist %s" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:50 +msgid "BASE" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:51 +msgid "ONELEVEL" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:52 +msgid "SUBTREE" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:56 +msgid "NEVER" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:57 +msgid "ALLOW" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:58 +msgid "TRY" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:59 +msgid "DEMAND" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:60 +msgid "HARD" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:64 +msgid "No encryption" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:65 +msgid "LDAPS connection" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:66 +msgid "START_TLS on LDAP connection" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:124 +msgid "LDAP settings updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:128 +msgid "Unable to activate ldap. The \"python-ldap\" library is missing." +msgstr "" + +#: rhodecode/controllers/admin/ldap_settings.py:145 +msgid "Error occurred during update of ldap settings" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:58 +#: rhodecode/controllers/admin/permissions.py:62 +#: rhodecode/controllers/admin/permissions.py:66 +msgid "None" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:59 +#: rhodecode/controllers/admin/permissions.py:63 +#: rhodecode/controllers/admin/permissions.py:67 +msgid "Read" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:60 +#: rhodecode/controllers/admin/permissions.py:64 +#: rhodecode/controllers/admin/permissions.py:68 +msgid "Write" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:61 +#: rhodecode/controllers/admin/permissions.py:65 +#: rhodecode/controllers/admin/permissions.py:69 +#: rhodecode/templates/admin/defaults/defaults.html:9 +#: rhodecode/templates/admin/ldap/ldap.html:9 +#: rhodecode/templates/admin/permissions/permissions.html:9 +#: rhodecode/templates/admin/repos/repo_add.html:10 +#: rhodecode/templates/admin/repos/repo_add.html:14 +#: rhodecode/templates/admin/repos/repos.html:9 +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:9 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:9 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:11 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:13 +#: rhodecode/templates/admin/settings/hooks.html:9 +#: rhodecode/templates/admin/settings/settings.html:9 +#: rhodecode/templates/admin/users/user_add.html:8 +#: rhodecode/templates/admin/users/user_edit.html:9 +#: rhodecode/templates/admin/users/user_edit.html:133 +#: rhodecode/templates/admin/users/users.html:9 +#: rhodecode/templates/admin/users/users.html:85 +#: rhodecode/templates/admin/users_groups/users_group_add.html:8 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:9 +#: rhodecode/templates/admin/users_groups/users_groups.html:9 +#: rhodecode/templates/base/base.html:317 +#: rhodecode/templates/base/base.html:318 +#: rhodecode/templates/base/base.html:324 +#: rhodecode/templates/base/base.html:325 +msgid "Admin" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:72 +#: rhodecode/controllers/admin/permissions.py:83 +#: rhodecode/controllers/admin/permissions.py:86 +#: rhodecode/controllers/admin/permissions.py:89 +#: rhodecode/controllers/admin/permissions.py:92 +msgid "Disabled" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:74 +msgid "Allowed with manual account activation" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:76 +msgid "Allowed with automatic account activation" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:79 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1439 rhodecode/model/db.py:1444 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:80 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1440 rhodecode/model/db.py:1445 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:84 +#: rhodecode/controllers/admin/permissions.py:87 +#: rhodecode/controllers/admin/permissions.py:90 +#: rhodecode/controllers/admin/permissions.py:93 +msgid "Enabled" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:138 +msgid "Default permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:152 +msgid "Error occurred during update of permissions" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:128 +msgid "--REMOVE FORK--" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:168 +#, python-format +msgid "Created repository %s from %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:174 +#, python-format +msgid "Created repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:197 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:270 +#, python-format +msgid "Repository %s updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:288 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:315 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Deleted %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:323 +#, python-format +msgid "Deleted repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:326 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:331 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:345 +msgid "Repository permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:375 +#: rhodecode/controllers/admin/repos_groups.py:332 +#: rhodecode/controllers/admin/users_groups.py:312 +msgid "An error occurred during revoking of permission" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:392 +msgid "An error occurred during deletion of repository stats" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:409 +msgid "An error occurred during cache invalidation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:429 +#: rhodecode/controllers/admin/repos.py:456 +msgid "An error occurred during unlocking" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:447 +msgid "Unlocked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:450 +msgid "Locked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:452 +#, python-format +msgid "Repository has been %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:476 +msgid "Updated repository visibility in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:480 +msgid "An error occurred during setting this repository in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:485 rhodecode/model/validators.py:302 +msgid "Token mismatch" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:498 +msgid "Pulled from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:501 +msgid "An error occurred during pull from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:517 +msgid "Nothing" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:519 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:523 +msgid "An error occurred during this operation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:562 +msgid "An error occurred during creation of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:576 +msgid "An error occurred during removal of field" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:147 +#, python-format +msgid "Created repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:159 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:217 +#, python-format +msgid "Updated repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:232 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:250 +#, python-format +msgid "This group contains %s repositores and cannot be deleted" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:257 +#, python-format +msgid "This group contains %s subgroups and cannot be deleted" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:263 +#, python-format +msgid "Removed repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:268 +#, python-format +msgid "Error occurred during deletion of repos group %s" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:279 +#: rhodecode/controllers/admin/repos_groups.py:314 +#: rhodecode/controllers/admin/users_groups.py:300 +msgid "Cannot revoke permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repos_groups.py:294 +msgid "Repository Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:123 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:132 +msgid "Whoosh reindex task scheduled" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:163 +msgid "Updated application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:167 +#: rhodecode/controllers/admin/settings.py:304 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:219 +msgid "Updated visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:224 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:300 +msgid "Updated VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:314 +msgid "Added new hook" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:326 +msgid "Updated hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:330 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:349 +msgid "Email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:413 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:455 +msgid "Your account was updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +#: rhodecode/controllers/admin/users.py:198 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:130 +#, python-format +msgid "Created user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:142 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:176 +msgid "User updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:214 +msgid "Successfully deleted user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:219 +msgid "An error occurred during deletion of user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:234 +msgid "You can't edit this user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:293 +#: rhodecode/controllers/admin/users_groups.py:372 +msgid "Updated permissions" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +#: rhodecode/controllers/admin/users_groups.py:376 +msgid "An error occurred during permissions saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:311 +#, python-format +msgid "Added email %s to user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:317 +msgid "An error occurred during email saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:327 +msgid "Removed email from user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:340 +#, python-format +msgid "Added ip %s to user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:346 +msgid "An error occurred during ip saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "Removed ip from user" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:162 +#, python-format +msgid "Created user group %s" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:173 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:210 +#, python-format +msgid "Updated user group %s" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:232 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:250 +msgid "Successfully deleted user group" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:255 +msgid "An error occurred during deletion of user group" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:274 +msgid "Target group cannot be the same" +msgstr "" + +#: rhodecode/controllers/admin/users_groups.py:280 +msgid "User Group permissions updated" +msgstr "" + +#: rhodecode/lib/auth.py:544 +#, python-format +msgid "IP %s not allowed" +msgstr "" + +#: rhodecode/lib/auth.py:593 +msgid "You need to be a registered user to perform this action" +msgstr "" + +#: rhodecode/lib/auth.py:634 +msgid "You need to be a signed in to view this page" +msgstr "" + +#: rhodecode/lib/diffs.py:66 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:82 +msgid "Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "" + +#: rhodecode/lib/diffs.py:92 +msgid "No changes detected" +msgstr "" + +#: rhodecode/lib/helpers.py:428 +#, python-format +msgid "%a, %d %b %Y %H:%M:%S" +msgstr "" + +#: rhodecode/lib/helpers.py:539 +msgid "True" +msgstr "" + +#: rhodecode/lib/helpers.py:542 +msgid "False" +msgstr "" + +#: rhodecode/lib/helpers.py:580 +#, python-format +msgid "Deleted branch: %s" +msgstr "" + +#: rhodecode/lib/helpers.py:583 +#, python-format +msgid "Created tag: %s" +msgstr "" + +#: rhodecode/lib/helpers.py:596 +msgid "Changeset not found" +msgstr "" + +#: rhodecode/lib/helpers.py:646 +#, python-format +msgid "Show all combined changesets %s->%s" +msgstr "" + +#: rhodecode/lib/helpers.py:652 +msgid "compare view" +msgstr "" + +#: rhodecode/lib/helpers.py:672 +msgid "and" +msgstr "" + +#: rhodecode/lib/helpers.py:673 +#, python-format +msgid "%s more" +msgstr "" + +#: rhodecode/lib/helpers.py:674 rhodecode/templates/changelog/changelog.html:53 +msgid "revisions" +msgstr "" + +#: rhodecode/lib/helpers.py:698 +#, python-format +msgid "fork name %s" +msgstr "" + +#: rhodecode/lib/helpers.py:715 +#: rhodecode/templates/pullrequests/pullrequest_show.html:8 +#, python-format +msgid "Pull request #%s" +msgstr "" + +#: rhodecode/lib/helpers.py:725 +msgid "[deleted] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:727 rhodecode/lib/helpers.py:739 +msgid "[created] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:729 +msgid "[created] repository as fork" +msgstr "" + +#: rhodecode/lib/helpers.py:731 rhodecode/lib/helpers.py:741 +msgid "[forked] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:733 rhodecode/lib/helpers.py:743 +msgid "[updated] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:735 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/helpers.py:737 +msgid "[delete] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:745 +msgid "[created] user" +msgstr "" + +#: rhodecode/lib/helpers.py:747 +msgid "[updated] user" +msgstr "" + +#: rhodecode/lib/helpers.py:749 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/helpers.py:751 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/helpers.py:753 +msgid "[commented] on revision in repository" +msgstr "" + +#: rhodecode/lib/helpers.py:755 +msgid "[commented] on pull request for" +msgstr "" + +#: rhodecode/lib/helpers.py:757 +msgid "[closed] pull request for" +msgstr "" + +#: rhodecode/lib/helpers.py:759 +msgid "[pushed] into" +msgstr "" + +#: rhodecode/lib/helpers.py:761 +msgid "[committed via RhodeCode] into repository" +msgstr "" + +#: rhodecode/lib/helpers.py:763 +msgid "[pulled from remote] into repository" +msgstr "" + +#: rhodecode/lib/helpers.py:765 +msgid "[pulled] from" +msgstr "" + +#: rhodecode/lib/helpers.py:767 +msgid "[started following] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:769 +msgid "[stopped following] repository" +msgstr "" + +#: rhodecode/lib/helpers.py:1088 +#, python-format +msgid " and %s more" +msgstr "" + +#: rhodecode/lib/helpers.py:1092 +msgid "No Files" +msgstr "" + +#: rhodecode/lib/helpers.py:1158 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1161 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1164 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1167 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1172 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1404 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from " +"the filesystem please run the application again in order to rescan " +"repositories" +msgstr "" + +#: rhodecode/lib/utils2.py:410 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:411 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:412 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:413 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:414 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:415 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:431 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:433 +#, python-format +msgid "%s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:435 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:438 +#, python-format +msgid "%s and %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:441 +msgid "just now" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1163 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1303 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1388 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1408 rhodecode/model/db.py:1413 +msgid "Repository no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1164 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1184 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1304 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1389 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1409 rhodecode/model/db.py:1414 +msgid "Repository read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1165 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1185 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1305 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1390 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1410 rhodecode/model/db.py:1415 +msgid "Repository write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1166 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1186 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1306 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1391 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1411 rhodecode/model/db.py:1416 +msgid "Repository admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1168 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1308 +msgid "Repositories Group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1169 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1309 +msgid "Repositories Group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1170 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1310 +msgid "Repositories Group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1171 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1311 +msgid "Repositories Group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1173 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1193 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1313 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1398 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1406 rhodecode/model/db.py:1411 +msgid "RhodeCode Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1174 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1194 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1314 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1399 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1429 rhodecode/model/db.py:1434 +msgid "Repository creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1175 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1195 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1315 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1400 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1430 rhodecode/model/db.py:1435 +msgid "Repository creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1176 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1196 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1316 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1401 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1432 rhodecode/model/db.py:1437 +msgid "Repository forking disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1177 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1197 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1317 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1402 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1433 rhodecode/model/db.py:1438 +msgid "Repository forking enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1178 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1318 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1403 +msgid "Register disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1319 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1404 +msgid "Register new user with RhodeCode with manual activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1202 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1407 +msgid "Register new user with RhodeCode with auto activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1623 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1643 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1763 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1838 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1934 rhodecode/model/db.py:1939 +msgid "Not Reviewed" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1624 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1644 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1764 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1839 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1935 rhodecode/model/db.py:1940 +msgid "Approved" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1625 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1645 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1765 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1840 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1936 rhodecode/model/db.py:1941 +msgid "Rejected" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:1626 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:1646 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:1766 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1841 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1937 rhodecode/model/db.py:1942 +msgid "Under Review" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1252 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1270 rhodecode/model/db.py:1275 +msgid "top level" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1393 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1413 rhodecode/model/db.py:1418 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1394 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1414 rhodecode/model/db.py:1419 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1395 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1415 rhodecode/model/db.py:1420 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:1396 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1416 rhodecode/model/db.py:1421 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1418 rhodecode/model/db.py:1423 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1419 rhodecode/model/db.py:1424 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1420 rhodecode/model/db.py:1425 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1421 rhodecode/model/db.py:1426 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1423 rhodecode/model/db.py:1428 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1424 rhodecode/model/db.py:1429 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1426 rhodecode/model/db.py:1431 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1427 rhodecode/model/db.py:1432 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1435 rhodecode/model/db.py:1440 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1436 rhodecode/model/db.py:1441 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:1437 rhodecode/model/db.py:1442 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/model/comment.py:75 +#, python-format +msgid "on line %s" +msgstr "" + +#: rhodecode/model/comment.py:220 +msgid "[Mention]" +msgstr "" + +#: rhodecode/model/forms.py:43 +msgid "Please enter a login" +msgstr "" + +#: rhodecode/model/forms.py:44 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "" + +#: rhodecode/model/forms.py:52 +msgid "Please enter a password" +msgstr "" + +#: rhodecode/model/forms.py:53 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "" + +#: rhodecode/model/notification.py:228 +#, python-format +msgid "%(user)s commented on changeset at %(when)s" +msgstr "" + +#: rhodecode/model/notification.py:229 +#, python-format +msgid "%(user)s sent message at %(when)s" +msgstr "" + +#: rhodecode/model/notification.py:230 +#, python-format +msgid "%(user)s mentioned you at %(when)s" +msgstr "" + +#: rhodecode/model/notification.py:231 +#, python-format +msgid "%(user)s registered in RhodeCode at %(when)s" +msgstr "" + +#: rhodecode/model/notification.py:232 +#, python-format +msgid "%(user)s opened new pull request at %(when)s" +msgstr "" + +#: rhodecode/model/notification.py:233 +#, python-format +msgid "%(user)s commented on pull request at %(when)s" +msgstr "" + +#: rhodecode/model/pull_request.py:98 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s" +msgstr "" + +#: rhodecode/model/scm.py:674 +msgid "latest tip" +msgstr "" + +#: rhodecode/model/user.py:232 +msgid "New user registration" +msgstr "" + +#: rhodecode/model/user.py:257 rhodecode/model/user.py:281 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:303 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:309 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch " +"owners or remove those repositories. %s" +msgstr "" + +#: rhodecode/model/user.py:334 +msgid "Password reset link" +msgstr "" + +#: rhodecode/model/user.py:366 +msgid "Your new password" +msgstr "" + +#: rhodecode/model/user.py:367 +#, python-format +msgid "Your new RhodeCode password:%s" +msgstr "" + +#: rhodecode/model/validators.py:38 rhodecode/model/validators.py:39 +msgid "Value cannot be an empty list" +msgstr "" + +#: rhodecode/model/validators.py:85 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:87 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "" + +#: rhodecode/model/validators.py:89 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or" +" dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:117 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "" + +#: rhodecode/model/validators.py:136 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:137 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:139 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:177 +msgid "Cannot assign this group as parent" +msgstr "" + +#: rhodecode/model/validators.py:178 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:180 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:238 +msgid "Invalid characters (non-ascii) in password" +msgstr "" + +#: rhodecode/model/validators.py:253 +msgid "Passwords do not match" +msgstr "" + +#: rhodecode/model/validators.py:270 +msgid "invalid password" +msgstr "" + +#: rhodecode/model/validators.py:271 +msgid "invalid user name" +msgstr "" + +#: rhodecode/model/validators.py:272 +msgid "Your account is disabled" +msgstr "" + +#: rhodecode/model/validators.py:316 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "" + +#: rhodecode/model/validators.py:318 +#, python-format +msgid "Repository named %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:319 +#, python-format +msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:321 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:438 +msgid "invalid clone url" +msgstr "" + +#: rhodecode/model/validators.py:439 +msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url" +msgstr "" + +#: rhodecode/model/validators.py:464 +msgid "Fork have to be the same type as parent" +msgstr "" + +#: rhodecode/model/validators.py:479 +msgid "You don't have permissions to create repository in this group" +msgstr "" + +#: rhodecode/model/validators.py:481 +msgid "no permission to create repository in root location" +msgstr "" + +#: rhodecode/model/validators.py:518 +msgid "You don't have permissions to create a group in this location" +msgstr "" + +#: rhodecode/model/validators.py:559 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:652 +msgid "This is not a valid path" +msgstr "" + +#: rhodecode/model/validators.py:667 +msgid "This e-mail address is already taken" +msgstr "" + +#: rhodecode/model/validators.py:687 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "" + +#: rhodecode/model/validators.py:724 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name " +"of the attribute that is equivalent to \"username\"" +msgstr "" + +#: rhodecode/model/validators.py:737 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "" + +#: rhodecode/model/validators.py:769 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:770 +#, python-format +msgid "The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:803 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:817 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "" + +#: rhodecode/templates/index_base.html:6 +#: rhodecode/templates/repo_switcher_list.html:4 +#: rhodecode/templates/admin/repos/repos.html:9 +#: rhodecode/templates/admin/users/user_edit_my_account.html:31 +#: rhodecode/templates/admin/users/users.html:9 +#: rhodecode/templates/bookmarks/bookmarks.html:9 +#: rhodecode/templates/branches/branches.html:9 +#: rhodecode/templates/journal/journal.html:9 +#: rhodecode/templates/journal/journal.html:46 +#: rhodecode/templates/journal/journal.html:47 +#: rhodecode/templates/tags/tags.html:9 +msgid "quick filter..." +msgstr "" + +#: rhodecode/templates/index_base.html:6 +#: rhodecode/templates/admin/repos/repos.html:9 +msgid "repositories" +msgstr "" + +#: rhodecode/templates/index_base.html:13 +#: rhodecode/templates/index_base.html:18 +#: rhodecode/templates/admin/repos/repo_add.html:5 +#: rhodecode/templates/admin/repos/repos.html:21 +msgid "Add repository" +msgstr "" + +#: rhodecode/templates/index_base.html:15 +#: rhodecode/templates/index_base.html:20 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:31 +msgid "Add group" +msgstr "" + +#: rhodecode/templates/index_base.html:27 +msgid "Edit group" +msgstr "" + +#: rhodecode/templates/index_base.html:27 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:40 +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:33 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:38 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:43 +#: rhodecode/templates/admin/users_groups/users_group_add.html:32 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:33 +#: rhodecode/templates/admin/users_groups/users_groups.html:37 +msgid "Group name" +msgstr "" + +#: rhodecode/templates/index_base.html:41 +#: rhodecode/templates/index_base.html:123 +#: rhodecode/templates/admin/repos/repo_add_base.html:56 +#: rhodecode/templates/admin/repos/repo_edit.html:68 +#: rhodecode/templates/admin/repos/repos.html:73 +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:42 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:47 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:44 +#: rhodecode/templates/email_templates/changeset_comment.html:9 +#: rhodecode/templates/email_templates/pull_request.html:9 +#: rhodecode/templates/forks/fork.html:56 +#: rhodecode/templates/pullrequests/pullrequest.html:43 +#: rhodecode/templates/pullrequests/pullrequest_show.html:81 +#: rhodecode/templates/summary/summary.html:106 +msgid "Description" +msgstr "" + +#: rhodecode/templates/index_base.html:51 +#: rhodecode/templates/admin/permissions/permissions.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:29 +#: rhodecode/templates/admin/repos/repo_edit.html:50 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:57 +#: rhodecode/templates/forks/fork.html:47 +msgid "Repository group" +msgstr "" + +#: rhodecode/templates/index_base.html:121 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit.html:32 +#: rhodecode/templates/admin/repos/repos.html:71 +#: rhodecode/templates/admin/users/user_edit_my_account.html:172 +#: rhodecode/templates/base/perms_summary.html:37 +#: rhodecode/templates/bookmarks/bookmarks.html:48 +#: rhodecode/templates/bookmarks/bookmarks_data.html:6 +#: rhodecode/templates/branches/branches.html:47 +#: rhodecode/templates/branches/branches_data.html:6 +#: rhodecode/templates/files/files_browser.html:47 +#: rhodecode/templates/journal/journal.html:193 +#: rhodecode/templates/journal/journal.html:283 +#: rhodecode/templates/summary/summary.html:55 +#: rhodecode/templates/summary/summary.html:124 +#: rhodecode/templates/tags/tags.html:48 +#: rhodecode/templates/tags/tags_data.html:6 +msgid "Name" +msgstr "" + +#: rhodecode/templates/index_base.html:124 +msgid "Last Change" +msgstr "" + +#: rhodecode/templates/index_base.html:126 +#: rhodecode/templates/admin/repos/repos.html:74 +#: rhodecode/templates/admin/users/user_edit_my_account.html:174 +#: rhodecode/templates/journal/journal.html:195 +#: rhodecode/templates/journal/journal.html:285 +msgid "Tip" +msgstr "" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repo_edit.html:114 +#: rhodecode/templates/admin/repos/repos.html:76 +msgid "Owner" +msgstr "" + +#: rhodecode/templates/index_base.html:136 +#: rhodecode/templates/admin/repos/repos.html:84 +#: rhodecode/templates/admin/users/user_edit_my_account.html:183 +#: rhodecode/templates/admin/users/users.html:107 +#: rhodecode/templates/bookmarks/bookmarks.html:74 +#: rhodecode/templates/branches/branches.html:73 +#: rhodecode/templates/journal/journal.html:204 +#: rhodecode/templates/journal/journal.html:294 +#: rhodecode/templates/tags/tags.html:74 +msgid "Click to sort ascending" +msgstr "" + +#: rhodecode/templates/index_base.html:137 +#: rhodecode/templates/admin/repos/repos.html:85 +#: rhodecode/templates/admin/users/user_edit_my_account.html:184 +#: rhodecode/templates/admin/users/users.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:75 +#: rhodecode/templates/branches/branches.html:74 +#: rhodecode/templates/journal/journal.html:205 +#: rhodecode/templates/journal/journal.html:295 +#: rhodecode/templates/tags/tags.html:75 +msgid "Click to sort descending" +msgstr "" + +#: rhodecode/templates/index_base.html:138 +msgid "No repositories found." +msgstr "" + +#: rhodecode/templates/index_base.html:139 +#: rhodecode/templates/admin/repos/repos.html:87 +#: rhodecode/templates/admin/users/user_edit_my_account.html:186 +#: rhodecode/templates/admin/users/users.html:110 +#: rhodecode/templates/bookmarks/bookmarks.html:77 +#: rhodecode/templates/branches/branches.html:76 +#: rhodecode/templates/journal/journal.html:207 +#: rhodecode/templates/journal/journal.html:297 +#: rhodecode/templates/tags/tags.html:77 +msgid "Data error." +msgstr "" + +#: rhodecode/templates/index_base.html:140 +#: rhodecode/templates/admin/repos/repos.html:88 +#: rhodecode/templates/admin/users/user_edit_my_account.html:58 +#: rhodecode/templates/admin/users/user_edit_my_account.html:187 +#: rhodecode/templates/admin/users/users.html:111 +#: rhodecode/templates/bookmarks/bookmarks.html:78 +#: rhodecode/templates/branches/branches.html:77 +#: rhodecode/templates/journal/journal.html:208 +#: rhodecode/templates/journal/journal.html:298 +#: rhodecode/templates/tags/tags.html:78 +msgid "Loading..." +msgstr "" + +#: rhodecode/templates/login.html:5 rhodecode/templates/base/base.html:239 +msgid "Log In" +msgstr "" + +#: rhodecode/templates/login.html:21 +#, python-format +msgid "Log In to %s" +msgstr "" + +#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/users/user_add.html:32 +#: rhodecode/templates/admin/users/user_edit.html:57 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:31 +#: rhodecode/templates/admin/users/users.html:77 +#: rhodecode/templates/base/base.html:215 +#: rhodecode/templates/summary/summary.html:123 +msgid "Username" +msgstr "" + +#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29 +#: rhodecode/templates/admin/ldap/ldap.html:46 +#: rhodecode/templates/admin/users/user_add.html:41 +#: rhodecode/templates/base/base.html:224 +msgid "Password" +msgstr "" + +#: rhodecode/templates/login.html:50 +msgid "Remember me" +msgstr "" + +#: rhodecode/templates/login.html:54 +msgid "Sign In" +msgstr "" + +#: rhodecode/templates/login.html:60 +msgid "Forgot your password ?" +msgstr "" + +#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:235 +msgid "Don't have an account ?" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +msgid "Password Reset" +msgstr "" + +#: rhodecode/templates/password_reset.html:11 +msgid "Reset your password to" +msgstr "" + +#: rhodecode/templates/password_reset.html:21 +msgid "Email address" +msgstr "" + +#: rhodecode/templates/password_reset.html:30 +msgid "Reset my password" +msgstr "" + +#: rhodecode/templates/password_reset.html:31 +msgid "Password reset link will be send to matching email address" +msgstr "" + +#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74 +msgid "Sign Up" +msgstr "" + +#: rhodecode/templates/register.html:11 +msgid "Sign Up to" +msgstr "" + +#: rhodecode/templates/register.html:38 +msgid "Re-enter password" +msgstr "" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/users/user_add.html:59 +#: rhodecode/templates/admin/users/user_edit.html:97 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62 +msgid "First Name" +msgstr "" + +#: rhodecode/templates/register.html:56 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit.html:106 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71 +msgid "Last Name" +msgstr "" + +#: rhodecode/templates/register.html:65 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit.html:115 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80 +#: rhodecode/templates/summary/summary.html:125 +msgid "Email" +msgstr "" + +#: rhodecode/templates/register.html:76 +msgid "Your account will be activated right after registration" +msgstr "" + +#: rhodecode/templates/register.html:78 +msgid "Your account must wait for activation by administrator" +msgstr "" + +#: rhodecode/templates/repo_switcher_list.html:10 +#: rhodecode/templates/admin/defaults/defaults.html:44 +#: rhodecode/templates/admin/repos/repo_add_base.html:65 +#: rhodecode/templates/admin/repos/repo_edit.html:78 +#: rhodecode/templates/data_table/_dt_elements.html:61 +#: rhodecode/templates/summary/summary.html:77 +msgid "Private repository" +msgstr "" + +#: rhodecode/templates/repo_switcher_list.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:63 +#: rhodecode/templates/summary/summary.html:79 +msgid "Public repository" +msgstr "" + +#: rhodecode/templates/switch_to_list.html:10 +#: rhodecode/templates/branches/branches_data.html:57 +msgid "There are no branches yet" +msgstr "" + +#: rhodecode/templates/switch_to_list.html:22 +#: rhodecode/templates/tags/tags_data.html:38 +msgid "There are no tags yet" +msgstr "" + +#: rhodecode/templates/switch_to_list.html:35 +#: rhodecode/templates/bookmarks/bookmarks_data.html:37 +msgid "There are no bookmarks yet" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:13 +#: rhodecode/templates/base/base.html:73 +msgid "Admin journal" +msgstr "" + +#: rhodecode/templates/admin/admin.html:10 +msgid "journal filter..." +msgstr "" + +#: rhodecode/templates/admin/admin.html:12 +#: rhodecode/templates/journal/journal.html:11 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:13 +#: rhodecode/templates/journal/journal.html:12 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/repos/repos.html:77 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46 +#: rhodecode/templates/admin/users/user_edit_my_account.html:176 +#: rhodecode/templates/admin/users/users.html:87 +#: rhodecode/templates/admin/users_groups/users_groups.html:40 +#: rhodecode/templates/journal/journal.html:197 +#: rhodecode/templates/journal/journal.html:287 +msgid "Action" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/permissions/permissions.html:41 +msgid "Repository" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:49 +#: rhodecode/templates/bookmarks/bookmarks_data.html:7 +#: rhodecode/templates/branches/branches.html:48 +#: rhodecode/templates/branches/branches_data.html:7 +#: rhodecode/templates/tags/tags.html:49 +#: rhodecode/templates/tags/tags_data.html:7 +msgid "Date" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:63 +msgid "No actions yet" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:25 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:11 +#: rhodecode/templates/base/base.html:80 +msgid "Defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:35 +#: rhodecode/templates/admin/repos/repo_add_base.html:38 +msgid "Type" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:48 +#: rhodecode/templates/admin/repos/repo_add_base.html:69 +#: rhodecode/templates/admin/repos/repo_edit.html:82 +#: rhodecode/templates/forks/fork.html:69 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:55 +#: rhodecode/templates/admin/repos/repo_edit.html:87 +msgid "Enable statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:59 +#: rhodecode/templates/admin/repos/repo_edit.html:91 +msgid "Enable statistics window on summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:65 +#: rhodecode/templates/admin/repos/repo_edit.html:96 +msgid "Enable downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:69 +#: rhodecode/templates/admin/repos/repo_edit.html:100 +msgid "Enable download menu on summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:75 +#: rhodecode/templates/admin/repos/repo_edit.html:105 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:64 +msgid "Enable locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:79 +#: rhodecode/templates/admin/repos/repo_edit.html:109 +msgid "Enable lock-by-pulling on repository." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:84 +#: rhodecode/templates/admin/ldap/ldap.html:89 +#: rhodecode/templates/admin/permissions/permissions.html:122 +#: rhodecode/templates/admin/repos/repo_edit.html:141 +#: rhodecode/templates/admin/repos/repo_edit.html:166 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:72 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:96 +#: rhodecode/templates/admin/settings/hooks.html:73 +#: rhodecode/templates/admin/users/user_add.html:94 +#: rhodecode/templates/admin/users/user_edit.html:140 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:88 +#: rhodecode/templates/admin/users_groups/users_group_add.html:49 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:90 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:143 +#: rhodecode/templates/base/default_perms_box.html:53 +msgid "Save" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:5 +#: rhodecode/templates/base/base.html:299 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:12 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:14 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:31 +#: rhodecode/templates/admin/gists/show.html:24 +#: rhodecode/templates/base/base.html:302 +msgid "Create new gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:48 +msgid "Created" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:51 +#: rhodecode/templates/admin/gists/index.html:53 +#: rhodecode/templates/admin/gists/show.html:43 +#: rhodecode/templates/admin/gists/show.html:45 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:51 +#: rhodecode/templates/admin/gists/show.html:43 +msgid "never" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:68 +msgid "There are no gists yet" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:16 +msgid "New gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:37 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:52 +msgid "Create private gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:53 +msgid "Create public gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:54 +#: rhodecode/templates/admin/permissions/permissions.html:123 +#: rhodecode/templates/admin/permissions/permissions.html:185 +#: rhodecode/templates/admin/repos/repo_edit.html:142 +#: rhodecode/templates/admin/repos/repo_edit.html:167 +#: rhodecode/templates/admin/repos/repo_edit.html:381 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:73 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:97 +#: rhodecode/templates/admin/settings/settings.html:115 +#: rhodecode/templates/admin/settings/settings.html:196 +#: rhodecode/templates/admin/settings/settings.html:288 +#: rhodecode/templates/admin/users/user_edit.html:141 +#: rhodecode/templates/admin/users/user_edit.html:198 +#: rhodecode/templates/admin/users/user_edit.html:246 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:89 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:144 +#: rhodecode/templates/base/default_perms_box.html:54 +#: rhodecode/templates/files/files_add.html:80 +#: rhodecode/templates/files/files_edit.html:66 +#: rhodecode/templates/pullrequests/pullrequest.html:86 +msgid "Reset" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:5 +msgid "gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:9 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Public gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:38 +msgid "Private gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:54 +#: rhodecode/templates/admin/repos/repo_edit.html:299 +#: rhodecode/templates/changeset/changeset_file_comment.html:40 +msgid "Delete" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:54 +#, fuzzy +msgid "Confirm to delete this gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:63 +#: rhodecode/templates/admin/gists/show.html:84 +#: rhodecode/templates/files/files_edit.html:48 +#: rhodecode/templates/files/files_source.html:25 +#: rhodecode/templates/files/files_source.html:55 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:71 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:5 +msgid "LDAP administration" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:11 +#: rhodecode/templates/admin/users/users.html:86 +#: rhodecode/templates/base/base.html:79 +msgid "LDAP" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:28 +msgid "Connection settings" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:30 +msgid "Enable LDAP" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:34 +msgid "Host" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:38 +msgid "Port" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:42 +msgid "Account" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:50 +msgid "Connection security" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:54 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:57 +msgid "Search settings" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:59 +msgid "Base DN" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:63 +msgid "LDAP Filter" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:67 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:70 +msgid "Attribute mappings" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:72 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:76 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:80 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/templates/admin/ldap/ldap.html:84 +msgid "E-mail Attribute" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:9 +msgid "My Notifications" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:29 +msgid "All" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:30 +#, fuzzy +msgid "Comments" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8 +msgid "Pull requests" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:35 +msgid "Mark all read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:11 +msgid "Show notification" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:9 +#: rhodecode/templates/base/base.html:253 +msgid "Notifications" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:11 +#: rhodecode/templates/admin/repos/repo_edit.html:151 +#: rhodecode/templates/admin/repos/repo_edit.html:158 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:81 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:88 +#: rhodecode/templates/admin/users/user_edit.html:150 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:129 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:136 +#: rhodecode/templates/base/base.html:78 +msgid "Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:24 +msgid "Default permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:31 +msgid "Anonymous access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:49 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will " +"be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:50 +#: rhodecode/templates/admin/permissions/permissions.html:63 +#: rhodecode/templates/admin/permissions/permissions.html:77 +msgid "Overwrite existing settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:62 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:69 +msgid "User group" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:76 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:83 +msgid "Repository creation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:91 +msgid "User group creation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:99 +msgid "Repository forking" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:107 +msgid "Registration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:115 +msgid "External auth account activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:133 +msgid "Default User Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:144 +#: rhodecode/templates/admin/users/user_edit.html:207 +msgid "Allowed IP addresses" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:158 +#: rhodecode/templates/admin/repos/repo_edit.html:340 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:70 +#: rhodecode/templates/admin/users/user_edit.html:175 +#: rhodecode/templates/admin/users/user_edit.html:220 +#: rhodecode/templates/admin/users_groups/users_groups.html:54 +#: rhodecode/templates/data_table/_dt_elements.html:122 +#: rhodecode/templates/data_table/_dt_elements.html:136 +msgid "delete" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:159 +#: rhodecode/templates/admin/users/user_edit.html:221 +#, fuzzy, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:165 +#: rhodecode/templates/admin/users/user_edit.html:227 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:176 +#: rhodecode/templates/admin/users/user_edit.html:238 +msgid "New ip address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:184 +#: rhodecode/templates/admin/repos/repo_add_base.html:73 +#: rhodecode/templates/admin/repos/repo_edit.html:380 +#: rhodecode/templates/admin/users/user_edit.html:197 +#: rhodecode/templates/admin/users/user_edit.html:245 +msgid "Add" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:12 +#: rhodecode/templates/admin/repos/repo_add.html:16 +#: rhodecode/templates/base/base.html:74 rhodecode/templates/base/base.html:88 +#: rhodecode/templates/base/base.html:116 +#: rhodecode/templates/base/base.html:275 +msgid "Repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:19 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:20 +#: rhodecode/templates/summary/summary.html:96 +#: rhodecode/templates/summary/summary.html:97 +msgid "Clone from" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:24 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +msgid "Optional http[s] url from which repository should be cloned." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:33 +#: rhodecode/templates/forks/fork.html:51 +msgid "Optionaly select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:42 +msgid "Type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:47 +#: rhodecode/templates/admin/repos/repo_edit.html:59 +#: rhodecode/templates/forks/fork.html:38 +msgid "Landing revision" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:51 +#: rhodecode/templates/admin/repos/repo_edit.html:63 +#: rhodecode/templates/forks/fork.html:42 +msgid "Default revision for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:60 +#: rhodecode/templates/admin/repos/repo_edit.html:72 +#: rhodecode/templates/forks/fork.html:60 +msgid "Keep it short and to the point. Use a README file for longer descriptions." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +msgid "Edit repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:12 +#: rhodecode/templates/admin/settings/hooks.html:9 +#: rhodecode/templates/admin/settings/settings.html:11 +#: rhodecode/templates/base/base.html:81 rhodecode/templates/base/base.html:134 +#: rhodecode/templates/summary/summary.html:212 +msgid "Settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:36 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:41 +msgid "Clone uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Optional select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:119 +msgid "Change owner of this repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:177 +msgid "Advanced settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:180 +msgid "Statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:184 +msgid "Reset current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:184 +msgid "Confirm to remove current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:187 +msgid "Fetched to rev" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:188 +msgid "Stats gathered" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:196 +msgid "Remote" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:200 +msgid "Pull changes from remote location" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:200 +msgid "Confirm to pull changes from remote side" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:211 +msgid "Cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:215 +msgid "Invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:215 +msgid "Confirm to invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:218 +msgid "" +"Manually invalidate cache for this repository. On first access repository" +" will be cached again" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:223 +msgid "List of cached values" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:226 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:227 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:228 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit.html:124 +#: rhodecode/templates/admin/users/users.html:84 +#: rhodecode/templates/admin/users_groups/users_group_add.html:41 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:42 +#: rhodecode/templates/admin/users_groups/users_groups.html:39 +msgid "Active" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:243 +#: rhodecode/templates/base/base.html:292 +#: rhodecode/templates/base/base.html:293 +msgid "Public journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:249 +msgid "Remove from public journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:251 +msgid "Add to public journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:256 +msgid "" +"All actions made on this repository will be accessible to everyone in " +"public journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:263 +msgid "Locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:268 +msgid "Unlock locked repo" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:268 +msgid "Confirm to unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:271 +msgid "Lock repo" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:271 +msgid "Confirm to lock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:272 +msgid "Repository is not locked" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:277 +msgid "Force locking on repository. Works only when anonymous access is disabled" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:284 +msgid "Set as fork of" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:289 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:293 +msgid "Manually set this repository as a fork of another from the list" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:308 +msgid "Remove this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:308 +msgid "Confirm to delete this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:310 +#, python-format +msgid "this repository has %s fork" +msgid_plural "this repository has %s forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit.html:311 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:312 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:315 +msgid "" +"This repository will be renamed in a special way in order to be " +"unaccesible for RhodeCode and VCS systems. If you need to fully delete it" +" from file system please do it manually" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:329 +msgid "Extra fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:341 +#, fuzzy, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:355 +msgid "New field key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:363 +msgid "New field label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:366 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:372 +msgid "New field description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:375 +msgid "Enter description of a field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:3 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:3 +msgid "none" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:4 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:4 +msgid "read" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:5 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:5 +msgid "write" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:6 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:6 +msgid "admin" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:7 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:7 +msgid "member" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:16 +msgid "private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:19 +#: rhodecode/templates/admin/repos/repo_edit_perms.html:28 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:20 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:35 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:20 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:35 +msgid "default" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:33 +#: rhodecode/templates/admin/repos/repo_edit_perms.html:58 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:25 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:55 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:25 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:55 +msgid "revoke" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_perms.html:83 +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81 +#: rhodecode/templates/admin/users_groups/user_group_edit_perms.html:81 +msgid "Add another member" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:86 +#: rhodecode/templates/admin/users/user_edit_my_account.html:185 +#: rhodecode/templates/admin/users/users.html:109 +#: rhodecode/templates/bookmarks/bookmarks.html:76 +#: rhodecode/templates/branches/branches.html:75 +#: rhodecode/templates/journal/journal.html:206 +#: rhodecode/templates/journal/journal.html:296 +#: rhodecode/templates/tags/tags.html:76 +msgid "No records found." +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:87 +msgid "apply to children" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:88 +msgid "" +"Set or revoke permission to all children of that group, including non-" +"private repositories and other groups" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups.html:4 +#, python-format +msgid "%s Group Dashboard" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups.html:9 +msgid "Home" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups.html:13 +msgid "with" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:5 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:11 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:11 +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:16 +#: rhodecode/templates/base/base.html:75 rhodecode/templates/base/base.html:91 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:13 +msgid "Add new repository group" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:51 +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:56 +msgid "Group parent" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:59 +msgid "save" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:5 +msgid "Edit repository group" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:13 +#, python-format +msgid "Edit repository group %s" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:27 +msgid "Add child group" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:68 +msgid "" +"Enable lock-by-pulling on group. This option will be applied to all other" +" groups and repositories inside" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:45 +msgid "Number of toplevel repositories" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:64 +#: rhodecode/templates/admin/users_groups/users_groups.html:48 +#: rhodecode/templates/changeset/changeset_file_comment.html:73 +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:65 +#: rhodecode/templates/admin/users_groups/users_groups.html:49 +#: rhodecode/templates/base/perms_summary.html:29 +#: rhodecode/templates/base/perms_summary.html:60 +#: rhodecode/templates/base/perms_summary.html:62 +#: rhodecode/templates/data_table/_dt_elements.html:116 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:130 +#: rhodecode/templates/data_table/_dt_elements.html:131 +msgid "edit" +msgstr "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:70 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:78 +msgid "There are no repository groups yet" +msgstr "" + +#: rhodecode/templates/admin/settings/hooks.html:5 +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "" + +#: rhodecode/templates/admin/settings/hooks.html:24 +msgid "Built in hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/hooks.html:40 +msgid "Custom hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/hooks.html:56 +msgid "remove" +msgstr "" + +#: rhodecode/templates/admin/settings/hooks.html:88 +msgid "Failed to remove hook" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:26 +msgid "Remap and rescan repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:34 +msgid "Rescan option" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:40 +msgid "" +"In case a repository was deleted from filesystem and there are leftovers " +"in the database check this option to scan obsolete data in database and " +"remove it." +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:41 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:43 +msgid "" +"Rescan repositories location for new repositories. Also deletes obsolete " +"if `destroy` flag is checked " +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:48 +msgid "Rescan repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:54 +msgid "Whoosh indexing" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:62 +msgid "Index build option" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:67 +msgid "Build from scratch" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:73 +msgid "Reindex" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:79 +msgid "Global application settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:88 +msgid "Site branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:97 +msgid "HTTP authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:106 +msgid "Google Analytics code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:114 +#: rhodecode/templates/admin/settings/settings.html:195 +#: rhodecode/templates/admin/settings/settings.html:287 +msgid "Save settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:121 +msgid "Visualisation settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:129 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:134 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:136 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:139 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:141 +msgid "Shows or hides displayed version of RhodeCode in the footer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:146 +msgid "Dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:150 +msgid "" +"Number of items displayed in lightweight dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:155 +msgid "Icons" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:160 +msgid "Show public repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:164 +msgid "Show private repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:166 +msgid "Show public/private icons next to repositories names" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:172 +msgid "Meta-Tagging" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:177 +msgid "Stylify recognised metatags:" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:204 +msgid "VCS settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:213 +msgid "Web" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:218 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:220 +msgid "" +"RhodeCode will require SSL for pushing or pulling. If SSL is missing it " +"will return HTTP Error 406: Not Acceptable" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:226 +msgid "Hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:231 +msgid "Update repository after push (hg update)" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:235 +msgid "Show repository size after push" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:239 +msgid "Log user push commands" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:243 +msgid "Log user pull commands" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:247 +msgid "Advanced setup" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:252 +msgid "Mercurial Extensions" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:257 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:261 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:263 +msgid "" +"Requires hgsubversion library installed. Allows cloning from svn remote " +"locations" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:274 +msgid "Repositories location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:279 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting" +" take effect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:280 +#: rhodecode/templates/base/base.html:143 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:282 +msgid "" +"Location where repositories are stored. After changing this value a " +"restart, and rescan is required" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:303 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:311 +msgid "Email to" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:319 +msgid "Send" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:325 +msgid "System Info and Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:328 +#: rhodecode/templates/changelog/changelog.html:51 +msgid "Show" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:10 +#: rhodecode/templates/admin/users/user_edit.html:11 +#: rhodecode/templates/base/base.html:76 +msgid "Users" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:12 +#: rhodecode/templates/admin/users/users.html:23 +msgid "Add new user" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:50 +msgid "Password confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +msgid "Edit user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:13 +#: rhodecode/templates/admin/users_groups/users_group_edit.html:13 +#, python-format +msgid "Edit %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10 +msgid "Change your avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:35 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11 +msgid "Using" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:43 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20 +msgid "API key" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:50 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:25 +msgid "Current IP" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:70 +msgid "LDAP DN" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:79 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44 +msgid "New password" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:88 +#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53 +msgid "New password confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:163 +msgid "Email addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:176 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:190 +msgid "New email address" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account.html:5 +#: rhodecode/templates/base/base.html:254 +msgid "My account" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account.html:9 +msgid "My Account" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account.html:35 +msgid "My permissions" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account.html:38 +#: rhodecode/templates/journal/journal.html:54 +msgid "My repos" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account.html:41 +msgid "My pull requests" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2 +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:4 +msgid "Show closed pull requests" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:6 +msgid "Opened by me" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:17 +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:45 +#: rhodecode/templates/pullrequests/pullrequest_data.html:11 +#: rhodecode/templates/pullrequests/pullrequest_show.html:27 +#: rhodecode/templates/pullrequests/pullrequest_show.html:42 +msgid "Closed" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:23 +msgid "Confirm to delete this pull request" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:30 +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:51 +msgid "Nothing here yet" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:34 +msgid "I participate in" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:42 +#: rhodecode/templates/pullrequests/pullrequest_data.html:8 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:9 +msgid "users" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:80 +msgid "Firstname" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:81 +msgid "Lastname" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:82 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_add.html:10 +#: rhodecode/templates/admin/users_groups/users_groups.html:11 +#: rhodecode/templates/base/base.html:77 rhodecode/templates/base/base.html:94 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_add.html:12 +#: rhodecode/templates/admin/users_groups/users_groups.html:26 +msgid "Add new user group" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:5 +msgid "Edit user group" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:11 +msgid "UserGroups" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:50 +#: rhodecode/templates/admin/users_groups/users_groups.html:38 +msgid "Members" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:58 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:61 +msgid "Remove all elements" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:75 +msgid "Available members" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:79 +msgid "Add all elements" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:109 +msgid "No members yet" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_group_edit.html:117 +msgid "Global Permissions" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_groups.html:55 +#, fuzzy, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/admin/users_groups/users_groups.html:62 +msgid "There are no user groups yet" +msgstr "" + +#: rhodecode/templates/base/base.html:42 +#, python-format +msgid "Server instance: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +msgid "Report a bug" +msgstr "" + +#: rhodecode/templates/base/base.html:121 +#: rhodecode/templates/data_table/_dt_elements.html:9 +#: rhodecode/templates/data_table/_dt_elements.html:11 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/summary/summary.html:8 +msgid "Summary" +msgstr "" + +#: rhodecode/templates/base/base.html:122 +#: rhodecode/templates/changelog/changelog.html:15 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:19 +#: rhodecode/templates/data_table/_dt_elements.html:21 +msgid "Changelog" +msgstr "" + +#: rhodecode/templates/base/base.html:123 +#: rhodecode/templates/data_table/_dt_elements.html:25 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:29 +#: rhodecode/templates/files/files.html:12 +msgid "Files" +msgstr "" + +#: rhodecode/templates/base/base.html:125 +msgid "Switch To" +msgstr "" + +#: rhodecode/templates/base/base.html:127 +#: rhodecode/templates/base/base.html:279 +msgid "loading..." +msgstr "" + +#: rhodecode/templates/base/base.html:131 +msgid "Options" +msgstr "" + +#: rhodecode/templates/base/base.html:137 +#: rhodecode/templates/forks/forks_data.html:21 +msgid "Compare fork" +msgstr "" + +#: rhodecode/templates/base/base.html:139 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/search/search.html:14 +#: rhodecode/templates/search/search.html:54 +msgid "Search" +msgstr "" + +#: rhodecode/templates/base/base.html:145 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:153 +msgid "Follow" +msgstr "" + +#: rhodecode/templates/base/base.html:154 +msgid "Unfollow" +msgstr "" + +#: rhodecode/templates/base/base.html:157 +#: rhodecode/templates/data_table/_dt_elements.html:33 +#: rhodecode/templates/data_table/_dt_elements.html:35 +#: rhodecode/templates/data_table/_dt_elements.html:37 +#: rhodecode/templates/data_table/_dt_elements.html:74 +#: rhodecode/templates/forks/fork.html:9 +msgid "Fork" +msgstr "" + +#: rhodecode/templates/base/base.html:159 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:165 +msgid "Show Pull Requests" +msgstr "" + +#: rhodecode/templates/base/base.html:165 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/base/base.html:202 +msgid "Not logged in" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Login to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:232 +msgid "Forgot password ?" +msgstr "" + +#: rhodecode/templates/base/base.html:255 +msgid "Log Out" +msgstr "" + +#: rhodecode/templates/base/base.html:274 +msgid "Switch repository" +msgstr "" + +#: rhodecode/templates/base/base.html:286 +msgid "Show recent activity" +msgstr "" + +#: rhodecode/templates/base/base.html:287 +#: rhodecode/templates/journal/journal.html:4 +msgid "Journal" +msgstr "" + +#: rhodecode/templates/base/base.html:298 +msgid "Show public gists" +msgstr "" + +#: rhodecode/templates/base/base.html:303 +msgid "All public gists" +msgstr "" + +#: rhodecode/templates/base/base.html:305 +msgid "My public gists" +msgstr "" + +#: rhodecode/templates/base/base.html:306 +msgid "My private gists" +msgstr "" + +#: rhodecode/templates/base/base.html:311 +msgid "Search in repositories" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherit default permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:18 +#, python-format +msgid "" +"Select to inherit permissions from %s settings. With this selected below " +"options does not apply." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:26 +msgid "Create repositories" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:30 +msgid "Select this option to allow repository creation for this user" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:35 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:39 +msgid "Select this option to allow user group creation for this user" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:44 +msgid "Fork repositories" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:48 +msgid "Select this option to allow repository forking for this user" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:11 +msgid "No permissions defined yet" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +#: rhodecode/templates/base/perms_summary.html:38 +msgid "Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +#: rhodecode/templates/base/perms_summary.html:39 +msgid "Edit Permission" +msgstr "" + +#: rhodecode/templates/base/root.html:43 +#, fuzzy +msgid "Add another comment" +msgstr "" + +#: rhodecode/templates/base/root.html:44 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Stop following this repository" +msgstr "" + +#: rhodecode/templates/base/root.html:45 +msgid "Start following this repository" +msgstr "" + +#: rhodecode/templates/base/root.html:46 +msgid "Group" +msgstr "" + +#: rhodecode/templates/base/root.html:47 +msgid "members" +msgstr "" + +#: rhodecode/templates/base/root.html:48 +#: rhodecode/templates/pullrequests/pullrequest.html:203 +msgid "Loading ..." +msgstr "" + +#: rhodecode/templates/base/root.html:49 +msgid "Search truncated" +msgstr "" + +#: rhodecode/templates/base/root.html:50 +msgid "No matching files" +msgstr "" + +#: rhodecode/templates/base/root.html:51 +#: rhodecode/templates/changelog/changelog.html:45 +msgid "Open new pull request" +msgstr "" + +#: rhodecode/templates/base/root.html:52 +msgid "Open new pull request for selected changesets" +msgstr "" + +#: rhodecode/templates/base/root.html:53 +msgid "Show selected changesets __S -> __E" +msgstr "" + +#: rhodecode/templates/base/root.html:54 +msgid "Show selected changeset __S" +msgstr "" + +#: rhodecode/templates/base/root.html:55 +msgid "Selection link" +msgstr "" + +#: rhodecode/templates/base/root.html:56 +#: rhodecode/templates/changeset/diff_block.html:8 +msgid "Collapse diff" +msgstr "" + +#: rhodecode/templates/base/root.html:57 +msgid "Expand diff" +msgstr "" + +#: rhodecode/templates/base/root.html:58 +msgid "Failed to remoke permission" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:26 +msgid "Compare bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:51 +#: rhodecode/templates/bookmarks/bookmarks_data.html:8 +#: rhodecode/templates/branches/branches.html:50 +#: rhodecode/templates/branches/branches_data.html:8 +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/tags/tags.html:51 +#: rhodecode/templates/tags/tags_data.html:8 +msgid "Author" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:52 +#: rhodecode/templates/bookmarks/bookmarks_data.html:9 +#: rhodecode/templates/branches/branches.html:51 +#: rhodecode/templates/branches/branches_data.html:9 +#: rhodecode/templates/changelog/changelog_summary_data.html:5 +#: rhodecode/templates/tags/tags.html:52 +#: rhodecode/templates/tags/tags_data.html:9 +msgid "Revision" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:54 +#: rhodecode/templates/bookmarks/bookmarks_data.html:10 +#: rhodecode/templates/branches/branches.html:53 +#: rhodecode/templates/branches/branches_data.html:10 +#: rhodecode/templates/tags/tags.html:54 +#: rhodecode/templates/tags/tags_data.html:10 +msgid "Compare" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:26 +msgid "Compare branches" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d revision" +msgid_plural "showing %d out of %d revisions" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:39 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:42 +#: rhodecode/templates/forks/forks_data.html:19 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:42 +msgid "Compare fork with parent" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:78 +#: rhodecode/templates/changelog/changelog_summary_data.html:28 +#, python-format +msgid "Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/summary/summary.html:403 +msgid "Show more" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:115 +#: rhodecode/templates/changelog/changelog_summary_data.html:50 +#: rhodecode/templates/changeset/changeset.html:107 +#: rhodecode/templates/changeset/changeset_range.html:86 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:121 +#: rhodecode/templates/changelog/changelog_summary_data.html:56 +#: rhodecode/templates/changeset/changeset.html:113 +#: rhodecode/templates/changeset/changeset_range.html:92 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#: rhodecode/templates/changelog/changelog_summary_data.html:61 +#: rhodecode/templates/changeset/changeset.html:117 +#: rhodecode/templates/changeset/changeset_range.html:96 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:286 +msgid "There are no changes yet" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/changeset/changeset.html:91 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +#: rhodecode/templates/changeset/changeset.html:92 +#, fuzzy +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +#: rhodecode/templates/changeset/changeset.html:93 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#: rhodecode/templates/changeset/changeset.html:95 +#: rhodecode/templates/changeset/changeset.html:96 +#: rhodecode/templates/changeset/changeset.html:97 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:61 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:7 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:86 +msgid "Add or upload files directly via RhodeCode" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:89 +#: rhodecode/templates/files/files_add.html:38 +#: rhodecode/templates/files/files_browser.html:31 +msgid "Add new file" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:95 +msgid "Push new repo" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:103 +msgid "Existing repository?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:6 +#, python-format +msgid "%s Changeset" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:39 +msgid "No parents" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:49 +msgid "No children" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:62 +#: rhodecode/templates/changeset/changeset_file_comment.html:20 +#: rhodecode/templates/changeset/changeset_range.html:44 +msgid "Changeset status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:67 +#: rhodecode/templates/changeset/diff_block.html:22 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:68 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:69 +#: rhodecode/templates/changeset/diff_block.html:23 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:73 +#: rhodecode/templates/changeset/changeset_file_comment.html:103 +#, python-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:73 +#: rhodecode/templates/changeset/changeset_file_comment.html:103 +#, python-format +msgid "(%d inline)" +msgid_plural "(%d inline)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:103 +#: rhodecode/templates/changeset/changeset_range.html:82 +msgid "merge" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:126 +#: rhodecode/templates/compare/compare_diff.html:40 +#: rhodecode/templates/pullrequests/pullrequest_show.html:113 +#, python-format +msgid "%s file changed" +msgid_plural "%s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/compare/compare_diff.html:42 +#: rhodecode/templates/pullrequests/pullrequest_show.html:115 +#, python-format +msgid "%s file changed with %s insertions and %s deletions" +msgid_plural "%s files changed with %s insertions and %s deletions" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:141 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:131 +#: rhodecode/templates/pullrequests/pullrequest_show.html:195 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:141 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/compare/compare_diff.html:58 +#: rhodecode/templates/compare/compare_diff.html:69 +#: rhodecode/templates/pullrequests/pullrequest_show.html:131 +#: rhodecode/templates/pullrequests/pullrequest_show.html:195 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +#, python-format +msgid "Status change on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:32 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:55 +msgid "Submitting..." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Commenting on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:59 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:147 +msgid "Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:65 +#: rhodecode/templates/changeset/changeset_file_comment.html:152 +#, fuzzy +msgid "Preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:170 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:80 +#: rhodecode/templates/changeset/changeset_file_comment.html:177 +#: rhodecode/templates/email_templates/changeset_comment.html:16 +#: rhodecode/templates/email_templates/pull_request_comment.html:16 +msgid "Comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:81 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:88 +msgid "You need to be logged in to comment." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:88 +msgid "Login now" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:92 +msgid "Hide" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:149 +msgid "Change status" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:179 +msgid "Comment and close" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Changesets" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:52 +msgid "Files affected" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:21 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:29 +msgid "Show inline comments" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:53 +msgid "Show file at latest version in this repo" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:54 +msgid "Show file at initial version in this repo" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:4 +msgid "No changesets" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:32 +msgid "Ancestor" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:5 +#, fuzzy, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:9 +msgid "Compare revisions" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:33 +#: rhodecode/templates/pullrequests/pullrequest_show.html:106 +#, python-format +msgid "Showing %s commit" +msgid_plural "Showing %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:48 +#: rhodecode/templates/pullrequests/pullrequest_show.html:121 +msgid "No files" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:58 +#: rhodecode/templates/compare/compare_diff.html:69 +msgid "confirm to show potentially huge diff" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:54 +#: rhodecode/templates/summary/summary.html:69 +msgid "Mercurial repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:56 +#: rhodecode/templates/summary/summary.html:72 +msgid "Git repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:74 +#, python-format +msgid "Fork of %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:88 +msgid "No changesets yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:95 +#: rhodecode/templates/data_table/_dt_elements.html:97 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:103 +#: rhodecode/templates/data_table/_dt_elements.html:105 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:122 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:137 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "" + +#: rhodecode/templates/email_templates/changeset_comment.html:4 +#: rhodecode/templates/email_templates/pull_request.html:4 +#: rhodecode/templates/email_templates/pull_request_comment.html:4 +msgid "URL" +msgstr "" + +#: rhodecode/templates/email_templates/changeset_comment.html:6 +#, python-format +msgid "%s commented on a %s changeset." +msgstr "" + +#: rhodecode/templates/email_templates/changeset_comment.html:14 +msgid "The changeset status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/main.html:8 +msgid "This is a notification from RhodeCode." +msgstr "" + +#: rhodecode/templates/email_templates/password_reset.html:4 +#, python-format +msgid "Hello %s" +msgstr "" + +#: rhodecode/templates/email_templates/password_reset.html:5 +msgid "We received a request to create a new password for your account." +msgstr "" + +#: rhodecode/templates/email_templates/password_reset.html:6 +msgid "You can generate it by clicking following URL" +msgstr "" + +#: rhodecode/templates/email_templates/password_reset.html:10 +msgid "Please ignore this email if you did not request a new password ." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request.html:6 +#, python-format +msgid "" +"%s opened a pull request for repository %s and wants you to review " +"changes." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:34 +#: rhodecode/templates/pullrequests/pullrequest_data.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:25 +msgid "Title" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.html:6 +#, python-format +msgid "%s commented on pull request \"%s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.html:10 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.html:12 +msgid "Pull request changed status" +msgstr "" + +#: rhodecode/templates/email_templates/registration.html:6 +msgid "View this user here" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:55 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, fuzzy, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:8 +msgid "File diff" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files.html:76 +#, fuzzy, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:30 +#: rhodecode/templates/files/files_add.html:31 +#: rhodecode/templates/files/files_edit.html:31 +msgid "Branch" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, fuzzy, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:19 +msgid "Add file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:43 +msgid "File Name" +msgstr "" + +#: rhodecode/templates/files/files_add.html:47 +#: rhodecode/templates/files/files_add.html:56 +msgid "or" +msgstr "" + +#: rhodecode/templates/files/files_add.html:47 +#: rhodecode/templates/files/files_add.html:52 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:56 +msgid "Create new file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:61 +#: rhodecode/templates/files/files_edit.html:37 +#: rhodecode/templates/files/files_ypjax.html:3 +msgid "Location" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "use / to separate directories" +msgstr "" + +#: rhodecode/templates/files/files_add.html:79 +#: rhodecode/templates/files/files_edit.html:65 +msgid "Commit changes" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "View" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:14 +msgid "Previous revision" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:16 +msgid "Next revision" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:23 +msgid "Follow current branch" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Search file list" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:35 +msgid "Loading file list..." +msgstr "" + +#: rhodecode/templates/files/files_browser.html:48 +msgid "Size" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:49 +msgid "Mimetype" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Last Revision" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Last modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last committer" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, fuzzy, python-format +msgid "%s Files Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:19 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:47 +#: rhodecode/templates/files/files_source.html:23 +msgid "Show annotation" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:49 +#: rhodecode/templates/files/files_source.html:26 +msgid "Download as raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:52 +msgid "Source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:57 +msgid "Editing file" +msgstr "" + +#: rhodecode/templates/files/files_history_box.html:2 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_history_box.html:9 +msgid "Diff to revision" +msgstr "" + +#: rhodecode/templates/files/files_history_box.html:10 +#, fuzzy +msgid "Show at revision" +msgstr "" + +#: rhodecode/templates/files/files_history_box.html:11 +msgid "Show full history" +msgstr "" + +#: rhodecode/templates/files/files_history_box.html:16 +#, fuzzy, python-format +msgid "%s author" +msgid_plural "%s authors" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:6 +msgid "Load file history" +msgstr "" + +#: rhodecode/templates/files/files_source.html:21 +msgid "Show source" +msgstr "" + +#: rhodecode/templates/files/files_source.html:29 +#, python-format +msgid "Edit on branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +msgid "Edit on branch:?" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +msgid "Editing files allowed only when on branch head revision" +msgstr "" + +#: rhodecode/templates/files/files_source.html:46 +#, python-format +msgid "Binary file (%s)" +msgstr "" + +#: rhodecode/templates/files/files_source.html:55 +msgid "File is too big to display" +msgstr "" + +#: rhodecode/templates/files/files_ypjax.html:5 +msgid "annotation" +msgstr "" + +#: rhodecode/templates/files/files_ypjax.html:15 +msgid "Go back" +msgstr "" + +#: rhodecode/templates/files/files_ypjax.html:16 +msgid "No files at given path" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#, python-format +msgid "%s Followers" +msgstr "" + +#: rhodecode/templates/followers/followers.html:9 +#: rhodecode/templates/summary/summary.html:183 +#: rhodecode/templates/summary/summary.html:184 +msgid "Followers" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:12 +msgid "Started following -" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "%s Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:28 +msgid "Fork name" +msgstr "" + +#: rhodecode/templates/forks/fork.html:65 +msgid "Private" +msgstr "" + +#: rhodecode/templates/forks/fork.html:74 +msgid "Copy permissions" +msgstr "" + +#: rhodecode/templates/forks/fork.html:78 +msgid "Copy permissions from forked repository" +msgstr "" + +#: rhodecode/templates/forks/fork.html:84 +msgid "Update after clone" +msgstr "" + +#: rhodecode/templates/forks/fork.html:88 +msgid "Checkout source after making a clone" +msgstr "" + +#: rhodecode/templates/forks/fork.html:93 +msgid "Fork this repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:9 +#: rhodecode/templates/summary/summary.html:189 +#: rhodecode/templates/summary/summary.html:190 +msgid "Forks" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:17 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:42 +msgid "There are no forks yet" +msgstr "" + +#: rhodecode/templates/journal/journal.html:21 +msgid "ATOM journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:22 +msgid "RSS journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:32 +msgid "Refresh" +msgstr "" + +#: rhodecode/templates/journal/journal.html:35 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "ATOM feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:51 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/journal/journal_data.html:55 +msgid "No entries yet" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:21 +msgid "Public Journal" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:13 +msgid "ATOM public journal feed" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:14 +msgid "RSS public journal feed" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:25 +msgid "Create new pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:47 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:53 +msgid "Changeset flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:60 +#: rhodecode/templates/pullrequests/pullrequest_show.html:65 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Send pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:94 +#: rhodecode/templates/pullrequests/pullrequest_show.html:137 +msgid "Pull request reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:103 +#: rhodecode/templates/pullrequests/pullrequest_show.html:149 +msgid "owner" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:115 +msgid "Add reviewer to this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:129 +msgid "Detailed compare view" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:150 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:35 +msgid "Review status" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:40 +msgid "Pull request status" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:53 +msgid "Still not reviewed by" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:57 +#, python-format +msgid "%d reviewer" +msgid_plural "%d reviewers" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:59 +msgid "Pull request was reviewed by all reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:89 +msgid "Created on" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:102 +msgid "Compare view" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:149 +#, fuzzy +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:164 +msgid "Add or remove reviewer to this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:168 +#, fuzzy +msgid "Save changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +msgid "Search repository" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:16 +msgid "Search in all repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:50 +msgid "Search term" +msgstr "" + +#: rhodecode/templates/search/search.html:62 +msgid "Search in" +msgstr "" + +#: rhodecode/templates/search/search.html:65 +msgid "File contents" +msgstr "" + +#: rhodecode/templates/search/search.html:66 +msgid "Commit messages" +msgstr "" + +#: rhodecode/templates/search/search.html:67 +msgid "File names" +msgstr "" + +#: rhodecode/templates/search/search_commit.html:35 +#: rhodecode/templates/search/search_content.html:21 +#: rhodecode/templates/search/search_path.html:15 +msgid "Permission denied" +msgstr "" + +#: rhodecode/templates/summary/summary.html:4 +#, python-format +msgid "%s Summary" +msgstr "" + +#: rhodecode/templates/summary/summary.html:16 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:62 +#, python-format +msgid "Repository locked by %s" +msgstr "" + +#: rhodecode/templates/summary/summary.html:64 +msgid "Repository unlocked" +msgstr "" + +#: rhodecode/templates/summary/summary.html:83 +#, python-format +msgid "Non changable ID %s" +msgstr "" + +#: rhodecode/templates/summary/summary.html:88 +msgid "Public" +msgstr "" + +#: rhodecode/templates/summary/summary.html:88 +#: rhodecode/templates/summary/summary.html:89 +msgid "Fork of" +msgstr "" + +#: rhodecode/templates/summary/summary.html:97 +msgid "Remote clone" +msgstr "" + +#: rhodecode/templates/summary/summary.html:117 +msgid "Contact" +msgstr "" + +#: rhodecode/templates/summary/summary.html:131 +msgid "Clone url" +msgstr "" + +#: rhodecode/templates/summary/summary.html:136 +msgid "Show by Name" +msgstr "" + +#: rhodecode/templates/summary/summary.html:137 +msgid "Show by ID" +msgstr "" + +#: rhodecode/templates/summary/summary.html:143 +msgid "Trending files" +msgstr "" + +#: rhodecode/templates/summary/summary.html:151 +#: rhodecode/templates/summary/summary.html:167 +msgid "Enable" +msgstr "" + +#: rhodecode/templates/summary/summary.html:159 +msgid "Download" +msgstr "" + +#: rhodecode/templates/summary/summary.html:163 +msgid "There are no downloads yet" +msgstr "" + +#: rhodecode/templates/summary/summary.html:165 +msgid "Downloads are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/summary.html:170 +msgid "Download as zip" +msgstr "" + +#: rhodecode/templates/summary/summary.html:174 +msgid "Check this to download archive with subrepos" +msgstr "" + +#: rhodecode/templates/summary/summary.html:174 +msgid "with subrepos" +msgstr "" + +#: rhodecode/templates/summary/summary.html:197 +msgid "Repository Size" +msgstr "" + +#: rhodecode/templates/summary/summary.html:204 +#: rhodecode/templates/summary/summary.html:206 +msgid "Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:224 +msgid "Commit activity by day / author" +msgstr "" + +#: rhodecode/templates/summary/summary.html:232 +msgid "enable" +msgstr "" + +#: rhodecode/templates/summary/summary.html:235 +msgid "Stats gathered: " +msgstr "" + +#: rhodecode/templates/summary/summary.html:256 +msgid "Latest changes" +msgstr "" + +#: rhodecode/templates/summary/summary.html:258 +msgid "Quick start" +msgstr "" + +#: rhodecode/templates/summary/summary.html:272 +#, python-format +msgid "Readme file from revision %s" +msgstr "" + +#: rhodecode/templates/summary/summary.html:332 +#, python-format +msgid "Download %s as %s" +msgstr "" + +#: rhodecode/templates/summary/summary.html:379 +msgid "files" +msgstr "" + +#: rhodecode/templates/summary/summary.html:689 +msgid "commits" +msgstr "" + +#: rhodecode/templates/summary/summary.html:690 +msgid "files added" +msgstr "" + +#: rhodecode/templates/summary/summary.html:691 +msgid "files changed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:692 +msgid "files removed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:694 +msgid "commit" +msgstr "" + +#: rhodecode/templates/summary/summary.html:695 +msgid "file added" +msgstr "" + +#: rhodecode/templates/summary/summary.html:696 +msgid "file changed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:697 +msgid "file removed" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:26 +msgid "Compare tags" +msgstr "" + diff --git a/rhodecode/i18n/es/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/es/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..3196143dd5c78c86f61107a91356f7636d43660e GIT binary patch literal 123634 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 Ox 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 diff --git a/rhodecode/i18n/es/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/es/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/es/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7992 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Belman Kraul-Garcia <bkraul@yahoo.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:09+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Spanish (http://www.transifex.com/rhodecode/RhodeCode/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "No hay cometidos todavía" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "Mostrar espacio" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "Mostrar espacio para todas las diferencias" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "Ignorar espacio" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "Ignorar espacio para todas las diferencias" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "Incrementar contexto" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "Incrementar contexto para todas las diferencias" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "Cambio de estado %(transition_icon)s %(status)s" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Página principal" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "La solicitud no pudo ser entendida por el servidor debido a sintaxis malformada." + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Acceso no autorizado a recurso" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Usted no tiene permiso para ver esta página" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "El recurso no pudo ser hallado" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "El servidor encontró una condición inesperada que le impidió completar la solicitud." + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "Servidor VCS requerido" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "Se requiere de un servidor VCS para esta acción. No existe actualmente un servidor VCS configurado." + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Cambios en repositorio %s" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s fuente" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "No hay archivos todavía. %s" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "El repositorio ha sido bloqueado por %s en %s" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "Sólo puede eliminar archivos con revisión siendo una rama válida" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "Se eliminó archivo %s vía RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "Se eliminó archivo %s exitosamente" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Error occurrido durante cometido" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Usted puede editar solamente archivos con revision siendo una rama válida" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "Se editó archivo %s vía RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Sin cambios" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Se cometió a %s exitosamente" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "Se agregó archivo vía RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Sin nombre de archivo" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "La localización específica debe ser una ruta relativa y no deve contener .. en la ruta" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Descargas deshabilitadas" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Revision desconocida %s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Repositorio vacío" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Typo de archivo desconocido" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Conjuntos de cambios" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Ramas" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Etiquetas" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Ocurrió un error durante bifurcación de repositorio %s" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Grupos" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Repositorios" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "diario público" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "diario" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "mal código de imagen" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "Se ha registrado exitosamente con RhodeCode" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Su liga de reinicio de contraseña fue enviada" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "Su reinicio de contraseña fue exitoso, una nueva contraseña ha sido enviada a su correo electrónico" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "La solicitud de extracción requiere un título con un mínimo de 3 caracteres" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "Se abrió nueva solicitud de extracción exitosamente" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Error ocurrido durante envío de solicitud de extracción" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "No se pueden actualizar solicitudes de extracción cerradas." + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "Título de solicitud de extracción & descripción actualizados." + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "Solicitud de extracción actualizada a \"{source_commit_id}\" con {count_added} cometidos agregados, {count_removed} removidos." + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "Nada cambió en solicitud de extracción" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "Omitiendo actualización de solicitud de extracción debido a tipo de referencia: {reference_type}" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "La actualización falló debido a cometidos faltantes" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "La aprobacion del revisador de la solicitud de extracción está pendiente" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "Se eliminó la solicitud de extracción exitosamente" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "La aprobación del revisador está pendiente." + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Cerrando con" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "Está prohibido el cerrar solicitudes de extracción otros estados que no sean rechazado o aprobado. El estado calculado por parte de todos los revisadores es actualmente: %s" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "Rama" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "Etiqueta" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "Marcador" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "Ramas cerradas" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Ajustes por defecto actualizados exitosamente" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "Error ocurrido durante actalización de valores por defecto" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "para siempre" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 minutos" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 hora" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 día" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 mes" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "De por vida" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "Requiere cuenta registrada" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "Puede ser accesado por usuarios anónimos" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Error ocurrido durante creación de quid" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "Se eliminó quid %s" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "Se actualizó exitosamente el contenido de quid" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "Se actualizaron exitosamente los datos de quid" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "Error ocurrido durante actualización de quid %s" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "nunca" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "%(expiry)s - valor actual" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Usted no puede editar este usuario porque es crucial para la aplicación entera" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Su cuenta fue actualizada exitosamente" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "Error ocurrido durante actualización de usuario %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "Contraseña actualizada exitosamente" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "Error ocurrido durante actualización de contraseña de usuario" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Ocurrió un error durante guardado de correo electrónico" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "Rol" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "Ficha de autenticación creada exitosamente" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "Ficha de autenticación reiniciada exitosamente" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "Ficha de autenticación eliminada exitosamente" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "Permisos de aplicación actualizados exitosamente" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Error ocurrido durante actualización de permisos" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "Permisos de objeto actualizados exitosamente" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "Permisos globales actualizado exitosamente" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Se creó grupo de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Error ocurrido durante creación de grupo de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Se actualizó grupo de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Error ocurrido durante actualización de grupo de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "Este grupo contiene %(num)d repositorio y no puede ser eliminado" +msgstr[1] "Este grupo contiene %(num)d repositorios y no puede ser eliminado" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "Este grupo contiene %(num)d subgrupo y no puede ser eliminado" +msgstr[1] "Este grupo contiene %(num)d subgrupos y no puede ser eliminado" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Se removió grup de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Error ocurrido durante eliminación de grupo de repositorio %s" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "No puede cambiar el permiso para usted como admin" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Permisos de Grupo de Repositorio actualizados" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "Error al crear repositorio %s: certificado inválido" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "Error al crear repositorio %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "Se creó repositorio %s a base de %s" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Se bifurcó repositorio %s como %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Se creó repositorio %s" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Repositorio %s actualizado exitosamente" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Error ocurrido durante actualización de repositorio %s" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "Se despegaron %s bifurcaciones" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "Se eliminaron %s bifurcaciones" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Se eliminó repositorio %s" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "No se puede eliminar %s todavía contiene bifurcaciones adjuntas" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Ocurrió un error durante eliminación de %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Permisos de repositorio actualizados" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Ocurrió un error durante creación de campo" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Ocurrió un error durante remoción de campo" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Se actualizó visibilidad de repositorio en diario público" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Ocurrió un error al ajustar este repositorio en diario público" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Nada" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Se marcó repositorio %s como bifurcación de %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Ocurrió un error durante esta operación" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "Repositorio blockeado" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "Repositorio desbloqueado" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Ocurrió un error durante desbloqueo" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Desbloqueado" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Bloqueado" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "El repositorio ha sido %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "Invalidación de caché exitosa" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Ocurrió un error durante invalidación de caché" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Extraído de localidad remota" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Ocurrió un error durante extracción de localidad remota" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Ocurrió un error durante eliminacion de estadísticas de repositorio" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "Error ocurrido al eliminar entrada en el seguidor de incidencias" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "Se eliminó entrada en el seguidor de incidencias" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "Se actualizaron entradas en el seguidor de incidencias" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "Algunos campos de entrada contienen datos inválidos" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "Error ocurrido al actualizar ajustes VCS del repositorio" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Se actualizaron ajustes VCS" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Error ocurrido durante actualización de ajustes de aplicación" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Repositorios reescaneados exitosamente agregados: %s ; eliminados: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Se actualizaron los ajustes de aplicación" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Se actualizaron los ajustes de visualización" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Error ocurrido al actualizar ajustes de visualización" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "Por favor ingrese una dirección de correo electrónico" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "Tarea de envío de correo electrónico creada" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Se agregó nuevo gancho" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Se actualizaron ganchos" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "Error ocurrido durante creación de gancho" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "Crítico: su espacio en disco está demasiado bajo <b>%s%%</b> usedpercent" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "Advertencia: su espacio en disco está bajo <b>%s%%</b> usedpercent" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "Error ocurrido al actiualizar ajustes de laboratorios" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "Se Actualizaron Ajustes de Laboratorios" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "Unión de lado de servidor Mercurial" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "Soporte Subversion HTTP" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "Solicitudes por proxy HTTP subversion" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "URL de Servidor HTTP Subversion" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "p.e. http://localhost:8080/" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "Se creó grupo de usuario %(user_group_link)s" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Error ocurrido al crear grupo de usuario %s" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Se actualizó grupo de usuario %s" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Error ocurrido al actualizar group de usuario %s" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Grupo de usuario eliminado exitosamente" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Ocurrió un error durante eliminación de grupo de usuario" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "El grupo de destino no puede ser el mismo" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Permisos de grupo de usuario actualizados" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "Permisos globales para Grupo de Usuario actualizados exitosamente" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Ocurrió un error al guardar permisos" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "Se creó usuario %(user_link)s" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Error ocurrido durante creación de usuario %s" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Usuario actualizado exitosamente" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "Se elminaron %s grupos de repositorio" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "Se eliminaron %s grupos de usuario" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Se eliminó usuario exitosamente" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Ocurrió un error durante eliminación de usuario" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "Forzar cambio de contraseña deshabilitado para usuario" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "Forzar cambio de contraseña habilitado para usuario" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "Ocurrió un error durante reinicio de contraseña para usuario" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "Se creó grupo de repositorio `%s`" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "Ocurrió un error durante creación de grupo de repositorio para usuario" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Usted no puede editar este usuario" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "Permisos globales de usario actualizados exitosamente" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "Ocurrió un error al guardar ip:%s" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Ocurrió un error al guardar ip" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "Se agregaron ips %s a la lista blanca de usuario" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "Se eliminó dirección ip de lista blanca de usuario" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[deleted] repositorio" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[created] repositorio" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[created] repositorio como bifurcación" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[forked] repositorio" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[updated] repositorio" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "Nombre de bifurcación %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Solicitud de extracción #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "comparar vista" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Se eliminó rama: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IP %s no permitida" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Usted necesita ser un usuario registrado para llevar a cabo esta acción" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "Acción no soportada para %s" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "Usted necesita estar en sesión para ver esta página" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Consulta de búsqueda inválidad. Intente agregar comillas." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "No hay un índice en el cual buscar. Por favor execute el indexador whoosh" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Un error ocurrió durante esta operación de búsqueda" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "" + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "" + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "En caso de que un repositorio o un grupo fue eliminado del sistema y aún existe en la base de datos, marque esta opción para eliminar datos obsoletos de la base de datos" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "%(num)s archivo cambiado: %(linesadd)s insertados, %(linesdel)s eliminados" +msgstr[1] "%(num)s archivos cambiados: %(linesadd)s insertados, %(linesdel)s eliminados" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "" + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "Las estadísticas para este repositorio están deshabilitadas" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" diff --git a/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..1c827814f7ad834f5efae4378f12bd58485cee7b GIT binary patch literal 124573 zc$~bw2Vm4y5<kAEXTkG46;!MX8k!*#Q4tlS8>9phz;X(k>?T>+?1ugB5(0!S%@Yt1 zq}XXTEObN^K@Sk6*`)~_>M6?EJ@x$0%xB)WY&Mkp{eFM%$n5L$=FOWoZ{EE3-E;0K z5Bli8Er0U)E+IHH%jfxT*WY};S_F3!{4>Fy2wp_+l)HSs_5?2{SchPc;N=9z5o|<o zA;HTCzDMvvg5MKtNbsz?eZDaSTM%qa@D+mB5j;%r7J?aleZJNNqXaVvF7AtbpY%n& zXZG{?ZX$R+!Da-@2wp?*X@a#0?ju;2;7I|WuK~dZ1e*}dC3rQ#F&bW};V%eg5WF<s z=c`Y!9l;I+BMM(4cqPG~6<%5Z*tP)qiwaQR6ou;u{)OPT1pi8~TF~dKLGWCH=Mt=^ z;g&(9cPCh#V80;f+h5@zf@c!ESHlkwJcHmPntzePB?QkWxK{JMr*MA|<Ms`~(+Qpt zLj1V|&*pK{aN`itZzOmg!44tdb$bZy-$U?Hf&)WnZ#u!#2tG>iR37IL@LEjpET(G+ z{d-gE`y>Ru`i9^`1pizJeCI1%Q;7C<7NY)xh2WQO3PG>ai_p%+1c^m`bu?VR2zWFu zLi^Vd>`kx@!CnL(B6tqLuZvKhuNe7j6=QsA6TFIGlVa5Ow_@N~KyWg_5gPy3u+Mig z!3)Bm+r?qf>#8v5*F22++Jw>X98C{te3T$hu!=DHdEPz1<H~zbKJy;nas55WAG!zi zBnVOw-vrI~9l@I1kN&9t{Qk&)d4JF)i{KTEPk+q2+xla^lxe>C{V{KsYW}VLm0$W} z-1heey^d)9lOky6oCxACihvH83Y$cLPxA=q);WUy6%o9P`Iq1$1m7n(jbO3_<9|jJ z<Ml)o<NYkbfdp3&yn*`>qdCWX7Xw``Ers03CRmT@Qi}OLw-obxM=9jPZ>5;WnFAn? zdJaH1IRNu=&H&W6WdP*H&jV2YsyMYtuvZ-Ik0IEW;A?TTcd~`_t1Q%ehXuSVEcAE0 zg?Tbd!}BeS-*OA`>n#iP``H3Lt0zG3^Ah0i+5|6PIwruUT@uO%3DlcNU|dHeAYbPx z+>pS$JgE6jN}}9fk{FLmlbByElc>K(65|z4VqOkUg1@I}x!Fm`v!{~alO0LmeK?8! z{E-B{H3niH)EfvszHT7;*?J)GhztZB1`R}iCuscCfhxZUo<eZZK(zmy#xK?UYZd-u zAoz3JK=AYKfsnhuX?pE4pRXgqhGoEGKpFV5ybSzZQ3m>qE(1P~m!Z9v%23}bg&&q- zTz}H^iv}TFdl1IGJ;9~~tw9){`GYVXYX_m-{ewW4e+@!?zYhZaFDdu={5-D}-cb&E z4k-sc?=Q!AJW-B%R+fVfua%>n%>=Uv9w-ODH5%;m<q>Q#7~^^WVDxkTV9@EA!5Ej7 zgHiuRjo+>D{~8Q>{AV!a<b^}fUTg^JFW2yxA*grK5R{uf1pS*g1oT;<@oR@*UcIB? zKZamkKYJ+Jojw%f{`gSv+jAPfZYcWuj)vbK3c4I1crn2rhN8Z6Ds-GH&`!e&w0~y> z*7^JjjMJD3%%_DFz;jsz%5SVdzdo!0e;-izZ3XCFZ5Z&oU>NYbVi@qbZW!{lABK8z zhk<_zh5^sSFyJ|M7}|Ye7{>brO@DhB<jCG(kUtj>M}ON4$9&AzaKGWGzj!$2+o0iC zucr+Me$Nd@zt<0k9RGee@T)Td<J))y#<Tqh)SIvI<s*RKq!Hk|rxm`X@T(D6SI!!V z@?|5z&kv3SzN-}O9SJ$}r%~X;j8V|5Vxv(1j8TvmFO9;y{A3i$`9`C@x}#CP^JvVU zdqyMQ+|g)v-Dvb@?`Y8fD~)F+V)=d<!D|WTjRF1d8v}VfmtaeR8^&N=_(S6x-ivYT zc`xW1P&nXT)IaiG@W+E1UUV<oTXQey^6|as->> P5k)Y(5tK>NpnlMaClk(6OlJ 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 z℘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 diff --git a/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7992 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: French (http://www.transifex.com/rhodecode/RhodeCode/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Autorisée" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Accueil" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "Le serveur n’a pas pu interpréter la requête à cause d’une erreur de syntaxe" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Accès interdit à cet ressource" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Vous n’avez pas la permission de voir cette page" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "Ressource introuvable" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "La requête n’a pu être traitée en raison d’une erreur survenue sur le serveur." + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Changements sur le dépôt %s" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "Flux %s de %s" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Une erreur est survenue durant le commit" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Aucun changement" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Commit réalisé avec succès sur %s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Aucun nom de fichier" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Les téléchargements sont désactivés" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Révision %s inconnue." + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Dépôt vide." + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Type d’archive inconnu" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Changesets" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Branches" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Tags" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Une erreur est survenue durant le fork du dépôt %s." + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Groupes" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Dépôts" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "Journal public" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "Journal" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Un lien de rénitialisation de votre mot de passe vous a été envoyé." + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "Les requêtes de pull nécessitent un titre d’au moins 3 caractères." + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "La requête de pull a été ouverte avec succès." + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Une erreur est survenue durant l’envoi de la requête de pull." + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "La requête de pull a été supprimée avec succès." + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 minute" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 heure" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 jour" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 mois" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Vous ne pouvez pas éditer cet utilisateur ; il est nécessaire pour le bon fonctionnement de l’application." + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Votre compte a été mis à jour avec succès" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Une erreur est survenue durant l’enregistrement de l’e-mail." + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "dépôt %s forké en tant que %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Dépôt %s mis à jour avec succès." + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "Impossible de supprimer le dépôt %s : Des forks y sont attachés." + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Erreur pendant la suppression de %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "La visibilité du dépôt dans le journal public a été mise à jour." + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Une erreur est survenue durant la configuration du journal public pour ce dépôt." + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "[Aucun dépôt]" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Le dépôt %s a été marké comme fork de %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Une erreur est survenue durant cette opération." + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Une erreur est survenue durant le déverrouillage." + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "Le dépôt a été %s." + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Une erreur est survenue durant l’invalidation du cache." + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Les changements distants ont été récupérés." + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Une erreur est survenue durant le pull depuis la source distante." + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Une erreur est survenue durant la suppression des statistiques du dépôt." + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Réglages des gestionnaires de versions mis à jour." + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Réglages mis à jour" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Réglages d’affichage mis à jour." + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Le nouveau hook a été ajouté." + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Hooks mis à jour" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "E-mail" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "Hooks" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Une erreur est survenue durant l’enregistrement des permissions." + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "L’utilisateur a été mis à jour avec succès." + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Une erreur est survenue durant la suppression de l’utilisateur." + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Vous ne pouvez pas éditer cet utilisateur" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[a supprimé] le dépôt" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[a créé] le dépôt" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[a créé] le dépôt en tant que fork" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[a forké] le dépôt" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[a mis à jour] le dépôt" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[a supprimé] le dépôt" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[a créé] l’utilisateur" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[a mis à jour] l’utilisateur" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[a commenté] la requête de pull pour" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[a fermé] la requête de pull de" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[a pushé] dans" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[a commité via RhodeCode] dans le dépôt" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[a pullé depuis un site distant] dans le dépôt" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[a pullé] depuis" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[suit maintenant] le dépôt" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[ne suit plus] le dépôt" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Requête de pull #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "vue de comparaison" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Vous devez être un utilisateur enregistré pour effectuer cette action." + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Cet ensemble de changements était trop gros pour être affiché et a été découpé, utilisez le menu « Diff » pour afficher les différences." + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Aucun changement détecté." + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "et %s de plus" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Aucun fichier" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "Le dépôt %s n’est pas représenté dans la base de données. Il a probablement été créé ou renommé manuellement. Veuillez relancer l’application pour rescanner les dépôts." + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d an" +msgstr[1] "%d ans" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d mois" +msgstr[1] "%d mois" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d jour" +msgstr[1] "%d jours" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d heure" +msgstr[1] "%d heures" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d minute" +msgstr[1] "%d minutes" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d seconde" +msgstr[1] "%d secondes" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "Il y a %s" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "Il y a %s et %s" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "à l’instant" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "Serveur" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "Port" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "Compte" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Mot de passe" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "Vérif. des certificats" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "Base de recherche" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "Portée de recherche" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "Attribut pour le nom d’utilisateur" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "Attribut pour le prénom" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "Attribut pour le nom de famille" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Aucun accès au dépôt" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Accès en lecture au dépôt" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Accès en écriture au dépôt" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Accès administrateur au dépôt" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Aucun accès au groupe de dépôts" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Accès en lecture au groupe de dépôts" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Accès en écriture au groupe de dépôts" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Accès administrateur au groupe de dépôts" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "Administrateur RhodeCode" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Création de dépôt désactivée" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Création de dépôt activée" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "Fork de dépôt désactivé" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "Fork de dépôt activé" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Enregistrement désactivé" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Enregistrer un nouvel utilisateur Rhodecode manuellement activé" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Enregistrer un nouvel utilisateur Rhodecode auto-activé" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Pas encore relue" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Approuvée " + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Rejetée" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "En cours de relecture" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Requête invalide. Essayer de la mettre entre guillemets." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "L’index de recherche n’est pas présent. Veuillez exécuter l’indexeur de code Whoosh." + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Une erreur est survenue durant l’opération de recherche." + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Veuillez entrer un identifiant" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Entrez une valeur d’au moins %(min)i caractères de long." + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Veuillez entrer un mot de passe" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Entrez au moins %(min)i caractères" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Signets" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "Dernier sommet" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Vous ne pouvez pas éditer cet utilisateur ; il est nécessaire pour le bon fonctionnement de l’application." + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Vous ne pouvez pas supprimer cet utilisateur ; il est nécessaire pour le bon fonctionnement de l’application." + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "Cette valeur ne peut être une liste vide." + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "Le nom d’utilisateur « %(username)s » existe déjà." + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "Le nom d’utilisateur « %(username)s » n’est pas autorisé" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "Le nom d’utilisateur « %(username)s » n’est pas valide." + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Impossible d’assigner ce groupe en tant que parent." + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "Le groupe « %(group_name)s » existe déjà." + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Un dépôt portant le nom « %(group_name)s » existe déjà." + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "Caractères incorrects (non-ASCII) dans le mot de passe." + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Les mots de passe ne correspondent pas." + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "mot de passe invalide" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "nom d’utilisateur invalide" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Votre compte est désactivé" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Jeton d’authentification incorrect." + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "Le nom de dépôt « %(repo)s » n’est pas autorisé." + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "Le fork doit être du même type que le parent." + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "Ceci n’est pas un chemin valide" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Cette adresse e-mail est déjà enregistrée" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "L’adresse e-mail « %(email)s » n’existe pas" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "L’attribut Login du CN doit être spécifié. Cet attribut correspond au nom d’utilisateur." + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "Les révisions %(revs)s font déjà partie de la requête de pull ou on des statuts définis." + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Tableau de bord" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "Filtre rapide…" + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Nom" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Description" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Propriétaire" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Dernière modification" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "Accueil" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Connexion" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Nom d’utilisateur" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Se souvenir de moi" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Votre nouveau mot de passe sera envoyé à l’adresse correspondante." + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Confirmation" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Prénom" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Nom" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "Historique d’administration" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "" + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Action" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Dépôt" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Date" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "Depuis l’adresse IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Aucune action n’a été enregistrée pour le moment." + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Administration" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "Désactivé" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Enregistrer" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Type" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "Les dépôts privés sont visibles seulement par les utilisateurs ajoutés comme collaborateurs." + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "Auteur" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "Créé le" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Réinitialiser" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Supprimer" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "Mon compte" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "Mon compte" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "Surveillé" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Ajouter" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "Veuillez confirmer la suppression de l’e-mail : %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "Nouvelle adrese" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "Vous pouvez changer votre avatar sur" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "Requête de pull nº%s ouverte le %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "Fermée" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "Veuillez confirmer la suppression de cette requête de pull." + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "Requête de pull nº%s ouverte par %s le %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Mes notifications" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Tous" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Commentaires" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Aucune notification pour le moment." + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Notification" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Notifications" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Permissions" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Enregistrement" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "Nom du groupe" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Options" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "Voulez-vous vraiment supprimer le groupe « %s » ?" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "Aucun" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Lire" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Écrire" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "Propriétaire" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "Parent du groupe" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Ajouter un dépôt" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Cloner depuis" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "Gardez cette description précise et concise. Utilisez un fichier README pour des descriptions plus détaillées." + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Dépôt distant" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Statistiques" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "Marquer ce dépôt comme fork d’un autre dépôt de la liste." + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "Voulez-vous vraiment supprimer le dépôt %s ?" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "Invalider le cache du dépôt" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "Voulez-vous vraiment invalider le cache du dépôt ?" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Actif" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "Dépôt privé" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "Récupérer les changements depuis le site distant" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "Voulez-vous vraiment récupérer les changements depuis le site distant ?" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "éditer" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Groupe de dépôt" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "Sélectionnez un groupe (optionel) dans lequel sera placé le dépôt." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "Changer le propriétaire de ce dépôt." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Dépôt privé" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Activer les statistiques" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "Afficher les statistiques sur la page du dépôt." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Activer les téléchargements" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "Afficher le menu de téléchargements sur la page du dépôt." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "Souhaitez-vous vraiment réinitialiser les statistiques de ce dépôt ?" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Enregister les options" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "Administration des dépôts" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "Dépôts" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "Administration générale" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "E-mail de test" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Envoyer" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "Titre" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "Hooks personnalisés" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "Meta-Tagging" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Icônes" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Afficher l’icône de dépôt public sur les dépôts" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Afficher l’icône de dépôt privé sur les dépôts" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Nom de groupe" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Membres" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "Révoquer" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Tout enlever" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Membres disponibles" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Tout ajouter" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Ajouter un utilisateur" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Utilisateurs" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Confirmation" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Voulez-vous vraiment supprimer l’utilisateur « %s » ?" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Administration des utilisateurs" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "Fork de" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Résumé" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "Historique" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "Fichiers" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Comparer" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Options" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Comparer le fork" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Rechercher" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Vous n’avez pas de compte ?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Historique" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Journal public" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "Montrer" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "Aucune" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "Lecture" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "Écriture" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "Administration" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Permission" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "Éditer" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "Création de dépôts" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "Forker les dépôts" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "Afficher la taille du dépôt après un push" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "Signets de %s" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "Signets" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "Branches de %s" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "Branches" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "Historique de %s" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "Nouvelle requête de pull" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "Il n’y a aucun changement pour le moment" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "Fusion" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "Le dépôt existe déjà ?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "Les commentaires sont analysés avec la syntaxe %s, avec le support de la commande %s." + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "Utilisez @nomutilisateur dans ce texte pour envoyer une notification à l’utilisateur RhodeCode en question." + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "Commentaire" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "Vous devez être connecté pour poster des commentaires." + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "Se connecter maintenant" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "Masquer" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Dépôt Mercurial" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Dépôt Git" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Dépôt public" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "S’abonner au flux RSS de %s" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "S’abonner au flux ATOM de %s" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "Privé" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "Vous serez redirigé vers %s dans %s secondes." + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "Fichiers de %s" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "Ajouter un nouveau fichier" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "ou" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "Téléverser un fichier" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "Commiter les changements" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "Chargement de la liste des fichiers…" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "Taille" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Chargement…" + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "Fichier binaire (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "Ce fichier est trop gros pour être affiché." + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "Source" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "annotation" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "Édition du fichier" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "Emplacement" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "Historique" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "Téléchargements" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "Followers de %s" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "Followers" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "Nom du fork" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "Copier les permissions" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "Copier les permissions depuis le dépôt forké" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "Forks de %s" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "Forks" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "Il n’y a pas encore de forks." + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "Flux ATOM du journal" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "Flux RSS du journal" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "Aucune entrée pour le moment" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Journal public" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "Flux ATOM du journal public" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "Flux RSS du journal public" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "Nouvelle requête de pull" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "Relecteurs de la requête de pull" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "Ouvertes par moi" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "Le contenu des fichiers" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "Les messages de commit" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "Les noms de fichiers" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "Résumé de %s" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "Afficher par nom" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "Afficher par ID" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "URL de clone" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "La mise à jour des statistiques est désactivée pour ce dépôt." + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "Il n’y a pas encore de téléchargements proposés." + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "Les téléchargements sont désactivés pour ce dépôt." + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "Démarrage rapide" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "Tags de %s" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "Tags" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" diff --git a/rhodecode/i18n/how_to.rst b/rhodecode/i18n/how_to.rst new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/how_to.rst @@ -0,0 +1,136 @@ +########################## +To create a new language +########################## + +Translations are available on transifex under:: + + https://www.transifex.com/projects/p/RhodeCode/ + +Log into transifex and request new language translation. + +manual creation of new language ++++++++++++++++++++++++++++++++ + +**Step 1:** If you don't have a dev environment set up, download sources of +RhodeCode. Run:: + + python setup.py develop + +Otherwise, update to the latest stable commit. + + +**Note:** The following commands are intended to be run in the main repo directory +using Linux; running them in nix-shell is fine. + + +**Step 2:** Make sure all translation strings are extracted by running:: + + python setup.py extract_messages + + +**Step 3:** Create a new language by executing following command:: + + python setup.py init_catalog -l <new_language_code> + +This creates a new language under directory rhodecode/i18n/<new_language_code> + + +**Step 4:** Be sure to update transifex mapping, located at rhodecode/.tx/config +The path to the new language should be identical to the others, instead using +the new language code. + + +**Step 5:** Verify the translation file and fix any errors. +This can be done by executing:: + + msgfmt -f -c rhodecode/i18n/<new_language_code>/LC_MESSAGES/<updated_file.po> + +Edit rhodecode/i18n/<new_language_code>/LC_MESSAGES/rhodecode.po for errors +with your favorite file editor (the errors will tell you what's missing, check +other rhodecode.po files in existing languages for clues). + + +**Step 6:** Finally, compile the translations:: + + python setup.py compile_catalog -l <new_language_code> + +**Note:** Make sure there is not a .mo file in the top-level folder! + + +########################## +To update translations +########################## + +**Note:** This is a different process, not needed when you are adding a translation. + +**Step 1:** Fetch the latest version of strings for translation by running:: + + python setup.py extract_messages + + +**Step 2:** Update the rhodecode.po file using:: + + python setup.py update_catalog -l <new_language_code> + + +**Step 3:** Update the po file as outlined in step 5 for new translations (see above). + + +**Step 4:** Compile the translations as outlined in step 6 for new translations (see above). + +**Note:** Make sure there is not a .mo file in the top-level folder! + + +########################### +Javascript translations +########################### + +First find all translation used in JS by running the command: + + grep "_TM\[.*\]" -R . -oh | sort -u + +Then compare it against the file scripts/tasks/file_generation/js_i18n_data.py. +Add or remove strings to that file remembering to add them surrounded by _(...), +or otherwise they won't get added to the catalog. + +In case the file changed, regenereate the catalog by following the +instructions above ('to update translations'). + +Once the new strings were transalated and the catalogs comiled with msgfmt, you +can generate the Javascript translation files. To do so, just run the command: + + invoke -r scripts/ generate.js-i18n + +Which will generate one JS file for detected language in the folder +rhodecode/public/js/rhodecode/i18n/{lang}.js + +Finally, commit the changes. + + +######################## +Testing translations +######################## + +Edit the test.ini file, setting the lang attribute to:: + + lang=<new_language_code> + +Run RhodeCode tests by executing:: + + nosetests + +########################### +Workflow for Transifex +########################### + +#0 new language: + edit .tx/config and add language +#1 extract messages to generate updated pot file + python setup.py extract_messages +#2 push source .pot file to Transifex + tx push -s +#3 when translations are ok pull changes + tx pull +#4 compile languages + python setup.py compile_catalog + diff --git a/rhodecode/i18n/it/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/it/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..061dfde33496c7828cc9502144d7443dbb59d7c7 GIT binary patch literal 126935 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 C5`{+q diff --git a/rhodecode/i18n/it/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/it/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/it/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7993 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Alessandro sauzher Ceglie, 2014-2016 +# FIRST AUTHOR <EMAIL@ADDRESS>, 2014 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Italian (http://www.transifex.com/rhodecode/RhodeCode/language/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "Globale" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Abilitato" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "Nessun commit" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "Mostra caratteri di spaziatura" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "Mostra caratteri di spaziatura per tutti i DIFF" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "Ignora caratteri di spaziatura" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "Ignora caratteri di spaziatura per tutti i DIFF" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "Allarga il contesto" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "Allarga il contesto per tutti i DIFF" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "Cambiamento stato %(transition_icon)s %(status)s" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "Seleziona una commit" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Home page" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "Il server non comprende la richiesta poiche' sembra malformata sintatticamente" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Accesso alla risorsa non autorizzato" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Non si hanno i permessi di visualizzazione per questa pagina" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "Risorsa non trovata" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "Il server ha incontrato difficolta' inattese e la richiesta non puo' essere completata" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "VCS Server Richiesto" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "Un server VCS è necessario per completare l'azione. Attualmente non risulta configurato alcun VCS Server" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Cambiamenti sul repository %s " + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s feed" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "Clicca qui per aggiungere un file" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "Nessun file selezionato. %s" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "Il repository è stato bloccato da %s il %s" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "Puoi eliminare solo file appartenenti ad una revisione con un branch valido" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "File %s eliminato via RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "File eliminato %s" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Un errore e' avvenuto durante l'operazione di commit" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Puoi modificare solo file appartenenti ad una revisione con un branch valido" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "File %s modificato via Rhodecode Enterprise" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Nessuna modifica" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Commit eseguita correttamente su %s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "File aggiunto via RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Nome file mancante" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "La locazione specificata deve essere un path relativo ma non deve contenere .. " + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Downloads disabilitati" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Revisione %s sconosciuta" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Repository vuoto" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Formato archivio sconosciuto" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Changesets" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Branches" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Tags" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Errore durante il fork del repository %s" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Gruppi" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Repositories" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "journal pubblico" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "journal" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "captcha invalido" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "La registrazione con RhodeCode ha avuto successo" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Il link di reset delle credenziali e' stato inviato" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "Reset della password confermato. Una nuova password è stata inviata alla tua email" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "La 'pull request' deve avere un titolo di almeno 3 caratteri" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "'Pull request' aperta correttamente" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Un errore e' avenuto durante l'invio della 'pull request'" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "Non è possibile aggiornare richieste PULL già chiuse" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "Titolo e Descrizione della richiesta PULL aggiornati." + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "Richiesta PULL aggiornata a \"{source_commit_id}\" con {count_added} commit aggiunti e {count_removed} rimossi." + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "Nulla di cambiato nella richiesta PULL" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "Salto l'aggiornamento della richiesta PULL a casa del tipo di referenza: {reference_type}" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "Aggiornamento fallito a causa di commit mancanti" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "Approvazione della richiesta PULL in attesa." + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "'Pull request' eliminata con successo" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "In attesa dell'approvazione del revisore" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "Chiudi Richiesta PULL" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Chiusura con" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "Non è consentito chiudere la richiesta PULL con stati diversi da \"rigettato\" o \"approvato\". Lo stato ricavato da tutti i revisori al momento è: %s." + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "Branch" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "Tag" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "Segnalibro" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "Branch chiusi" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Impostazioni di default aggiornate" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "Errore avvenuto durante l'aggiornamento dei valori di default" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "per sempre" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 minuti" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 ora" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 giorno" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 mese" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "a vita" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "Richiede un account registrato" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "Può essere acceduto da utenti anonimi" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Errore durante la creazione del 'gist'" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "'Gist' %s eliminato" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "Contenuto del 'gist' aggiornato" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "Proprieta' del 'gist' aggiornate" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "Errore durante l'aggiornamento del 'gist' %s" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "mai" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "%(expiry)s - valore corrente" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Utente critico per l'intera applicazione. Editing disabilitato." + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Account aggiornato correttamente" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "Errore durante l'aggiornamento dell'utente %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "Password aggiornata correttamente" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "Errore durante l'aggiornamento della password" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Errore durante il salvataggio dell'email" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "Ruolo" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "Token Autorizzativo creato" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "Token autorizzativo resettato" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "Token autorizzativo cancellato" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "Permessi applicati con successo." + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Errore durante l'aggiornamento dei permessi" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "Permessi sull'oggetto aggiornati." + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "Permessi globali aggiornati correttamente" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Creato gruppo di repository %s" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Errore durante la creazione del gruppo di repository %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Gruppo di repository %s aggiornato" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Errore durante l'aggiornamento del gruppo di repository %s" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "Questo gruppo contiene %(num)d repository e non può essere cancellato." +msgstr[1] "Questo gruppo contiene %(num)d repository e non può essere cancellato." + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "Questo gruppo contiene %(num)d sotto-gruppo e non può essere eliminato" +msgstr[1] "Questo gruppo contiene %(num)d sotto-gruppi e non può essere eliminato" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Gruppo di repository %s eliminato" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Errore durante l'eliminazione del gruppo di repository %s" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "Impossibile cambiare i permessi per se stessi come admin" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Permessi del gruppo di repository aggiornati" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "Errore durante la creazione del repository %s: certificato invalido" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "Errore durante la creazione del repository %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "Repository %s creato da %s" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Fork del repository %s come %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Repository %s creato" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Repository %s aggiornato correttamente" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Errore durante l'aggiornamento del repository %s" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "Delocalizzazione del fork %s" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "Cancellati %s fork" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Repository %s eliminato" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "Non e' possibile eliminare %s in quanto contiene fork collegati" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Errore durante l'eliminazione di %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Permessi sul repository aggiornati" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Errore durante la crezione del campo" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Errore durante la rimozione del campo" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Visibilita' del repository nel journal pubblico aggiornata" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Errore durante l'impostazione del repository nel journal pubblico" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Nulla" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Il repository %s e' stato marcato come fork di %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Errore durante il completamento dell'operazione" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "Repository bloccato" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "Repository sbloccato" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Errore durante lo sblocco" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Sbloccato" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Bloccato" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "Il repository e' stato %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "Cache invalidata" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Errore durante l'invalidazione della cache" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Effettuato 'Pull' dal remoto" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Errore durante il 'Pull' dal remoto" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Errore durante l'eliminazione delle statistiche del repository" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "Errore durante la rimozione dell'entry dall'issue tracker" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "Entry dell'issue tracker rimossa" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "Dati dell'Issue Tracker aggiornati" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "Ci son dati non validi tra i dati immessi" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "Errore durante l'aggiornamento delle impostazioni del repository VCS" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Impostazioni VCS aggiornate" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Errore durante l'aggiornamento delle impostazioni" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Scansione dei repository completata. Aggiunti: %s ; rimossi: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Impostazioni applicazione aggiornate" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Impostazioni di visualizzazione aggiornate" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Errore durante l'aggiornamento delle impostazioni di visualizzazione" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "Prego fornire un indirizzo email" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "Task 'invio posta' creato" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Aggiunto nuovo 'hook'" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "'Hook' aggiornato" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "Errore durante creazione hook'" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "Critico: lo spazio disco e' troppo basso. Occupazione <b>%s%%</b> " + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "Attenzione: lo spazio disco si sta esaurendo. Occupazione <b>%s%%</b> " + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "Errore durante l'aggiornamento delle impostazioni sui lab" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "Impostazioni sui Lab aggiornate" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "Merge mercurial, lato server " + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "Utilizzare \"rebase\" tramite l'interfaccia web per includere le modifiche, anziché committare un merge fatto in locale." + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "Supporto all'HTTP Subversion" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "Proxy per le richieste HTTP Subversion" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "URL del server HTTP Subversion" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "es. http://localhost:8080/" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "VCS" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "Interfaccia" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "Email" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "Hooks" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "Informazioni sistema" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "Laboratori" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "Creato il gruppo utenti %(user_group_link)s" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Errore avvenuto durante la creazione del gruppo di utenti %s" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Gruppo utenti %s aggiornato" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Errore durante l'aggiornamento del gruppo utenti %s" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Gruppo utenti eliminato" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Errore avvenuto durante l'eliminazione del gruppo utenti" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "Il gruppo di destinazione non può coincidere con l'origine" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Permessi del gruppo utenti aggiornati" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "Permessi globali dei Gruppi Utenti aggiornati." + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Errore avvenuto durante il salvataggio dei permessi" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "Creato l'utente %(user_link)s" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Errore durante la creazione dell'utente %s" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Utente aggiornato correttamente" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "Distaccati %s repository" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "%s repository cancellati" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "Distaccati %s gruppi di repository" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "%s gruppo di repository cancellati" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "Distaccati %s gruppi utente" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "%s gruppi utente cancellati" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Utente eliminato" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Errore durante la cancellazione dell'utente" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "Obbligo del cambiamento password disabilitato per l'utente" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "Obbligo del cambio password abilitato per l'utente" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "Errore durante il ripristino della password dell'utente" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "Creato il gruppo di repository `%s`" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "Errore durante la creazione del gruppo di repository per l'utente" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Non si hanno i permessi per editare l'utente" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "Permessi globali Utente aggiornati" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "Errore durante il salvataggio dell'ip: %s" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Errore durante il salvataggio dell'ip" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "Aggiunti gli ip %s alla 'whitelist' dell'utente" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "Indirizzo ip rimosso dalla 'whitelist' dell'utente" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr " [eliminato] repository" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "repository [creato]" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[creato] repository come fork" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[forked] repository" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[aggiornato] repository" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "[scaricato] archivio dal repository" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[elimina] repository" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[creato] utente" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[aggiornato] utente" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "[creato] gruppo utenti" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "[aggiornato] gruppo utenti" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "[commentato] al commit nel repository" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[commentato] sulla richiesta di 'Pull' per" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[chiusa] Richiesta di 'Pull' per" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "[merged] richiesta pull per" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[pushed] nel" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[committato via Rhodecode] nel repository" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[pulled da remoto] nel repository" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[pulled] da" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[da ora segui] repository" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[non segui più] repository" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "Nome del 'fork' %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Richiesta di 'Pull' #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "Mostra tutte le commit combinate %s->%s" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "vista comparativa" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Eliminato il branch: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "Creato il tag: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "Commit non trovata" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IP %s non consentito" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "È necessario essere utenti registrati per eseguire l'azione" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "Azione non supportata per %s." + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "Bisogna autenticarsi per vedere questa pagina" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "Il repository in %(repo_name)s non può essere localizzato." + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "File binario" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Il changeset è troppo lungo ed è stato troncato. Usa il menù 'diff' per visualizzare tutte le differenze" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Nessun cambiamento rilevato" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "e %s ulteriore/i" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Nessun file" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "nuovo file" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "mod" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "del" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "rinomina" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "Esempio termini di ricerca:\n repository:vcs\n username:marcin\n action:*push*\n ip:127.0.0.1\n date:20120101\n date:[20120101100000 TO 20120102]\n\nUso del carattere joly '*':\n \"repository:vcs*\" - search everything starting with 'vcs'\n \"repository:*vcs*\" - search for repository containing 'vcs'\n\nInterrogazioni con operatori opzionali AND / OR:\n \"repository:vcs OR repository:test\"\n \"username:test AND repository:test*\"\n" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "Il repository %s non ha corrispondenze nel db. Probabilmente è stato creato o rinominato direttamente sul filesystem. Provare ad avviare nuovamente l'applicazione per consentire la ri-scansione dei repository" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d anno" +msgstr[1] "%d anni" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d mese" +msgstr[1] "%d mesi" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d giorno" +msgstr[1] "%d giorni" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d ora" +msgstr[1] "%d ore" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d minuto" +msgstr[1] "%d minuti" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d secondo" +msgstr[1] "%d secondi" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "in %s" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s fa" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "%s, %s fa" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "in %s, %s" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "%s e %s" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s e %s fa" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "in %s e %s" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "proprio ora" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "URL" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Password" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Repository nessun accesso" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Repository accesso in lettura" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Repository accesso in scrittura" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Repository accesso admin" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Gruppo di repository: nessun accesso" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Gruppo di repository: accesso in lettura" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Gruppo di repository: accesso in scrittura" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Gruppo di repository: accesso admin" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "RhodeCode Administrator" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Creazione di Repository disabilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Creazione di Repository abilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "Forking Repository disabilitato" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "Forking Repository abilitato" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Registrazione disabilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Registrazione nuovo utente con RhodeCode e attivazione manuale" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Registrazione nuovo utente attraverso RhodeCode e attivazione automatica" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Non Revisionato" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Approvato" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Rifiutato" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "in Revisione" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "Gruppo di repository: nessun accesso" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "Gruppo di repository: accesso in lettura" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "Gruppo di repository: accesso in scrittura" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "Gruppo di repository: accesso admin" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "Gruppo utenti: nessun accesso" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "Gruppo utenti: accesso in lettura" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "Gruppo utenti: accesso in scrittura" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "Gruppo utenti: accesso admin" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "Creazione gruppo di repository disabiltiata" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "Creazione gruppo di repository abilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "Creazione gruppo utenti disabilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "Creazione gruppo utenti abilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "Registrazione disabilitata" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "Registrazione utente con attivazione manuale dell'account" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "Registrazione utente con attivazione automatica dell'account" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "Attivazione manuale di account esterni" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "Attivazione automatrica di account esterni" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "Creazione di repository abilitata con permessi di scrittura al gruppo di repository" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "Creazione di repository disabilitata abilitata con permessi di scrittura al gruppo di repository" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "RhodeCode Super Administrator" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "Ereditarietà dei permessi \"user default\" sull'oggetto disabilitata." + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "Ereditarietà dei permessi \"user default\" sull'oggetto abilitata" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Stringa di ricerca invalida. Provare a quotarla" + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "Non ci sono indici con cui effettuare la ricerca. Avviare 'whoosh indexer'" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Errore durante la ricerca" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "Indice del File" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "Documenti indicizzati" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "Ultimo aggiornamento" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "tutti" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "interfaccia http/web" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "vcs (protocollo git/hg)" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "chiamate API" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "accesso al feed" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Prego specificare una login" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Inserire un valore di almeno %(min)i caratteri" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Prego inserire una password" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Inserire almeno %(min)i caratteri" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "%(user)s ha commentato il commit %(date_or_age)s" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "%(user)s ha commentato il commit il %(date_or_age)s" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "%(user)s ha inviato un messaggio %(date_or_age)s" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "%(user)s ha inviato un messaggio il %(date_or_age)s" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "%(user)s ti ha menzionato %(date_or_age)s" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "%(user)s ti ha menzionato il %(date_or_age)s" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "%(user)s registrato in RhodeCode %(date_or_age)s" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "%(user)s registrato in RhodeCode il %(date_or_age)s" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "%(user)s ha aperto una richiesta PULL %(date_or_age)s" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "%(user)s ha aperto una richiesta PULL il %(date_or_age)s" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "%(user)s ha commenato la richiesta PULL %(date_or_age)s" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "%(user)s ha commentato la richiesta PULL il %(date_or_age)s" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "Questa richiesta PULL può essere incorporata automaticamente." + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "Questa richiesta PULL non può essere incorporata a causa di un eccezione non gestita" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "Questa richiesta PULL non può essere incorporata perchè emergono conflitti." + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "Questa richiesta PULL non può esere incorporata perché è fallito il PUSH sul target." + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "Questa richiesta PULL non può essere incorporata perché il target indicato non è la versione di testa (head)." + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "Questa richiesta PULL non può esser incorporata perché la sorgente contiene un numero superiore di branch rispetto al target" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "Questa richiesta di PULL non può essere incorporata perché il target ha versioni di testa multiple" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "La richiesta PULL non può essere \"merged\" poiché il repository target è \"locked\"" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "La \"richiesta di PULL\" non può essere incorporata poichè manca il riferimento alla sorgente o alla destinazione" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "Richiesta PULL chiusa. Merge effettuato." + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "L'Incorporamento lato server delle richiesta di PULL è disabilitato" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "Questa richiesta PULL è chiusa." + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "L'incorporamento delle richieste PULL non è supportato." + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "Il supporto ai file di grosse dimensioni sul repository target è disabilitato." + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "Sul repository sorgente, il supporto a file di grosse dimensioni è disabilitato." + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Segnalibri" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "Commit IDs" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "Branch chiusi" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "ultimo consiglio" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Utente critico per l'intera applicazione. Editing disabilitato." + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "Non puoi editare questo utente (`%(username)s`) poiché è cruciale per l'intera applicazione" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Utente critico per l'intera applicazione. Eliminazione disabilitata." + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "L'utente \"%s\" è ancora proprietario di %s repository e non può' essere rimosso. Sostituire i proprietari o rimuovere quei repository: %s" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "L'utente \"%s\" è ancora proprietario del/dei %s gruppi di repositor y e non può essere rimosso. Sostituire il proprietario o rimuovere quel/quei gruppi di repository: %s" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "L'utente \"%s\" è ancora proprietario di %s gruppi utente e non può essere rimosso. Sostituire il proprietario o rimuovere quei gruppi utente: %s" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "Il valore non può essere una lista vuota" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "Pattern esistente" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "Il nome utente \"%(username)s\" esiste già" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "Il nome utente \"%(username)s\" è riservato" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "Il nome utente può contenere solo caratteri alfanumerici, trattini (bassi e medi) e deve cominciare necessariamente con un carattere alfanumerico o un trattino (basso)" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "Il dato immesso non è valido" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "Nome utente %(username)s non valido" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "Nome del gruppo non valido" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "Un gruppo col nome \"%(usergroup)s\" esiste già" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "Il nome di un gruppo può contenere solo caratteri alfanumerici, trattini (bassi e medi) e deve cominciare necessariamente con un carattere alfanumerico o un trattino (basso)" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Questo gruppo non può essere genitore" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "Un gruppo chiamato \"%(group_name)s\" esiste giÎ" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Un repository chiamato \"%(group_name)s\" esiste già" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "Non hai i permessi per salvare qui questo gruppo di repository" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "Non hai i permessi per salvare il gruppo di repository nella radice" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "La password contiene dei caratteri (non ascii) non consentiti" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "Vecchia password sbagliata" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Le password non corrispondono" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "Password errata" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "Nome utente errato" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Account disabilitato" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Il token non corrisponde" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "Non è consentito chiamare un repository %(repo)s " + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "Un repository chiamato \"%(repo)s\" esiste già" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "Un gruppo di repository col nome \"%(repo)s\" esiste già" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "Un repository chiamato %(repo)s è presente nel gruppo \"%(group)s\"" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "Un gruppo di repository chiamato \"%(repo)s\" è presente nel gruppo \"%(group)s\"" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "L'URL per la clonazione non corrisponde ai repository di tipo %(rtype)s " + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "URL invalido. Fornire un URL che cominci con un prefisso incluso tra %(allowed_prefixes)s" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "Un Fork deve essere dello stesso tipo del genitore" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "Non hai permessi per creare repository in questo gruppo." + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "Non hai permessi per memorizzare repository nella radice." + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "Nome utente o nome gruppo invalidi" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "Questo non è un path valido" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Indirizzo e-mail già in uso da qualcuno" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "L'e-mail \"%(email)s\" non esiste." + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "Bisogna specificare l'attributo CN della login LDAP. Il CN è l'equivalente LDAP del campo \"username\"" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "Le revisioni %(revs)s fanno già parte della richiesta 'Pull' o hanno lo stato" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "Inserire un indirizzo IPv4 o IPv6 valido" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "Il dimensionamento in bit della network deve essere nel range di 0-32 (non %(bits)r)" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "Il nome della chiave può contenere solo lettere, trattini (bassi o medi) o numeri" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "Il nome file non deve essere presente dentro la directory" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "I plugin %(loaded)s e %(next_to_load)s esportano entrambi lo stesso nome" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "Questo gistid è già in uso" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Dashboard" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "filtro rapido..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "corrispondenze" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "Aggiungi Repository" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "Aggiungi un Gruppo di Repository" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "Hai i diritti di admin sul gruppo e puoi modificarlo" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "Modifica il Gruppo di Repository" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Nome" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Descrizione" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Proprietario" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Ultimo cambiamento" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "Commit" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "Bacheca del gruppo di repository %s" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "Base" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Autenticati" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Nome utente" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Ricordami" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "Password dimenticata?" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "Ripristina la tua Password" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "Indirizzo Email" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "Captcha" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "Invia mail per il ripristino della password" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Il link per il ripristino della Password verrà inviato all'indirizzo email corrispondente" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Ripetere la password" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Nome" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Cognome" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "L'attivazione dell'account richiede l'approvazione di un admin" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "admin Journal" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "Filtra il journal..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "filtro" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s elemento" +msgstr[1] "%s elementi" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "Query di esempio" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Azione" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Repository" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Data" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "Dall'IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Nessuna azione" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "Impostazioni di Autenticazione" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Admin" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "Plugin di Autenticazione" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "Plugin abilitati" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "Aggiungere una lista di plugin separati da virgole. L'ordine dei plugin è anche l'ordine in cui RhodeCode Enterprise proverà ad autenticare un utente" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "abilitato" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "disabilitato" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Salva" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "Plugin" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "Repository: impostazioni di base" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "Impostazioni base per nuovi repository" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Tipo" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "Repository privato" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "I repository 'privati' sono visibili soltanto alle chi è aggiunto esplicitamente tra i collaboratori." + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "Abilita le statistiche" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "Abilita una finestra per le statistiche sulla pagine di riepilogo del repository" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "Abilita i download" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "Abilita l'opzione per il download nella pagina di riepilogo del repository" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "Abilita il blocco" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "Abilita il blocco automatico del repository. Una richiesta di PULL imporrà un blocco che sarà rimosso al successivo PUSH da parte dell'utente." + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "Modifica il Gist" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "Il Gist è cambiato da quando l'hai aperto. Copia i tuoi cambiamenti e clicca %(here)s per ricaricare la nuova versione" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "Descrizione del Gist" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "Storia del Gist" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "Livello di accesso ai Gist" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "testo semplice" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "Aggiorna il Gist" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "Annulla" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "Gist privati per l'utente %s" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "Gist pubblici per l'utente %s" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "Gist pubblici" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "Tutti i Gist dell'user %s" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "Tutti i Gist pubblici" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "Crea un Nuovo Gist" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "Tutti i Gist" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "Tutto pubblico" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "I miei Gist" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "Mio Privato" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "Mio Pubblico" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "Autore" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "Creato il" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "Scade" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "Nuovo Gist" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "Gist id" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "Auto generato" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "dai un nome al file..." + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "Crea un Gist Privato" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "Crea un Gist Pubblico" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Ripristina" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "Gist" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Elimina" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "Conferma di voler eliminare questo Gist" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "Modifica" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "Mostra sorgente" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "Gist Privato" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "creato" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "Mostra sorgente" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "il mio Account" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "il mio Account" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "Profilo" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "Tocken autorizzativi" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "le mie Email" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "i miei Repository" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "Osservato" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "Richieste 'Pull'" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "Permessi" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "I Token integrati possono essere usati per autenticarsi con tutte le possibili opzioni" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "Ciascun token può essere associato ad un ruolo. I token per i VCS possono essere utilizzati congiuntamente al plugin authtoken di autenticazione per eseguire operazioni git/hg." + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "Integrati" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "scade" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "Conferma di voler resettare il Token autorizzativo: %s" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "scaduto" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "Conferma di voler rimuovere il Token autorizzativo: %s" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "Token autorizzativo aggiuntivo non specificato" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "Nuovo token di autenticazione" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Aggiungi" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "Primario" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "Conferma l'eliminazione dell'email: %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "Indirizzi email aggiuntivi non specificati" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "Nuovo indirizzo email" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "Cambia la tua Password" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "Password corrente" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "Nuova password" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "Conferma nuova password" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "Foto" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "Gli Avatar sono disabilitati" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "Email mancante, si prega di aggiornare il proprio indirizzo email" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "I dettagli del tuo account sono gestiti in una sorgente esterna (es. LDAP). Tali dettagli non possono essere gestiti qui." + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "Cambia l'avatar" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "Mostra richieste di PULL chiuse." + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "Richiesta 'Pull' #%s aperta su %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "Chiuso" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "Conferma l'eliminazione di questa richiesta 'Pull'" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "Al momento non hai richieste di PULL pendenti." + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "Richiesta di 'Pull' #%s aperta da %s su %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "Al momento non ci sono richieste di PULL che richiedono il tuo intervento" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "Repository che ti appartengono" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "I Repository che osservi" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Le mie Notifiche" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Tutto" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Commenti" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "Marca tutti come letti" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Nessuna notifica" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Mostra notifica" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Notifiche" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "Amministrazione Permessi" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Permessi" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "Applicazione" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "Oggetto" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "Whitelist IP" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "Panoramica" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "Permessi di Sistema" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "Accesso Anonimo" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "Consenti l'accesso a Rhodecode Enterprise senza la necessità di autenticarsi. Gli anonimi erediteranno i permessi %s." + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Registrazione" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "Messaggio della pagina di Registrazione" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "Messaggio personalizzato che sarà mostrato nella pagina di registrazione. HTML supportato." + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "Attivazione account ad autenticazione esterna" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "Whitelist di base di indirizzi IP per tutti gli utenti" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "Conferma eliminazione dell'ip: %s" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "Tutti gli indirizzi IP possono accedere" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "Nuovo indirizzo IP" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "Descrizione.." + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "Inserisci una lista separata da virgole di indirizzi ip come 127.0.0.1,\no in notazione a maschera 127.0.0.1/24, per identificare un insieme di reti.\nPer specificare degli intervalli continui di indirizzi usa la sintassi 127.0.0.1-127.0.0.10" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "Permessi di default per repository, gruppi utente e gruppi di repository" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "Permessi di default di sistema. Ogni nuova entità di gestione dei permessi, sarà creata con i seguenti parametri di default. Utilizzare la casella di controllo di \"sovrascrittura, per forzare il cambiamento dei permessi sugli oggetti già esistenti." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "Tutti i permessi di base saranno resettati, per ciascun repository, al permesso selezionato. Nota bene: tutti permessi locali dei repository saranno perduti." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "Sovrascrivi impostazioni esistenti" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "Gruppi di Repository" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Tutti i permessi di base saranno resettati, per ciascun gruppo di repository, al permesso selezionato. Nota bene: tutti permessi locali dei gruppi di repository saranno perduti." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "Gruppi utente" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Tutti i permessi di base saranno resettati, per ciascun gruppo di utenti, al permesso selezionato. Nota bene: tutti permessi locali dei gruppi utente saranno perduti." + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "Panoramica permessi utente di default" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "Aggiungi Gruppo di Repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "Gruppi di Repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "Nome gruppo" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "Gruppo genitore" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "Copia i permessi del gruppo genitore" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "Copia i parametri dei permessi dal gruppo repository genitore" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "Impostazioni del gruppo di repository %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "Aggiungi Gruppo Figlio" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Impostazioni" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "Avanzate" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "Repository totali" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "Repository di primo livello" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "Gruppi figli" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "Gruppo di Repository: %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "Elimina il gruppo di repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "Questo gruppo di repository include all'interno %s altro gruppo di repository" +msgstr[1] "Questo gruppo di repository include all'interno %s altri gruppo di repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "Questo gruppo di repository include all'interno %s altro repository" +msgstr[1] "Questo gruppo di repository include all'interno %s altri repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "Conferma la cancellazione di questo gruppo: %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "Elimina questo gruppo di repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "Permessi del Gruppo di Repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "None" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Lettura" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Scrittura" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "Utente/Utente Gruppo" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "super admin" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "proprietario" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "Revoca" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "admin delegato" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "Aggiungi nuovo" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "Applica ai figli" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "Entrambi" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "Se spuntato, imposta o revoca i permessi del tipo selezionato a tutti i discendenti di questo gruppo, inclusi i repository non-privati e altri sotto gruppi." + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "Cambia il proprietario al gruppo di repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "Gruppo genitore" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "Abilita il Blocco del repository" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "Il blocco sarà abilitato su tutti i sottogruppi e repositori inclusi all'interno di questo gruppo di repository. Il blocco su un repository si attiva al PULL, e viene rimosso al successivo PUSH effettuato dal medesimo utente." + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "Amministrazione Gruppi di Repository" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "gruppi di repository" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "Numero di repository livello top" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Aggiungi repository" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "Importare un repository esistente?" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Clona da" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "URL http[s] opzionale da cui clonare un repository." + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "Mantenersi concisi e dritti al punto. Usare un file README per descrizioni più verbose" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "Gruppo di Repository" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "Seleziona il mio gruppo personale (%(repo_group_name)s)" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "Seleziona, opzionalmente, un gruppo in cui porre questo repository" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "%s Creazione repository" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "Creazione del repository" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "Repository \"%(repo_name)s\" in creazione. Sarete reindirizzati automaticamente al termine del processo." + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "Impostazioni del repository %s" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "Caches" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Remoto" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Statistiche" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "Set" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "Imposta manualmente questo repository come fork di un altro della lista" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "Conferma sbloccaggio repository." + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "Sblocca repository" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "Conferma il blocco del repository." + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "Scollega i fork" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "Cancella i fork" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "Conferma la cancellazione del repository: %s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "Invalida la cache del repository" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "Conferma l'invalidazione della cache del repository" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "Prefisso" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "Chiave" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Attivo" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "Etichetta" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "Conferma cancellazione del campo: %s" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "Inserisci una breve etichetta" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "Schema" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "URL" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "repository privato" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "URL remoto" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "PULL - Incorpora i cambiamenti dalla origine remota" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "Conferma il 'Pull' dalla origine remota" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "ID non modificabile" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "cos'è quello ?" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "URL per ID" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "In caso il repository sia rinominato o spostato in un altro gruppo l'URL cambierebbe.\nUsare l'indirizzo sopra riportato, garantisce che questo repository sarà sempre accessibile da quell'URL.\nUtile per i sistemi CI, o ogni altro caso in cui si necessiti di cablare l'URL in servizi di terze parti" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "URI remoto" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "modifica" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "nuovo valore. lascia vuoto per eliminarlo" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "annulla" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "URL http[s] da cui il repository è stato importato. Usato anche per PULL remoti." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Gruppo di Repository" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "Opzionale: selezionare un gruppo all'interno del quale aggiungere questo repository" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "Cambia il proprietario del repository" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Repository privato" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Abilita statistiche" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "Abilita la finestra delle statistiche sulla pagina di riepilogo" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Abilita i download" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "Abilita il menù per il download sulla pagina di riepilogo" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "Abilita il blocco automatico" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "Abilita il blocco automatico sul repository. Un PULL da questo repository creerà un blocco che potrà essere rilasciato con un PUSH da parte dello stesso utente" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "Commit processati" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "Progresso processato" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "Azzeza le statistiche" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "Conferma di eliminare le statistiche correnti" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Salve impostazioni" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "Amministrazione repository" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "repository" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "Stato" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "Amministrazione impostazioni" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "Prefisso email" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "Email mittente RhodeCode" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "Mittente email errori" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "Destintatario email errori" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "SMTP server" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "SMTP username" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "SMTP password" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "porta SMTP" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "Uso di SMTP TLS " + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "Uso di SMTP SSL" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "Autenticazione SMTP" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Invia" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "Titolo" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "La chiave pubblica per l'utilizzo del sistema ReCaptcha" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "La chiave privata per l'uso del sistema ReCaptcha. Impostando un valore si abiliterà il captcha al momento della registrazione" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "Modelli..." + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "Aannuncio del server" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "Codici js/css da aggiungere alla chiusura del tag <header>" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "Usa tag <script> o <css> per definire stili e script personalizzati" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "Codici js/css da aggiungere alla chiusura del tag <body>" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "Hooks Mercurial integrati - sola lettura" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "Gli \"hooks\" possono essere usati per scatenare azioni al verificarsi di determinati eventi che si verificano lato server come push e pull. Essi possono richiamare funzioni Python o applicazioni esterne." + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "Hooks personali" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "Distruggi dati obsoleti" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "In caso un repository venga eliminato dal filesystem e questo persista nel database, abilitare questa opzione per eliminare dati obsoleti dal database." + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "Invalida la cache per tutti i repository" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "Ogni dato in memoria cache per ciascun repository sarà ripulito. Usa questa opzione per ricaricare i dati e pulire le chiavi di memorizzazione" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "Ultimi %(size)s bytes per i log di processo, usa il parametro ?offset=[num] GET per cambiare la dimensione" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "Versione RhodeCode Enterprise" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "controlla aggiornamenti" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "Verifica aggiornamenti da" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "Nota: assicurarsi che il server possa accedere a quest'URL" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "File INI di configurazione" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "RhodeCode Enterprise Server IP" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "RhodeCode Enterprise Server ID" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "Piattaforma" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "Attivo da" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "Percorso di storage" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "Spazio disco di storage" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "Storage indici di ricerca" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "Dimensione indice di ricerca" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "Storage del Gist" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "Dimensione del Gist storage" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "Cache dell'archivio" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "Abilitalo impostando l'opzione archive_cache_dir=/path/to/cache nel file .ini" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "Dimensione dell'archivio cache" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "Memoria di sistema" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "CPU" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "Carico" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "Versione python" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "Percorso Python" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "Versione GIT" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "Versione HG" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "Versione SVN" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "Database" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "Versione Database" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "Controllo nuove versioni..." + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "Generali" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "Utilizza i campi extra del repository" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "Permette l'uso di ulteriori campi personalizzati per repository" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "Mostra la versione di RhodeCode" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "Mostra o nasconde la versione di RodeCode nel footer" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "Meta-Tagging" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "Riconosce dei meta tag all'interno dei testi nel repository e li converte in tag colorati." + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "Numero di elementi mostrati nella pagina princiaple della dashboard prima dei controlli di paginazione" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "Elementi pagine Admin" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "Numero di elementi mostrati nelle griglie delle pagine dell'amministratore." + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "Lunghezza SHA del commit" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "Mostra il num. di rev. del commit" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Icone" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Mostra l'icona \"pubblico\" dei repository" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Mostra l'icona 'privato' dei repository" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "Mostra le icone 'pubblico/privato' accanto ai nomi dei repository" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "Aggiungi gruppo utente" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "Gruppi utente" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "Aggiungi gruppo utente" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Nome gruppo" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "Breve, opzionale, descrizione del gruppo" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "Impostazioni del gruppo utente %s" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "Permessi globali" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "Riepilogo dei permessi" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Membri" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "Assegnati ai repository" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "Assegnati ai gruppi di repository" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "Gruppo utente: %s" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "Conferma l'eliminazione del gruppo utente `%(ugroup)s` con tutti i permessi assegnati" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "nessun membro" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "revoca" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "Cambia il proprietario di questo gruppo utente" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "Gruppo utenti scelto" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Rimuovi tutti gli elementi" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Membri disponibili" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Aggiunge tutti gli elementi" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "Amministrazione gruppi utente" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "gruppi utente" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Aggiungi utente" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Utenti" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "Aggiungi utente" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Conferma password" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "Genera una password" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "Cambia password" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "Forza l'utente a cambiare la propria password al prossimo login" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "Aggiunge un gruppo di repository con lo stesso nome dello username.\nL'utente sarà impostato automaticamente come proprietario del gruppo" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "Password generata:" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "Impostazioni utente %s" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "Token autorizzativi" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "le Email" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "Origine Esterna" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "Ultimo login" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "Ultima attivit" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "Membro di gruppi utente" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "Forza il cambiamento password" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "Utente: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "Crea un gruppo di repository personale" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "Distacca i repository" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "Cancella i repository" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "Distacca i gruppi di repository" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "Distacca i gruppi utente" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Conferma l'eliminazione dell'utente: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "Cancella l'utente" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "Quando l'opzione di \"distacco\" viene selezionata, gli oggetti dipendenti dell'utente saranno assegnati al `%s` super admin del sistema. L'opzione \"Ellimina\" cancellerà i repository dell'utente!" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "Nessun auth token aggiuntivo è stato specificato" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "Nuovo Token atuorizzativo" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "Ereditato da %s" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "Inserisci una lista separata da virgole di indirizzi ip come 127.0.0.1,\no in notazione a maschera 127.0.0.1/24, per identificare un insieme di reti.\nPer specificare degli intervalli usa la sintassi 127.0.0.1-127.0.0.10" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "Nome nell'Origine Esterna" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "Lingua" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "Aiuta a tradurre %(rc_link)s nella tua lingua." + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Amministrazione utenti" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "Tipo di autenticazione" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "Supporto" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "Autenticazione" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "Parametri di default" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "Fork di" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "Repository bloccato da %(user)s" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Riassunto" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "Registro" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "i File" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Confronta" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "Mostra le richieste PULL da %s" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Opzioni" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Confronta FORK" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Ricerca" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "Sblocca" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "Blocca" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "Fork" +msgstr[1] "Forks" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "Crea richiesta di PULL" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "Accedi" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "Accedi al tuo account" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "(Password dimenticata?)" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Non possiedi un account?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Journal" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Journal pubblico" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "i Gist" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "Stile" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "Scorciatoie da tastiera" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "Scorciatoie per tutto il sito" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "Le opzioni seguenti configurano i permessi di default che erediteranno utenti e gruppi. Questi permessi possono essere ulteriormente ridefiniti nelle impostazioni presenti sui singoli utenti o singoli gruppi." + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "Leggi di pi" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "Anteprima" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "mostra" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "nessuno" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "lettura" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "scrittura" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "admin" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Permesso" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "Modifica Permesso" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "Super admi" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "Permessi base del repository" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "Permessi base del gruppo di repository" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "Permessi base del gruppo utente" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "Crea i repository" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "Fork di repository" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "Crea gruppi di repository" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "Crea gruppi utente" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "Nessun permesso definito" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "Richiedi SSL per operazioni sul VCS" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "Attivare per forzare RhodeCode ad accettare richieste PUSH o PULL solo su protocollo SSL. Se il certificato SSL non sarà disponibile sarà restituito un HTTP Error 406: Not Acceptable." + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "Clicca per sbloccare. E' necessario riavviare RhodeCode perch­è questa modifica abbia effetto" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "Ubicazione sul filesystem dove i repository saranno archiviati. Dopo il cambiamento di questo valore è necessario un riavvio e un \"rescan\" del repository." + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "Dopo un PUSH mostra la dimensione del repository" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "Esegue gli hooks pre/post previsti per i PUSH" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "Esegue gli hooks pre/post previsti per i PULL" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "Abilita l'estensione \"largefiles\"" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "Imposta la pubblicazione dei repository" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "Abilita l'estensione \"hgsubversion\"" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "Richiede che sia installata la libreria hgsubversion. Permette il \"clone\" di repository SVN remoti e la loro migrazione a Mercurial" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "Pattern del Repository" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "\"Pattern\" per identificare \"branch\" e \"tag\" svn. Per ricerche ricorsive, usare \"*\". Es.: \"/branches/*\"" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "Abilita l'incorporamento lato server delle \"richieste di PULL\"" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "Invalida e realloca i commenti in linea durante l'aggiornmento" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "Aggiorna la posizione dei commenti inline durante l'aggiornamento di una \"richiesta di PULL\". I commenti inline non più sognificativi saranno nascosti." + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "%s Segnalibri" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "segnalibri" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "confronta i Segnalibri Selezionati" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "Segnalibro %s" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "%s Branch" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "i branch" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "confronta i Branch Selezionati" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "Branch %s" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "%s Changelog" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "Confronta fork con %s" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "Apri una richiesta PULL" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "Ripulisci selezione" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "Et" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "Messaggio Commit" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "Espandi il messaggio commit" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "Tag %s" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "Filtra registro" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "Nessun cambiamento" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "Rimosso" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "Cambiato" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "Aggiunto" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "Interessa %s file" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "merge" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "Messaggio commit" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "Aggiungi Nuovo File" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "Repository esistente?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "diff semplice" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "Patch diff" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "Download diff" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "Nessun file" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "Mostra diff completo" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "Voto sulla richiesta PULL #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "Commento sulla richiesta PULL #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "Commenti analizzati usando la sintassi %s col supporto %s." + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "Usa @username all'interno del testo per notificare l'utente RhodeCode." + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "Preview del commento" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "Commento" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "E' necessario autenticarsi prima di commentare" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "Autenticati ora" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "Nascondi" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "(%s commit)" +msgstr[1] "(%s commit)" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "Mostra confronto combinato" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "Mostra il DIFF completo per questo file" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "Mostra, affiancando, il DIFF completo per il file" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "%s Confronti" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "%s commit" +msgstr[1] "%s commit" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "Scambia" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Repository Mercurial" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Repository Git" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "Repositiory subversion" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Repository pubblico" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "Creazione repository in corso..." + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "Sottoscrivi il feed rss %s" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "Sottoscrivi l' atom feed %s" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "Creazione" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "Creato" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "Conferma l'eliminazione del gruppo: %s incluso %s repository" +msgstr[1] "Conferma l'eliminazione del gruppo: %s inclusi %s repository" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "Conferma la cancellazione di questo gruppo utente: %s" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "Gruppo utenti" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "Privato" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "Pulsanti" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "Richiesta PULL chiusa con stato" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "Sarete rediretti a %s in %s secondi" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "DIFF affiancato del file %s" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "modalit" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "Diff del file %s" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "%s file" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "Aggiungi %s File" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "Aggiungi nuovo file" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "oppure" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "Carica un file" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "Crea Nuovo File" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "accapo automatico" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "acceso" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "spento" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "Commit modifiche" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "Lista Ricerca File" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "Caricamento lista file..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "Dimensione" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "Modificato" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Caricamento..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "Cancellazione %s File" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "Elimina file" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "File binario (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "Il file è troppo grande per essere mostrato" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "Modifica %s File" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "Modifica file" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "storia" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "sorgente" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "annotazione" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "raw" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "download" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "Modifica file" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "Ubicazione" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "Download" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "Impossibile modificare file binari" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "%s Follower" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "i Follower" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "Fork del repository %s" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "nome Fork" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "Copia permessi" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "Copia permessi dal fork del repository" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "Fai un Fork del repository" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "%s Fork" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "i Fork" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "è un Fork" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "Non ci sono Fork" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "Feed ATOM del journal" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "Feed RSS del journal" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "Nessuna entry" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Journal Pubblico" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "Feed ATOM del journal pubblico" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "Feed RSS del journal pubblico" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "Nuova richiesta PULL" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "Scrivi una breve descrizione sulla richiesta PULL" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "Origine del repository" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "Revisori della richiesta PULL" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "Repository di destinazione" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "%s: Richiesta PULL #%s" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "Salva i Cambiamenti" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "revisore" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "Aggiorna i commit" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "Mostrare un diff di grosse dimensioni potrebbe prendere tel tempo e occupare risorse" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "%s Richieste di PULL" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "Aperto da me" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "Contenuti dei file" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "Messaggi di commit" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "Nomi dei file" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "%s Riassunto" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "%s feed ATOM" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "%s feed RSS" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "Mostra per Nome" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "Mostra per ID" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "Clona url" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "Le statistiche sono state disabilitate su questo repository" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "Non ci sono download" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "Download disabilitati sul repository" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "Avvio rapido" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "%s Tag" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "i tag" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "Confronta i Tag Selezionati" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "Profilo" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" diff --git a/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c29698b97d69b79ea4fc164daf6d401d58c4f46 GIT binary patch literal 130213 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 E0H7H8Qvd(} diff --git a/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7958 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# しろう, 2013 +# shirou - しろう <shirou.faw@gmail.com>, 2013 +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011 +# Takayuki KONDO <tkondou@gmail.com>, 2013 +# Takumi IINO <trot.thunder@gmail.com>, 2013-2014 +# Takayuki KONDO <tkondou@gmail.com>, 2013 +# shirou - しろう <shirou.faw@gmail.com>, 2013 +# Yasushi Masuda <whosaysni@gmail.com>, 2014 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Japanese (http://www.transifex.com/rhodecode/RhodeCode/language/ja/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: ja\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "全般" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "有効" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "ホームページ" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "形式が間違っているため、サーバーはリクエストを処理できませんでした" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "リソースにアクセスする権限がありません" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "このページを閲覧する権限がありません" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "リソースが見つかりません" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "サーバーが不正な状態になったため、リクエストに答えることができませんでした。" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "%s リポジトリでの変更" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s フィード" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "まだファイルがありません。 %s" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "有効なブランチ上のリビジョンからしかファイルを削除できません" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "%s ファイルの削除に成功しました" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "コミット中にエラーが発生しました" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "有効なブランチを示すリビジョンでのみファイルを編集できます。" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "変更点なし" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "%s へのコミットが成功しました" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "ファイル名がありません" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "ダウンロードは無効化されています" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "%s は未知のリビジョンです" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "空のリポジトリ" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "未知のアーカイブ種別です" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "チェンジセット" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "ブランチ" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "タグ" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "リポジトリ %s のフォーク中にエラーが発生しました" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "グループ" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "リポジトリ" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "公開ジャーナル" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "ジャーナル" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "キャプチャが一致しません" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "パスワードリセットのリンクを送信しました" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "プルリクエストには3文字以上のタイトルが必要です" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "新しいプルリクエストの作成に成功しました" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "プルリクエストの作成中にエラーが発生しました" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "プルリクエストの削除に成功しました" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "この状態で閉じる:" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "ブランチ" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "タグ" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "ブックマーク" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "閉鎖済みブランチ" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "デフォルト設定の更新に成功しました" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "無期限" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 分" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 時間" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 日" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 ヶ月" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "有効期間" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "gist の作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "gist %s を削除しました" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "Gist の内容を更新しました" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "Gist データを更新しました" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "Gist %s の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "無し" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "このユーザーを編集できません。このユーザーはアプリケーションにとって必要不可欠です。" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "アカウントの更新に成功しました" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "ユーザー %s の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "メールの保存時にエラーが発生しました" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "権限の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "全般の権限の更新に成功しました" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "リポジトリグループ %s を作成しました" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "リポジトリグループ %s の作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "リポジトリグループ %s を更新しました" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "リポジトリグループ %s の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "リポジトリグループ %s を削除しました" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "リポジトリグループ %s の削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "リポジトリグループ権限を更新しました" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "リポジトリ %s の作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "リポジトリ %s を %s から作成しました" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "リポジトリ %s を %s としてフォークしました" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "リポジトリ %s を作成しました" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "リポジトリ %s の更新に成功しました" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "リポジトリ %s の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "%s 個のフォークを切り離しました" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "%s 個のフォークを削除しました" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "リポジトリ %s を削除しました" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "フォークしたリポジトリが存在するため、 %s は削除できません" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "%s の削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "リポジトリ権限を更新しました" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "フィールドの作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "フィールドの削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "公開ジャーナルでのリポジトリの可視性を更新しました" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "このリポジトリの公開ジャーナルの設定中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "ありません" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "%s リポジトリを %s のフォークとする" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "操作中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "リポジトリをロックしました" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "リポジトリのロックを解除しました" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "アンロック中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "アンロック" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "ロック" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "リポジトリは %s されています" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "キャッシュの無効化に成功しました" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "キャッシュの無効化中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "リモートから取得" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "リモートから取得中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "リポジトリステートの削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "VCS設定を更新しました" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "アプリケーション設定の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "リポジトリの再スキャンに成功しました。 追加: %s 削除: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "アプリケーション設定を更新しました" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "表示設定を更新しました" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "表示設定の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "メールアドレスを入力してください" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "メール送信タスクを作成しました" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "新しいフックを追加しました" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "フックを更新しました" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "フックの作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "VCS" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "表示" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "メールアドレス" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "フック" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "システム情報" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "ユーザーグループ %s の作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "ユーザーグループ %s を更新しました" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "ユーザーグループ %s の更新中にエラーが発生しました" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "ユーザーグループの削除に成功しました" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "ユーザーグループの削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "対象に同じ物を選ぶことはできません" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "ユーザーグループ権限を更新しました" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "権限の保存時にエラーが発生しました" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "ユーザー %s の作成中にエラーが発生しました" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "ユーザーの更新に成功しました" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "ユーザーの削除に成功しました" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "ユーザーの削除中にエラーが発生しました" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "このユーザーは編集できません" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "IPアドレスの保存中にエラーが発生しました" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "ユーザーホワイトリストからIPアドレスを削除しました" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "リポジトリを[削除]" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "リポジトリを[作成]" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "フォークしてリポジトリを[作成]" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "リポジトリを[フォーク]" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "リポジトリを[更新]" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "リポジトリからアーカイブを[ダウンロード]" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "リポジトリを[削除]" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "ユーザーを[作成]" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "ユーザーを[更新]" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "ユーザーグループを[作成]" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "ユーザーグループを[更新]" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "プルリクエストに[コメント]" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "プルリクエストを[クローズ]" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[プッシュ]" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "リポジトリに[RhodeCode経由でコミット]" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "リポジトリに[リモートからプル]" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[プル]" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "リポジトリの[フォローを開始]" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "リポジトリの[フォローを停止]" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "フォーク名 %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "プルリクエスト #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "比較ビュー" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "削除されたブランチ: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "作成したタグ: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IPアドレス %s は許可されません" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "このアクションを実行するためには登録済みのユーザーである必要があります" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "バイナリファイル" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "チェンジセットが大きすぎるため省略しました。差分を表示する場合は差分メニューを使用してください" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "検出された変更はありません" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr " と %s 以上" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "ファイルなし" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "新しいファイル" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "変更" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "削除" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "リネーム" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "%s リポジトリはDB内に見つかりませんでした。おそらくファイルシステム上で作られたか名前が変更されたためです。リポジトリをもう一度チェックするためにアプリケーションを立ち上げ直してください。" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d 年" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d ヶ月" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d 日" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d 時間" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d 分" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d 秒" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "%s 以内" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s 前" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s と %s 前" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "%s と %s の間" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "たったいま" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "ホスト" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "ポート" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "URL" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "アカウント" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "パスワード" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "証明書チェック" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "Base DN" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "LDAP検索範囲" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "ログイン属性" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "名前(First Name)属性" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "名字(Last Name)属性" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "LDAP" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "リポジトリへのアクセス権限無し" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "リポジトリに読込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "リポジトリに書込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "リポジトリに管理権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "リポジトリグループへのアクセス権限なし" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "リポジトリグループに読込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "リポジトリグループに書込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "リポジトリグループに管理権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "RhodeCode 管理者" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "リポジトリの作成を有効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "リポジトリの作成を有効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "リポジトリのフォークを無効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "リポジトリのフォークを有効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "新規登録を無効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Rhodecodeに登録した新しいユーザーを手動でアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Rhodecodeに登録した新しいユーザーを自動でアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "未レビュー" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "承認" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "却下" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "レビュー中" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "リポジトリグループへのアクセス権限なし" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "リポジトリグループに読込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "リポジトリグループに書込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "リポジトリグループに管理権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "ユーザーグループへのアクセス権限なし" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "ユーザーグループに読込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "ユーザーグループに書込権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "ユーザーグループに管理権限でアクセス" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "リポジトリグループの作成を無効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "リポジトリグループの作成を有効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "ユーザーグループの作成を無効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "ユーザーグループの作成を有効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "新規登録を無効にする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "ユーザーの新規登録時に手動でアカウントをアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "ユーザーの新規登録時に自動でアカウントをアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "外部アカウントを手動でアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "外部アカウントを自動でアクティベートする" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "リポジトリグループの書き込みパーミッションを使ったリポジトリ作成が有効です" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "リポジトリグループの書き込みパーミッションを使ったリポジトリ作成は無効です" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "無効な検索クエリーです。\\\"で囲んで下さい" + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "検索するためのインデックスがありません。whooshでインデックスを作成して下さい" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "検索を実行する際にエラーが発生しました" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "ログイン名を入力してください" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "%(min)i 文字以上必要です" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "パスワードを入力してください" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "%(min)i 文字以上必要です" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "ブックマーク" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "閉鎖済みブランチ" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "最新のtip" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "このユーザーを編集できません。このユーザーはアプリケーションにとって必要不可欠です。" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "このユーザーを削除できません。このユーザーはアプリケーションにとって必要不可欠です。" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "空のリストにはできません" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "ユーザー名 \"%(username)s\" はすでに使われています" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "ユーザー名 \"%(username)s\" は許可されていません" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "ユーザー名はアルファベット、アンダースコア(_)、ピリオド(.)、ダッシュ(-)しか使えません。また、アルファベットまたはアンダースコア(_)から始まる必要があります" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "入力が正しくありません" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "ユーザー名 %(username)s は不正です" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "不正なユーザーグループ名です" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "ユーザーグループ \"%(usergroup)s\" はすでに存在します" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "ユーザーグループ名はアルファベット、アンダースコア(_)、ピリオド(.)、ダッシュ(-)しか使えません。また、アルファベットから始まる必要があります " + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "このグループは親にできません" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "グループ \"%(group_name)s\" はすでに存在します" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "グループ名 \"%(group_name)s\" を持つリポジトリはすでに存在します" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "パスワードに利用出来ない文字列(non-ascii)です" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "パスワードが一致しません" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "不正なパスワードです" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "不正なユーザー名です" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "アカウントは無効です" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "トークンが一致しません" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "リポジトリ名 %(repo)s は許可されていません" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "リポジトリグループ名 \"%(repo)s\" はすでに存在します" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "フォークは親と同じ種別の必要があります" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "ユーザー名かユーザーグループが不正です" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "不正なパスです" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "このメールアドレスはすでに取得されています" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "メールアドレス \"%(email)s\" は存在しません" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "LDAPのこのCNに対するログイン属性は必須です。 - これは \"ユーザー名\" と同じです" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "リビジョン %(revs)s はすでにプルリクエストの一部かステータスが設定されています" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "有効なIPv4かIPv6のアドレスを入力してください" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "ネットワークサイズ (bits) は0-32の範囲にする必要があります ( %(bits)r は不正です)" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "キー名はアルファベット、アンダースコア(_)、ピリオド(.)、ダッシュ(-)、数字しか使えません。" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "ファイル名はディレクトリ内にすることはできません" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "%(loaded)s プラグインと %(next_to_load)s プラグインで同じ名前が使われています" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "ダッシュボード" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "クイックフィルタ..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "リポジトリを追加" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "リポジトリグループを追加" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "管理者権限をもっているため編集できます" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "リポジトリグループを編集" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "名前" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "説明" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "所有者" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "最後の変更点" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "%s リポジトリグループダッシュボード" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "ホーム" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "サインイン" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "ユーザー名" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "次回から自動的にサインイン" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "パスワードをリセット" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "メールアドレス" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "キャプチャ" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "パスワードリセットのメールを送信" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "該当するメールアドレスにパスワードリセットのリンクを送信します" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "パスワード再入力" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "名前" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "名字" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "管理者ジャーナル" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "ジャーナルフィルタ..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "フィルタ" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s 個のエントリ" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "アクション" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "リポジトリ" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "日時" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "アクセス元IPアドレス" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "まだアクションがありません" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "認証設定" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "管理" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "認証プラグイン" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "有効なプラグイン" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "有効" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "無効" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "保存" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "プラグイン" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "リポジトリのデフォルト設定" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "リポジトリの種別" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "非公開リポジトリはコラボレーターとして明示的に追加された人でないと見つけられません" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "Gistを編集" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "Gist の説明..." + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "Gist 有効期間" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "plain" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "Gistを更新" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "キャンセル" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "ユーザー %s の非公開 Gists" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "ユーザー %s の公開 Gists" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "公開 Gists" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "新しい Gist を作成" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "作成者" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "作成日" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "失効" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "Gistを新規作成" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "ファイルに名前をつける..." + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "非公開 Gist を作成" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "公開 Gist を作成" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "リセット" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "Gist" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "削除" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "このGistを削除してもよろしいですか?" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "編集" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "Raw形式で表示" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "非公開 Gist" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "作成日" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "Raw形式で表示" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "アカウント" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "アカウント" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "メールアドレス" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "リポジトリ" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "ウォッチ中" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "プルリクエスト" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "ビルトイン" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "失効" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "失効済み" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "追加" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "プライマリ" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "このメールアドレスを削除してもよろしいですか? : %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "追加のメールアドレスはありません" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "新しいメールアドレス" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "アバターは無効です" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "メールアドレスがありません。更新してください。" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "アバターを変更できます : " + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "プルリクエスト #%s %s に作成" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "クローズ" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "このプルリクエストを削除してもよろしいですか?" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "プルリクエスト #%s %s によって %s に作成" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "通知" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "すべて" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "コメント" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "まだ通知がありません" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "通知を表示" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "通知" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "権限設定" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "概要" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "新規登録" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "このIPアドレスを削除してもよろしいですか? : %s" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "すべてのIPアドレスが許可されています" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "選択したパーミッションで、各リポジトリのデフォルトパーミッションをリセットします。各リポジトリの既存のカスタムデフォルトパーミッション設定は無くなるので注意してください" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "リポジトリグループ" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "選択したパーミッションで、各リポジトリグループのデフォルトパーミッションをリセットします。各リポジトリグループの既存のカスタムデフォルトパーミッション設定は無くなるので注意してください" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "ユーザーグループ" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "選択したパーミッションで、各ユーザーグループのデフォルトパーミッションをリセットします。各ユーザーグループの既存のカスタムデフォルトパーミッション設定は無くなるので注意してください" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "リポジトリグループを追加" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "リポジトリグループ" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "グループ名" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "子グループを追加" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "設定" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "高度な設定" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "リポジトリ総数" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "トップレベルリポジトリ数" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "子グループ数" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "リポジトリグループ: %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "このリポジトリグループを削除" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "なし" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "読込" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "書込" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "所有者" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "代理 admin" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "新規追加" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "両方" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "親グループ" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "リポジトリグループ管理" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "リポジトリグループ" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "リポジトリを追加" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "クローン元" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "短く要点を絞ってください。長い説明にはREADMEファイルを利用してください。" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "%s Creating repository" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "リポジトリを作成中" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "%s リポジトリ設定" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "キャッシュ" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "リモート" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "統計" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "保存" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "このリポジトリをリスト中の他のリポジトリのフォークとして、手動で設定します" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "リポジトリのロックを解除" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "フォークの切り離し" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "フォークも削除" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "このリポジトリを削除してもよろしいですか? : %s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "リポジトリのキャッシュを無効化" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "リポジトリのキャッシュを無効化してもよろしいですか?" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "プレフィックス" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "キー" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "アクティブ" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "ラベル" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "このフィールドを削除してもよろしいですか? : %s" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "ラベルを入力してください" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "非公開リポジトリ" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "リモート URL" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "リモートから変更を取り込む" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "リモートから変更を取り込んでもよろしいですか?" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "変更不能ID" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "これは何?" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "id を使ってURLを表現" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "編集" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "リポジトリグループ" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "オプション:このリポジトリが属するグループを選択します" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "リポジトリの所有者を変更" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "非公開リポジトリ" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "統計を有効にする" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "概要ページの統計ウィンドウを有効にします" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "ダウンロードを有効にする" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "概要ページのダウンロードメニューを有効にします" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "処理済みコミット数" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "処理状況" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "統計情報をリセット" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "現在の統計情報をリセットしてもよろしいですか?" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "設定を保存" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "リポジトリ管理" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "リポジトリ" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "状態" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "設定管理" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "メールアドレスプレフィックス" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "RhodeCode メールのFrom" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "エラーメールのFrom" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "エラーメールの宛先" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "SMTP サーバー" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "SMTP ユーザー名" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "SMTP パスワード" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "SMTP ポート" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "SMTP TLSの使用" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "SMTP SSLの使用" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "SMTP 認証" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "テストメール" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "送信" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "タイトル" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "reCaptchaの公開鍵。" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "reCaptchaの秘密鍵。この値が設定されると登録時のキャプチャが有効になります。" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "組み込みのMercurialフック - 編集不可" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "フックを使うと、リポジトリへのプッシュやプルといった特定のイベントに合わせて、何らかのアクションを実行できます。フック機能では、Pythonの関数を呼び出したり、外部アプリケーションを起動したりできます。" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "カスタムフック" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "古いデータを削除する" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "すべてのリポジトリのキャッシュを無効化する" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "このオプションを選ぶと、各リポジトリのキャッシュデータを抹消します。データのリロードやキャッシュキーの消去が必要なときに使ってください。" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "更新を確認" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "更新情報のエンドポイント" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "ノート: サーバーがこのURLにアクセスできることを確認して下さい" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "プラットフォーム" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "システムメモリ" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "CPU" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "Load" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "Python バージョン" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "GIT バージョン" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "更新を確認中..." + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "一般" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "リポジトリの拡張フィールドを使用する" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "追加のカスタムフィールドをリポジトリ毎に保存することを許可します。" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "Rhodecodeのバージョンを表示する" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "フッターに表示されるRhodeCodeのバージョン番号の表示、非表示を設定します。" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "メタタグ" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "リポジトリの説明のメタタグを解析して色つきのタグに変換します。" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "メインページダッシュボードで1ページに表示する要素数。" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "管理ページの項目" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "管理ページで、ページ分割しないでグリッドに表示する項目の数" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "アイコン" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "公開リポジトリのアイコンを表示する" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "非公開リポジトリのアイコンを表示する" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "リポジトリ名の横に公開/非公開アイコンを表示します。" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "ユーザーグループを追加" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "ユーザーグループ" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "ユーザーグループを追加" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "グループ名" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "このユーザーグループの簡潔な説明を書いてください" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "%s ユーザーグループ設定" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "グローバル権限" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "メンバー" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "ユーサーグループ: %s" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "まだメンバーがいません" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "取消" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "グループメンバーを選ぶ" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "全ての要素を削除" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "有効なメンバー" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "全ての要素を追加" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "ユーザーグループ管理" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "ユーザーグループ" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "ユーザーを追加" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "ユーザー" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "ユーザーを追加" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "パスワード再入力" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "%s ユーザー設定" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "メールアドレス" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "アカウントのソース" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "最終ログイン日時" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "グループのメンバー数" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "ユーザー: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "このユーザーを削除してもよろしいですか? : %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "このユーザーを削除" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "%s から継承" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "アカウントのソースでの名前" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "ユーザー管理" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "サポート" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "認証" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "デフォルト設定" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "フォーク元" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "要約" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "履歴" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "ファイル" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "比較" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "%s のプルリクエストを表示" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "オプション" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "フォークを比較" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "検索" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "アンロック" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "ロック" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "プルリクエストを作成" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "アカウントを持っていない?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "ジャーナル" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "公開ジャーナル" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "Gists" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "キーボードショートカット" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "サイト全体" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "プレビュー" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "表示" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "なし" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "読込" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "書込" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "管理" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "権限" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "権限を編集" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "リポジトリを作成する" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "リポジトリをフォークする" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "ユーザーグループを作成" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "VCSの操作にSSLを必須とする" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "プッシュ、プル時にSSLを要求します。SSLでない場合はHTTP Error 406: Not Acceptableを返します。" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "アンロックする。この設定を有効にするためにはRhodeCodeの再起動が必要です。" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "リポジトリを保存するファイルシステムのロケーション。この値を変更した場合、サーバーの再起動とリポジトリフォルダの再スキャンが必要です。" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "プッシュ後にリポジトリのサイズを表示する" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "largefilesエクステンションを有効にする" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "hgsubversionエクステンションを有効にする" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "hgsubversion ライブラリのインストールが必要です。リモートのSVNリポジトリをクローンしてMercurialリポジトリに変換するすることが可能です。" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "%s ブックマーク" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "ブックマーク" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "ブックマーク %s" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "%s ブランチ" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "ブランチ" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "ブランチ %s" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "%s チェンジログ" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "%s とフォークを比較" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "新しいプルリクエストを作成" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "選択を解除" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "経過時間" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "コミットメッセージ" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "Refs" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "コミットメッセージを展開" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "タグ %s" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "まだ変更がありません" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "削除" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "変更" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "追加" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "%s ファイルに影響" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "マージ" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "コミットメッセージ" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "新しいファイルを追加" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "存在するリポジトリをプッシュ" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "diffとして差分を表示" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "パッチとして差分を表示" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "差分をダウンロード" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "ファイルはありません" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "すべての差分を表示" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "プルリクエスト #%s に投票" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "プルリクエスト #%s にコメント" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "コメントには %s 構文 ( %s サポートつき ) が利用出来ます" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "テキスト内で @username を使うと、その RhodeCode のユーザーに通知を送信します" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "コメントのプレビュー" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "コメント" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "コメントするにはログインが必要です" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "今すぐログインする" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "隠す" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "このファイルのすべての差分を表示" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "このファイルの差分を並べて表示" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "%s 比較" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "ソース" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "入れ替え" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Mercurialリポジトリ" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Gitリポジトリ" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "公開リポジトリ" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "リポジトリを作成しています..." + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "%s の RSS フィードを購読" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "%s の ATOM フィードを購読" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "作成中" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "作成日" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "このグループを削除してもよろしいですか? : %s %s 個のリポジトリ" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "このユーザーグループを削除してもよろしいですか?: %s" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "ユーザーグループ" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "非公開" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "プルリクエストを以下のステータスで閉じました:" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "%s へ %s 秒後にリダイレクトします" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "%s ファイルの差分を並べて表示" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "%s ファイル差分" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "%s ファイル" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "%s ファイルを追加" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "新しいファイルを追加" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "または" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "アップロードファイル" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "ファイルをアップロード" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "新しいファイルを作成" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "変更をコミット" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "ファイル一覧を検索" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "ファイル一覧を読み込み中..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "サイズ" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "読み込み中..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "%s のファイルを削除" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "ファイルを削除" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "バイナリファイル (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "表示するには大きすぎるファイルです" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "%s のファイルを編集" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "ファイルを編集" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "ソース" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "アノテーション" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "ファイルを編集" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "場所" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "変更履歴" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "全ての履歴を表示" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "ダウンロード" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "ブランチ:%s で編集" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "バイナリファイルの編集は行えません" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "%s フォロワー" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "フォロワー" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "リポジトリ %s をフォーク" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "フォーク名" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "権限のコピー" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "フォーク元リポジトリから権限をコピーします" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "このリポジトリをフォーク" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "%s フォーク" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "フォーク" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "フォークしました" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "まだフォークがありません" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "ATOM ジャーナルフィード" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "RSS ジャーナルフィード" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "まだエントリがありません" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "公開ジャーナル" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "ATOM 公開ジャーナルフィード" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "RSS 公開ジャーナルフィード" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "新しいプルリクエスト" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "このプルリクエストの簡潔な説明を書いてください" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "元のリポジトリ" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "プルリクエストレビュアー" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "相手のリポジトリ" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "%s プルリクエスト #%s" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "変更を保存" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "レビュアー" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "巨大な差分の表示はすこし時間とリソースがかかる場合があります" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "%s プルリクエスト" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "あなたが作成したプルリクエスト" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "ファイルの内容" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "コミットメッセージ" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "ファイル名" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "%s 要約" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "%s ATOM フィード" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "%s RSS フィード" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "名前で表示" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "IDで表示" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "クローンURL" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "このリポジトリの統計は無効化されています" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "まだダウンロードがありません" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "このリポジトリのダウンロードは無効化されています" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "クイックスタート" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "%s タグ" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "タグ" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "プロフィール" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" diff --git a/rhodecode/i18n/pl/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/pl/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..bdde8659e683e751d559e09d0f000901c0c3c86a GIT binary patch literal 125994 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 diff --git a/rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po @@ -0,0 +1,8038 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Nemcio <areczek01@gmail.com>, 2013 +# FIRST AUTHOR <EMAIL@ADDRESS>, 2010 +# Marcin Kuzminski <marcin@rhodecode.com>, 2015 +# Marcin Kuzminski <marcin@rhodecode.com>, 2013 +# Nemcio <bogdan114@g.pl>, 2012 +# Nemcio <areczek01@gmail.com>, 2012-2013 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Polish (http://www.transifex.com/rhodecode/RhodeCode/language/pl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "Globalne" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Włączone" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "Brak commitów" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "Pokaż białe znaki" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "Pokaż białe znaki dla wszystkich zmian" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "Ignoruj białe znaki" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "Ignoruj białe znaki dla wszystkich zmian" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Strona główna" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "Wniosek nie może być rozumiany przez serwer z powodu zniekształconej składni." + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Nieautoryzowany dostęp do zasobów" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Nie masz uprawnień do przeglądania tej strony" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "Zasób nie został znaleziony" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "Serwer napotkał niespodziewany warunek, który uniemożliwia jej spełnienie żądania." + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Zmiany w %s repozytorium" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s zasilać" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Wystąpił błąd w trakcie zatwierdzania" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Można tylko edytować pliki z rewizji obecnej gałęzi" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Bez zmian" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Committ wykonany do %s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Brak nazwy pliku" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Pobieranie wyłączone" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Nieznana wersja %s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Puste repozytorium" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Nieznany typ archiwum" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Różnice" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Gałęzie" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Etykiety" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Wystąpił błąd podczas rozgałęzienia %s repozytorium" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Grupy" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Repozytoria" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "Dziennik publiczny" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "dziennik" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Twój link zresetowania hasła został wysłany" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "Wniosek połączenia gałęzi wymaga tytułu z min. 3 znakami" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "Prośba o wykonanie połączenia gałęzi została wykonana prawidłowo" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Wystąpił błąd podczas prośby o połączenie gałęzi" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "Prośba o skasowanie połączenia gałęzi została wykonana prawidłowo" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Zamykanie" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "gałąź" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "Tag" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "Bookmark" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "Zamkniętę gałęzie" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Domyślne ustawienia zostały pomyślnie zaktualizowane" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "na zawsze" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 minut" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 godzina" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 dzień" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 miesiąc" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "Czas życia" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Wystąpił błąd podczas tworzenia git" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "Usuń gist %s" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "nigdy" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Nie możesz edytować tego użytkownika ponieważ jest kluczowy dla całej aplikacji" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Twoje konto zostało pomyślnie zaktualizowane" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "wystąpił błąd podczas aktualizacji użytkownika %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Wystąpił błąd podczas zapisywania e-maila" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "Rola" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Wystąpił błąd podczas aktualizacji uprawnień" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "Globalne uprawnienia zaktualizowane poprawnie" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Utworzono grupę repo %s" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Wystąpił błąd podczas tworzenia grupy repo %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Zaktualizowano grupę repo %s" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Wystąpił błąd podczas aktualizacji grupy repo %s" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Usunięto grupę repo %s" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Wystąpił błąd podczas usuwania z repozytorium grupy %s" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Aktualizacja uprawnień grup repozytorium" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "utworzone repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "utworzone repozytorium %s z %s" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Gałęzi %s w repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Utworzone repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Repozytorium %s zostało pomyślnie zaktualizowane" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Wystąpił błąd podczas aktualizacji repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "Oderwane rozgałęzienie %s" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "Usunięte repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Usunięte repozytorium %s" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "Nie można usunąć %s nadal zawiera załączniki rozgałęzienia" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Wystąpił błąd podczas usuwania %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Uprawnienia repozytorium zostały zaktualizowane" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Wystąpił błąd podczas tworzenia użytkownika %s" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Wystąpił błąd podczas zapisywania e-maila" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Zaktualizowano widoczność stron w publicznym dzienniku" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Wystąpił błąd podczas ustawiania tego repozytorium w dzienniku publicznym" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Brak" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Oznaczono %s repo jako rozwidlenie %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Wystąpił błąd podczas tej operacji" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "Zablokowane repozytorium" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "Odblokowane repozytorium" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Wystąpił błąd podczas odblokowywania" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Odblokowany" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Zablokowany" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "Repozytoriów jest %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "Cache wyczyszczony poprawnie" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Wystąpił błąd podczas unieważniania cache" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Pobieranie z lokalizacji zdalnej" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Wystąpił błąd podczas pobierania z lokalizacji zdalnej" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Wystąpił błąd podczas usuwania z repozytorium statystyk" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Aktualizacja ustawień VCS" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Wystąpił błąd podczas aktualizacji ustawień aplikacji" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Repozytoria z powodzeniem zostały ponownie zeskanowane dodano: %s, usunięto: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Aktualizacja ustawień aplikacji" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Aktualizacja ustawień wizualizacji" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Wystąpił błąd podczas aktualizacji ustawień wizualizacji" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "Proszę podać adres email" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Dodano nowy hook" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Aktualizacja hooku" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "Wystąpił błąd podczas tworzenia hooku" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "E-mail" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "Aktualizacja" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Wystąpił błąd podczas tworzenia grupy użytkowników %s" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Zaktualizowano grupę użytkowników %s" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Wystąpił błąd podczas aktualizacji grupy użytkowników %s" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Grupa użytkowników została usunięta z powodzeniem" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Wystąpił błąd podczas usuwania grupy użytkowników" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "Grupa docelowa nie może być taka sama" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Aktualizacja uprawnień grupy użytkowników" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Wystąpił błąd podczas zapisywania uprawnień" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Wystąpił błąd podczas tworzenia użytkownika %s" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Użytkownik został zaktualizowany" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Użytkownik został usunięty" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Wystąpił błąd podczas usuwania użytkownika" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Nie możesz edytować tego użytkownika" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Wystąpił błąd podczas zapisywania e-maila" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "Usunięto adres ip z listy dozwolonych adresów dla użytkownika" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[usunięte] repozytorium" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[utworzone] repozytorium" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[utworzone] repozytorium jako rozgałęzienie" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[rozgałęzione] repozytorium" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[zaktualizowane] repozytorium" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "[pobierz] archiwum z repozytorium" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[skasowane] repozytorium" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[utworzony] użytkownik" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[zaktualizowany] użytkownik" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "[utworzona] grupa użytkowników" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "[zaktualizowana] grupa użytkowników" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[komentarz] wniosek o połączenie gałęzi" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[zamknięty] wniosek o połączenie gałęzi" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[wysłane zmiany] w" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[synchronizacja przez RhodeCode] z repozytorium" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[pobieranie z zdalnego] do repozytorium" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[pobrano] " + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[start następnego] repozytorium" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[zatrzymany po] repozytorium" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "nazwa rozgałęzienia %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Połączonych gałęzi #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "Wyświetl porównanie" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Usunięta gałąź: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "Utworzony tag: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "Obserwatorzy %s" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Musisz być zarejestrowanym użytkownikiem, żeby wykonać to działanie" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "Plik binarny" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Lista zmian była zbyt duża i została obcięta, użyj menu porównań żeby wyświetlić różnice" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Nie wykryto zmian" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "i %s więcej" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Brak Plików" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "nowy plik" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "modyfikuj" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "kasuj" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "zmień nazwę" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "%s repozytorium nie jest mapowane do db może zostało utworzone lub zmienione z systemie plików proszę uruchomić aplikację ponownie, aby ponownie przeskanować repozytoria" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d rok" +msgstr[1] "%d lata" +msgstr[2] "%d lat" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d miesiąc" +msgstr[1] "%d miesięcy" +msgstr[2] "%d miesięcy" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d dzień" +msgstr[1] "%d dni" +msgstr[2] "%d dni" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d godzina" +msgstr[1] "%d godziny" +msgstr[2] "%d godzin" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d minuta" +msgstr[1] "%d minuty" +msgstr[2] "%d minut" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d sekunda" +msgstr[1] "%d sekund" +msgstr[2] "%d sekund" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "w %s" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s temu" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s i %s temu" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "w %s i %s" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "przed chwilą" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "Host" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "Port" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "Adres URL" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "Konto" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Hasło" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "Kontrola certyfikatów" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "Bazowy DN" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "Zakres wyszukiwania LDAP" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "Atrybuty logowania" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "Atrybut Nazwiska" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "Atrybut Imienia" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "LDAP" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Brak dostępu do repozytorium" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Repozytorium do odczytu" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Repozytorium do zapisu" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Administracja dostępu do repozytorium" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Grupy repozytoriów brak dostępu" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Grupy repozytoriów dostęp do odczytu" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Grupy repozytoriów dostęp do zapisu" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Repozytoria Grupy dostęp administratora" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "Administrator Repo" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Tworzenie repozytorium jest wyłączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Tworzenie repozytorium jest włączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "Rozwidlenie repozytorium wyłączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "Rozwidlenie repozytorium włączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Rejestracja wyłączona" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Rejestracja nowego użytkownika na stronie z ręczną aktywacją" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Rejestracja nowego użytkownika na stronie z automatyczną aktywacją" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Brak Korekty" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Zaakceptowano" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Odrzucono" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "Objęty Przeglądem" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "Grupy repozytoriów brak dostępu" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "Grupy repozytoriów dostęp do odczytu" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "Grupy repozytoriów dostęp do zapisu" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "Repozytoria Grupy dostęp administratora" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "Ta grupa użytkowników nie ma dostępu" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "Dostęp do grupy parametrów użytkownika" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "Ta grupa użytkowników ma prawo do zapisu" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "Ta grupa użytkowników ma uprawnienia administratora" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "Tworzenie grup repozytoriów wyłączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "Tworzenie grup repozytoriów włączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "Tworzenie grup użytkowników wyłączone" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "Tworzenie grup użytkowników właczone" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "Rejestracja wyłączona" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "Rejestracja użytkownika z ręczną aktywacją konta" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "Rejestracja użytkownika z automatyczną aktywacją konta" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "Ręczna aktywacja nowego konta" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "Automatyczna aktywacja nowego konta" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Nieprawidłowe zapytania. Spróbuj zacytować go." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "Nie ma szukanego indeksu. Proszę uruchomić indeksowanie whoosh" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Wystąpił błąd podczas wyszukiwania tej operacji" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Wpisz login" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Wprowadź wartość %(min)i znaków lub więcej" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Wpisz hasło" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Wpisz %(min)i lub więcej znaków" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Zakładki" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "Zamknięte Gałęzie" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "ostatni tip" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Nie możesz edytować tego użytkownika ponieważ jest kluczowy dla całej aplikacji" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Nie możesz usunąć tego użytkownika ponieważ jest kluczowy dla całej aplikacji" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "Wartość listy nie może być pusta" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "Użytkownik \"%(username)s\" już istnieje" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "Nazwa użytkownika \"%(username)s\" jest zabroniona" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "Nazwa użytkownika może zawierać tylko znaki alfanumeryczne, podkreślenia, kropki lub myślniki i muszą zaczynać się znakiem alfanumerycznym lub podkreśleniem" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "Nazwa użytkownika %(username)s jest nieprawidłowa" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "Niewłaściwa nazwa grupy" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "Nazwa grupy \"%(usergroup)s\" już istnieje" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "nazwa grupy może zawierać tylko znaki alfanumeryczne, podkreślenia, kropki lub myślniki i musi zaczynać się znakiem alfanumerycznym" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Nie można przypisać do tej grupy jako rodzic" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "Nazwa grupy \"%(group_name)s\" już istnieje" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Repozytorium o nazwie \"%(group_name)s\" już istnieje" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "Nieprawidłowe znaki (nie-ascii) w haśle" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Hasła różnią się" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "nieprawidłowe hasło" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "niepoprawna nazwa użytkownika" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Twoje konto jest wyłączone" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Niezgodność tokenu" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "Nazwa repozytorium %(repo)s jest zabroniona" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "Grupa repozytoriów z nazwą \"%(repo)s\" już istnieje" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "Fork musi być tego samego typu, jak rodzic" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "Ta nazwa użytkownika lub grupy użytkowników nie jest prawidłowa" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "To nie jest prawidłowa ścieżka" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Ten adres e-mail jest już zajęty" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "e-mail \"%(email)s\" nie istnieje." + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "Atrybut logowania CN do LDAP należy określić, jest to nazwa atrybutu, który jest odpowiednikiem \"username\"" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "Rewizja %(revs)s jest już częścią nowej gałęzi więc określ jego status" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "Proszę podać poprawny adres IPv4 lub IPv6" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "Rozmiar sieci (bits) może mieścić się w zakresie od 0-32 (nie %(bits)r)" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "Klucz nazwy może składać się tylko z liter, podkreślenia, myślnika lub numerów" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "Nazwa pliku nie może znajdować się w katalogu" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Repozytorium" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "szybki filtr..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "Dodaj Repozytorium" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "Dodaj Grupę Repozytoriów" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "Jako administrator uprawnienia tej grupy, i możesz je edytować" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "Edytuj Grupę Repozytoriów" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Nazwa" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Opis" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Właściciel" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Ostatnia akytwność" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "Strona Główna" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Zaloguj się" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Nazwa użytkownika" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Zapamiętaj mnie" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "Adres Email" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Link do zresetowania hasła zostanie wysłany na adres e-mail" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Ponownie wprowadź hasło" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Imię" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Nazwisko" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "Dziennik administratora" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "szybkie wyszukiwanie..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "filtr" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s wejście" +msgstr[1] "%s wejść" +msgstr[2] "%s wejść" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Działanie" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Repozytorium" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Data" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "Z IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Brak akcji" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "Ustawienia Autentykacji" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Administracja" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "Wtyczki Autentykacji" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "Włączone Wtyczki" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Zapisz" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "Wtyczka" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "Repozytoria domyślne" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Typ" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "Prywatne repozytoria są widoczne tylko dla osób bezpośrednio dodanych jako współpracownicy." + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "Edytuj Gist" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "Opis Gist ..." + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "Trwałość Gist" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "zwykły" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "Zaktualizuj Gist" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "Anuluj" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "Prywatne Gists użytkownika %s" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "Publiczne Gists użytkownika %s" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "Publiczne Gists" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "Utwórz Nowy Gist" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "Autor" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "Utworzono" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "Wygasa" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "Nowy Gist" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "Utwórz Prywatny Gist" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "Utwórz Publiczny Gist" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Zresetuj" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "Gist" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Usuń" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "Potwierdź aby usunąć ten Gist" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "Edycja" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "Prywatny Gist" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "utworzono" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "wyświetl jako raw" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "Moje konto" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "Moje konto" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "Moje Emaile" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "Moje Repozytoria" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "Obserwowane" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "Połączone gałęzie" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Dodaj" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "Główny" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "Potwierdź, aby usunąć ten e-mail: %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "Brak dodatkowych emaili" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "Nowy adres e-mail" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "Avatary są wyłączone" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "Zmiana awataru na" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "Wniosek połączenia gałęzi #%s otwarty %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "Zamknięte" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "Potwierdź usunięcie połączenia gałęzi" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "Wniosek połączenia gałęzi #%s otwarty %s dnia %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Opcje powiadomień" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Wszystkie" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Komentarze" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Brak powiadomień" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Pokaż powiadomienia" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Powiadomienia" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Uprawnienia" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "Podgląd" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Rejestracja" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "Potwierdź, aby usunąć to ip: %s" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "Wszystkie adresy IP są dozwolone" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "Wszystkie uprawnienia domyślne każdego repozytorium zostaną przywrócone. Wybrane uprawnienie zostaną skasowane. Pamiętaj, że wszystkie niestandardowe uprawnienia w repozytoriach zostaną utracone." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "Grupy Repozytoriów" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Wszystkie uprawnienia domyślne każdego repozytorium zostaną przywrócone. Wybrane uprawnienie zostaną skasowane. Pamiętaj, że wszystkie niestandardowe uprawnienia w repozytoriach zostaną utracone." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Wszystkie Uprawnienia domyślne każdej grupy użytkowników zostaną przywrócone do wybranego zezwolenia, trzeba pamiętać, że wszystkie niestandardowe uprawnienia domyślne dla grup repozytorium zostaną utracone" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "Repozytorium grupy" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "Repozytorium grupy" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "Nazwa Grupy" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Ustawienia" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "Zaawansowane" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "Ogólna liczba repozytoriów" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "Grupa Repozytoriów: %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "Usuń ta grupę repozytoriów" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "Brak" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Odczyt" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Zapis" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "właściciel" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "Dodaj nowe" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "Oba" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "Rodzic gropy" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "Repozytoria grup administracyjnych" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Dodaj repozytorium" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Klonuj z" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "Powinna być krótka i na temat. Użyj pliku README dla dłuższych opisów." + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Zdalnie" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Statystyki" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "Ustaw" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "Ręczne ustawienie rozwidlenia z listy" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "Ustaw jako rozwidlenie" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "Usuń rozwidlenie" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "Potwierdź usunięcie repozytorium: %s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "Unieważnij pamięć podręczną repozytorium" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "Potwierdź unieważnienie pamięci podręcznej repozytorium" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "Prefiks" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "Klucz" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Aktywny" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "Potwierdź, aby usunąć to pole: %s" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "Wpisz krótką etykietę" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "prywatne repozytorium" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "Pobierz z zdalnej lokalizacji" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "Potwierdź pull z zdalnej strony" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "Brak zmiennej id" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "edycja" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Repozytorium grupy" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "Opcjonalnie wybierz grupę do wprowadzenia tego repozytorium." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "Zmiana właściciela tego repozytorium." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Prywatne repozytorium" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Włącz statystyki" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "Włącz okno statystyk na stronie podsumowania." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Włącz pobieranie" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "Włącz menu pobierania na stronie podsumowania." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "Potwierdź usunięcie aktualnych statystyk" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Zapisz ustawienia" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "Administracja repozytoriami" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "repozytoria" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "Ustawienia administracji" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "Test e-maila" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Wyślij" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "Tytuł" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "Niestandardowa aktualizacja" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "Zniszcz stare dane" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "Unieważnia cache dla wszystkich repozytoriów" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "Główne" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "Używaj w repozytorium dodatkowych pól" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "Umożliwia przechowywanie dodatkowych niestandardowych pól w repozytorium." + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "Pokaż wersję RhodeCode" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "Tagowanie meta" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Ikony" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Pokazuj w publicznym repo ikonę w repozytoriach" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Pokazuj w prywatnym repo ikonę w repozytoriach" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "Dodaj grupę użytkowników" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "Grupy użytkowników" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Nazwa grupy" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Użytkownik" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "Nie ma jeszcze żadnego użytkownika" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "odwołane" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "Wybrane grupy użytkowników" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Usuń wszystkie elementy" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Dostępni użytkownicy" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Dodaj wszystkie elementy" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "Użytkownicy grupy administracji" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Dodaj użytkownika" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Użytkownicy" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Potwierdzenie hasła" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "Ostatnio zalogowany" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Potwierdź usunięcie tego użytkownika: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Administracja użytkownikami" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "Autentykacja" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "Domyślne" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "Gałąź z" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Podsumowanie" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "Dziennik zmian" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "Pliki" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Porównaj" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "Pokaż Prośby Pobrania %s" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Opcje" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Porównaj rozwidlenie" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Szukaj" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "Odblokowany" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "zablokowane" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "Stwórz nowe żądanie połączenia gałęzi" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Nie masz konta?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Dziennik" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Dziennik publiczny" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "Gists" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "Podgląd" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "brak" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "odczyt" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "zapis" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "administracja" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Uprawnienia" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "Edycja Uprawnień" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "Utwórz repozytorium" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "Rozwidlenie repozytorium" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "Tworzenie grup użytkowników" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "Wymagaj ssl dla operacji vcs" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "Kliknij, aby odblokować. Musisz ponownie uruchomić RhodeCode żeby wprowadzić to ustawienie w życie." + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "Pokaż rozmiar repozytorium po wysłaniu zmian" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "Rozszerzenia dużych pliów" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "Rozszerzenia hgsubversion" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "%s Zakładki" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "Zakładki %s" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "%s Gałęzie" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "Gałęzie %s" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "%s Dziennik zmian" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "porównaj gałęzie %s" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "Otwórz nową prośbę o połączenie gałęzi" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "Wyczyść zaznaczenie" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "Ostatnia zmiana" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "Gałąź/Etykieta" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "Tagi %s" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "Nie ma jeszcze zmian" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "Usunięto" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "Zmiana" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "Dodana" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "Zarażone pliki %s" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "połącz" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "Komentarz" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "Istniejące repozytorium?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "Raw różnic" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "Poprawka różnic" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "Pobierz różnice" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "Rozwiń Wszystko" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "Złóż Wszystko" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "Brak plików" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "Pokaż pełną historię" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "Głosowanie do grupy zmian #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "Komentarz połączenia gałęzi %s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "Komentarze analizowane za pomocą %s składni od %s wsparcia." + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "Użyj @username wewnątrz tego tekstu, aby wysłać powiadomienie do użytkownika strony" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "Podgląd komentarza" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "Komentarz" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "Musisz być zalogowany żeby komentarz." + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "Zaloguj się teraz" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "Ukryj" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "Pokaż pełną edycję tego pliku" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "Pokaż pełną listę zmian i różnic obok siebie" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "%s Porównaj" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "Źródło" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Repozytorium mercurial" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Repozytorium git" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Publiczne repozytorium" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "Subskrybuj %s kanał rss" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "Subskrybuj %s kanał atom" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "Utworzono" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "Potwierdź żeby usunąć grupę %s wraz z %s repozytorium" +msgstr[1] "Potwierdź żeby usunąć grupę %s wraz z %s repozytoriami" +msgstr[2] "Potwierdź żeby usunąć grupę %s wraz z %s repozytoriami" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "Potwierdź usunięcie grupy użytkowników: %s" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "Grupa użytkownika" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "Prywatny" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "Wniosek połączenia został zamknięty ze statusem" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "Zostaniesz przekierowany do %s za %s sekund" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "Pliki z listą zmian i różnic: %s" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "%s Pliki różnic" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "Pliki %s" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "Pliki %s" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "Dodaj nowy plik" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "lub" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "Dodaj plik" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "Zatwierdź zmiany" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "Dodaj Plik" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "Wczytywanie listy plików..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "Rozmiar" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Wczytywanie..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "%s Usuń Plik" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "Usuń plik" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "Plik binarny (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "Plik jest za duży do wyświetlenia" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "Edytuj plik" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "historia" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "Źródło" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "adnotacja" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "Edycja pliku" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "Położenie" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "Historia" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "Pobierz" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "Edycja plików binarnych jest zabroniona" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "Obserwatorzy %s" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "Obserwuje" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "Nazwa rozgałęzienia" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "Skopiuj uprawnienia" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "Skopiuj zezwolenia z rozwidlenia repozytorium" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "Gałąź %s" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "Gałęzie" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "Rozgałęziony" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "Nie ma jeszcze gałęzi" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "Dziennik kanału ATOM" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "Dziennik kanału RSS" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "Brak wpisów jeszcze" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Dziennik Publiczny" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "Publiczny dziennik kanału ATOM" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "Publiczny dziennik kanału RSS" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "Nowa prośba o połączenie gałęzi" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "Napisz krótki opis tego tego połączenia gałęzi" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "Repozytorium git" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "Recenzje wniosków połączenia gałęzi" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "Repozytorium docelowe" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "%s Połączonych gałęzi #%s" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "Zamknij" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "Zapisz zmiany" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "recenzent" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "Pokazuje pełną edycję, może zająć to trochę czasu i zasobów" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "%s Moje prośby połączenia gałęzi" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "Otwarty przez mnie" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "Zawartość pliku" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "Komunikaty" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "Nazwy plików" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "Podsumowanie %s" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "%s ATOM" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "%s RSS" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "Pokaż nazwę" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "Pokaż ID" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "Url klonowania" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "Statystyki są wyłączone dla tego repozytorium" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "Nie pobrano jeszcze plików" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "Pliki do pobrania są zostały wyłączone dla tego repozytorium" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "Szybki start" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "Etykiety pliku %s" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "Profil" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" diff --git a/rhodecode/i18n/pt/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/pt/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..473331c042e876263366a92bbd4653a89ebb1750 GIT binary patch literal 124843 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 diff --git a/rhodecode/i18n/pt/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/pt/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/pt/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7993 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Augusto Herrmann <augusto.herrmann@gmail.com>, 2012 +# Gustavo Chaves <gustavo@gnustavo.com>, 2013 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Portuguese (http://www.transifex.com/rhodecode/RhodeCode/language/pt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Habilitado" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Página inicial" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "A requisição não pôde ser compreendida pelo servidor devido à sintaxe mal formada." + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Acesso não autorizado ao recurso" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "Você não tem permissão para ver esta página" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "O recurso não pôde ser encontrado" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "O servidor encontrou uma condição inesperada que o impediu de satisfazer a requisição." + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Modificações no repositório %s" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s - feed %s" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Ocorreu um erro ao realizar commit" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Só é possível editar arquivos quando a revisão é um ramo válido" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Sem modificações" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Commit realizado com sucesso para %s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Nenhum nome de arquivo" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Downloads desabilitados" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Revisão desconhecida %s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Repositório vazio" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Tipo de arquivo desconhecido" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Conjuntos de mudanças" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Ramos" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Etiquetas" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Ocorreu um erro ao bifurcar o repositório %s" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Grupos" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Repositórios" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "diário público" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "diário" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Seu link de reinicialização de senha foi enviado" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "O pull request requer um título com no mínimo três caracteres" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "Novo pull request criado com sucesso" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Ocorreu um erro durante o envio do pull request" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "Pull request excluído com sucesso" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Fechando com" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "Ramo" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Configurações padrão atualizadas com sucesso" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "para sempre" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "cinco minutos" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "uma hora" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "um dia" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "um mês" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Ocorreu um erro durante a criação de um gist" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "Gist %s excluído" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "nunca" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Você não pode editar esse usuário pois ele é crucial para toda a aplicação" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Sua conta foi atualizada com sucesso" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "Ocorreu um erro durante a atualização do usuário %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Ocorreu um erro durante o salvamento do email" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Ocorreu um erro durante a atualização das permissões" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Grupo de repositórios %s criado" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Ocorreu um erro durante a criação do grupo de repositórios %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Grupo de repositórios %s atualizado" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Ocorreu um erro durante a atualização do grupo de repositórios %s" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Grupo de repositórios %s excluído" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Ocorreu um erro durante a exclusão do grupo de repositórios %s" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Permissões atualizadas do Grupo de Repositórios" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "Erro ao criar repositório %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "Repositório %s criado de %s" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Repositório %s bifurcado como %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Repositório %s criado" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Repositório %s atualizado com sucesso" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Ocorreu um erro durante a atualização do repositório %s" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "%s bifurcações excluídas" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Repositório %s excluído" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "Nao é possível excluir %s pois ele ainda contém bifurcações vinculadas" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Ocorreu um erro durante a exclusão de %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Permissões do repositório atualizadas" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Ocorreu um erro durante a criação do campo" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Ocorreu um erro durante a remoção do campo" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Atualizada a visibilidade do repositório no diário público" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Ocorreu um erro ao ajustar esse repositório no diário público" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Nada" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Marcado repositório %s como bifurcação de %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Ocorreu um erro durante essa operação" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Ocorreu um erro durante o destravamento" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Destravado" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Travado" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "O repositório foi %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Ocorreu um erro ao invalidar o cache" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Realizado pull de localização remota" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Ocorreu um erro ao realizar pull de localização remota" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Ocorreu um erro ao excluir estatísticas de repositório" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Configurações de VCS atualizadas" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Ocorreu um erro durante a atualização das configurações da aplicação" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Repositórios varridos com sucesso adicionados: %s ; removidos: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Configurações da aplicação atualizadas" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Configurações de visualização atualizadas" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Ocorreu um erro durante a atualização das configurações de visualização" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Adicionado novo gancho" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Atualizados os ganchos" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "Ocorreu um erro durante a criação do hook" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "E-mail" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "Ganchos" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Ocorreu um erro durante a criação do grupo de usuários %s" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Grupo de usuários %s atualizado" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Ocorreu um erro durante a atualização do grupo de usuários %s" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Grupo de usuários excluído com sucesso" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Ocorreu um erro durante a exclusão do grupo de usuários" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "O grupo destino não pode ser o mesmo" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Permissões do Grupo de Usuários atualizadas" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Ocorreu um erro durante o salvamento das permissões" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Ocorreu um erro durante a criação do usuário %s" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Usuário atualizado com sucesso" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Usuário excluído com sucesso" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Ocorreu um erro ao excluir o usuário" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Você não pode editar esse usuário" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Ocorreu um erro durante o salvamento do IP" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "repositório [excluído]" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "repositório [criado]" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "repositório [criado] como uma bifurcação" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "repositório [bifurcado]" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "repositório [atualizado]" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "[baixado] archive do repositório" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[excluir] repositório" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "usuário [criado]" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "usuário [atualizado]" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "[criado] grupo de usuários" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "[atualizado] grupo de usuários" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[comentado] no pull request para" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[fechado] pull request para" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[realizado push] para" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[commitado via RhodeCode] no repositório" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[pulled do remote] no repositório" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[realizado pull] a partir de" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[passou a seguir] o repositório" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[parou de seguir] o repositório" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "nome da bifurcação %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Pull request #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "comparar exibir" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Excluído ramo: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "Tag criada: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IP %s não permitido" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Você precisa ser um usuário registrado para realizar essa ação" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "Arquivo binário" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Conjunto de mudanças é grande demais e foi cortado, use o menu de diferenças para ver as diferenças" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Nenhuma alteração detectada" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr " e mais %s" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Nenhum Arquivo" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "novo arquivo" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "mod" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "excluir" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "renomear" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "O repositório %s não está mapeado ao BD. Talvez ele tenha sido criado ou renomeado a partir do sistema de arquivos. Por favor, execute a aplicação outra vez para varrer novamente por repositórios" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d ano" +msgstr[1] "%d anos" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d mês" +msgstr[1] "%d meses" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d dia" +msgstr[1] "%d dias" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d hora" +msgstr[1] "%d horas" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d minuto" +msgstr[1] "%d minutos" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d segundo" +msgstr[1] "%d segundos" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "em %s" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s atrás" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s e %s atrás" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "em %s e %s" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "agora há pouco" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "URL" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Senha" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Nenhum acesso ao repositório" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Acesso de leitura ao repositório" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Acesso de escrita ao repositório" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Acesso administrativo ao repositório" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Nenhum acesso ao Grupo de Repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Acesso de leitura ao Grupo de Repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Acesso de escrita ao Grupo de Repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Acesso administrativo ao Grupo de Repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "Administrador do RhodeCode" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Criação de repositórios desabilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Criação de repositórios habilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "Bifurcação de repositórios desabilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "Bifurcação de repositórios habilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Registro desabilitado" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Registro de novo usuário no RhodeCode com ativação manual" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Registro de novo usuário no RhodeCode com auto-ativação" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Não Revisado" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Aprovado" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Rejeitado" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "Sob Revisão" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "Sem acesso ao grupo de repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "Acesso de leitura ao grupo de repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "Acesso de escrita ao grupo de repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "Acesso administrativo ao grupo de repositórios" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "Sem acesso ao grupo de usuários" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "Acesso de leitura ao grupo de usuários" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "Acesso de escrita ao grupo de usuários" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "Acesso administrativo ao grupo de usuários" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "Criação de Grupo de Repositórios desatilibada" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "Criação de Grupo de Repositórios habilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "Criação de Grupo de Usuários desabilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "Criação de Grupo de Usuários habilitada" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "Registro desatilitado" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "Registro de Usuário com ativação manual de conta" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "Registro de Usuário com ativação automática de conta" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "Ativação manual de conta externa" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "Ativação automática de conta externa" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Consulta de busca inválida. Tente usar aspas." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "Não há índice onde pesquisa. Por favor execute o indexador whoosh" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Ocorreu um erro durante essa operação de busca" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Por favor entre um login" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Entre um valor com %(min)i caracteres ou mais" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Por favor entre com uma senha" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Entre com %(min)i caracteres ou mais" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Marcadores" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "Ramos Fechados" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "tip mais recente" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Você não pode Editar esse usuário, pois ele é crucial para toda a aplicação" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Você não pode remover esse usuário, pois ele é crucial para toda a aplicação" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "O valor não pode ser uma lista vazia" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "O username \\\"%(username)s\\\" já existe" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "O username \\\"%(username)s\\\" é proibido" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "Nome de usuário pode conter somente caracteres alfanuméricos, sublinha, pontos e hífens e deve iniciar com caractere alfanumérico" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "O username \"%(username)s\" não é válido" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "Nome inválido de grupo de usuários" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "O grupo de usuários \"%(usergroup)s\" já existe" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "O nome de um grupo de usuários só pode conter characters alfa-numéricos, underscores, pontos ou hífens, e deve começar om um caractere alfa-numérico" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Não é possível associar esse grupo como progenitor" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "O grupo \\\"%(group_name)s\\\" já existe" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Um repositório com o nome \"%(group_name)s\" já existe" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "Caracteres inválidos (não-ascii) na senha" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Senhas não conferem" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "senha inválida" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "nome de usuário inválido" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Sua conta está desabilitada" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Descompasso de Token" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "O nome de repositório %(repo)s não é permitido" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "Um Grupo de Repositórios chamado \"%(repo)s\" já existe" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "A bifurcação deve ser do mesmo tipo que o pai" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "Este nome de usuário ou de grupo de usuários não é válido" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "Esse não é um caminho válido" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Esse endereço de e-mail já está tomado" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "o e-mail \"%(email)s\" não existe." + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "O atributo de login LDAP do CN deve ser especificado - isto é o nome do atributo que é equivalente ao 'nome de usuário'" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "As revisões %(revs)s já fazem parte de um pull request ou já setaram o estado" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "Por favor, forneça um endereço válido IPv4 ou IPv6" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "O tamanho da rede (bits) deve estar no intervalo 0-32 (não %(bits)r)" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "O nome da chave só pode conter letras, underscore, hífen ou dígitos" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "O nome de arquivo não pode estar dentro de um diretório" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Painel de Controle" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "filtro rápido..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "Você tem direitos de administrador neste grupo e pode editá-lo" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Nome" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Descrição" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Dono" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Última Alteração" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "Início" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Entrar" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Nome de usuário" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Lembre-se de mim" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Link de reinicialização de senha será enviado ao endereço de e-mail correspondente" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Repita a senha" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Primeiro Nome" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Último Nome" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "Diário do administrador" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "filtro de diário..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "filtro" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s entrada" +msgstr[1] "%s entradas" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Ação" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Repositório" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Data" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "A partir do IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Ainda não há ações" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Administrador" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "desabilitado" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Salvar" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "Padrões de repositórios" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Tipo" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "Repositórios privados são visíveis somente por pessoas explicitamente adicionadas como colaboradores." + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "Descrição do gist ..." + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "Tempo de vida do Gist" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "Cancelar" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "Gists privados do usuário %s" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "Gists públicos do usuário %s" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "Gists Públicos" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "Autor" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "Criado em" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "Expira" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Limpar" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "Gist" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Excluir" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "Editar" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "criado" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "Mostrar original" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "Minha conta" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "Minha Conta" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "Seguindo" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "Pull Requests" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Adicionar" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "Confirme para excluir este email: %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "Novo endereço de email" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "Altere o seu avatar em" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "Pull request $%s aberto em %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "Fechado" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "Confirme para excluir este pull request" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "Pull request #%s aberto por %s em %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Minhas Notificações" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Todos" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Comentários" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Ainda não há notificações aqui" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Mostrar notificação" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Notificações" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Permissões" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Registro" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "Confirme para excluir este IP: %s" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "Todos os endereços IP são permitidos" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "Todas as permissões padrão em cada repositório serão modificadas para a permissão escolhida, note que todas as permissões padrão customizadas nos repositórios serão perdidas" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Todas as permissões padrão em cada grupo de repositórios serão modificadas para a permissão escolhida, note que todas as permissões padrão customizadas em grupos de repositórios serão perdidas" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Todas as permissões padrão em cada repositório serão reinicializadas para as permissões escolhidas. Note que todas as permissões padrão customizadas nos repositórios serão perdidas" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "Adicionar grupo de repositórios" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "Grupo de repositórios" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Configurações" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "Nenhum" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Ler" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Gravar" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "dono" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "Adicionar novo" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "Progenitor do grupo" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "Administração de grupos de repositórios" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Adicionar repositório" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Clonar de" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "Seja sucinto e objetivo. Use um arquivo README para descrições mais longas." + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Remoto" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Estatísticas" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "Marque manualmente este repositório como uma bifurcação de um outro da lista" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "Desassociar bifurcações" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "Excluir bifurcações" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "Confirma excluir esse repositório: %s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "Invalidar cache do repositório" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "Confirma invalidar cache do repositório" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "Prefixo" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "Chave" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Ativo" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "Confirme para excluir este campo: %s" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "Entre com o rótulo curto" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "repositório privado" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "Realizar pull de alterações a partir de localização remota" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "Confirma realizar pull de alterações a partir de lado remoto" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "ID inalterável" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "editar" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Grupo de repositórios" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "Opcionalmente selecione um grupo no qual colocar esse repositório." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "Mudar o dono desse repositório." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Repositório privado" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Habilitar estatísticas" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "Habilitar janela de estatísticas na página de sumário." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Habilitar downloads" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "Habilitar menu de descarregar na página de sumário." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "Confirma remover atuais estatísticas" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Salvar configurações" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "Administração de repositórios" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "repositórios" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "Administração de configurações" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Enviar" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "Título" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "Ganchos customizados" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "Destruir dados antigos" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "Invalidar o cache para todos os repositórios" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "Geral" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "Usar campos extras do repositório" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "Permite armazenar campos customizados adicionais por repositório." + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "Mostrar versão do RhodeCode" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "Meta-Tagging" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Ícones" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Mostrar ícone de repositório público nos repositórios" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Mostrar ícone de repositório privado nos repositórios" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "Adicionar grupo de usuários" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "Grupos de usuários" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Nome do grupo" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Membros" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "Nenhum membro ainda" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "revogar" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "Membros escolhidos do grupo" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Remover todos os elementos" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Membros disponíveis" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Adicionar todos os elementos" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "Administração de grupos de usuários" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Adicionar usuário" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Usuários" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Confirmação de senha" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "Último login" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Confirma excluir este usuário: %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Administração de usuários" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "Padrões" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "Bifurcação de" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Sumário" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "Registro de alterações" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "Arquivos" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Compare" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "Mostrar Pull Requests para %s" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Opções" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Compare bifurcação" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Pesquisar" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "Destravar" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "Travar" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "Criar Pull Request" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Não possui uma conta ?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Diário" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Diário público" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "Gists" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "Visualizar" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "mostrar" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "nenhum" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "ler" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "escrever" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "administrador" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Permissão" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "Editar Permissão" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "Criar repositórios" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "Bufurcar repositórios" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "Criar grupos de usuários" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "Requer SSL para operações de VCS" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "Clique para destravar. Você deve reiniciar o RhodeCode para que esta configuração tenha efeito." + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "Mostrar tamanho do repositório após o push" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "Habilitar extensão largefiles" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "Habilitar extensão hgsubversion" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "%s Bookmarks" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "Bookmark %s" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "%s Ramos" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "Ramo %s" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "%s Changelog" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "Comparar bifurcação com %s" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "Crie novo pull request" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "Deselecionar seleção" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "Idade" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "Tag %s" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "Ainda não há alteações" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "Removido" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "Modificado" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "Adicionado" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "Afetados %s arquivos" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "mesclar" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "Mensagem de commit" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "Repositório existente?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "Diff cru" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "D" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "Baixar diff" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "Nenhum arquivo" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "Mostrar diff completo" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "Vote no pull request #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "Comentar no pull request #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "Comentários interpretados usando a sintaxe %s com suporte a %s." + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "Use @nomedeusuário dentro desse texto para enviar notificação a este usuário do RhodeCode" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "Visualizar comentário" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "Comentário" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "Você precisa estar logado para comentar." + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "Entrar agora" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "Ocultar" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "Mostrar diff completo para este arquivo" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "Mostrar diff completo lado-a-lado para este arquivo" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "%s Comparar" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Repositório Mercurial" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Repositório Git" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Repositório público" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "Assinar o feed rss de %s" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "Assinar o feed atom de %s" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "Criado" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "Confirme para excluir este grupo: %s com %s repositório" +msgstr[1] "Confirme para excluir este grupo: %s com %s repositórios" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "Confirme para excluir este grupo de usuário: %s" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "Grupo de usuários" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "Privado" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "O pull request foi fechado com o estado" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "Você será redirecionado para %s em %s segundos" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "Arquivo %s diff lado-a-lado" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "%s Diff de Arquivo" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "%s Arquivos" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "%s Adicionar Arquivos" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "Adicionar novo arquivo" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "ou" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "Realizar commit das alterações" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "Carregando lista de arquivos..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "Tamanho" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Carregando..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "Arquivo binário (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "Arquivo é grande demais para exibir" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "Editar arquivo" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "fonte" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "anotação" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "Editando arquivo" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "Local" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "Download" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "%s Seguidores" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "Seguidores" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "Nome da bifurcação" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "Copiar permissões" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "Copiar permissões do repositório bifurcado" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "%s Bifurcações" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "Bifurcações" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "Bifurcado" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "Ainda não há bifurcações" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "ATOM feed do diário" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "RSS feed do diário" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "Ainda não há entradas" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Diário Público" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "ATOM feed do diário público" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "RSS feed do diário público" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "Novo pull request" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "Escreva uma breve descrição para este pull request" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "Repositório origem" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "Revisores do pull request" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "Repositório de destino" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "%s Pull Request #%s" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "revisor" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "Mostrar um diff muito grande pode levar muito tempo e gastar muitos recursos" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "%s Pull Requests" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "Abertos por mim" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "Conteúdo dos arquivos" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "Mensagens de commit" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "Nomes dos arquivos" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "%s Sumário" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "%s ATOM feed" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "%s RSS feed" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "Mostrar por Nome" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "Mostrar por ID" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "URL de clonagem" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "As estatísticas estão desabillitadas para este repositório" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "Ainda não há downloads" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "Downloads estão desabilitados para este repositório" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "Início rápido" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "%s Tags" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" diff --git a/rhodecode/i18n/rhodecode.pot b/rhodecode/i18n/rhodecode.pot new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/rhodecode.pot @@ -0,0 +1,7772 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2016. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: rhodecode-enterprise-ce 4.0.0\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "" + +#: rhodecode/authentication/schema.py:45 +msgid "Amount of seconds to cache the authentication call for this plugin. Useful for long calls like LDAP to improve the responsiveness of the authentication system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "Changing the status of a commit associated with a closed pull request is not allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "Repositories unrelated. Cannot compare commit %(commit1)s from repository %(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "" + +#: rhodecode/controllers/error.py:114 +msgid "The request could not be understood by the server due to malformed syntax." +msgstr "" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "" + +#: rhodecode/controllers/error.py:123 +msgid "The server encountered an unexpected condition which prevented it from fulfilling the request." +msgstr "" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "A VCS Server is required for this action. There is currently no VCS Server configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "" + +#: rhodecode/controllers/files.py:665 +msgid "The location specified must be a relative path and must not contain .. in the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "" + +#: rhodecode/controllers/login.py:307 +msgid "Your password reset was successful, a new password has been sent to your email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "You need to finish registration process to bind your external identity to your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "Pull request updated to \"{source_commit_id}\" with {count_added} added, {count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "Closing pull request on other statuses than rejected or approved is forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:412 +msgid "The user participates as reviewer in pull requests and cannot be deleted. You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:91 +msgid "Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "%s repository is not mapped to db perhaps it was created or renamed from the filesystem please run the application again in order to rescan repositories" +msgstr "" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "No external user id found? Perhaps permissionsfor authentication are set incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "A comma separated list of group names that identify users as RhodeCode Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 rhodecode/templates/login.html:45 +#: rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "" + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "This pull request cannot be merged because the source contains more branches than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "This pull request cannot be merged because the target or the source reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "You can't edit this user (`%(username)s`) since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "user \"%s\" still owns %s repositories and cannot be removed. Switch owners or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "user \"%s\" still owns %s repository groups and cannot be removed. Switch owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "user \"%s\" still owns %s user groups and cannot be removed. Switch owners or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "" + +#: rhodecode/model/validators.py:162 +msgid "Username may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "user group name may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "Invalid clone url, provide a valid clone url starting with one of %(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "" + +#: rhodecode/model/validators.py:912 +msgid "The LDAP Login attribute of the CN must be specified - this is the name of the attribute that is equivalent to \"username\"" +msgstr "" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "" + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "" + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "Add a list of plugins, separated by commas. The order of the plugins is also the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "Private repositories are only visible to people explicitly added as collaborators." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "Enable automatic repository locking. Pulling from a repository will lock it, and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "Gist was updated since you started editing. Copy your changes and click %(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "Each token can have a role. VCS tokens can be used together with the authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "Your user account details are managed by an external source, i.e. LDAP. Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "Allow access to RhodeCode Enterprise without requiring users to login. Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "Custom message to be displayed on the registration page. HTML syntax is supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "Default system permissions. Each permissions management entity will be created with the following default settings. Check the overwrite checkbox to force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "Set or revoke permissions to selected types of children of this group, including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "Repository locking will be enabled on all subgroups and repositories inside this repository group. Pulling from a repository locks it, and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "Keep it short and to the point. Use a README file for longer descriptions." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "The default commit for file pages, downloads, full text search index, and README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "Repository \"%(repo_name)s\" is being created, you will be redirected when this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "All actions made on this repository will be visible to everyone following the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "Force repository locking. This only works when anonymous access is disabled. Pulling from the repository locks the repository to that user until the same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "Manually invalidate the repository cache. On the next access a repository cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "Extra fields are disabled. You can enable them from the Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "http[s] url where from repository was imported, also used for doing remote pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "Enable automatic locking on repository. Pulling from this repository creates a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "Set a custom text that is shown as authentication message to clients trying to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "Private key for reCaptcha system. Setting this value will enable captcha on registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "Hooks can be used to trigger actions on certain events such as push / pull. They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "In case a repository or a group was deleted from the filesystem and it still exists in the database, check this option to remove obsolete data from the database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "Each cache data for repositories will be cleaned with this option selected. Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "Last %(size)s bytes of process logs, use ?offset=[num] GET param to set custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Enable this by setting archive_cache_dir=/path/to/cache option in the .ini file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "Use gravatar.com as avatar system for RhodeCode accounts. If this is disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "Parses meta tags from repository description field and turns them into colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "Number of items displayed in the main page dashboard before pagination is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "Number of items displayed in the admin pages grids before pagination is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "Default renderer used to render comments, pull request descriptions and other description elements. After change old entries will still work correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "When selecting the detach option, the depending objects owned by this user will be assigned to the `%s` super admin in the system. The delete option will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "This user was created from external source (%s). Editing some of the settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "The following options configure the default permissions each user or group will inherit. You can override these permissions for each individual user or user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "Permission to create root level repositories. When disabled, users can still create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "Write permission given on a repository group will allow creating repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "Permission to create root level repository forks. When disabled, users can still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "Permission to create root level repository groups. When disabled, repository group admins can still create repository subgroups within their repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "Permission to allow user group creation. When disabled, user group admins can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "Inherit default permissions from the default user. Turn off this option to force explicit permissions for users, even if they are more restrictive than the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "Click to unlock. You must restart RhodeCode in order to make this setting take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "When this is enabled all commits in the repository are seen as public commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "Patterns for identifying SVN branches and tags. For recursive search, use \"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "" + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "" + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "Please update this pull request, push the commits back into the source repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" + diff --git a/rhodecode/i18n/ru/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/ru/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..302fe9c635be03a95fcd47607f77c4e4ee5a6c69 GIT binary patch literal 139998 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 Wgic0VLT3k^|Aoj?09aa{=>GyetBN!L diff --git a/rhodecode/i18n/ru/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/ru/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/ru/LC_MESSAGES/rhodecode.po @@ -0,0 +1,8093 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# Alexander Litvinov <aleclitvinov1980@gmail.com>, 2013 +# Andre <mokeev_andre@mail.ru>, 2013 +# Andrey Mivrenik <myvrenik@gmail.com>, 2013 +# Alexander Litvinov <aleclitvinov1980@gmail.com>, 2013 +# Invision <invision70@gmail.com>, 2014 +# Ivlev Denis <ivlevdenis.ru@gmail.com>, 2013 +# Ivlev Denis <ivlevdenis.ru@gmail.com>, 2013-2015 +# Mikhail Zholobov <legal90@gmail.com>, 2013 +# Mikhail Zholobov <legal90@gmail.com>, 2013 +# Andre <mokeev_andre@mail.ru>, 2013 +# Andrey Mivrenik <myvrenik@gmail.com>, 2013 +# Ruslan <furyinbox@gmail.com>, 2013 +# Ruslan <furyinbox@gmail.com>, 2013 +# SkryabinD <skryabind@gmail.com>, 2014 +# softforwinxp <softforwinxp@gmail.com>, 2013 +# softforwinxp <softforwinxp@gmail.com>, 2013 +# Cyber Tailor <cybertailor@gmail.com>, 2015 +# zhmylove <zhmylove@narod.ru>, 2013 +# Алексей <za82@mail.ru>, 2015 +# Mikhail Zholobov <legal90@gmail.com>, 2013 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Russian (http://www.transifex.com/rhodecode/RhodeCode/language/ru/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: ru\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "Включено" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "Ещё не было коммитов" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "Показывать пробел" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "Всегда показывать пробел при сравнении файлов" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "Игнорировать пробел" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "Всегда игнорировать пробел при сравнении файлов" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "Выделять несовпадения увеличением текста" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "Всегда выделять несовпадения увеличением текста при сравнении файлов" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "Изменить статус %(transition_icon)s %(status)s" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "Домашняя страница" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "Запрос не распознан сервером из-за неправильного синтаксиса." + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "Несанкционированный доступ к ресурсу" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "У вас нет прав для просмотра этой страницы" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "Ресурс не найден" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "Сервер не может выполнить запрос, из-за неправильного условия в запросе" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "Требуется VCS-сервер" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "Для этого действия требуется VCS-сервер. В данный момент не сконфигурировано ни одного VCS-сервера." + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "Изменения в репозитарии %s" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "Лента новостей %s %s" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "Файлов пока нет. %s" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "Репозиторий заблокировал %s в %s" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "Файлы с новыми версиями можно удалять только из ветки с правом доступа" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "Файл %s удален с помощью RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "Файл %s успешно удален" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "Во время фиксации изменений произошла ошибка" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "Вы можете редактировать файлы только в редакции, связанной с существующей веткой" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "Файл %s отредактирован с помощью RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "Без изменений" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "Изменения применены в %s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "Файл добавлен с помощью RhodeCode Enterprise" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "Безымянный" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "Указанное расположение должно быть релятивным и не должно содержать \"..\" в имени пути" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "Возможность скачивать отключена" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "Неизвестная версия %s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "Пустой репозитарий" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "Неизвестный тип архива" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "Набор изменений" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "Ветки" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "Метки" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "Произошла ошибка во время создания форка репозитория %s" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "Группы" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "Репозитории" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "общедоступный журнал" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "журнал" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "ошибка в CAPTHA" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "Регистрация в RhodeCode прошла успешно" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "Ссылка для сброса пароля отправлена" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "Сброс пароля прошел успешно, новый пароль отправлен на ваш адрес электронной почты" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "Заголовок Pull запроса должен быть не менее 3-х символов" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "Pull запрос создан успешно" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "Произошла ошибка при создании Pull запроса" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "Не могу обновить закрытые запросы на включение изменений." + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "Заголовок и описание запроса на включение изменений обновлены." + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "Pull запрос успешно удалён" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "Закрытый с" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "Ветка" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "Тэги" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "Закладки" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "Стандартные настройки успешно обновлены" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "навсегда" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "5 минут" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "1 час" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "1 день" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "1 месяц" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "Срок" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "Произошла ошибка во время создания сути" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "Запись gist %s удалена" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "никогда" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "Вы не можете изменить данные пользователя, поскольку это критично для работы всего приложения" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "Ваша учетная запись успешно обновлена" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "Произошла ошибка при обновлении пользователя %s" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "Произошла ошибка при сохранении E-mail" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "Произошла ошибка во время обновления привилегий" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "Глобальные привилегии успешно обновлены" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "Создана новая группа репозиториев %s" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "Произошла ошибка при создании группы репозиториев %s" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "Группа репозиториев %s обновлена" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "Произошла ошибка при обновлении группы репозиториев %s" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "Группа репозиториев %s удалена" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "Произошла ошибка при удалении группы репозиториев %s" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "Привилегии группы репозиториев обновлены" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "Произошла ошибка при создании репозитория %s" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "Репозиторий %s создан из %s" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "Сделан форк(копия) репозитория %s на %s" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "Репозиторий %s создан" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "Репозитарий %s успешно обновлён" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "Произошла ошибка во время обновления репозитория %s" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "Форки %s отсоединены" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "Удалены форки репозитория %s" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "Репозиторий %s удалён" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "Невозможно удалить %s, он всё-ещё содержит форки" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "Произошла ошибка во время удаления %s" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "Привилегии репозитория обновлены" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "Произошла ошибка при создании поля" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "Произошла ошибка при удалении поля" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "Видимость репозитория в публичном журнале обновлена" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "Произошла ошибка при установке репозитария в общедоступный журнал" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "Ничего" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "Репозиторий %s отмечен как форк %s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "Произошла ошибка при выполнении операции" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "Закрытый репозиторий" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "Открытый репозиторий" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "Произошла ошибка во время разблокирования" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "Разблокировано" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "Заблокировано" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "Репозиторий %s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "Произошла ошибка при очистке кэша" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "Внесены изменения из удалённого репозитория" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "Произошла ошибка при внесении изменений из удалённого репозитория" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "Произошла ошибка при удалении статистики репозитория" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "Обновлены настройки VCS" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "Произошла ошибка при обновлении настроек приложения" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "Репозитории успешно пересканированы, добавлено: %s ; удалено: %s" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "Обновленные параметры настройки приложения" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "Настройки визуализации обновлены" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "Произошла ошибка при обновлении настроек визуализации" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "Пожалуйста, введите адрес электронной почты" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "Задача отправки Email создана" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "Добавлена новая ловушка" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "Обновлённые ловушки" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "Произошла ошибка при создании хука" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "E-mail" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "Хуки" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "Произошла ошибка при создании группы пользователей %s" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "Группа пользователей %s обновлена" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "Произошла ошибка при обновлении группы пользователей %s" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "Группа пользователей успешно удалена" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "Произошла ошибка при удалении группы пользователей" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "Целевая группа не может быть такой же" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "Привилегии группы пользователей обновлены" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "Произошла ошибка при сохранении привилегий" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "Произошла ошибка при создании пользователя %s" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "Пользователь успешно обновлён" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "Пользователь успешно удалён" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "Произошла ошибка при удалении пользователя" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "Вы не можете редактировать данного пользователя" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "Произошла ошибка при сохранении IP" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "IP %s удален из белого списка пользователя" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[удален] репозиторий" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[создан] репозиторий" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[создан] репозиторий как форк" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[форкнут] репозиторий" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[обновлён] репозиторий" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "[загружен] архив из репозитория" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[удален] репозиторий" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[создан] пользователь" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[обновлён] пользователь" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "[создана] группа пользователей" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "[обновлена] группа пользователей" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[прокомментировано] в запросе на внесение изменений для" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[закрыт] pull запрос для" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[отправлено] в" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[внесены изменения с помощью RhodeCode] в репозитории" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[внесены изменения из удалённого репозитория] в репозиторий" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[внесены изменения] из" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[добавлен в наблюдения] репозиторий" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[удалён из наблюдения] репозиторий" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "имя форка %s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "Pull запрос #%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "сравнение" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "Удалена ветка: %s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "Создан тег: %s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "IP %s заблокирован" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "Вы должны быть зарегистрированным пользователем, чтобы выполнить это действие" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "Двоичный файл" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "Набор изменения оказался слишком большими и был урезан, используйте меню сравнения для показа результата сравнения" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "Изменений не обнаружено" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "и на %s больше" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "Файлов нет" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "новый файл" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "изменить" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "удалить" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "переименовать" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "chmod" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "Репозиторий %s отсутствует в базе данных; возможно, он был создан или переименован из файловой системы. Пожалуйста, перезапустите приложение для сканирования репозиториев." + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d год" +msgstr[1] "%d лет" +msgstr[2] "%d года" +msgstr[3] "%d года" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d месяц" +msgstr[1] "%d месяца" +msgstr[2] "%d месяцев" +msgstr[3] "%d месяцев" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d день" +msgstr[1] "%d дня" +msgstr[2] "%d дней" +msgstr[3] "%d дней" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d час" +msgstr[1] "%d часов" +msgstr[2] "%d часа" +msgstr[3] "%d часа" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d минута" +msgstr[1] "%d минут" +msgstr[2] "%d минуты" +msgstr[3] "%d минуты" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d секунды" +msgstr[1] "%d секунды" +msgstr[2] "%d секунды" +msgstr[3] "%d секунды" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "в %s" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s назад" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s и %s назад" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "в %s и %s" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "прямо сейчас" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "Хост" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "Порт" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "URL" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "Учетная запись" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "Пароль" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "Проверка сертификата" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "База (Base DN)" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "Глубина (scope)" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "Атрибут \"Логин\"" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "Атрибут \"Имя\"" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "Атрибут \"Фамилия\"" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "LDAP" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "Репозитарий - нет доступа" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "Репозитарий - доступ на чтение" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "Репозитарий - доступ на запись" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "Репозитарий - администрирование" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "Группа Репозиториев - нет доступа" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "Группа Репозиториев - доступ на чтение" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "Группа Репозиториев - доступ на запись" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "Группа Репозиториев - администрирование" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "Администратор RhodeCode " + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "Создание репозиториев отключено" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "Создание репозиториев включено" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "Возможность создавать форк репозитория отключена" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "Возможность создавать форк репозитория включена" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "Регистрация отключена" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "Регистрация нового пользователя в RhodeCode с ручной активацией" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "Регистрация нового пользователя в RhodeCode с автоматической активацией" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "Не просмотрено" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "Одобрено" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "Отклонено" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "На рассмотрении" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "Группа репозиториев - нет доступа" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "Группа репозиториев - доступ на чтение" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "Группа репозиториев - доступ на запись" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "Группа репозиториев - администрирование" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "Группа пользователей - нет доступа" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "Группа пользователей - доступ на чтение" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "Группа пользователей - доступ на запись" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "Группа пользователей - администрирование" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "Создание групп репозиториев отключено" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "Создание групп репозиториев включено" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "Создание групп пользователей отключено" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "Создание групп пользователей включено" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "Регистрация отключена" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "Регистрация пользователя с ручной активацией учётной записи" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "Регистрация пользователя с автоматической активацией учётной записи" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "Ручная активация внешней учетной записи" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "Автоматическая активация внешней учетной записи" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "Недопустимый поисковый запрос. Попробуйте заключить его в кавычки." + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "Индексы отсутствуют. Пожалуйста, запустите индексатор Whoosh." + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "Произошла ошибка при выполнении этого поиска" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "Пожалуйста, введите логин" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "Введите значение длиной не менее %(min)i символов" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "Пожалуйста, введите пароль" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "Введите не менее %(min)i символов" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "Закладки" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "Закрытые ветки" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "последняя версия" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "Вы не можете редактировать пользователя, поскольку это критично для работы всего приложения" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "Вы не можете удалить пользователя, поскольку это критично для работы всего приложения" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "Значение не может быть пустым списком" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "Пользователь с именем \"%(username)s\" уже существует" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "Имя \"%(username)s\" отклонено" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "Имя пользователя может содержать только буквы, цифры, символы подчеркивания, точки и тире; а так же должно начинаться с буквы, цифры либо с символа подчеркивания" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "Имя \"%(username)s\" недопустимо" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "Недопустимое имя группы пользователей" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "Группа пользователей \"%(usergroup)s\" уже существует" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "имя группы пользователей может содержать только буквы, цифры, символы подчеркивания, точки и тире; а так же должно начинаться с буквы или цифры" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "Невозможно использовать эту группу как родителя" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "Группа \"%(group_name)s\" уже существует" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "Репозитарий с именем \"%(group_name)s\" уже существует" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "Недопустимые символы (не ascii) в пароле" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "Пароли не совпадают" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "неверный пароль" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "неверное имя пользователя" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "Ваш аккаунт выключен" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "Несовпадение токенов" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "Имя репозитория %(repo)s запрещено" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "Группа репозиториев \"%(repo)s\" уже существует" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "Тип форка будет совпадать с родительским" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "Данное имя пользователя или группы пользователей недопустимо" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "Этот путь ошибочен" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "Этот E-mail уже занят" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "\"%(email)s\" не существует" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "Для входа по LDAP должно быть указано значение аттрибута CN - это эквивалент имени пользователя" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "Ревизии %(revs)s уже включены в pull-request или имеют установленный статус" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "Пожалуйста, введите существующий IPv4 или IpV6 адре" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "Значение маски подсети должно быть в пределах от 0 до 32 (%(bits)r - неверно)" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "Ключевое имя может только состоять из букв, символа подчеркивания, тире или чисел" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "Файла нет в каталоге" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "Панель управления" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "фильтр..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "Добавить репозиторий" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "Добавить группу репозиториев" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "Вы имеете администраторские права на эту группу и можете редактировать её" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "Изменить группу репозиториев" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "Имя" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "Описание" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "Владелец" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "Последнее изменение" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "Домой" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "Войти" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "Имя пользователя" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "Запомнить" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "Почтовый адрес" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "Ссылка для сброса пароля была отправлена на соответствующий E-mail" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "Повторите пароль" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "Имя" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "Фамилия" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "Журнал администратора" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "Фильтр журнала..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "Отфильтровать" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s запись" +msgstr[1] "%s записей" +msgstr[2] "%s записи" +msgstr[3] "%s записи" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "Действие" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "Репозитарий" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "Дата" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "С IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "Действия ещё не производились" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "Настройки аутентификации" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "Администратор" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "Плагины аутентификации" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "Включенные плагины" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "отключено" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "Сохранить" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "Плагин" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr " Значения по умолчанию" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "Тип" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "Приватные репозитории видны только их участникам" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "Описание..." + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "plain" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "Отмена" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "Приватная запись Gist для пользователя %s" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "Публичная запись Gist для пользователя %s" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "Публичные записи Gist" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "Автор" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "Создано" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "Истекает" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "Сброс" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "Gist" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "Удалить" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "Редактировать" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "создал" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "Показать без форматирования" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "Мой аккаунт" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "Мой Аккаунт" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "Мои Email-ы" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "Мои репозитории" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "Просмотрено" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "Pull-request'ы" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "Добавить" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "Основной" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "Подтвердите удаление E-mail: %s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "Дополнительных Email не указано" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "Новый E-mail" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "Аватары отключены" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "Не указан email. Пожалуйста, обновите ваш email." + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "Измените аватар через сайт" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "Pull-request #%s открыт %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "Закрыто" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "Подтвердите удаление этого pull-request'а" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "Pull-request #%s открыт пользователем %s %s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "Мои уведомления" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "Всё" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "Комментарии" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "Уведомлений нет" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "Показать уведомление" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "Уведомления" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "Привилегии" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "Обзор" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "Регистрация" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "Подтвердите удаление ip %s" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "Разрешены любые IP-адреса" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "Выбранные привилегии будут установлены по умолчанию для каждого репозитория. Учтите, что ранее установленные привилегии по умолчанию будут сброшены." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "Группы репозиториев" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Выбранные привилегии будут установлены по умолчанию для каждой группы репозиториев. Учтите, что ранее установленные привилегии по умолчанию для групп репозиториев будут сброшены." + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "Выбранные привилегии будут установлены по умолчанию для каждой группы пользователей. Учтите, что ранее установленные привилегии по умолчанию для групп пользователей будут сброшены." + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "Добавить группу репозиториев" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "Группы репозиториев" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "Имя группы" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "Добавить подгруппу" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "Настройки" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "Дополнительно" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "Группа репозиториев: %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "Подтвердите удаление группы %s" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "Ничего" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "Чтение" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "Запись" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "владелец" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "Добавить новый" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "Родительская группа" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "Администрирование групп репозиториев" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "Добавить репозиторий" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "Клонировать из" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "Короткое и осмысленное. Для развернутого описания используйте файл README." + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "Удалённый" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "Статистика" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "Набор" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "Вручную сделать этот репозиторий форком выбранного из списка" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "Отсоединить fork'и" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "Удалить fork'и" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "Подтвердите удаление этого репозитория: %s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "Сбросить кэш репозитория" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "Подтвердите сброс кэша" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "Префикс" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "Ключ" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "Активный" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "Подтвердите удаление этого поля: %s" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "Введите краткое имя поля" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "приватный репозиторий" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "Получить изменения с удалённой стороны" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "Подтвердите скачивание изменений" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "Неизменяемый id" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "редактировать" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "Группа репозиториев" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "Опционально выбрать группу, в которую поместить данный репозиторий." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "Изменить владельца репозитория" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "Приватный репозиторий" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "Включить статистику." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "Включить окно статистики на странице 'Общие сведения'." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "Включить скачивание" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "Включить меню скачивания на странице 'Общие сведения'." + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "Подтвердите сброс статистики" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "Сохранить настройки" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "Администрирование репозиториев" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "репозитарии" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "Администрирование настроек" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "Проверка E-mail" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "Отправить" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "Заголовок" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "Пользовательские хуки" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "Уничтожить все данные" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "Сбросить кэш для всех репозиториев" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "Главное" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "Использовать дополнительные поля в репозиториях" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "Позволяет хранить дополнительные поля в репозиториях" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "Отображать версию RhodeCode" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "Метатегирование" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "Иконки" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "Показывать иконки публичных репозиториев" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "Показывать иконки приватных репозиториев" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "Добавить группу пользователей" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "Группы пользователей" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "Имя группы" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "Участники" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "Нет участников" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "отозвать" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "Выбранные участники группы" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "Удалить всё" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "Доступные участники" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "Добавить всё" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "Администрирование групп пользователей" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "Добавить пользователя" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "Пользователи" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "Подтверждение пароля" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "Последний вход" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "Подтвердите удаление пользователя %s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "Администрирование пользователей" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "Аутентификация" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "Значения по умолчанию" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "Форк от" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "Общие сведения" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "История изменений" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "Файлы" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "Сравнить" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "Показать pull-request'ы для %s" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "Опции" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "Сравнить форк" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "Поиск" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "Разблокировать" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "Заблокировать" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "Создать Pull запрос" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "Нет аккаунта?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "Журнал" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "Общедоступный журнал" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "Gist" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "Предпросмотр" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "показать" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "ничего" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "читать" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "записывать" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "администратор" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "Привилегия" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "Изменить привилегии" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "Создать репозитории" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "Создавать fork от репозиториев" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "Создавать группы пользователей" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "Запрашивать SSL для операций с VCS" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "Нажмите для разблокирования. Изменения вступят в силу после перезагрузки RhodeCode." + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "Показывать размер репозитория после отправки" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "Включить поддержку больших файлов" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "Включить поддержку hgsubversion" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "Закладки %s" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "закладки" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "Закладка %s" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "Ветки %s" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "ветки" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "Ветка %s" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "Логи изменений %s" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "Сравнить fork с %s" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "Создать новый pull запрос" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "Очистить выбор" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "Возраст" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "Ссылки" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "Метка %s" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "Изменений ещё нет" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "Удалено" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "Изменено" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "Добавлено" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "Затрагивает %s файлов" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "свести" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "Сообщение commit'а" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "Существующий репозиторий?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "Родитель" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "Отобразить в формате diff" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "Применить разностное исправление (Patch diff)" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "Скачать diff" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "Нет файлов" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "Показать полный diff" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "Комментарий в Pull запросе #%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "Парсинг комментариев выполнен с использованием синтаксиса %s с поддержкой %s." + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "Используйте @имя_пользователя в тексте, чтобы отправить оповещение указанному пользователю RhodeCode" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "Предварительный просмотр комментария" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "Комментировать" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "Вам необходимо авторизоваться, чтобы оставлять комментарии" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "Авторизоваться сейчас" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "Скрыть" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "Показать полный diff для этого файла" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "Показать полный diff для этого файла" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "%s Сравнить" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "Исходный код" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Репозиторий Mercurial" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Git репозиторий" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "Публичный репозиторий" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "Подписаться на ленту RSS %s" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "Подписаться на ленту Atom %s" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "Создано" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "Подтвердите удаление группы %s содержащей %s репозиториев." +msgstr[1] "Подтвердите удаление группы %s содержащей %s репозиториев." +msgstr[2] "Подтвердите удаление группы %s содержащей %s репозиториев." +msgstr[3] "Подтвердите удаление группы %s содержащей %s репозиториев." + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "Подтвердите удаление следующей группы пользователей: %s" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "Группа пользователей" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "Приватный" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "Pull-request был закрыт со статусом" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "Вы будете посланы на %s через %s секунд" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "Сравнение файла %s" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "%s Файлы" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "%s Файлов добавлено" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "Добавить файл" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "или" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "Загрузить файл" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "Применить изменения" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "Загружается список файлов..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "Размер" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "Загрузка..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "Бинарный файл (%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "Файл слишком большой для отображения" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "Редактировать файл" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "исходник" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "аннотация" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "Редактирование файла" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "Расположение" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "История" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "Скачать" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "%s Наблюдатели" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "Наблюдатели" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "Имя форка" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "Скопировать привилегии" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "Скопировать привилегии с форкнутого репозитория" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "Форки %s" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "Ответвления" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "Форкнуто" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "Форки ещё не созданы" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "Лента журнала ATOM" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "Лента журнала RSS" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "Записи отсуствуют" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "Публичный журнал" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "Общая лента журнала ATOM" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "Общая лента журнала RSS" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "Новый pull запрос" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "Написать короткое писание по этому запросу" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "Первоначальный репозиторий" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "Рецензенты запросов на внесение изменений Pull request" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "Репозиторий назначения" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "%s Запрос на внесение изменений #%s" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "рецензент" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "Отображение слишком большого diff'а может занять длительное время" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "%s Запросы на внесение изменений" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "Открыто мной" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "Содержимое файлов" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "Сообщения commit'а" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "Имя файла" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "%s общие сведения" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "ATOM лента репозитория %s" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "RSS лента репозитория %s" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "Показать по имени" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "Показать по ID" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "Ссылка для клонирования" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "Статистические данные отключены для этого репозитария" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "Скачиваний ещё нет" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "Скачивание отключено в этом репозитории" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "Быстрый старт" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "%s Меток" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "метки" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "Профиль" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" diff --git a/rhodecode/i18n/zh/LC_MESSAGES/rhodecode.mo b/rhodecode/i18n/zh/LC_MESSAGES/rhodecode.mo new file mode 100644 index 0000000000000000000000000000000000000000..a68268ebade576d48f47c4065fe23cd8ed1b9c43 GIT binary patch literal 119625 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 diff --git a/rhodecode/i18n/zh/LC_MESSAGES/rhodecode.po b/rhodecode/i18n/zh/LC_MESSAGES/rhodecode.po new file mode 100644 --- /dev/null +++ b/rhodecode/i18n/zh/LC_MESSAGES/rhodecode.po @@ -0,0 +1,7953 @@ +# Translations template for rhodecode-enterprise-ce. +# Copyright (C) 2016 RhodeCode GmbH +# This file is distributed under the same license as the rhodecode-enterprise-ce project. +# +# Translators: +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011 +# mikespook <mikespook@gmail.com>, 2012 +# xpolife <xpolife@gmail.com>, 2012 +msgid "" +msgstr "" +"Project-Id-Version: RhodeCode\n" +"Report-Msgid-Bugs-To: marcin@rhodecode.com\n" +"POT-Creation-Date: 2016-05-22 18:01+0000\n" +"PO-Revision-Date: 2016-05-22 18:10+0000\n" +"Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" +"Language-Team: Chinese (http://www.transifex.com/rhodecode/RhodeCode/language/zh/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: zh\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: rhodecode/authentication/routes.py:61 +#: rhodecode/controllers/admin/settings.py:825 +#: rhodecode/templates/admin/permissions/permissions.html:36 +msgid "Global" +msgstr "" + +#: rhodecode/authentication/schema.py:37 +msgid "Enable or disable this authentication plugin." +msgstr "" + +#: rhodecode/authentication/schema.py:39 +msgid "Enabled" +msgstr "启用" + +#: rhodecode/authentication/schema.py:45 +msgid "" +"Amount of seconds to cache the authentication call for this plugin. Useful " +"for long calls like LDAP to improve the responsiveness of the authentication" +" system (0 means disabled)." +msgstr "" + +#: rhodecode/authentication/schema.py:50 +msgid "Auth Cache TTL" +msgstr "" + +#: rhodecode/authentication/views.py:108 +msgid "" +"Errors exist when saving plugin settings. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:131 rhodecode/authentication/views.py:200 +msgid "Auth settings updated successfully." +msgstr "" + +#: rhodecode/authentication/views.py:205 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + +#: rhodecode/authentication/views.py:215 +msgid "Error occurred during update of auth settings." +msgstr "" + +#: rhodecode/controllers/changelog.py:90 rhodecode/controllers/compare.py:63 +#: rhodecode/controllers/pullrequests.py:279 +msgid "There are no commits yet" +msgstr "" + +#: rhodecode/controllers/changeset.py:77 +#: rhodecode/templates/files/diff_2way.html:75 +msgid "Show whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:78 +msgid "Show whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:84 +#: rhodecode/templates/files/diff_2way.html:74 +msgid "Ignore whitespace" +msgstr "" + +#: rhodecode/controllers/changeset.py:85 +msgid "Ignore whitespace for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:141 +msgid "Increase context" +msgstr "" + +#: rhodecode/controllers/changeset.py:142 +msgid "Increase context for all diffs" +msgstr "" + +#: rhodecode/controllers/changeset.py:181 rhodecode/controllers/files.py:104 +#: rhodecode/controllers/files.py:125 +msgid "No such commit exists for this repository" +msgstr "" + +#: rhodecode/controllers/changeset.py:335 +#: rhodecode/controllers/pullrequests.py:744 +#: rhodecode/model/pull_request.py:828 +#, python-format +msgid "Status change %(transition_icon)s %(status)s" +msgstr "" + +#: rhodecode/controllers/changeset.py:372 +msgid "" +"Changing the status of a commit associated with a closed pull request is not" +" allowed" +msgstr "" + +#: rhodecode/controllers/compare.py:87 +msgid "Select commit" +msgstr "" + +#: rhodecode/controllers/compare.py:142 +#, python-format +msgid "Could not find the original repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:150 +#, python-format +msgid "Could not find the other repo: %(repo)s" +msgstr "" + +#: rhodecode/controllers/compare.py:159 +msgid "The comparison of two different kinds of remote repos is not available" +msgstr "" + +#: rhodecode/controllers/compare.py:186 +msgid "Could not compare repos with different large file settings" +msgstr "" + +#: rhodecode/controllers/compare.py:223 +#, python-format +msgid "" +"Repositories unrelated. Cannot compare commit %(commit1)s from repository " +"%(repo1)s with commit %(commit2)s from repository %(repo2)s." +msgstr "" + +#: rhodecode/controllers/error.py:85 rhodecode/controllers/error.py:136 +msgid "Home page" +msgstr "主页" + +#: rhodecode/controllers/error.py:114 +msgid "" +"The request could not be understood by the server due to malformed syntax." +msgstr "由于错误的语法,服务器无法对请求进行响应。" + +#: rhodecode/controllers/error.py:117 +msgid "Unauthorized access to resource" +msgstr "未授权的资源访问" + +#: rhodecode/controllers/error.py:119 +msgid "You don't have permission to view this page" +msgstr "无权访问该页面" + +#: rhodecode/controllers/error.py:121 +msgid "The resource could not be found" +msgstr "资源未找到" + +#: rhodecode/controllers/error.py:123 +msgid "" +"The server encountered an unexpected condition which prevented it from " +"fulfilling the request." +msgstr "服务进入非预期的混乱状态,这会阻止它对请求进行响应。" + +#: rhodecode/controllers/error.py:128 +msgid "VCS Server Required" +msgstr "" + +#: rhodecode/controllers/error.py:129 +msgid "" +"A VCS Server is required for this action. There is currently no VCS Server " +"configured." +msgstr "" + +#: rhodecode/controllers/feed.py:70 +#, python-format +msgid "Changes on %s repository" +msgstr "%s库的修改" + +#: rhodecode/controllers/feed.py:71 +#, python-format +msgid "%s %s feed" +msgstr "%s %s订阅" + +#: rhodecode/controllers/files.py:96 +msgid "Click here to add a new file." +msgstr "" + +#: rhodecode/controllers/files.py:101 +#, python-format +msgid "There are no files yet. %s" +msgstr "" + +#: rhodecode/controllers/files.py:390 rhodecode/controllers/files.py:443 +#: rhodecode/controllers/files.py:474 rhodecode/controllers/files.py:549 +#: rhodecode/controllers/files.py:594 rhodecode/controllers/files.py:685 +#, python-format +msgid "This repository has been locked by %s on %s" +msgstr "" + +#: rhodecode/controllers/files.py:398 rhodecode/controllers/files.py:451 +msgid "You can only delete files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:407 rhodecode/controllers/files.py:460 +#, python-format +msgid "Deleted file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:427 +#, python-format +msgid "Successfully deleted file %s" +msgstr "" + +#: rhodecode/controllers/files.py:430 rhodecode/controllers/files.py:536 +#: rhodecode/controllers/files.py:673 +msgid "Error occurred during commit" +msgstr "提交时发生错误" + +#: rhodecode/controllers/files.py:482 rhodecode/controllers/files.py:557 +msgid "You can only edit files with revision being a valid branch " +msgstr "" + +#: rhodecode/controllers/files.py:494 rhodecode/controllers/files.py:569 +#, python-format +msgid "Edited file %s via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:511 +msgid "No changes" +msgstr "无变更" + +#: rhodecode/controllers/files.py:533 rhodecode/controllers/files.py:662 +#, python-format +msgid "Successfully committed to %s" +msgstr "成功提交到%s" + +#: rhodecode/controllers/files.py:607 rhodecode/controllers/files.py:696 +msgid "Added file via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/controllers/files.py:632 +msgid "No filename" +msgstr "无文件名" + +#: rhodecode/controllers/files.py:665 +msgid "" +"The location specified must be a relative path and must not contain .. in " +"the path" +msgstr "" + +#: rhodecode/controllers/files.py:719 +msgid "Downloads disabled" +msgstr "" + +#: rhodecode/controllers/files.py:725 +#, python-format +msgid "Unknown revision %s" +msgstr "未知版本%s" + +#: rhodecode/controllers/files.py:727 +msgid "Empty repository" +msgstr "空版本库" + +#: rhodecode/controllers/files.py:729 rhodecode/controllers/files.py:763 +msgid "Unknown archive type" +msgstr "未知包类型" + +#: rhodecode/controllers/files.py:930 +#, python-format +msgid "Commit %(commit)s does not exist." +msgstr "" + +#: rhodecode/controllers/files.py:947 +#, python-format +msgid "%(file_path)s has not changed between %(commit_1)s and %(commit_2)s." +msgstr "" + +#: rhodecode/controllers/files.py:1014 +msgid "Changesets" +msgstr "修订集" + +#: rhodecode/controllers/files.py:1035 rhodecode/controllers/summary.py:256 +#: rhodecode/model/pull_request.py:1037 rhodecode/model/scm.py:783 +#: rhodecode/templates/base/vcs_settings.html:138 +msgid "Branches" +msgstr "分支" + +#: rhodecode/controllers/files.py:1039 rhodecode/model/scm.py:798 +#: rhodecode/templates/base/vcs_settings.html:163 +msgid "Tags" +msgstr "标签" + +#: rhodecode/controllers/forks.py:191 +#, python-format +msgid "An error occurred during repository forking %s" +msgstr "在复刻版本库%s的时候发生错误" + +#: rhodecode/controllers/home.py:174 +msgid "Groups" +msgstr "组" + +#: rhodecode/controllers/home.py:181 rhodecode/controllers/home.py:203 +#: rhodecode/controllers/pullrequests.py:382 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:128 +#: rhodecode/templates/admin/repos/repo_add.html:15 +#: rhodecode/templates/admin/repos/repo_add.html:19 +#: rhodecode/templates/admin/users/user_edit_advanced.html:11 +#: rhodecode/templates/base/base.html:79 +#: rhodecode/templates/base/base.html:147 +#: rhodecode/templates/base/base.html:621 +msgid "Repositories" +msgstr "版本库" + +#: rhodecode/controllers/journal.py:107 rhodecode/controllers/journal.py:150 +msgid "public journal" +msgstr "公共日志" + +#: rhodecode/controllers/journal.py:111 rhodecode/controllers/journal.py:154 +msgid "journal" +msgstr "日志" + +#: rhodecode/controllers/login.py:227 rhodecode/controllers/login.py:281 +msgid "bad captcha" +msgstr "" + +#: rhodecode/controllers/login.py:241 +msgid "You have successfully registered with RhodeCode" +msgstr "" + +#: rhodecode/controllers/login.py:286 +msgid "Your password reset link was sent" +msgstr "密码重置链接已经发送" + +#: rhodecode/controllers/login.py:307 +msgid "" +"Your password reset was successful, a new password has been sent to your " +"email" +msgstr "" + +#: rhodecode/controllers/login.py:340 +msgid "There was an error during OAuth processing." +msgstr "" + +#: rhodecode/controllers/login.py:406 +msgid "" +"You need to finish registration process to bind your external identity to " +"your account or sign in to existing account" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:293 +msgid "Commit does not exist" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:405 +msgid "Pull request requires a title with min. 3 chars" +msgstr "拉取请求的标题至少3个字符" + +#: rhodecode/controllers/pullrequests.py:407 +msgid "Error creating pull request: {}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:454 +msgid "Successfully opened new pull request" +msgstr "成功提交拉取请求" + +#: rhodecode/controllers/pullrequests.py:457 +msgid "Error occurred during sending pull request" +msgstr "提交拉取请求时发生错误" + +#: rhodecode/controllers/pullrequests.py:497 +msgid "Cannot update closed pull requests." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:503 +msgid "Pull request title & description updated." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:513 +msgid "" +"Pull request updated to \"{source_commit_id}\" with {count_added} added, " +"{count_removed} removed commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:523 +msgid "Nothing changed in pull request." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:526 +msgid "" +"Skipping update of pull request due to reference type: {reference_type}" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:533 +msgid "Update failed due to missing commits." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:579 +msgid "Pull request reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:629 +msgid "Successfully deleted pull request" +msgstr "成功删除拉取请求" + +#: rhodecode/controllers/pullrequests.py:662 +msgid "Reviewer approval is pending." +msgstr "" + +#: rhodecode/controllers/pullrequests.py:704 +msgid "Close Pull Request" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:748 +#: rhodecode/model/pull_request.py:832 +msgid "Closing with" +msgstr "" + +#: rhodecode/controllers/pullrequests.py:793 +#, python-format +msgid "" +"Closing pull request on other statuses than rejected or approved is " +"forbidden. Calculated status from all reviewers is currently: %s" +msgstr "" + +#: rhodecode/controllers/summary.py:240 +msgid "Branch" +msgstr "" + +#: rhodecode/controllers/summary.py:241 +msgid "Tag" +msgstr "" + +#: rhodecode/controllers/summary.py:242 +msgid "Bookmark" +msgstr "" + +#: rhodecode/controllers/summary.py:257 +msgid "Closed branches" +msgstr "" + +#: rhodecode/controllers/admin/defaults.py:84 +msgid "Default settings updated successfully" +msgstr "默认设置已经成功更新" + +#: rhodecode/controllers/admin/defaults.py:99 +msgid "Error occurred during update of default values" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:59 +#: rhodecode/controllers/admin/my_account.py:308 +#: rhodecode/controllers/admin/users.py:434 +msgid "forever" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:60 +#: rhodecode/controllers/admin/my_account.py:309 +#: rhodecode/controllers/admin/users.py:435 +msgid "5 minutes" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:61 +#: rhodecode/controllers/admin/my_account.py:310 +#: rhodecode/controllers/admin/users.py:436 +msgid "1 hour" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:62 +#: rhodecode/controllers/admin/my_account.py:311 +#: rhodecode/controllers/admin/users.py:437 +msgid "1 day" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:63 +#: rhodecode/controllers/admin/my_account.py:312 +#: rhodecode/controllers/admin/users.py:438 +msgid "1 month" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:67 +#: rhodecode/controllers/admin/my_account.py:314 +#: rhodecode/controllers/admin/users.py:440 +msgid "Lifetime" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:69 +msgid "Requires registered account" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:70 +msgid "Can be accessed by anonymous users" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:180 +msgid "Error occurred during gist creation" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:211 +#, python-format +msgid "Deleted gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:284 +msgid "Successfully updated gist content" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:289 +msgid "Successfully updated gist data" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:292 +#, python-format +msgid "Error occurred during update of gist %s" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:315 +#: rhodecode/templates/admin/gists/show.html:67 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/data_table/_dt_elements.html:253 +msgid "never" +msgstr "" + +#: rhodecode/controllers/admin/gists.py:320 +#, python-format +msgid "%(expiry)s - current value" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:71 +msgid "You can't edit this user since it's crucial for entire application" +msgstr "由于是系统帐号,无法编辑该用户" + +#: rhodecode/controllers/admin/my_account.py:129 +msgid "Your account was updated successfully" +msgstr "你的帐号已经更新完成" + +#: rhodecode/controllers/admin/my_account.py:144 +#: rhodecode/controllers/admin/users.py:221 +#, python-format +msgid "Error occurred during update of user %s" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:203 +msgid "Successfully updated password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:214 +msgid "Error occurred during update of user password" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:262 +#: rhodecode/controllers/admin/users.py:614 +#, python-format +msgid "Added new email address `%s` for user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:269 +#: rhodecode/controllers/admin/users.py:621 +msgid "An error occurred during email saving" +msgstr "保存电子邮件时发生错误" + +#: rhodecode/controllers/admin/my_account.py:279 +#: rhodecode/controllers/admin/users.py:636 +msgid "Removed email address from user account" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:317 +#: rhodecode/controllers/admin/users.py:443 +msgid "Role" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:330 +#: rhodecode/controllers/admin/users.py:467 +msgid "Auth token successfully created" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:343 +#: rhodecode/controllers/admin/users.py:486 +msgid "Auth token successfully reset" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:347 +#: rhodecode/controllers/admin/users.py:490 +msgid "Auth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/my_account.py:371 +msgid "OAuth token successfully deleted" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:111 +msgid "Application permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:126 +#: rhodecode/controllers/admin/permissions.py:175 +#: rhodecode/controllers/admin/permissions.py:229 +msgid "Error occurred during update of permissions" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:160 +msgid "Object permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/permissions.py:214 +msgid "Global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:197 +#, python-format +msgid "Created repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:210 +#, python-format +msgid "Error occurred during creation of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:259 +#, python-format +msgid "Updated repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:275 +#, python-format +msgid "Error occurred during update of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:297 +#, python-format +msgid "This group contains %(num)d repository and cannot be deleted" +msgid_plural "This group contains %(num)d repositories and cannot be deleted" +msgstr[0] "" + +#: rhodecode/controllers/admin/repo_groups.py:306 +#, python-format +msgid "This group contains %(num)d subgroup and cannot be deleted" +msgid_plural "This group contains %(num)d subgroups and cannot be deleted" +msgstr[0] "" + +#: rhodecode/controllers/admin/repo_groups.py:313 +#, python-format +msgid "Removed repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:318 +#, python-format +msgid "Error occurred during deletion of repository group %s" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:389 +#: rhodecode/controllers/admin/user_groups.py:323 +msgid "Cannot change permission for yourself as admin" +msgstr "" + +#: rhodecode/controllers/admin/repo_groups.py:406 +msgid "Repository Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:128 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:132 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:264 +#, python-format +msgid "Created repository %s from %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:273 +#, python-format +msgid "Forked repository %s as %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:276 +#, python-format +msgid "Created repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:318 +#, python-format +msgid "Repository %s updated successfully" +msgstr "版本库%s成功更新" + +#: rhodecode/controllers/admin/repos.py:337 +#, python-format +msgid "Error occurred during update of repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:365 +#, python-format +msgid "Detached %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:368 +#, python-format +msgid "Deleted %s forks" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:373 +#, python-format +msgid "Deleted repository %s" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:376 +#, python-format +msgid "Cannot delete %s it still contains attached forks" +msgstr "无法删除%s因为它还有其他分复刻本库" + +#: rhodecode/controllers/admin/repos.py:381 +#, python-format +msgid "An error occurred during deletion of %s" +msgstr "在删除%s的时候发生错误" + +#: rhodecode/controllers/admin/repos.py:435 +msgid "Repository permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:466 +msgid "An error occurred during creation of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:481 +msgid "An error occurred during removal of field" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:520 +msgid "Updated repository visibility in public journal" +msgstr "成功更新在公共日志中的可见性" + +#: rhodecode/controllers/admin/repos.py:524 +msgid "An error occurred during setting this repository in public journal" +msgstr "设置版本库到公共日志时发生错误" + +#: rhodecode/controllers/admin/repos.py:548 +msgid "Nothing" +msgstr "无" + +#: rhodecode/controllers/admin/repos.py:550 +#, python-format +msgid "Marked repo %s as fork of %s" +msgstr "成功将版本库%s标记为复刻自%s" + +#: rhodecode/controllers/admin/repos.py:557 +msgid "An error occurred during this operation" +msgstr "在搜索操作中发生错误" + +#: rhodecode/controllers/admin/repos.py:575 +msgid "Locked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:578 +msgid "Unlocked repository" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:581 +#: rhodecode/controllers/admin/repos.py:610 +msgid "An error occurred during unlocking" +msgstr "解锁时发生错误" + +#: rhodecode/controllers/admin/repos.py:600 +msgid "Unlocked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:604 +msgid "Locked" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:606 +#, python-format +msgid "Repository has been %s" +msgstr "版本库已被%s" + +#: rhodecode/controllers/admin/repos.py:621 +msgid "Cache invalidation successful" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:625 +msgid "An error occurred during cache invalidation" +msgstr "清除缓存时发生错误" + +#: rhodecode/controllers/admin/repos.py:645 +msgid "Pulled from remote location" +msgstr "成功拉取自远程路径" + +#: rhodecode/controllers/admin/repos.py:648 +msgid "An error occurred during pull from remote location" +msgstr "从远程路径拉取时发生错误" + +#: rhodecode/controllers/admin/repos.py:670 +msgid "An error occurred during deletion of repository stats" +msgstr "删除版本库统计时发生错误" + +#: rhodecode/controllers/admin/repos.py:717 +msgid "Error occurred during deleting issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:720 +#: rhodecode/controllers/admin/settings.py:361 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:750 +#: rhodecode/controllers/admin/settings.py:406 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:809 +#: rhodecode/controllers/admin/settings.py:140 +#: rhodecode/controllers/admin/settings.py:686 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/controllers/admin/repos.py:827 +msgid "Error occurred during updating repository VCS settings" +msgstr "" + +#: rhodecode/controllers/admin/repos.py:831 +#: rhodecode/controllers/admin/settings.py:166 +msgid "Updated VCS settings" +msgstr "成功更新版本控制系统设置" + +#: rhodecode/controllers/admin/settings.py:162 +#: rhodecode/controllers/admin/settings.py:265 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:209 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:260 +msgid "Updated application settings" +msgstr "更新应用设置" + +#: rhodecode/controllers/admin/settings.py:325 +msgid "Updated visualisation settings" +msgstr "成功更新可视化设置" + +#: rhodecode/controllers/admin/settings.py:328 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:419 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:437 +msgid "Send email task created" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:470 +msgid "Added new hook" +msgstr "新建钩子" + +#: rhodecode/controllers/admin/settings.py:485 +msgid "Updated hooks" +msgstr "更新钩子" + +#: rhodecode/controllers/admin/settings.py:489 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:536 +#, python-format +msgid "Critical: your disk space is very low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:540 +#, python-format +msgid "Warning: your disk space is running low <b>%s%%</b> usedpercent" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:707 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:711 +msgid "Updated Labs settings" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:775 +msgid "Mercurial server-side merge" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:776 +msgid "" +"Use rebase instead of creating a merge commit when merging via web interface" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:782 +msgid "Subversion HTTP Support" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:783 +msgid "Proxy subversion HTTP requests" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:789 +msgid "Subversion HTTP Server URL" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:791 +msgid "e.g. http://localhost:8080/" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:826 +#: rhodecode/templates/admin/repos/repo_edit.html:48 +msgid "VCS" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:827 +msgid "Visual" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:828 +msgid "Remap and Rescan" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:830 +#: rhodecode/templates/admin/repos/repo_edit.html:54 +msgid "Issue Tracker" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:832 +#: rhodecode/templates/register.html:51 +#: rhodecode/templates/admin/my_account/my_account_profile.html:48 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:94 +#: rhodecode/templates/admin/users/user_add.html:86 +#: rhodecode/templates/admin/users/user_edit_profile.html:65 +#: rhodecode/templates/admin/users/users.html:91 +#: rhodecode/templates/users/user_profile.html:51 +msgid "Email" +msgstr "电子邮件" + +#: rhodecode/controllers/admin/settings.py:833 +msgid "Hooks" +msgstr "钩子" + +#: rhodecode/controllers/admin/settings.py:834 +msgid "Full Text Search" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:836 +#: rhodecode/templates/admin/settings/settings_system.html:47 +msgid "System Info" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:838 +msgid "Open Source Licenses" +msgstr "" + +#: rhodecode/controllers/admin/settings.py:856 +msgid "Labs" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:167 +#, python-format +msgid "Created user group %(user_group_link)s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:181 +#, python-format +msgid "Error occurred during creation of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:221 +#, python-format +msgid "Updated user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:236 +#, python-format +msgid "Error occurred during update of user group %s" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:258 +msgid "Successfully deleted user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:263 +msgid "An error occurred during deletion of user group" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:331 +msgid "Target group cannot be the same" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:337 +msgid "User Group permissions updated" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:422 +msgid "User Group global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/user_groups.py:438 +#: rhodecode/controllers/admin/users.py:564 +msgid "An error occurred during permissions saving" +msgstr "保存权限时发生错误" + +#: rhodecode/controllers/admin/users.py:147 +#, python-format +msgid "Created user %(user_link)s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:162 +#, python-format +msgid "Error occurred during creation of user %s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:206 +msgid "User updated successfully" +msgstr "用户更新成功" + +#: rhodecode/controllers/admin/users.py:255 +#, python-format +msgid "Detached %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:260 +#, python-format +msgid "Deleted %s repositories" +msgstr "" + +#: rhodecode/controllers/admin/users.py:268 +#, python-format +msgid "Detached %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:273 +#, python-format +msgid "Deleted %s repository groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:281 +#, python-format +msgid "Detached %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:286 +#, python-format +msgid "Deleted %s user groups" +msgstr "" + +#: rhodecode/controllers/admin/users.py:297 +msgid "Successfully deleted user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:303 +msgid "An error occurred during deletion of user" +msgstr "删除用户时发生错误" + +#: rhodecode/controllers/admin/users.py:322 +msgid "Force password change disabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:324 +msgid "Force password change enabled for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:328 +msgid "An error occurred during password reset for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:354 +#, python-format +msgid "Created repository group `%s`" +msgstr "" + +#: rhodecode/controllers/admin/users.py:358 +msgid "An error occurred during repository group creation for user" +msgstr "" + +#: rhodecode/controllers/admin/users.py:377 +#: rhodecode/controllers/admin/users.py:398 +#: rhodecode/controllers/admin/users.py:428 +#: rhodecode/controllers/admin/users.py:459 +#: rhodecode/controllers/admin/users.py:476 +#: rhodecode/controllers/admin/users.py:499 +#: rhodecode/controllers/admin/users.py:573 +#: rhodecode/controllers/admin/users.py:586 +#: rhodecode/controllers/admin/users.py:644 +msgid "You can't edit this user" +msgstr "无法编辑该用户" + +#: rhodecode/controllers/admin/users.py:412 +msgid "" +"The user participates as reviewer in pull requests and cannot be deleted. " +"You can set the user to \"inactive\" instead of deleting it." +msgstr "" + +#: rhodecode/controllers/admin/users.py:548 +msgid "User global permissions updated successfully" +msgstr "" + +#: rhodecode/controllers/admin/users.py:676 +#, python-format +msgid "An error occurred during ip saving:%s" +msgstr "" + +#: rhodecode/controllers/admin/users.py:691 +msgid "An error occurred during ip saving" +msgstr "" + +#: rhodecode/controllers/admin/users.py:695 +#, python-format +msgid "Added ips %s to user whitelist" +msgstr "" + +#: rhodecode/controllers/admin/users.py:713 +msgid "Removed ip address from user whitelist" +msgstr "" + +#: rhodecode/lib/action_parser.py:89 +msgid "[deleted] repository" +msgstr "[删除]版本库" + +#: rhodecode/lib/action_parser.py:92 rhodecode/lib/action_parser.py:110 +msgid "[created] repository" +msgstr "[创建]版本库" + +#: rhodecode/lib/action_parser.py:95 +msgid "[created] repository as fork" +msgstr "[创建]复刻版本库" + +#: rhodecode/lib/action_parser.py:98 rhodecode/lib/action_parser.py:113 +msgid "[forked] repository" +msgstr "[复刻]版本库" + +#: rhodecode/lib/action_parser.py:101 rhodecode/lib/action_parser.py:116 +msgid "[updated] repository" +msgstr "[更新]版本库" + +#: rhodecode/lib/action_parser.py:104 +msgid "[downloaded] archive from repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:107 +msgid "[delete] repository" +msgstr "[删除]版本库" + +#: rhodecode/lib/action_parser.py:119 +msgid "[created] user" +msgstr "[创建]用户" + +#: rhodecode/lib/action_parser.py:122 +msgid "[updated] user" +msgstr "[更新]用户" + +#: rhodecode/lib/action_parser.py:125 +msgid "[created] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:128 +msgid "[updated] user group" +msgstr "" + +#: rhodecode/lib/action_parser.py:131 +msgid "[commented] on commit in repository" +msgstr "" + +#: rhodecode/lib/action_parser.py:134 +msgid "[commented] on pull request for" +msgstr "[评论]拉取请求" + +#: rhodecode/lib/action_parser.py:137 +msgid "[closed] pull request for" +msgstr "[关闭] 拉取请求" + +#: rhodecode/lib/action_parser.py:140 +msgid "[merged] pull request for" +msgstr "" + +#: rhodecode/lib/action_parser.py:143 +msgid "[pushed] into" +msgstr "[推送]到" + +#: rhodecode/lib/action_parser.py:146 +msgid "[committed via RhodeCode] into repository" +msgstr "[通过RhodeCode提交]到版本库" + +#: rhodecode/lib/action_parser.py:149 +msgid "[pulled from remote] into repository" +msgstr "[远程拉取]到版本库" + +#: rhodecode/lib/action_parser.py:152 +msgid "[pulled] from" +msgstr "[拉取]自" + +#: rhodecode/lib/action_parser.py:155 +msgid "[started following] repository" +msgstr "[开始关注]版本库" + +#: rhodecode/lib/action_parser.py:158 +msgid "[stopped following] repository" +msgstr "[停止关注]版本库" + +#: rhodecode/lib/action_parser.py:166 +#, python-format +msgid "fork name %s" +msgstr "复刻名称%s" + +#: rhodecode/lib/action_parser.py:183 +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +#, python-format +msgid "Pull request #%s" +msgstr "拉取请求#%s" + +#: rhodecode/lib/action_parser.py:216 +#, python-format +msgid "Show all combined commits %s->%s" +msgstr "" + +#: rhodecode/lib/action_parser.py:220 +msgid "compare view" +msgstr "比较显示" + +#: rhodecode/lib/action_parser.py:227 +#, python-format +msgid " and %(num)s more commits" +msgstr "" + +#: rhodecode/lib/action_parser.py:279 +#, python-format +msgid "Deleted branch: %s" +msgstr "已经删除分支%s" + +#: rhodecode/lib/action_parser.py:282 +#, python-format +msgid "Created tag: %s" +msgstr "创建标签%s" + +#: rhodecode/lib/action_parser.py:295 +msgid "Commit not found" +msgstr "" + +#: rhodecode/lib/auth.py:1106 +#, python-format +msgid "IP %s not allowed" +msgstr "" + +#: rhodecode/lib/auth.py:1180 +msgid "You need to be a registered user to perform this action" +msgstr "必须是注册用户才能进行此操作" + +#: rhodecode/lib/auth.py:1227 +#, python-format +msgid "Action not supported for %s." +msgstr "" + +#: rhodecode/lib/auth.py:1264 +msgid "You need to be signed in to view this page" +msgstr "" + +#: rhodecode/lib/base.py:513 +#, python-format +msgid "The repository at %(repo_name)s cannot be located." +msgstr "" + +#: rhodecode/lib/diffs.py:71 +msgid "Binary file" +msgstr "" + +#: rhodecode/lib/diffs.py:91 +msgid "" +"Changeset was too big and was cut off, use diff menu to display this diff" +msgstr "修订集因过大而被截断,可查看原始修订集作为替代" + +#: rhodecode/lib/diffs.py:102 +msgid "No changes detected" +msgstr "未发现差异" + +#: rhodecode/lib/helpers.py:1246 +#, python-format +msgid " and %s more" +msgstr "还有%s个" + +#: rhodecode/lib/helpers.py:1250 +msgid "No Files" +msgstr "没有文件" + +#: rhodecode/lib/helpers.py:1323 +msgid "new file" +msgstr "" + +#: rhodecode/lib/helpers.py:1326 +msgid "mod" +msgstr "" + +#: rhodecode/lib/helpers.py:1329 +msgid "del" +msgstr "" + +#: rhodecode/lib/helpers.py:1332 +msgid "rename" +msgstr "" + +#: rhodecode/lib/helpers.py:1337 +msgid "chmod" +msgstr "" + +#: rhodecode/lib/helpers.py:1579 +msgid "" +"Example filter terms:\n" +" repository:vcs\n" +" username:marcin\n" +" action:*push*\n" +" ip:127.0.0.1\n" +" date:20120101\n" +" date:[20120101100000 TO 20120102]\n" +"\n" +"Generate wildcards using '*' character:\n" +" \"repository:vcs*\" - search everything starting with 'vcs'\n" +" \"repository:*vcs*\" - search for repository containing 'vcs'\n" +"\n" +"Optional AND / OR operators in queries\n" +" \"repository:vcs OR repository:test\"\n" +" \"username:test AND repository:test*\"\n" +msgstr "" + +#: rhodecode/lib/helpers.py:1599 +#, python-format +msgid "" +"%s repository is not mapped to db perhaps it was created or renamed from the" +" filesystem please run the application again in order to rescan repositories" +msgstr "版本库%s没有映射到数据库,可能是从文件系统创建或者重命名,请重启RhodeCode以重新扫描版本库" + +#: rhodecode/lib/utils2.py:446 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d年" + +#: rhodecode/lib/utils2.py:447 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d月" + +#: rhodecode/lib/utils2.py:448 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d天" + +#: rhodecode/lib/utils2.py:449 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "%d时" + +#: rhodecode/lib/utils2.py:450 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "%d分" + +#: rhodecode/lib/utils2.py:451 +#, python-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "%d秒" + +#: rhodecode/lib/utils2.py:469 +#, python-format +msgid "in %s" +msgstr "%s" + +#: rhodecode/lib/utils2.py:475 +#, python-format +msgid "%s ago" +msgstr "%s前" + +#: rhodecode/lib/utils2.py:485 +#, python-format +msgid "%s, %s ago" +msgstr "" + +#: rhodecode/lib/utils2.py:487 +#, python-format +msgid "in %s, %s" +msgstr "" + +#: rhodecode/lib/utils2.py:489 +#, python-format +msgid "%s and %s" +msgstr "" + +#: rhodecode/lib/utils2.py:491 +#, python-format +msgid "%s and %s ago" +msgstr "%s零%s前" + +#: rhodecode/lib/utils2.py:493 +#, python-format +msgid "in %s and %s" +msgstr "%s零%s" + +#: rhodecode/lib/utils2.py:497 +msgid "just now" +msgstr "刚才" + +#: rhodecode/lib/auth_modules/__init__.py:690 +msgid "This provider is currently disabled" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:708 +msgid "Your external identity is now connected with your account" +msgstr "" + +#: rhodecode/lib/auth_modules/__init__.py:712 +msgid "" +"No external user id found? Perhaps permissionsfor authentication are set " +"incorrectly" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:60 +msgid "The FQDN or IP of the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:61 +msgid "Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:66 +msgid "The Port in use by the Atlassian CROWD Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:67 +#: rhodecode/lib/auth_modules/auth_ldap.py:81 +msgid "Port" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:73 +msgid "The Application Name to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:74 +msgid "Application Name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:79 +msgid "The password to authenticate to CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:80 +msgid "Application Password" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:85 +msgid "" +"A comma separated list of group names that identify users as RhodeCode " +"Administrators" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:88 +msgid "Admin Groups" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_crowd.py:208 +msgid "CROWD" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:63 +msgid "The url of the Jasig CAS REST service" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:64 +#: rhodecode/templates/admin/gists/show.html:21 +msgid "URL" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_jasig_cas.py:90 +msgid "Jasig-CAS" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:74 +msgid "Host of the LDAP Server" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:75 +msgid "LDAP Host" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:80 +msgid "Port that the LDAP server is listening on" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:87 +msgid "User to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:89 +msgid "Account" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:94 +msgid "Password to connect to LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:96 +#: rhodecode/templates/login.html:45 rhodecode/templates/register.html:43 +#: rhodecode/templates/admin/my_account/my_account.html:30 +#: rhodecode/templates/admin/users/user_add.html:44 +#: rhodecode/templates/base/base.html:312 +#: rhodecode/templates/debug_style/login.html:45 +msgid "Password" +msgstr "密码" + +#: rhodecode/lib/auth_modules/auth_ldap.py:101 +msgid "TLS Type" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:102 +msgid "Connection Security" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:108 +msgid "Require Cert over TLS?" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:109 +msgid "Certificate Checks" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:115 +msgid "Base DN to search (e.g., dc=mydomain,dc=com)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:117 +msgid "Base DN" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:122 +msgid "Filter to narrow results (e.g., ou=Users, etc)" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:124 +msgid "LDAP Search Filter" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:129 +msgid "How deep to search LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:130 +msgid "LDAP Search Scope" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:136 +msgid "LDAP Attribute to map to user name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:137 +msgid "Login Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:138 +msgid "The LDAP Login attribute of the CN must be specified" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:143 +msgid "LDAP Attribute to map to first name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:145 +msgid "First Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:150 +msgid "LDAP Attribute to map to last name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:152 +msgid "Last Name Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:157 +msgid "LDAP Attribute to map to email address" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:159 +msgid "Email Attribute" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_ldap.py:335 +msgid "LDAP" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:60 +msgid "PAM service name to use for authentication." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:61 +msgid "PAM service name" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:66 +msgid "" +"Regular expression for extracting user name/email etc. from Unix userinfo." +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:68 +msgid "Gecos Regex" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_pam.py:94 +msgid "PAM" +msgstr "" + +#: rhodecode/lib/auth_modules/auth_rhodecode.py:66 +msgid "Rhodecode" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:819 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 rhodecode/model/db.py:2243 +msgid "Repository no access" +msgstr "无版本库访问权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:768 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974 rhodecode/model/db.py:2244 +msgid "Repository read access" +msgstr "版本库读取权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:572 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 rhodecode/model/db.py:2245 +msgid "Repository write access" +msgstr "版本库写入权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:602 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:660 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:720 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 rhodecode/model/db.py:2246 +msgid "Repository admin access" +msgstr "版本库管理权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604 +msgid "Repositories Group no access" +msgstr "无版本库组访问权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605 +msgid "Repositories Group read access" +msgstr "版本库组读取权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:577 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606 +msgid "Repositories Group write access" +msgstr "版本库组写入" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:590 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:607 +msgid "Repositories Group admin access" +msgstr "版本库组管理权限" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:655 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:657 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738 +msgid "RhodeCode Administrator" +msgstr "RhodeCode 管理员" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:840 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 rhodecode/model/db.py:2264 +msgid "Repository creation disabled" +msgstr "禁用创建版本库" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:679 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:704 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:739 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:760 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:799 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995 rhodecode/model/db.py:2265 +msgid "Repository creation enabled" +msgstr "允许创建版本库" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 rhodecode/model/db.py:2269 +msgid "Repository forking disabled" +msgstr "禁用复刻版本库" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:682 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/model/db.py:2270 +msgid "Repository forking enabled" +msgstr "允许复刻版本库" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:585 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:699 +msgid "Register disabled" +msgstr "禁用注册" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:586 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:598 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:615 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700 +msgid "Register new user with RhodeCode with manual activation" +msgstr "用手动激活注册新用户" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:589 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:601 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:618 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:703 +msgid "Register new user with RhodeCode with auto activation" +msgstr "用自动激活注册新用户" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1179 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1188 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/model/db.py:2900 +msgid "Not Reviewed" +msgstr "未检视" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1077 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1080 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1091 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1094 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1124 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1138 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1180 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1189 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1199 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1321 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1346 +#: rhodecode/model/db.py:2901 +msgid "Approved" +msgstr "已批准" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:847 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1078 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1081 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1092 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1095 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1125 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1139 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1181 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1190 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1200 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1322 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1347 +#: rhodecode/model/db.py:2902 +msgid "Rejected" +msgstr "驳回" + +#: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:868 +#: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:877 +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:962 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:998 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1023 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1024 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1041 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1058 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1079 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1082 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1093 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1096 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1126 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1140 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1183 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1182 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1191 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1201 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1323 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1348 +#: rhodecode/model/db.py:2903 +msgid "Under Review" +msgstr "检视中" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 rhodecode/model/db.py:2248 +msgid "Repository group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:741 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:773 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979 rhodecode/model/db.py:2249 +msgid "Repository group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 rhodecode/model/db.py:2250 +msgid "Repository group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:665 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:708 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:725 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 rhodecode/model/db.py:2251 +msgid "Repository group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:829 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 rhodecode/model/db.py:2253 +msgid "User group no access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:778 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:788 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984 rhodecode/model/db.py:2254 +msgid "User group read access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 rhodecode/model/db.py:2255 +msgid "User group write access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:670 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:695 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:696 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:730 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:832 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:833 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 rhodecode/model/db.py:2256 +msgid "User group admin access" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 rhodecode/model/db.py:2258 +msgid "Repository Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:673 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:698 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:699 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:716 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:733 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:835 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:836 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 rhodecode/model/db.py:2259 +msgid "Repository Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 rhodecode/model/db.py:2261 +msgid "User Group creation disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:676 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:678 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:701 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:702 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:719 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:736 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 rhodecode/model/db.py:2262 +msgid "User Group creation enabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:767 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:796 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:806 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002 +#: rhodecode/model/db.py:2272 +msgid "Registration disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/model/db.py:2273 +msgid "User Registration with manual account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:686 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:711 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:712 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:729 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:746 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:851 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/model/db.py:2274 +msgid "User Registration with automatic account activation" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:768 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:771 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:773 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/model/db.py:2276 +msgid "Manual activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:689 +#: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:691 +#: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:714 +#: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:715 +#: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:732 +#: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:749 +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:769 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:772 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:774 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:853 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:854 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/model/db.py:2277 +msgid "Automatic activation of external account" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 rhodecode/model/db.py:2266 +msgid "" +"Repository creation enabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759 +#: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:843 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:844 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 rhodecode/model/db.py:2267 +msgid "" +"Repository creation disabled with write permission to a repository group" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738 +#: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 rhodecode/model/db.py:2241 +msgid "RhodeCode Super Administrator" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:813 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:855 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:862 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:984 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1009 +#: rhodecode/model/db.py:2279 +msgid "Inherit object permissions from default user disabled" +msgstr "" + +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:814 +#: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:856 +#: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:857 +#: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:863 +#: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1010 +#: rhodecode/model/db.py:2280 +msgid "Inherit object permissions from default user enabled" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:129 +msgid "Invalid search query. Try quoting it." +msgstr "错误的搜索。请尝试用引号包含它。" + +#: rhodecode/lib/index/whoosh.py:131 +msgid "There is no index to search in. Please run whoosh indexer" +msgstr "没有索引用于搜索。请运行whoosh索引器" + +#: rhodecode/lib/index/whoosh.py:136 +msgid "An error occurred during this search operation" +msgstr "在搜索操作中发生异常" + +#: rhodecode/lib/index/whoosh.py:144 +msgid "Index Type" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:145 +msgid "File Index" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:146 rhodecode/lib/index/whoosh.py:151 +msgid "Indexed documents" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:148 rhodecode/lib/index/whoosh.py:153 +msgid "Last update" +msgstr "" + +#: rhodecode/lib/index/whoosh.py:150 +msgid "Commit index" +msgstr "" + +#: rhodecode/model/db.py:871 +msgid "all" +msgstr "" + +#: rhodecode/model/db.py:872 +msgid "http/web interface" +msgstr "" + +#: rhodecode/model/db.py:873 +msgid "vcs (git/hg protocol)" +msgstr "" + +#: rhodecode/model/db.py:874 +msgid "api calls" +msgstr "" + +#: rhodecode/model/db.py:875 +msgid "feed access" +msgstr "" + +#: rhodecode/model/db.py:2020 +msgid "No parent" +msgstr "" + +#: rhodecode/model/forms.py:66 +msgid "Please enter a login" +msgstr "请登录" + +#: rhodecode/model/forms.py:67 +#, python-format +msgid "Enter a value %(min)i characters long or more" +msgstr "输入一个不少于%(min)i个字符的值" + +#: rhodecode/model/forms.py:76 +msgid "Please enter a password" +msgstr "请输入密码" + +#: rhodecode/model/forms.py:77 +#, python-format +msgid "Enter %(min)i characters or more" +msgstr "输入少于%(min)i个字符" + +#: rhodecode/model/notification.py:247 +#, python-format +msgid "%(user)s commented on commit %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:248 +#, python-format +msgid "%(user)s commented on commit at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:251 +#, python-format +msgid "%(user)s sent message %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:252 +#, python-format +msgid "%(user)s sent message at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:255 +#, python-format +msgid "%(user)s mentioned you %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:256 +#, python-format +msgid "%(user)s mentioned you at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:259 +#, python-format +msgid "%(user)s registered in RhodeCode %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:260 +#, python-format +msgid "%(user)s registered in RhodeCode at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:263 +#, python-format +msgid "%(user)s opened new pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:264 +#, python-format +msgid "%(user)s opened new pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:267 +#, python-format +msgid "%(user)s commented on pull request %(date_or_age)s" +msgstr "" + +#: rhodecode/model/notification.py:268 +#, python-format +msgid "%(user)s commented on pull request at %(date_or_age)s" +msgstr "" + +#: rhodecode/model/pull_request.py:69 +msgid "This pull request can be automatically merged." +msgstr "" + +#: rhodecode/model/pull_request.py:71 +msgid "This pull request cannot be merged because of an unhandled exception." +msgstr "" + +#: rhodecode/model/pull_request.py:74 +msgid "This pull request cannot be merged because of conflicts." +msgstr "" + +#: rhodecode/model/pull_request.py:76 +msgid "This pull request could not be merged because push to target failed." +msgstr "" + +#: rhodecode/model/pull_request.py:79 +msgid "This pull request cannot be merged because the target is not a head." +msgstr "" + +#: rhodecode/model/pull_request.py:82 +msgid "" +"This pull request cannot be merged because the source contains more branches" +" than the target." +msgstr "" + +#: rhodecode/model/pull_request.py:85 +msgid "" +"This pull request cannot be merged because the target has multiple heads." +msgstr "" + +#: rhodecode/model/pull_request.py:88 +msgid "" +"This pull request cannot be merged because the target repository is locked." +msgstr "" + +#: rhodecode/model/pull_request.py:91 +msgid "" +"This pull request cannot be merged because the target or the source " +"reference is missing." +msgstr "" + +#: rhodecode/model/pull_request.py:411 +#, python-format +msgid "" +"Merge pull request #%(pr_id)s from %(source_repo)s %(source_ref_name)s\n" +"\n" +" %(pr_title)s" +msgstr "" + +#: rhodecode/model/pull_request.py:443 +msgid "Pull request merged and closed" +msgstr "" + +#: rhodecode/model/pull_request.py:859 +msgid "Server-side pull request merging is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:861 +msgid "This pull request is closed." +msgstr "" + +#: rhodecode/model/pull_request.py:872 +msgid "Pull request merging is not supported." +msgstr "" + +#: rhodecode/model/pull_request.py:890 +msgid "Target repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:893 +msgid "Source repository large files support is disabled." +msgstr "" + +#: rhodecode/model/pull_request.py:1036 rhodecode/model/scm.py:791 +msgid "Bookmarks" +msgstr "书签" + +#: rhodecode/model/pull_request.py:1041 +msgid "Commit IDs" +msgstr "" + +#: rhodecode/model/pull_request.py:1044 +msgid "Closed Branches" +msgstr "" + +#: rhodecode/model/scm.py:773 +msgid "latest tip" +msgstr "最新tip版本" + +#: rhodecode/model/user.py:124 +msgid "You can't Edit this user since it's crucial for entire application" +msgstr "由于是系统帐号,无法编辑该用户" + +#: rhodecode/model/user.py:283 +#, python-format +msgid "" +"You can't edit this user (`%(username)s`) since it's crucial for entire " +"application" +msgstr "" + +#: rhodecode/model/user.py:456 +msgid "You can't remove this user since it's crucial for entire application" +msgstr "由于是系统帐号,无法删除该用户" + +#: rhodecode/model/user.py:464 +#, python-format +msgid "" +"user \"%s\" still owns %s repositories and cannot be removed. Switch owners " +"or remove those repositories:%s" +msgstr "" + +#: rhodecode/model/user.py:473 +#, python-format +msgid "" +"user \"%s\" still owns %s repository groups and cannot be removed. Switch " +"owners or remove those repository groups:%s" +msgstr "" + +#: rhodecode/model/user.py:482 +#, python-format +msgid "" +"user \"%s\" still owns %s user groups and cannot be removed. Switch owners " +"or remove those user groups:%s" +msgstr "" + +#: rhodecode/model/validators.py:96 rhodecode/model/validators.py:97 +msgid "Value cannot be an empty list" +msgstr "值不能为空" + +#: rhodecode/model/validators.py:140 +msgid "Pattern already exists" +msgstr "" + +#: rhodecode/model/validators.py:158 +#, python-format +msgid "Username \"%(username)s\" already exists" +msgstr "用户名称%(username)s已经存在" + +#: rhodecode/model/validators.py:160 +#, python-format +msgid "Username \"%(username)s\" is forbidden" +msgstr "不允许用户名 \"%(username)s\"" + +#: rhodecode/model/validators.py:162 +msgid "" +"Username may only contain alphanumeric characters underscores, periods or " +"dashes and must begin with alphanumeric character or underscore" +msgstr "" + +#: rhodecode/model/validators.py:190 +msgid "The input is not valid" +msgstr "" + +#: rhodecode/model/validators.py:197 +#, python-format +msgid "Username %(username)s is not valid" +msgstr "用户名称 %(username)s 无效" + +#: rhodecode/model/validators.py:216 +msgid "Invalid user group name" +msgstr "" + +#: rhodecode/model/validators.py:217 +#, python-format +msgid "User group \"%(usergroup)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:219 +msgid "" +"user group name may only contain alphanumeric characters underscores, " +"periods or dashes and must begin with alphanumeric character" +msgstr "" + +#: rhodecode/model/validators.py:257 +msgid "Cannot assign this group as parent" +msgstr "不能将这个组作为parent" + +#: rhodecode/model/validators.py:258 +#, python-format +msgid "Group \"%(group_name)s\" already exists" +msgstr "组 \"%(group_name)s\" 已经存在" + +#: rhodecode/model/validators.py:259 +#, python-format +msgid "Repository with name \"%(group_name)s\" already exists" +msgstr "已经存在名为 \"%(group_name)s\" 的版本库" + +#: rhodecode/model/validators.py:261 +msgid "no permission to store repository groupin this location" +msgstr "" + +#: rhodecode/model/validators.py:263 +msgid "no permission to store repository group in root location" +msgstr "" + +#: rhodecode/model/validators.py:379 +msgid "Invalid characters (non-ascii) in password" +msgstr "密码含有无效(非ASCII)字符" + +#: rhodecode/model/validators.py:394 +msgid "Invalid old password" +msgstr "" + +#: rhodecode/model/validators.py:412 +msgid "Passwords do not match" +msgstr "密码不符" + +#: rhodecode/model/validators.py:430 +msgid "invalid password" +msgstr "无效密码" + +#: rhodecode/model/validators.py:431 +msgid "invalid user name" +msgstr "无效用户名" + +#: rhodecode/model/validators.py:432 +msgid "Your account is disabled" +msgstr "该帐号已被禁用" + +#: rhodecode/model/validators.py:465 +msgid "Token mismatch" +msgstr "令牌不匹配" + +#: rhodecode/model/validators.py:479 +#, python-format +msgid "Repository name %(repo)s is disallowed" +msgstr "版本库名称不能为%(repo)s" + +#: rhodecode/model/validators.py:481 +#, python-format +msgid "Repository with name %(repo)s already exists" +msgstr "" + +#: rhodecode/model/validators.py:483 +#, python-format +msgid "Repository group with name \"%(repo)s\" already exists" +msgstr "" + +#: rhodecode/model/validators.py:486 +#, python-format +msgid "Repository with name %(repo)s exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:488 +#, python-format +msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" +msgstr "" + +#: rhodecode/model/validators.py:615 +#, python-format +msgid "invalid clone url for %(rtype)s repository" +msgstr "" + +#: rhodecode/model/validators.py:616 +#, python-format +msgid "" +"Invalid clone url, provide a valid clone url starting with one of " +"%(allowed_prefixes)s" +msgstr "" + +#: rhodecode/model/validators.py:645 +msgid "Fork have to be the same type as parent" +msgstr "复刻版本库必须和父版本库类型相同" + +#: rhodecode/model/validators.py:660 +msgid "You do not have the permission to create repositories in this group." +msgstr "" + +#: rhodecode/model/validators.py:663 +msgid "" +"You do not have the permission to store repositories in the root location." +msgstr "" + +#: rhodecode/model/validators.py:723 +msgid "This username or user group name is not valid" +msgstr "" + +#: rhodecode/model/validators.py:841 +msgid "This is not a valid path" +msgstr "不是一个合法的路径" + +#: rhodecode/model/validators.py:856 +msgid "This e-mail address is already taken" +msgstr "该邮件地址已被使用" + +#: rhodecode/model/validators.py:876 +#, python-format +msgid "e-mail \"%(email)s\" does not exist." +msgstr "邮件地址\"%(email)s\"不存在" + +#: rhodecode/model/validators.py:912 +msgid "" +"The LDAP Login attribute of the CN must be specified - this is the name of " +"the attribute that is equivalent to \"username\"" +msgstr "LDAP 登陆属性的 CN 必须指定 - 这个名字作为用户名" + +#: rhodecode/model/validators.py:926 +#, python-format +msgid "Revisions %(revs)s are already part of pull request or have set status" +msgstr "修订%(revs)s已经包含在拉取请求中或者或者已经设置状态" + +#: rhodecode/model/validators.py:957 +msgid "Please enter a valid IPv4 or IpV6 address" +msgstr "" + +#: rhodecode/model/validators.py:958 +#, python-format +msgid "" +"The network size (bits) must be within the range of 0-32 (not %(bits)r)" +msgstr "" + +#: rhodecode/model/validators.py:985 +msgid "Key name can only consist of letters, underscore, dash or numbers" +msgstr "" + +#: rhodecode/model/validators.py:1000 +msgid "Filename cannot be inside a directory" +msgstr "" + +#: rhodecode/model/validators.py:1016 +#, python-format +msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" +msgstr "" + +#: rhodecode/model/validators.py:1048 +msgid "This gistid is already in use" +msgstr "" + +#: rhodecode/templates/index.html:5 +msgid "Dashboard" +msgstr "控制面板" + +#: rhodecode/templates/index_base.html:8 +#: rhodecode/templates/admin/gists/index.html:18 +#: rhodecode/templates/admin/my_account/my_account_repos.html:7 +#: rhodecode/templates/admin/my_account/my_account_watched.html:7 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:12 +#: rhodecode/templates/admin/repos/repos.html:12 +#: rhodecode/templates/admin/user_groups/user_groups.html:12 +#: rhodecode/templates/admin/users/users.html:12 +#: rhodecode/templates/bookmarks/bookmarks.html:12 +#: rhodecode/templates/branches/branches.html:12 +#: rhodecode/templates/journal/journal.html:12 +#: rhodecode/templates/tags/tags.html:12 +msgid "quick filter..." +msgstr "快速过滤..." + +#: rhodecode/templates/index_base.html:10 +msgid "matches" +msgstr "" + +#: rhodecode/templates/index_base.html:30 +#: rhodecode/templates/index_base.html:39 +#: rhodecode/templates/admin/repos/repo_add.html:22 +#: rhodecode/templates/admin/repos/repos.html:27 +msgid "Add Repository" +msgstr "" + +#: rhodecode/templates/index_base.html:34 +#: rhodecode/templates/index_base.html:42 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:16 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:27 +msgid "Add Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "You have admin right to this group, and can edit it" +msgstr "" + +#: rhodecode/templates/index_base.html:45 +msgid "Edit Repository Group" +msgstr "" + +#: rhodecode/templates/index_base.html:97 +#: rhodecode/templates/index_base.html:122 +#: rhodecode/templates/admin/gists/index.html:112 +#: rhodecode/templates/admin/my_account/my_account_repos.html:31 +#: rhodecode/templates/admin/my_account/my_account_watched.html:31 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:53 +#: rhodecode/templates/admin/repos/repo_add_base.html:9 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:12 +#: rhodecode/templates/admin/repos/repos.html:54 +#: rhodecode/templates/admin/user_groups/user_groups.html:55 +#: rhodecode/templates/base/perms_summary.html:103 +#: rhodecode/templates/bookmarks/bookmarks.html:59 +#: rhodecode/templates/branches/branches.html:58 +#: rhodecode/templates/files/files_browser.html:49 +#: rhodecode/templates/pullrequests/pullrequests.html:100 +#: rhodecode/templates/tags/tags.html:59 +msgid "Name" +msgstr "名称" + +#: rhodecode/templates/index_base.html:100 +#: rhodecode/templates/index_base.html:125 +#: rhodecode/templates/admin/gists/index.html:114 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:77 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:45 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:30 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:56 +#: rhodecode/templates/admin/repos/repo_add_base.html:32 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:29 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:83 +#: rhodecode/templates/admin/repos/repos.html:57 +#: rhodecode/templates/admin/user_groups/user_group_add.html:43 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:29 +#: rhodecode/templates/admin/user_groups/user_groups.html:57 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:74 +#: rhodecode/templates/base/issue_tracker_settings.html:10 +#: rhodecode/templates/changeset/changeset.html:53 +#: rhodecode/templates/compare/compare_cs.html:24 +#: rhodecode/templates/email_templates/pull_request_review.mako:30 +#: rhodecode/templates/email_templates/pull_request_review.mako:67 +#: rhodecode/templates/files/file_tree_detail.html:5 +#: rhodecode/templates/files/file_tree_detail.html:12 +#: rhodecode/templates/forks/fork.html:48 +#: rhodecode/templates/forks/forks_data.html:8 +#: rhodecode/templates/pullrequests/pullrequest.html:47 +#: rhodecode/templates/pullrequests/pullrequest_show.html:122 +#: rhodecode/templates/summary/components.html:73 +msgid "Description" +msgstr "描述" + +#: rhodecode/templates/index_base.html:102 +#: rhodecode/templates/index_base.html:133 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:5 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:21 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:60 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:5 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:74 +#: rhodecode/templates/admin/repos/repos.html:65 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:5 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:20 +#: rhodecode/templates/admin/user_groups/user_groups.html:64 +#: rhodecode/templates/summary/components.html:195 +msgid "Owner" +msgstr "所有者" + +#: rhodecode/templates/index_base.html:128 +#: rhodecode/templates/admin/repos/repos.html:60 +msgid "Last Change" +msgstr "最后修改" + +#: rhodecode/templates/index_base.html:131 +#: rhodecode/templates/admin/my_account/my_account_repos.html:35 +#: rhodecode/templates/admin/my_account/my_account_watched.html:35 +#: rhodecode/templates/admin/repos/repos.html:63 +#: rhodecode/templates/bookmarks/bookmarks.html:66 +#: rhodecode/templates/branches/branches.html:65 +#: rhodecode/templates/changelog/changelog.html:106 +#: rhodecode/templates/changelog/changelog_summary_data.html:6 +#: rhodecode/templates/changeset/changeset.html:36 +#: rhodecode/templates/compare/compare_cs.html:22 +#: rhodecode/templates/email_templates/commit_comment.mako:16 +#: rhodecode/templates/email_templates/commit_comment.mako:45 +#: rhodecode/templates/search/search_commit.html:6 +#: rhodecode/templates/tags/tags.html:66 +msgid "Commit" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:5 +#, python-format +msgid "%s Repository group dashboard" +msgstr "" + +#: rhodecode/templates/index_repo_group.html:13 +msgid "Home" +msgstr "首页" + +#: rhodecode/templates/login.html:6 rhodecode/templates/login.html:36 +#: rhodecode/templates/login.html:52 rhodecode/templates/base/base.html:326 +#: rhodecode/templates/debug_style/login.html:60 +msgid "Sign In" +msgstr "登录" + +#: rhodecode/templates/login.html:38 +msgid "Go to the registration page to create a new account." +msgstr "" + +#: rhodecode/templates/login.html:43 rhodecode/templates/register.html:41 +#: rhodecode/templates/admin/admin_log.html:5 +#: rhodecode/templates/admin/my_account/my_account_profile.html:24 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:21 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:66 +#: rhodecode/templates/admin/users/user_add.html:35 +#: rhodecode/templates/admin/users/user_edit_profile.html:39 +#: rhodecode/templates/admin/users/users.html:89 +#: rhodecode/templates/base/base.html:303 +#: rhodecode/templates/debug_style/login.html:36 +#: rhodecode/templates/users/user_profile.html:27 +msgid "Username" +msgstr "帐号" + +#: rhodecode/templates/login.html:48 +msgid "Remember me" +msgstr "记住密码" + +#: rhodecode/templates/login.html:50 +msgid "Forgot your password?" +msgstr "" + +#: rhodecode/templates/login.html:62 +msgid "Sign In using one of external services" +msgstr "" + +#: rhodecode/templates/password_reset.html:5 +#: rhodecode/templates/register.html:6 +msgid "Create an Account" +msgstr "" + +#: rhodecode/templates/password_reset.html:35 +msgid "Reset your Password" +msgstr "" + +#: rhodecode/templates/password_reset.html:36 +msgid "Go to the login page to sign in." +msgstr "" + +#: rhodecode/templates/password_reset.html:40 +msgid "Email Address" +msgstr "" + +#: rhodecode/templates/password_reset.html:45 +#: rhodecode/templates/register.html:56 +msgid "Captcha" +msgstr "" + +#: rhodecode/templates/password_reset.html:51 +msgid "Send password reset email" +msgstr "" + +#: rhodecode/templates/password_reset.html:52 +msgid "Password reset link will be send to matching email address" +msgstr "密码重置地址已经发送到邮件" + +#: rhodecode/templates/register.html:36 +msgid "Create an account" +msgstr "" + +#: rhodecode/templates/register.html:37 +msgid "Go to the login page to sign in with an existing account." +msgstr "" + +#: rhodecode/templates/register.html:45 +msgid "Re-enter password" +msgstr "确认密码" + +#: rhodecode/templates/register.html:47 +#: rhodecode/templates/admin/my_account/my_account_profile.html:32 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:30 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:76 +#: rhodecode/templates/admin/users/user_add.html:68 +#: rhodecode/templates/admin/users/user_edit_profile.html:47 +#: rhodecode/templates/admin/users/users.html:93 +msgid "First Name" +msgstr "名" + +#: rhodecode/templates/register.html:49 +#: rhodecode/templates/admin/my_account/my_account_profile.html:40 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:39 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:85 +#: rhodecode/templates/admin/users/user_add.html:77 +#: rhodecode/templates/admin/users/user_edit_profile.html:56 +#: rhodecode/templates/admin/users/users.html:95 +msgid "Last Name" +msgstr "姓" + +#: rhodecode/templates/register.html:64 +msgid "Account activation requires admin approval." +msgstr "" + +#: rhodecode/templates/register.html:71 +msgid "Create Account" +msgstr "" + +#: rhodecode/templates/register.html:77 +msgid "Register using one of external services" +msgstr "" + +#: rhodecode/templates/admin/admin.html:5 +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/base/base.html:78 +msgid "Admin journal" +msgstr "系统日志" + +#: rhodecode/templates/admin/admin.html:13 +msgid "journal filter..." +msgstr "日志过滤..." + +#: rhodecode/templates/admin/admin.html:14 +msgid "filter" +msgstr "过滤" + +#: rhodecode/templates/admin/admin.html:15 +#: rhodecode/templates/journal/journal.html:14 +#, python-format +msgid "%s entry" +msgid_plural "%s entries" +msgstr[0] "%s条" + +#: rhodecode/templates/admin/admin.html:17 +#: rhodecode/templates/journal/journal.html:17 +msgid "Example Queries" +msgstr "" + +#: rhodecode/templates/admin/admin_log.html:6 +#: rhodecode/templates/admin/my_account/my_account_repos.html:37 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:13 +#: rhodecode/templates/admin/repos/repos.html:69 +#: rhodecode/templates/admin/user_groups/user_groups.html:66 +#: rhodecode/templates/admin/users/users.html:106 +msgid "Action" +msgstr "操作" + +#: rhodecode/templates/admin/admin_log.html:7 +#: rhodecode/templates/admin/defaults/defaults.html:31 +#: rhodecode/templates/admin/permissions/permissions_objects.html:13 +#: rhodecode/templates/search/search_commit.html:5 +#: rhodecode/templates/search/search_path.html:3 +msgid "Repository" +msgstr "版本库" + +#: rhodecode/templates/admin/admin_log.html:8 +#: rhodecode/templates/bookmarks/bookmarks.html:61 +#: rhodecode/templates/branches/branches.html:60 +#: rhodecode/templates/tags/tags.html:61 +msgid "Date" +msgstr "日期" + +#: rhodecode/templates/admin/admin_log.html:9 +msgid "From IP" +msgstr "来源IP" + +#: rhodecode/templates/admin/admin_log.html:44 +msgid "No actions yet" +msgstr "无操作" + +#: rhodecode/templates/admin/auth/auth_settings.html:5 +#: rhodecode/templates/admin/auth/plugin_settings.html:5 +msgid "Authentication Settings" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:12 +#: rhodecode/templates/admin/auth/plugin_settings.html:12 +#: rhodecode/templates/admin/defaults/defaults.html:12 +#: rhodecode/templates/admin/permissions/permissions.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:12 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:14 +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:13 +#: rhodecode/templates/admin/repos/repo_add.html:17 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:15 +#: rhodecode/templates/admin/repos/repos.html:13 +#: rhodecode/templates/admin/settings/settings.html:12 +#: rhodecode/templates/admin/user_groups/user_group_add.html:11 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:14 +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +#: rhodecode/templates/admin/users/user_add.html:11 +#: rhodecode/templates/admin/users/user_edit.html:12 +#: rhodecode/templates/admin/users/users.html:13 +#: rhodecode/templates/admin/users/users.html:102 +#: rhodecode/templates/base/base.html:403 +#: rhodecode/templates/base/base.html:410 +msgid "Admin" +msgstr "管理" + +#: rhodecode/templates/admin/auth/auth_settings.html:14 +#: rhodecode/templates/admin/auth/plugin_settings.html:14 +msgid "Authentication Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:47 +msgid "Enabled and Available Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:53 +msgid "Enabled Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:58 +msgid "" +"Add a list of plugins, separated by commas. The order of the plugins is also" +" the order in which RhodeCode Enterprise will try to authenticate a user." +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:65 +msgid "Available Built-in Plugins" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "enabled" +msgstr "" + +#: rhodecode/templates/admin/auth/auth_settings.html:71 +msgid "disabled" +msgstr "禁用" + +#: rhodecode/templates/admin/auth/auth_settings.html:81 +#: rhodecode/templates/admin/auth/plugin_settings.html:90 +#: rhodecode/templates/admin/defaults/defaults_repositories.html:63 +#: rhodecode/templates/admin/my_account/my_account_password.html:36 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:103 +#: rhodecode/templates/admin/permissions/permissions_application.html:50 +#: rhodecode/templates/admin/permissions/permissions_objects.html:56 +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:72 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:135 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:55 +#: rhodecode/templates/admin/repos/repo_add_base.html:88 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:79 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:110 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:145 +#: rhodecode/templates/admin/settings/settings_hooks.html:63 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:15 +#: rhodecode/templates/admin/user_groups/user_group_add.html:60 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:120 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:72 +#: rhodecode/templates/admin/users/user_add.html:125 +#: rhodecode/templates/admin/users/user_edit_profile.html:134 +#: rhodecode/templates/base/default_perms_box.html:88 +msgid "Save" +msgstr "保存" + +#: rhodecode/templates/admin/auth/plugin_settings.html:45 +msgid "Plugin" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults.html:5 +#: rhodecode/templates/admin/defaults/defaults.html:14 +msgid "Repositories defaults" +msgstr "版本库默认设置" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:3 +msgid "Default Settings For New Repositories" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:14 +#: rhodecode/templates/admin/gists/index.html:110 +#: rhodecode/templates/admin/repos/repo_add_base.html:62 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:12 +msgid "Type" +msgstr "类型" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:23 +#: rhodecode/templates/admin/repos/repo_add_base.html:80 +msgid "Private Repository" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:27 +#: rhodecode/templates/admin/repos/repo_add_base.html:84 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:97 +#: rhodecode/templates/forks/fork.html:85 +msgid "" +"Private repositories are only visible to people explicitly added as " +"collaborators." +msgstr "私有版本库只对成员可见。" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:34 +msgid "Enable Statistics" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:38 +msgid "Enable a statistics window on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:44 +msgid "Enable Downloads" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:48 +msgid "Enable the download option on the repository summary page." +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:54 +msgid "Enable Locking" +msgstr "" + +#: rhodecode/templates/admin/defaults/defaults_repositories.html:58 +msgid "" +"Enable automatic repository locking. Pulling from a repository will lock it," +" and it is unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:5 +#: rhodecode/templates/admin/gists/edit.html:12 +msgid "Edit Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:29 +#, python-format +msgid "" +"Gist was updated since you started editing. Copy your changes and click " +"%(here)s to reload the new version." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:39 +#: rhodecode/templates/admin/gists/new.html:30 +msgid "Gist description ..." +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:44 +#: rhodecode/templates/admin/gists/new.html:38 +msgid "Gist lifetime" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:47 +#: rhodecode/templates/admin/gists/new.html:41 +msgid "Gist access level" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:59 +#: rhodecode/templates/admin/gists/new.html:50 +#: rhodecode/templates/files/files_add.html:74 +#: rhodecode/templates/files/files_edit.html:78 +msgid "plain" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:103 +msgid "Update Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/edit.html:104 +#: rhodecode/templates/base/issue_tracker_settings.html:74 +#: rhodecode/templates/changeset/changeset_file_comment.html:139 +#: rhodecode/templates/files/files_add.html:102 +#: rhodecode/templates/files/files_delete.html:69 +#: rhodecode/templates/files/files_edit.html:105 +msgid "Cancel" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:6 +#: rhodecode/templates/admin/gists/index.html:20 +#, python-format +msgid "Private Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:8 +#: rhodecode/templates/admin/gists/index.html:22 +#, python-format +msgid "Public Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:10 +msgid "Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:24 +#, python-format +msgid "All Gists for user %s" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:26 +msgid "All Public Gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:44 +#: rhodecode/templates/admin/gists/show.html:36 +msgid "Create New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:56 +msgid "All gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:58 +msgid "All public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:60 +msgid "My gists" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:61 +msgid "My private" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:62 +msgid "My public" +msgstr "" + +#: rhodecode/templates/admin/gists/index.html:108 +#: rhodecode/templates/bookmarks/bookmarks.html:63 +#: rhodecode/templates/branches/branches.html:62 +#: rhodecode/templates/changelog/changelog.html:102 +#: rhodecode/templates/changelog/changelog_summary_data.html:10 +#: rhodecode/templates/changeset/changeset.html:164 +#: rhodecode/templates/compare/compare_cs.html:21 +#: rhodecode/templates/files/files_browser.html:53 +#: rhodecode/templates/pullrequests/pullrequest_show.html:169 +#: rhodecode/templates/pullrequests/pullrequests.html:102 +#: rhodecode/templates/search/search_commit.html:10 +#: rhodecode/templates/tags/tags.html:63 +msgid "Author" +msgstr "作者" + +#: rhodecode/templates/admin/gists/index.html:116 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:6 +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:6 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_advanced.html:5 +msgid "Created on" +msgstr "创建于" + +#: rhodecode/templates/admin/gists/index.html:118 +#: rhodecode/templates/admin/gists/show.html:65 +msgid "Expires" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:5 +#: rhodecode/templates/admin/gists/new.html:12 +msgid "New Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:35 +msgid "Gist id" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:36 +msgid "Auto generated" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:49 +msgid "name this file..." +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:60 +msgid "Create Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:61 +msgid "Create Public Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/new.html:62 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:27 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:84 +#: rhodecode/templates/admin/my_account/my_account_emails.html:65 +#: rhodecode/templates/admin/my_account/my_account_password.html:37 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:104 +#: rhodecode/templates/admin/permissions/permissions_application.html:51 +#: rhodecode/templates/admin/permissions/permissions_ips.html:61 +#: rhodecode/templates/admin/permissions/permissions_objects.html:57 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:136 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:56 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:66 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:80 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:111 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:146 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:46 +#: rhodecode/templates/admin/settings/settings_global.html:110 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:16 +#: rhodecode/templates/admin/settings/settings_labs.html:46 +#: rhodecode/templates/admin/settings/settings_vcs.html:14 +#: rhodecode/templates/admin/settings/settings_visual.html:220 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:121 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:23 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:81 +#: rhodecode/templates/admin/users/user_edit_emails.html:63 +#: rhodecode/templates/admin/users/user_edit_ips.html:70 +#: rhodecode/templates/admin/users/user_edit_profile.html:135 +#: rhodecode/templates/base/default_perms_box.html:89 +msgid "Reset" +msgstr "重置" + +#: rhodecode/templates/admin/gists/show.html:13 +#: rhodecode/templates/admin/gists/show.html:20 +msgid "Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:49 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:56 +#: rhodecode/templates/admin/my_account/my_account_emails.html:32 +#: rhodecode/templates/admin/my_account/my_account_oauth.html:50 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:34 +#: rhodecode/templates/admin/permissions/permissions_ips.html:26 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:25 +#: rhodecode/templates/admin/settings/settings_hooks.html:46 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:52 +#: rhodecode/templates/admin/users/user_edit_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_ips.html:34 +#: rhodecode/templates/base/issue_tracker_settings.html:70 +#: rhodecode/templates/base/vcs_settings.html:147 +#: rhodecode/templates/base/vcs_settings.html:172 +#: rhodecode/templates/changeset/changeset_file_comment.html:49 +#: rhodecode/templates/changeset/changeset_file_comment.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:117 +#: rhodecode/templates/data_table/_dt_elements.html:174 +#: rhodecode/templates/data_table/_dt_elements.html:188 +#: rhodecode/templates/data_table/_dt_elements.html:200 +#: rhodecode/templates/debug_style/buttons.html:132 +#: rhodecode/templates/files/files_source.html:33 +#: rhodecode/templates/files/files_source.html:37 +#: rhodecode/templates/files/files_source.html:40 +msgid "Delete" +msgstr "删除" + +#: rhodecode/templates/admin/gists/show.html:49 +msgid "Confirm to delete this Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:56 +#: rhodecode/templates/admin/my_account/my_account_profile.html:5 +#: rhodecode/templates/base/issue_tracker_settings.html:61 +#: rhodecode/templates/changeset/changeset_file_comment.html:145 +#: rhodecode/templates/changeset/changeset_file_comment.html:292 +#: rhodecode/templates/data_table/_dt_elements.html:112 +#: rhodecode/templates/data_table/_dt_elements.html:170 +#: rhodecode/templates/data_table/_dt_elements.html:183 +#: rhodecode/templates/data_table/_dt_elements.html:196 +#: rhodecode/templates/debug_style/buttons.html:128 +#: rhodecode/templates/files/files_add.html:204 +#: rhodecode/templates/files/files_edit.html:165 +#: rhodecode/templates/files/files_source.html:36 +#: rhodecode/templates/files/files_source.html:39 +#: rhodecode/templates/pullrequests/pullrequest_show.html:50 +#: rhodecode/templates/pullrequests/pullrequest_show.html:184 +#: rhodecode/templates/users/user_profile.html:7 +msgid "Edit" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:58 +msgid "Show as Raw" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:62 +msgid "Private Gist" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:77 +msgid "created" +msgstr "" + +#: rhodecode/templates/admin/gists/show.html:91 +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "Show as raw" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:5 +#: rhodecode/templates/base/base.html:340 +msgid "My account" +msgstr "我的账户" + +#: rhodecode/templates/admin/my_account/my_account.html:12 +msgid "My Account" +msgstr "我的账户" + +#: rhodecode/templates/admin/my_account/my_account.html:29 +#: rhodecode/templates/admin/my_account/my_account_profile.html:4 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:4 +msgid "My Profile" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:31 +msgid "Auth Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:32 +msgid "OAuth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:33 +msgid "My Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:34 +msgid "My Repositories" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:35 +msgid "Watched" +msgstr "关注的" + +#: rhodecode/templates/admin/my_account/my_account.html:36 +#: rhodecode/templates/admin/notifications/notifications.html:33 +#: rhodecode/templates/base/base.html:240 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.html:37 +msgid "My Permissions" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:3 +msgid "Authentication Tokens" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:7 +msgid "Built-in tokens can be used to authenticate with all possible options." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:8 +msgid "" +"Each token can have a role. VCS tokens can be used together with the " +"authtoken auth plugin for git/hg operations." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:14 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:11 +msgid "Built-in" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:19 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:42 +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:47 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:16 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:38 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:43 +msgid "expires" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:25 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:22 +#, python-format +msgid "Confirm to reset this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:45 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:41 +msgid "expired" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:55 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:51 +#, python-format +msgid "Confirm to remove this auth token: %s" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:63 +msgid "No additional auth token specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:74 +msgid "New authentication token" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_auth_tokens.html:83 +#: rhodecode/templates/admin/my_account/my_account_emails.html:64 +#: rhodecode/templates/admin/permissions/permissions_ips.html:60 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:65 +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:80 +#: rhodecode/templates/admin/users/user_edit_emails.html:62 +#: rhodecode/templates/admin/users/user_edit_ips.html:69 +msgid "Add" +msgstr "增加" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:5 +msgid "Account Emails" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:17 +#: rhodecode/templates/admin/users/user_edit_emails.html:16 +msgid "Primary" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:31 +#: rhodecode/templates/admin/users/user_edit_emails.html:30 +#, python-format +msgid "Confirm to delete this email: %s" +msgstr "确认删除邮箱:%s" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:42 +#: rhodecode/templates/admin/users/user_edit_emails.html:41 +msgid "No additional emails specified" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_emails.html:57 +#: rhodecode/templates/admin/users/user_edit_emails.html:55 +msgid "New email address" +msgstr "增加邮箱" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:5 +msgid "Oauth Identities" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:9 +msgid "External services currently connected with your Rhodecode user" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:15 +msgid "No social authentication plugins are enabled by administrator" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:49 +msgid "Confirm to remove this provider from your account" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_oauth.html:59 +msgid "You have no accounts linked yet" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:3 +msgid "Change Your Account Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:10 +msgid "Current Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:19 +#: rhodecode/templates/admin/users/user_edit_profile.html:74 +msgid "New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_password.html:28 +msgid "Confirm New Password" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:11 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:52 +#: rhodecode/templates/admin/users/user_edit_profile.html:25 +#: rhodecode/templates/users/user_profile.html:14 +msgid "Photo" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:18 +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:60 +#: rhodecode/templates/admin/users/user_edit_profile.html:33 +#: rhodecode/templates/users/user_profile.html:21 +msgid "Avatars are disabled" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile.html:51 +#: rhodecode/templates/users/user_profile.html:54 +msgid "Missing email, please update your user email address." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:18 +msgid "" +"Your user account details are managed by an external source, i.e. LDAP. " +"Details cannot be managed here." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_profile_edit.html:57 +msgid "Change your avatar at" +msgstr "修改你的头像" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:6 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:8 +msgid "Show Closed Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:16 +msgid "Pull Requests You Opened" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:27 +#, python-format +msgid "Pull request #%s opened on %s" +msgstr "拉取请求#%s创建于%s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:29 +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:64 +#: rhodecode/templates/changeset/changeset_file_comment.html:284 +#: rhodecode/templates/pullrequests/pullrequest_show.html:14 +#: rhodecode/templates/pullrequests/pullrequest_show.html:112 +#: rhodecode/templates/pullrequests/pullrequests.html:51 +msgid "Closed" +msgstr "已关闭" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:35 +msgid "Confirm to delete this pull request" +msgstr "确认删除拉取请求" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:42 +msgid "You currently have no open pull requests." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:50 +msgid "Pull Requests You Participate In" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:61 +#, python-format +msgid "Pull request #%s opened by %s on %s" +msgstr "拉取请求#%s由%s创建于%s" + +#: rhodecode/templates/admin/my_account/my_account_pullrequests.html:70 +msgid "" +"There are currently no open pull requests requiring your participation." +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_repos.html:3 +msgid "Repositories You Own" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_watched.html:3 +msgid "Your Watched Repositories" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications.html:5 +#: rhodecode/templates/admin/notifications/notifications.html:12 +msgid "My Notifications" +msgstr "我的通知" + +#: rhodecode/templates/admin/notifications/notifications.html:31 +msgid "All" +msgstr "全部" + +#: rhodecode/templates/admin/notifications/notifications.html:32 +#: rhodecode/templates/changeset/changeset.html:140 +#: rhodecode/templates/pullrequests/pullrequest_show.html:133 +msgid "Comments" +msgstr "评论" + +#: rhodecode/templates/admin/notifications/notifications.html:37 +msgid "Mark all as read" +msgstr "" + +#: rhodecode/templates/admin/notifications/notifications_data.html:39 +msgid "No notifications here yet" +msgstr "无通知" + +#: rhodecode/templates/admin/notifications/show_notification.html:5 +#: rhodecode/templates/admin/notifications/show_notification.html:14 +msgid "Show notification" +msgstr "显示通知" + +#: rhodecode/templates/admin/notifications/show_notification.html:12 +msgid "Notifications" +msgstr "通知" + +#: rhodecode/templates/admin/permissions/permissions.html:5 +msgid "Permissions Administration" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:45 +#: rhodecode/templates/admin/repos/repo_edit.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:34 +#: rhodecode/templates/base/base.html:83 +msgid "Permissions" +msgstr "权限" + +#: rhodecode/templates/admin/permissions/permissions.html:33 +msgid "Application" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:39 +msgid "Object" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:42 +msgid "IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions.html:45 +msgid "Overview" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:3 +msgid "System Wide Application Permissions" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:12 +msgid "Anonymous Access" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:18 +#, python-format +msgid "" +"Allow access to RhodeCode Enterprise without requiring users to login. " +"Anonymous users get the %s permission settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:24 +msgid "Registration" +msgstr "注册" + +#: rhodecode/templates/admin/permissions/permissions_application.html:33 +msgid "Registration Page Message" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:37 +msgid "" +"Custom message to be displayed on the registration page. HTML syntax is " +"supported." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_application.html:43 +msgid "External Authentication Account Activation" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:5 +msgid "Default IP Whitelist For All Users" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:27 +#: rhodecode/templates/admin/users/user_edit_ips.html:35 +#, python-format +msgid "Confirm to delete this ip: %s" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:34 +#: rhodecode/templates/admin/users/user_edit_ips.html:43 +msgid "All IP addresses are allowed" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:49 +#: rhodecode/templates/admin/users/user_edit_ips.html:59 +msgid "New IP Address" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:53 +#: rhodecode/templates/admin/users/user_edit_ips.html:62 +msgid "Description..." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_ips.html:54 +msgid "" +"Enter a comma separated list of IP Addresses like 127.0.0.1,\n" +"or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:3 +msgid "" +"Default Permissions for Repositories, User Groups and Repository Groups." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:6 +msgid "" +"Default system permissions. Each permissions management entity will be " +"created with the following default settings. Check the overwrite checkbox to" +" force any permission changes on already existing settings." +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:20 +msgid "" +"All default permissions on each repository will be reset to chosen " +"permission, note that all custom default permission on repositories will be " +"lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:21 +#: rhodecode/templates/admin/permissions/permissions_objects.html:35 +#: rhodecode/templates/admin/permissions/permissions_objects.html:49 +msgid "Overwrite Existing Settings" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:28 +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:14 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:127 +msgid "Repository Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:34 +msgid "" +"All default permissions on each repository group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:42 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:14 +msgid "User Groups" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_objects.html:48 +msgid "" +"All default permissions on each user group will be reset to chosen " +"permission, note that all custom default permission on repository groups " +"will be lost" +msgstr "" + +#: rhodecode/templates/admin/permissions/permissions_perms.html:1 +msgid "Default User Permissions Overview" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:5 +#: rhodecode/templates/admin/users/user_add.html:116 +msgid "Add repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:14 +#: rhodecode/templates/admin/users/user_edit_advanced.html:12 +#: rhodecode/templates/base/base.html:80 +#: rhodecode/templates/base/base.html:150 +msgid "Repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:36 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:13 +msgid "Group Name" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:54 +msgid "Group Parent" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:63 +#: rhodecode/templates/admin/repos/repo_add_base.html:53 +msgid "Copy Parent Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_add.html:67 +msgid "Copy permission settings from parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:5 +#, python-format +msgid "%s repository group settings" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:24 +msgid "Add Child Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:44 +#: rhodecode/templates/admin/repos/repo_edit.html:15 +#: rhodecode/templates/admin/repos/repo_edit.html:39 +#: rhodecode/templates/admin/settings/settings.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:33 +#: rhodecode/templates/base/base.html:86 +#: rhodecode/templates/base/base.html:248 +msgid "Settings" +msgstr "设置" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit.html:46 +#: rhodecode/templates/admin/repos/repo_edit.html:45 +#: rhodecode/templates/admin/user_groups/user_group_edit.html:35 +#: rhodecode/templates/admin/users/user_edit.html:35 +msgid "Advanced" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:8 +msgid "Total repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:9 +msgid "Top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:11 +msgid "Children groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:17 +#, python-format +msgid "Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:27 +msgid "Delete repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:35 +#, python-format +msgid "This repository group includes %s children repository group." +msgid_plural "This repository group includes %s children repository groups." +msgstr[0] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:44 +#, python-format +msgid "This repository group includes %s repository." +msgid_plural "This repository group includes %s repositories." +msgstr[0] "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:56 +#, python-format +msgid "Confirm to delete this group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html:57 +msgid "Delete this repository group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:5 +msgid "Repository Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:11 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:126 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:12 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:11 +msgid "None" +msgstr "无" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:12 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:13 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:12 +msgid "Read" +msgstr "读" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:13 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:14 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:13 +msgid "Write" +msgstr "写" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:15 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:16 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:15 +msgid "User/User Group" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:31 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:31 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:31 +msgid "super admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:34 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:34 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:34 +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "owner" +msgstr "所有者" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:52 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:76 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:61 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:76 +msgid "permission for all other users" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:62 +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:109 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:71 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:99 +msgid "Revoke" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:80 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:80 +msgid "delegated admin" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:118 +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:107 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:117 +#: rhodecode/templates/base/issue_tracker_settings.html:84 +msgid "Add new" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:123 +msgid "Apply to children" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:129 +msgid "Both" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html:130 +msgid "" +"Set or revoke permissions to selected types of children of this group, " +"including non-private repositories and other groups if chosen." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:4 +#, python-format +msgid "Settings for Repository Group: %s" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:25 +msgid "Change Repository Group Owner." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:39 +msgid "Group parent" +msgstr "上级组" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:47 +msgid "Enable Repository Locking" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html:51 +msgid "" +"Repository locking will be enabled on all subgroups and repositories inside " +"this repository group. Pulling from a repository locks it, and it is " +"unlocked by pushing back by the same user." +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:5 +msgid "Repository groups administration" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:13 +msgid "repository groups" +msgstr "" + +#: rhodecode/templates/admin/repo_groups/repo_groups.html:58 +msgid "Number of top level repositories" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add.html:5 +msgid "Add repository" +msgstr "添加版本库" + +#: rhodecode/templates/admin/repos/repo_add_base.html:14 +msgid "Import Existing Repository ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:23 +#: rhodecode/templates/base/base.html:195 +msgid "Clone from" +msgstr "克隆自" + +#: rhodecode/templates/admin/repos/repo_add_base.html:27 +msgid "Optional http[s] URL from which to clone a repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:36 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:87 +#: rhodecode/templates/forks/fork.html:52 +msgid "" +"Keep it short and to the point. Use a README file for longer descriptions." +msgstr "保持简短。用README文件来写更长的描述。" + +#: rhodecode/templates/admin/repos/repo_add_base.html:41 +msgid "Repository Group" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:46 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:58 +#: rhodecode/templates/forks/fork.html:63 +#, python-format +msgid "Select my personal group (%(repo_group_name)s)" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:48 +#: rhodecode/templates/forks/fork.html:65 +msgid "Optionally select a group to put this repository into." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:57 +msgid "Copy permission set from the parent repository group." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:66 +msgid "Set the type of repository to create." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:71 +#: rhodecode/templates/admin/repos/repo_edit_settings.html:65 +#: rhodecode/templates/forks/fork.html:71 +msgid "Landing commit" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_add_base.html:75 +msgid "" +"The default commit for file pages, downloads, full text search index, and " +"README generation." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:9 +#, python-format +msgid "%s Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:16 +msgid "Creating repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_creating.html:30 +#, python-format +msgid "" +"Repository \"%(repo_name)s\" is being created, you will be redirected when " +"this process is finished.repo_name" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:8 +#, python-format +msgid "%s repository settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:51 +msgid "Extra Fields" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:57 +msgid "Caches" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit.html:61 +msgid "Remote" +msgstr "远程" + +#: rhodecode/templates/admin/repos/repo_edit.html:65 +#: rhodecode/templates/summary/components.html:135 +msgid "Statistics" +msgstr "统计" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:7 +#: rhodecode/templates/pullrequests/pullrequests.html:108 +msgid "Updated on" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:8 +msgid "Cached Commit id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:14 +#, python-format +msgid "Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:24 +msgid "Fork Reference" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:30 +#, python-format +msgid "This repository is a fork of %(repo_link)s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:5 +msgid "Set" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:39 +#: rhodecode/templates/admin/repos/repo_edit_fork.html:9 +msgid "Manually set this repository as a fork of another from the list" +msgstr "从列表中手动设置这个版本库复刻自另一版本库" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:48 +msgid "Public Journal Visibility" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:56 +msgid "Remove from Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:60 +msgid "Add to Public Journal" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:65 +msgid "" +"All actions made on this repository will be visible to everyone following " +"the public journal." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:74 +msgid "Locking state" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:83 +msgid "This Repository is not currently locked." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:90 +msgid "Confirm to unlock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:92 +msgid "Unlock repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:97 +msgid "Confirm to lock repository." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:99 +msgid "Lock Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:105 +msgid "" +"Force repository locking. This only works when anonymous access is disabled." +" Pulling from the repository locks the repository to that user until the " +"same user pushes to that repository again." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:114 +msgid "Delete repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:121 +#, python-format +msgid "This repository has %s fork." +msgid_plural "This repository has %s forks." +msgstr[0] "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:125 +msgid "Detach forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:130 +msgid "Delete forks" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:139 +#: rhodecode/templates/data_table/_dt_elements.html:118 +#, python-format +msgid "Confirm to delete this repository: %s" +msgstr "确认删除版本库:%s" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:141 +msgid "Delete This Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:146 +msgid "" +"This repository will be renamed in a special way in order to make it " +"inaccessible to RhodeCode Enterprise and its VCS systems. If you need to " +"fully delete it from the file system, please do it manually, or with " +"rhodecode-cleanup-repos command." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Change repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.html:180 +msgid "Pick repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:3 +msgid "Invalidate Cache for Repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Invalidate repository cache" +msgstr "清除版本库缓存" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:10 +msgid "Confirm to invalidate repository cache" +msgstr "确认清除版本库缓存" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:14 +msgid "" +"Manually invalidate the repository cache. On the next access a repository " +"cache will be recreated." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:28 +#, python-format +msgid "List of repository caches (%(count)s entry)" +msgid_plural "List of repository caches (%(count)s entries)" +msgstr[0] "" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:35 +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:32 +#: rhodecode/templates/base/issue_tracker_settings.html:13 +msgid "Prefix" +msgstr "前缀" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:36 +#: rhodecode/templates/admin/repos/repo_edit_fields.html:11 +msgid "Key" +msgstr "键" + +#: rhodecode/templates/admin/repos/repo_edit_caches.html:37 +#: rhodecode/templates/admin/user_groups/user_group_add.html:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:38 +#: rhodecode/templates/admin/user_groups/user_groups.html:62 +#: rhodecode/templates/admin/users/user_add.html:97 +#: rhodecode/templates/admin/users/user_edit_profile.html:90 +#: rhodecode/templates/admin/users/users.html:100 +msgid "Active" +msgstr "启用" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:3 +msgid "Custom extra fields for this repository" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:10 +msgid "Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:24 +#, python-format +msgid "Confirm to delete this field: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:40 +msgid "New Field Key" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:48 +msgid "New Field Label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:51 +msgid "Enter short label" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:57 +msgid "New Field Description" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:60 +msgid "Enter a full description for the field" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_fields.html:73 +msgid "" +"Extra fields are disabled. You can enable them from the " +"Admin/Settings/Visual page." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:9 +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:9 +msgid "Inherit from global settings" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:14 +msgid "Select to inherit global patterns for issue tracker." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:24 +msgid "Inherited Issue Tracker Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:30 +#: rhodecode/templates/base/issue_tracker_settings.html:11 +msgid "Pattern" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:31 +#: rhodecode/templates/base/issue_tracker_settings.html:12 +msgid "Url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:70 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:5 +msgid "Issue Tracker / Wiki Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_issuetracker.html:91 +#: rhodecode/templates/admin/settings/settings_issuetracker.html:24 +msgid "Test Patterns" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:5 +msgid "Repository Permissions" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:43 +msgid "private repository" +msgstr "私有版本库" + +#: rhodecode/templates/admin/repos/repo_edit_permissions.html:48 +msgid "only users/user groups explicitly added here will have access" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:3 +msgid "Remote url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:9 +msgid "Remote mirror url" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +#: rhodecode/templates/admin/repos/repo_edit_remote.html:22 +msgid "Pull changes from remote location" +msgstr "从远程路径拉取修订集" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:14 +msgid "Confirm to pull changes from remote side" +msgstr "确认从远程拉取修订集" + +#: rhodecode/templates/admin/repos/repo_edit_remote.html:19 +msgid "This repository does not have any remote mirror url set." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:3 +#, python-format +msgid "Settings for Repository: %s" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "Non-changeable id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:16 +msgid "what is that ?" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:18 +msgid "URL by id" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:19 +msgid "" +"In case this repository is renamed or moved into another group the repository url changes.\n" +" Using above url guarantees that this repository will always be accessible under such url.\n" +" Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:27 +msgid "Remote uri" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:33 +#: rhodecode/templates/base/perms_summary.html:80 +#: rhodecode/templates/base/perms_summary.html:142 +#: rhodecode/templates/base/perms_summary.html:144 +#: rhodecode/templates/debug_style/form-elements.html:45 +msgid "edit" +msgstr "编辑" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:36 +msgid "new value, leave empty to remove" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:38 +msgid "cancel" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:45 +msgid "" +"http[s] url where from repository was imported, also used for doing remote " +"pulls." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:53 +#: rhodecode/templates/data_table/_dt_elements.html:158 +#: rhodecode/templates/forks/fork.html:58 +msgid "Repository group" +msgstr "版本库组" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:60 +msgid "Optional select a group to put this repository into." +msgstr "可选的,选择一个组将版本库放到其中" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:69 +#: rhodecode/templates/forks/fork.html:75 +msgid "Default commit for files page, downloads, whoosh and readme" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:78 +msgid "Change owner of this repository." +msgstr "修改这个版本库的所有者" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:93 +#: rhodecode/templates/data_table/_dt_elements.html:58 +msgid "Private repository" +msgstr "私有版本库" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:102 +msgid "Enable statistics" +msgstr "启用统计" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:106 +msgid "Enable statistics window on summary page." +msgstr "启用概况页的统计窗口" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:111 +msgid "Enable downloads" +msgstr "启用下载" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:115 +msgid "Enable download menu on summary page." +msgstr "启用概况页的下载菜单" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:120 +msgid "Enable automatic locking" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_settings.html:124 +msgid "" +"Enable automatic locking on repository. Pulling from this repository creates" +" a lock that can be released by pushing back by the same user" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:3 +msgid "Repository statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:11 +msgid "Processed commits" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:12 +msgid "Processed progress" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Reset statistics" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_statistics.html:15 +msgid "Confirm to remove current statistics" +msgstr "确认移除当前统计" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:14 +msgid "Select to inherit global vcs settings." +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_vcs.html:45 +#: rhodecode/templates/admin/settings/settings_global.html:109 +#: rhodecode/templates/admin/settings/settings_labs.html:45 +#: rhodecode/templates/admin/settings/settings_vcs.html:13 +#: rhodecode/templates/admin/settings/settings_visual.html:219 +msgid "Save settings" +msgstr "保存设置" + +#: rhodecode/templates/admin/repos/repos.html:5 +msgid "Repositories administration" +msgstr "版本库管理员" + +#: rhodecode/templates/admin/repos/repos.html:13 +msgid "repositories" +msgstr "版本库" + +#: rhodecode/templates/admin/repos/repos.html:67 +msgid "State" +msgstr "" + +#: rhodecode/templates/admin/settings/settings.html:5 +msgid "Settings administration" +msgstr "系统设置" + +#: rhodecode/templates/admin/settings/settings_email.html:3 +msgid "Email Configuration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:8 +msgid "Email prefix" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:9 +msgid "RhodeCode email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:10 +msgid "Error email from" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:11 +msgid "Error email recipients" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:13 +msgid "SMTP server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:14 +msgid "SMTP username" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:15 +msgid "SMTP password" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:16 +msgid "SMTP port" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:18 +msgid "SMTP use TLS" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:19 +msgid "SMTP use SSL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:20 +msgid "SMTP auth" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:34 +msgid "Test Email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:40 +msgid "enter valid email" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:44 +msgid "Send an auto-generated email from this server to above email..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_email.html:48 +msgid "Send" +msgstr "发送" + +#: rhodecode/templates/admin/settings/settings_global.html:5 +msgid "Branding" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:9 +#: rhodecode/templates/email_templates/pull_request_review.mako:28 +#: rhodecode/templates/email_templates/pull_request_review.mako:65 +#: rhodecode/templates/pullrequests/pullrequest.html:38 +#: rhodecode/templates/pullrequests/pullrequests.html:104 +msgid "Title" +msgstr "标题" + +#: rhodecode/templates/admin/settings/settings_global.html:16 +msgid "" +"Set a custom title for your RhodeCode instance (limited to 40 characters)." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:20 +msgid "HTTP[S] authentication realm" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:27 +msgid "" +"Set a custom text that is shown as authentication message to clients trying " +"to connect." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:35 +msgid "Registration Captcha" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:39 +msgid "Google ReCaptcha public key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:46 +msgid "Public key for reCaptcha system." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:51 +msgid "Google ReCaptcha private key" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:58 +msgid "" +"Private key for reCaptcha system. Setting this value will enable captcha on " +"registration" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:66 +msgid "Custom Header Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:71 +#: rhodecode/templates/admin/settings/settings_global.html:93 +#: rhodecode/templates/debug_style/form-elements-small.html:59 +#: rhodecode/templates/debug_style/form-elements.html:57 +#: rhodecode/templates/debug_style/form-elements.html:82 +#: rhodecode/templates/debug_style/form-elements.html:225 +#: rhodecode/templates/debug_style/form-elements.html:381 +#: rhodecode/templates/debug_style/form-elements.html:407 +#: rhodecode/templates/debug_style/form-elements.html:515 +#: rhodecode/templates/debug_style/form-elements.html:519 +#: rhodecode/templates/debug_style/form-elements.html:537 +#: rhodecode/templates/debug_style/form-elements.html:587 +#: rhodecode/templates/debug_style/form-inline.html:38 +#: rhodecode/templates/debug_style/form-inline.html:139 +#: rhodecode/templates/debug_style/form-inline.html:147 +#: rhodecode/templates/debug_style/form-vertical.html:60 +#: rhodecode/templates/debug_style/forms.html:37 +#: rhodecode/templates/debug_style/forms.html:60 +#: rhodecode/templates/debug_style/forms.html:78 +#: rhodecode/templates/debug_style/forms.html:96 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:44 +msgid "Templates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:74 +#: rhodecode/templates/admin/settings/settings_global.html:96 +#: rhodecode/templates/debug_style/form-elements-small.html:62 +#: rhodecode/templates/debug_style/form-elements.html:60 +#: rhodecode/templates/debug_style/form-elements.html:85 +#: rhodecode/templates/debug_style/form-elements.html:228 +#: rhodecode/templates/debug_style/form-elements.html:384 +#: rhodecode/templates/debug_style/form-elements.html:410 +#: rhodecode/templates/debug_style/form-elements.html:518 +#: rhodecode/templates/debug_style/form-elements.html:522 +#: rhodecode/templates/debug_style/form-elements.html:540 +#: rhodecode/templates/debug_style/form-elements.html:590 +#: rhodecode/templates/debug_style/form-inline.html:41 +#: rhodecode/templates/debug_style/form-inline.html:142 +#: rhodecode/templates/debug_style/form-inline.html:150 +#: rhodecode/templates/debug_style/form-vertical.html:63 +#: rhodecode/templates/debug_style/forms.html:40 +#: rhodecode/templates/debug_style/forms.html:63 +#: rhodecode/templates/debug_style/forms.html:81 +#: rhodecode/templates/debug_style/forms.html:99 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:47 +msgid "Server Announcement" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:80 +msgid "Custom js/css code added at the end of the <header> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:81 +#: rhodecode/templates/admin/settings/settings_global.html:103 +msgid "Use <script> or <css> tags to define custom styling or scripting" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:88 +msgid "Custom Footer Code" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_global.html:102 +msgid "Custom js/css code added at the end of the <body> tag." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:3 +msgid "Built in Mercurial hooks - read only" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:19 +msgid "" +"Hooks can be used to trigger actions on certain events such as push / pull. " +"They can trigger Python functions or external applications." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_hooks.html:27 +msgid "Custom hooks" +msgstr "自定义钩子" + +#: rhodecode/templates/admin/settings/settings_labs.html:3 +msgid "Labs Settings" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:5 +msgid "Import New Groups or Repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:10 +msgid "Destroy old data" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:12 +msgid "" +"In case a repository or a group was deleted from the filesystem and it still" +" exists in the database, check this option to remove obsolete data from the " +"database." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:16 +msgid "Invalidate cache for all repositories" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:18 +msgid "" +"Each cache data for repositories will be cleaned with this option selected. " +"Use this to reload data and clear cache keys." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_mapping.html:21 +msgid "Rescan Filesystem" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_open_source.html:3 +msgid "Licenses of Third Party Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_search.html:3 +msgid "RhodeCode Full Text Search" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_supervisor_tail.html:1 +#, python-format +msgid "" +"Last %(size)s bytes of process logs, use ?offset=[num] GET param to set " +"custom size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "RhodeCode Enterprise version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:4 +msgid "check for updates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Upgrade info endpoint" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:5 +msgid "Note: please make sure this server can access this url" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:6 +msgid "Configuration INI file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:8 +msgid "RhodeCode Enterprise Server IP" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:9 +msgid "RhodeCode Enterprise Server ID" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:10 +msgid "Platform" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:11 +msgid "Uptime" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:12 +msgid "Storage location" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:13 +msgid "Storage disk space" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:15 +msgid "Search index storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:16 +msgid "Search index size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:18 +msgid "Gist storage" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:19 +msgid "Gist storage size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "Archive cache" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:21 +msgid "" +"Enable this by setting archive_cache_dir=/path/to/cache option in the .ini " +"file" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:22 +msgid "Archive cache size" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:24 +msgid "System memory" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:25 +msgid "CPU" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:26 +msgid "Load" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:29 +msgid "Python version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:30 +msgid "Python path" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:31 +msgid "GIT version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:32 +msgid "HG version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:33 +msgid "SVN version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:34 +msgid "Database" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:35 +msgid "Database version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:41 +msgid "Checking for updates..." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_system.html:61 +msgid "Python Packages" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:5 +#: rhodecode/templates/base/vcs_settings.html:10 +msgid "General" +msgstr "通用" + +#: rhodecode/templates/admin/settings/settings_visual.html:10 +msgid "Use repository extra fields" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:12 +msgid "Allows storing additional customized fields per repository." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:17 +msgid "Show RhodeCode version" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:19 +msgid "Shows or hides a version number of RhodeCode displayed in the footer." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:26 +msgid "Gravatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:31 +msgid "Use Gravatars based avatars" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:33 +msgid "" +"Use gravatar.com as avatar system for RhodeCode accounts. If this is " +"disabled avatars are generated based on initials and email." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:36 +msgid "Gravatar URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:44 +msgid "" +"Gravatar url allows you to use other avatar server application.\n" +" Following variables of the URL will be replaced accordingly.\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {email} user email,\n" +" {md5email} md5 hash of the user email (like at gravatar.com),\n" +" {size} size of the image that is expected from the server application,\n" +" {netloc} network location/server host of running RhodeCode server" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:59 +msgid "Meta-Tagging" +msgstr "元标记" + +#: rhodecode/templates/admin/settings/settings_visual.html:64 +msgid "Stylify recognised meta tags" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:66 +msgid "" +"Parses meta tags from repository description field and turns them into " +"colored tags." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:86 +msgid "Dashboard Items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:90 +msgid "Main page dashboard items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:96 +msgid "" +"Number of items displayed in the main page dashboard before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:100 +msgid "Admin pages items" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:106 +msgid "" +"Number of items displayed in the admin pages grids before pagination is " +"shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:115 +msgid "Commit ID Style" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:119 +msgid "Commit sha length" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:126 +msgid "" +"Number of chars to show in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" length of the sha after the `r123:` part." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Show commit ID numeric reference" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:134 +msgid "Commit show revision number" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:136 +msgid "" +"Show revision number in commit sha displayed in web interface.\n" +" By default it's shown as r123:9043a6a4c226 this value defines the\n" +" if the `r123:` part is shown." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:145 +#: rhodecode/templates/debug_style/index.html:62 +msgid "Icons" +msgstr "图标" + +#: rhodecode/templates/admin/settings/settings_visual.html:150 +msgid "Show public repo icon on repositories" +msgstr "显示公共版本库图标" + +#: rhodecode/templates/admin/settings/settings_visual.html:156 +msgid "Show private repo icon on repositories" +msgstr "显示私有版本库图标" + +#: rhodecode/templates/admin/settings/settings_visual.html:158 +msgid "Show public/private icons next to repositories names." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:165 +msgid "Markup Renderer" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:172 +msgid "" +"Default renderer used to render comments, pull request descriptions and " +"other description elements. After change old entries will still work " +"correctly." +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:179 +msgid "Clone URL" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:188 +msgid "" +"Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" +" {scheme} 'http' or 'https' sent from running RhodeCode server,\n" +" {user} current user username,\n" +" {netloc} network location/server host of running RhodeCode server,\n" +" {repo} full repository name,\n" +" {repoid} ID of repository, can be used to contruct clone-by-id" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:201 +msgid "Custom Support Link" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.html:209 +#, python-format +msgid "" +"Custom url for the support link located at the bottom.\n" +" The default is set to %(default_url)s. In case there's a need\n" +" to change the support link to internal issue tracker, it should be done here.\n" +" " +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:5 +msgid "Add user group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:13 +#: rhodecode/templates/admin/users/user_edit_advanced.html:13 +#: rhodecode/templates/base/base.html:82 +#: rhodecode/templates/base/base.html:153 +msgid "User groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:15 +#: rhodecode/templates/admin/user_groups/user_groups.html:28 +msgid "Add User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:35 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:12 +msgid "Group name" +msgstr "组名" + +#: rhodecode/templates/admin/user_groups/user_group_add.html:47 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:33 +msgid "Short, optional description for this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:5 +#, python-format +msgid "%s user group settings" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:36 +#: rhodecode/templates/admin/users/user_edit.html:36 +msgid "Global permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:37 +#: rhodecode/templates/admin/users/user_edit.html:37 +msgid "Permissions summary" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit.html:38 +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:8 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:46 +#: rhodecode/templates/admin/user_groups/user_groups.html:60 +#: rhodecode/templates/debug_style/form-elements.html:509 +msgid "Members" +msgstr "成员" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:9 +msgid "Assigned to repositories" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:10 +msgid "Assigned to repo groups" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:17 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:3 +#, python-format +msgid "User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:26 +msgid "Delete User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:32 +#, python-format +msgid "" +"Confirm to delete user group `%(ugroup)s` with all permission assignments" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_advanced.html:34 +msgid "Delete This User Group" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:5 +#, python-format +msgid "Members of User Group: %s" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_members.html:27 +msgid "No members yet" +msgstr "还没有成员" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:5 +msgid "User Group Permissions" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:62 +#: rhodecode/templates/admin/user_groups/user_group_edit_perms.html:109 +msgid "revoke" +msgstr "移除" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:24 +msgid "Change owner of this user group." +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:50 +#: rhodecode/templates/debug_style/form-elements.html:513 +#: rhodecode/templates/debug_style/form-elements.html:571 +#: rhodecode/templates/debug_style/forms.html:236 +msgid "Chosen group members" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:53 +#: rhodecode/templates/debug_style/form-elements.html:525 +#: rhodecode/templates/debug_style/form-elements.html:575 +#: rhodecode/templates/debug_style/forms.html:240 +msgid "Remove all elements" +msgstr "移除全部项目" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:63 +#: rhodecode/templates/debug_style/form-elements.html:535 +#: rhodecode/templates/debug_style/form-elements.html:585 +#: rhodecode/templates/debug_style/forms.html:250 +msgid "Available members" +msgstr "启用成员" + +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.html:66 +#: rhodecode/templates/debug_style/form-elements.html:543 +#: rhodecode/templates/debug_style/form-elements.html:593 +#: rhodecode/templates/debug_style/forms.html:258 +msgid "Add all elements" +msgstr "添加全部项目" + +#: rhodecode/templates/admin/user_groups/user_groups.html:5 +msgid "User groups administration" +msgstr "" + +#: rhodecode/templates/admin/user_groups/user_groups.html:13 +msgid "user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:5 +msgid "Add user" +msgstr "添加用户" + +#: rhodecode/templates/admin/users/user_add.html:13 +#: rhodecode/templates/admin/users/user_edit.html:14 +#: rhodecode/templates/base/base.html:81 +msgid "Users" +msgstr "用户" + +#: rhodecode/templates/admin/users/user_add.html:15 +#: rhodecode/templates/admin/users/users.html:27 +msgid "Add User" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:53 +msgid "Password confirmation" +msgstr "确认密码" + +#: rhodecode/templates/admin/users/user_add.html:59 +msgid "Generate password" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:106 +msgid "Password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:110 +msgid "Force user to change his password on the next login" +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:120 +msgid "" +"Add repository group with the same name as username. \n" +"User will be automatically set as this group owner." +msgstr "" + +#: rhodecode/templates/admin/users/user_add.html:137 +msgid "generated password:" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:5 +#, python-format +msgid "%s user settings" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:33 +#: rhodecode/templates/admin/users/user_edit_profile.html:5 +msgid "User Profile" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:34 +msgid "Auth tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:38 +msgid "Emails" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit.html:39 +msgid "Ip Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:6 +#: rhodecode/templates/admin/users/user_edit_profile.html:106 +msgid "Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:8 +#: rhodecode/templates/admin/users/users.html:98 +msgid "Last login" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:9 +msgid "Last activity" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:15 +msgid "Member of User groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:16 +msgid "Force password change" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:22 +#, python-format +msgid "User: %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:31 +msgid "Force Password Reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:39 +msgid "Disable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:41 +msgid "Enable forced password reset" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:47 +msgid "" +"When this is enabled user will have to change they password when they next " +"use RhodeCode system. This will also forbid vcs operations until someone " +"makes a password change in the web interface" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:56 +msgid "Personal Repository Group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:62 +msgid "Users personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:64 +msgid "This user currently does not have a personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:68 +msgid "Create personal repository group" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:77 +msgid "Delete User" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:85 +#, python-format +msgid "This user owns %s repository." +msgid_plural "This user owns %s repositories." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:89 +msgid "Detach repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:94 +#: rhodecode/templates/admin/users/user_edit_advanced.html:110 +#: rhodecode/templates/admin/users/user_edit_advanced.html:126 +msgid "Delete repositories" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:101 +#, python-format +msgid "This user owns %s repository group." +msgid_plural "This user owns %s repository groups." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:105 +msgid "Detach repository groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:117 +#, python-format +msgid "This user owns %s user group." +msgid_plural "This user owns %s user groups." +msgstr[0] "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:121 +msgid "Detach user groups" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:135 +#: rhodecode/templates/data_table/_dt_elements.html:189 +#, python-format +msgid "Confirm to delete this user: %s" +msgstr "确认删除用户:%s" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:137 +msgid "Delete this user" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_advanced.html:147 +#, python-format +msgid "" +"When selecting the detach option, the depending objects owned by this user " +"will be assigned to the `%s` super admin in the system. The delete option " +"will delete the user's repositories!" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:3 +msgid "Authentication Access Tokens" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:59 +msgid "No additional auth tokens specified" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_auth_tokens.html:71 +msgid "New auth token" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_emails.html:5 +msgid "Additional Email Addresses" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:3 +msgid "Custom IP Whitelist" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:19 +#, python-format +msgid "Inherited from %s" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ips.html:63 +msgid "" +"Enter comma separated list of ip addresses like 127.0.0.1,\n" +"or use a ip address with a mask 127.0.0.1/24, to create a network range.\n" +"To specify multiple address range use 127.0.0.1-127.0.0.10 syntax" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:17 +#, python-format +msgid "" +"This user was created from external source (%s). Editing some of the " +"settings is limited." +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:30 +msgid "Change the avatar at" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:82 +msgid "New Password Confirmation" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:98 +msgid "Super Admin" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:115 +msgid "Name in Source of Record" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:124 +msgid "Language" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_profile.html:130 +#, python-format +msgid "Help translate %(rc_link)s into your language." +msgstr "" + +#: rhodecode/templates/admin/users/users.html:5 +msgid "Users administration" +msgstr "用户管理员" + +#: rhodecode/templates/admin/users/users.html:104 +msgid "Authentication type" +msgstr "" + +#: rhodecode/templates/base/base.html:45 +#: rhodecode/templates/errors/error_document.html:51 +msgid "Support" +msgstr "" + +#: rhodecode/templates/base/base.html:52 +#, python-format +msgid "RhodeCode instance id: %s" +msgstr "" + +#: rhodecode/templates/base/base.html:84 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.html:85 +msgid "Defaults" +msgstr "默认设置" + +#: rhodecode/templates/base/base.html:103 +#: rhodecode/templates/files/files_pjax.html:24 +#: rhodecode/templates/summary/components.html:42 +msgid "Show More" +msgstr "" + +#: rhodecode/templates/base/base.html:187 +msgid "Fork of" +msgstr "复刻自" + +#: rhodecode/templates/base/base.html:204 +#, python-format +msgid "Repository locked by %(user)s" +msgstr "" + +#: rhodecode/templates/base/base.html:209 +msgid "Repository not locked. Pull repository to lock it." +msgstr "" + +#: rhodecode/templates/base/base.html:227 +#: rhodecode/templates/data_table/_dt_elements.html:12 +#: rhodecode/templates/data_table/_dt_elements.html:13 +#: rhodecode/templates/data_table/_dt_elements.html:147 +msgid "Summary" +msgstr "概况" + +#: rhodecode/templates/base/base.html:228 +#: rhodecode/templates/data_table/_dt_elements.html:17 +#: rhodecode/templates/data_table/_dt_elements.html:18 +msgid "Changelog" +msgstr "修订记录" + +#: rhodecode/templates/base/base.html:229 +#: rhodecode/templates/data_table/_dt_elements.html:22 +#: rhodecode/templates/data_table/_dt_elements.html:23 +#: rhodecode/templates/files/files.html:15 +msgid "Files" +msgstr "浏览" + +#: rhodecode/templates/base/base.html:231 +#: rhodecode/templates/bookmarks/bookmarks.html:68 +#: rhodecode/templates/branches/branches.html:67 +#: rhodecode/templates/files/file_diff.html:11 +#: rhodecode/templates/files/file_diff.html:29 +#: rhodecode/templates/tags/tags.html:68 +msgid "Compare" +msgstr "比较显示" + +#: rhodecode/templates/base/base.html:236 +#, python-format +msgid "Show Pull Requests for %s" +msgstr "" + +#: rhodecode/templates/base/base.html:245 +msgid "Options" +msgstr "选项" + +#: rhodecode/templates/base/base.html:252 +#: rhodecode/templates/forks/forks_data.html:28 +msgid "Compare fork" +msgstr "比较复刻" + +#: rhodecode/templates/base/base.html:255 +#: rhodecode/templates/base/base.html:397 +#: rhodecode/templates/search/search.html:64 +msgid "Search" +msgstr "搜索" + +#: rhodecode/templates/base/base.html:259 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.html:261 +msgid "Lock" +msgstr "" + +#: rhodecode/templates/base/base.html:266 +#: rhodecode/templates/data_table/_dt_elements.html:27 +#: rhodecode/templates/data_table/_dt_elements.html:28 +#: rhodecode/templates/forks/forks_data.html:7 +#: rhodecode/templates/summary/components.html:103 +msgid "Fork" +msgid_plural "Forks" +msgstr[0] "" + +#: rhodecode/templates/base/base.html:267 +msgid "Create Pull Request" +msgstr "" + +#: rhodecode/templates/base/base.html:289 +msgid "Sign in" +msgstr "" + +#: rhodecode/templates/base/base.html:297 +#: rhodecode/templates/debug_style/login.html:28 +msgid "Sign in to your account" +msgstr "" + +#: rhodecode/templates/base/base.html:313 +#: rhodecode/templates/debug_style/login.html:46 +msgid "(Forgot password?)" +msgstr "" + +#: rhodecode/templates/base/base.html:322 +#: rhodecode/templates/debug_style/login.html:56 +msgid "Don't have an account ?" +msgstr "还没有帐号?" + +#: rhodecode/templates/base/base.html:343 +msgid "Sign Out" +msgstr "" + +#: rhodecode/templates/base/base.html:379 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:380 +#: rhodecode/templates/journal/journal.html:4 +#: rhodecode/templates/journal/journal.html:14 +msgid "Journal" +msgstr "日志" + +#: rhodecode/templates/base/base.html:385 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.html:386 +msgid "Public journal" +msgstr "公共日志" + +#: rhodecode/templates/base/base.html:391 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:392 +msgid "Gists" +msgstr "" + +#: rhodecode/templates/base/base.html:396 +msgid "Search in repositories you have access to" +msgstr "" + +#: rhodecode/templates/base/base.html:402 +msgid "Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:409 +msgid "Delegated Admin settings" +msgstr "" + +#: rhodecode/templates/base/base.html:419 +#: rhodecode/templates/base/base.html:420 +#: rhodecode/templates/debug_style/buttons.html:5 +#: rhodecode/templates/debug_style/code-block.html:6 +#: rhodecode/templates/debug_style/collapsable-content.html:5 +#: rhodecode/templates/debug_style/form-elements-small.html:5 +#: rhodecode/templates/debug_style/form-elements.html:5 +#: rhodecode/templates/debug_style/form-inline.html:5 +#: rhodecode/templates/debug_style/form-vertical.html:5 +#: rhodecode/templates/debug_style/forms.html:5 +#: rhodecode/templates/debug_style/icons.html:5 +#: rhodecode/templates/debug_style/index.html:12 +#: rhodecode/templates/debug_style/labels.html:5 +#: rhodecode/templates/debug_style/layout-form-sidebar.html:5 +#: rhodecode/templates/debug_style/login.html:6 +#: rhodecode/templates/debug_style/panels.html:5 +#: rhodecode/templates/debug_style/tables-wide.html:5 +#: rhodecode/templates/debug_style/tables.html:5 +#: rhodecode/templates/debug_style/typography.html:5 +msgid "Style" +msgstr "" + +#: rhodecode/templates/base/base.html:474 +msgid "Go to" +msgstr "" + +#: rhodecode/templates/base/base.html:585 +msgid "Keyboard shortcuts" +msgstr "" + +#: rhodecode/templates/base/base.html:593 +msgid "Site-wide shortcuts" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:14 +msgid "Inherited Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:15 +msgid "Custom Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:17 +msgid "Default Global Permissions" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:23 +msgid "" +"The following options configure the default permissions each user or group " +"will inherit. You can override these permissions for each individual user or" +" user group using individual permissions settings." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:27 +msgid "Repository Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:32 +msgid "" +"Permission to create root level repositories. When disabled, users can still" +" create repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:37 +msgid "Repository Creation With Group Write Access" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:42 +msgid "" +"Write permission given on a repository group will allow creating " +"repositories inside that group." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:47 +msgid "Repository Forking" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:52 +msgid "" +"Permission to create root level repository forks. When disabled, users can " +"still fork repositories inside their own repository groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:57 +msgid "Repository Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:62 +msgid "" +"Permission to create root level repository groups. When disabled, repository" +" group admins can still create repository subgroups within their repository " +"groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:67 +msgid "User Group Creation" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:72 +msgid "" +"Permission to allow user group creation. When disabled, user group admins " +"can still create subgroups within their user groups." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:78 +msgid "Inherit Permissions From The Default User" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:83 +msgid "" +"Inherit default permissions from the default user. Turn off this option to " +"force explicit permissions for users, even if they are more restrictive than" +" the default user permissions." +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:102 +msgid "Inherit from default settings" +msgstr "" + +#: rhodecode/templates/base/default_perms_box.html:107 +#, python-format +msgid "" +"Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n" +"permission by members of user groups." +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:22 +msgid "Read more" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:92 +msgid "New Entry" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:96 +msgid "Confirm to remove this pattern:" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:192 +#: rhodecode/templates/changeset/changeset_file_comment.html:144 +#: rhodecode/templates/changeset/changeset_file_comment.html:291 +#: rhodecode/templates/files/files_add.html:78 +#: rhodecode/templates/files/files_add.html:224 +#: rhodecode/templates/files/files_edit.html:82 +#: rhodecode/templates/files/files_edit.html:185 +msgid "Preview" +msgstr "" + +#: rhodecode/templates/base/issue_tracker_settings.html:193 +msgid "Test Pattern Preview" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:19 +msgid "show" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:20 +msgid "none" +msgstr "无" + +#: rhodecode/templates/base/perms_summary.html:21 +msgid "read" +msgstr "读" + +#: rhodecode/templates/base/perms_summary.html:22 +msgid "write" +msgstr "写" + +#: rhodecode/templates/base/perms_summary.html:23 +msgid "admin" +msgstr "管理" + +#: rhodecode/templates/base/perms_summary.html:30 +msgid "No permissions defined" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:38 +#: rhodecode/templates/base/perms_summary.html:104 +msgid "Permission" +msgstr "权限" + +#: rhodecode/templates/base/perms_summary.html:40 +#: rhodecode/templates/base/perms_summary.html:106 +msgid "Edit Permission" +msgstr "编辑权限" + +#: rhodecode/templates/base/perms_summary.html:86 +msgid "Super admin" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:88 +msgid "Repository default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:89 +msgid "Repository group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:90 +msgid "User group default permission" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:92 +msgid "Create repositories" +msgstr "创建版本库" + +#: rhodecode/templates/base/perms_summary.html:93 +msgid "Fork repositories" +msgstr "复刻版本库" + +#: rhodecode/templates/base/perms_summary.html:94 +msgid "Create repository groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:95 +msgid "Create user groups" +msgstr "" + +#: rhodecode/templates/base/perms_summary.html:155 +msgid "No permission defined" +msgstr "" + +#: rhodecode/templates/base/root.html:150 +msgid "Please enable JavaScript to use RhodeCode Enterprise" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:6 +msgid "Sign in with" +msgstr "" + +#: rhodecode/templates/base/social_buttons.html:8 +msgid "Connect with" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:16 +msgid "Require SSL for vcs operations" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:19 +msgid "" +"Activate to set RhodeCode to require SSL for pushing or pulling. If SSL " +"certificate is missing it will return a HTTP Error 406: Not Acceptable." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:29 +msgid "Main Storage Location" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:37 +msgid "" +"Click to unlock. You must restart RhodeCode in order to make this setting " +"take effect." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:41 +msgid "" +"Repository location change is disabled. You can enable this by changing the " +"`allow_repo_location_change` inside .ini file." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:48 +msgid "" +"Filesystem location where repositories should be stored. After changing this" +" value a restart and rescan of the repository folder are required." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:57 +msgid "Internal Hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:63 +msgid "Show repository size after push" +msgstr "推送后显示版本库大小" + +#: rhodecode/templates/base/vcs_settings.html:67 +msgid "Trigger a hook that calculates repository size after each push." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:71 +msgid "Execute pre/post push hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:74 +msgid "" +"Execute Built in pre/post push hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:78 +msgid "Execute pre/post pull hooks" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:81 +msgid "" +"Execute Built in pre/post pull hooks. This also executes rcextensions hooks." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:91 +msgid "Mercurial Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:96 +msgid "Enable largefiles extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:99 +msgid "Enable Largefiles extensions for all repositories." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repositories as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:103 +msgid "Set repository as publishing" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:106 +msgid "" +"When this is enabled all commits in the repository are seen as public " +"commits by clients." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:111 +msgid "Enable hgsubversion extension" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:114 +msgid "" +"Requires hgsubversion library to be installed. Allows cloning remote SVN " +"repositories and migrates them to Mercurial type." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:124 +msgid "Subversion Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:129 +msgid "Repository patterns" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:133 +msgid "" +"Patterns for identifying SVN branches and tags. For recursive search, use " +"\"*\". Eg.: \"/branches/*\"" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:196 +msgid "Pull Request Settings" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:201 +msgid "Enable server-side merge for pull requests" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:204 +msgid "" +"Note: when this feature is enabled, it only runs hooks defined in the " +"rcextension package. Custom hooks added on the Admin -> Settings -> Hooks " +"page will not be run when pull requests are automatically merged from the " +"web interface." +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:208 +msgid "Invalidate and relocate inline comments during update" +msgstr "" + +#: rhodecode/templates/base/vcs_settings.html:211 +msgid "" +"During the update of a pull request, the position of inline comments will be" +" updated and outdated inline comments will be hidden." +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:5 +#, python-format +msgid "%s Bookmarks" +msgstr "%s书签" + +#: rhodecode/templates/bookmarks/bookmarks.html:13 +msgid "bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks.html:31 +msgid "Compare Selected Bookmarks" +msgstr "" + +#: rhodecode/templates/bookmarks/bookmarks_data.html:13 +#: rhodecode/templates/changelog/changelog.html:180 +#: rhodecode/templates/changelog/changelog_summary_data.html:53 +#: rhodecode/templates/changeset/changeset.html:92 +#: rhodecode/templates/files/base.html:10 +#, python-format +msgid "Bookmark %s" +msgstr "" + +#: rhodecode/templates/branches/branches.html:5 +#, python-format +msgid "%s Branches" +msgstr "%s分支" + +#: rhodecode/templates/branches/branches.html:13 +msgid "branches" +msgstr "" + +#: rhodecode/templates/branches/branches.html:31 +msgid "Compare Selected Branches" +msgstr "" + +#: rhodecode/templates/branches/branches_data.html:12 +#: rhodecode/templates/changelog/changelog.html:172 +#: rhodecode/templates/changelog/changelog_summary_data.html:67 +#: rhodecode/templates/changeset/changeset.html:105 +#: rhodecode/templates/files/base.html:23 +#, python-format +msgid "Branch %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:6 +#, python-format +msgid "%s Changelog" +msgstr "%s修订记录" + +#: rhodecode/templates/changelog/changelog.html:19 +#, python-format +msgid "showing %d out of %d commit" +msgid_plural "showing %d out of %d commits" +msgstr[0] "" + +#: rhodecode/templates/changelog/changelog.html:41 +#: rhodecode/templates/forks/forks_data.html:26 +#, python-format +msgid "Compare fork with %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:53 +#, python-format +msgid "Compare fork with Parent (%s)" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:62 +msgid "Open new pull request" +msgstr "新建拉取请求" + +#: rhodecode/templates/changelog/changelog.html:68 +#: rhodecode/templates/changelog/changelog.html:69 +msgid "Clear selection" +msgstr "清除选择" + +#: rhodecode/templates/changelog/changelog.html:83 +msgid "Clear filter" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:103 +#: rhodecode/templates/changelog/changelog_summary_data.html:9 +#: rhodecode/templates/search/search_commit.html:9 +msgid "Age" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:105 +#: rhodecode/templates/files/files_add.html:93 +#: rhodecode/templates/files/files_delete.html:60 +#: rhodecode/templates/files/files_edit.html:96 +msgid "Commit Message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:108 +#: rhodecode/templates/changelog/changelog_summary_data.html:11 +msgid "Refs" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:122 +#: rhodecode/templates/changelog/changelog_summary_data.html:22 +#, python-format +msgid "" +"Commit status: %s\n" +"Click to open associated pull request #%s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:126 +#, python-format +msgid "Commit status: %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:141 +#: rhodecode/templates/compare/compare_cs.html:47 +#: rhodecode/templates/search/search_commit.html:30 +msgid "Expand commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:162 +#: rhodecode/templates/changelog/changelog_summary_data.html:33 +msgid "Commit has comments" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:188 +#: rhodecode/templates/changelog/changelog_summary_data.html:60 +#: rhodecode/templates/changeset/changeset.html:99 +#: rhodecode/templates/files/base.html:17 +#: rhodecode/templates/tags/tags_data.html:12 +#, python-format +msgid "Tag %s" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:338 +msgid "Filter changelog" +msgstr "" + +#: rhodecode/templates/changelog/changelog.html:411 +msgid "There are no changes yet" +msgstr "没有任何变更" + +#: rhodecode/templates/changelog/changelog_details.html:4 +#: rhodecode/templates/pullrequests/pullrequest_show.html:358 +msgid "Removed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:5 +msgid "Changed" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:6 +msgid "Added" +msgstr "" + +#: rhodecode/templates/changelog/changelog_details.html:8 +#: rhodecode/templates/changelog/changelog_details.html:9 +#: rhodecode/templates/changelog/changelog_details.html:10 +#, python-format +msgid "Affected %s files" +msgstr "" + +#: rhodecode/templates/changelog/changelog_file_history.html:20 +#: rhodecode/templates/changeset/changeset.html:86 +#: rhodecode/templates/files/base.html:4 +msgid "merge" +msgstr "合并" + +#: rhodecode/templates/changelog/changelog_file_history.html:39 +#: rhodecode/templates/changeset/diff_block.html:65 +#: rhodecode/templates/changeset/diff_block.html:70 +msgid "Show File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:8 +#: rhodecode/templates/search/search_commit.html:8 +msgid "Commit message" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:91 +msgid "Add or upload files directly via RhodeCode:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:94 +#: rhodecode/templates/files/files_browser.html:25 +msgid "Add New File" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:102 +msgid "Push new repo:" +msgstr "" + +#: rhodecode/templates/changelog/changelog_summary_data.html:113 +msgid "Existing repository?" +msgstr "已有版本库?" + +#: rhodecode/templates/changeset/changeset.html:7 +#, python-format +msgid "%s Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:43 +msgid "Parent" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child Commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:47 +msgid "Child" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:58 +msgid "Expand" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:66 +#: rhodecode/templates/changeset/changeset.html:72 +#: rhodecode/templates/changeset/changeset_file_comment.html:36 +#: rhodecode/templates/changeset/changeset_file_comment.html:90 +msgid "Commit status" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:79 +#: rhodecode/templates/files/file_tree_detail.html:21 +#: rhodecode/templates/files/files_detail.html:20 +msgid "References" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:115 +msgid "Diffs" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:119 +#: rhodecode/templates/changeset/diff_block.html:85 +msgid "Raw diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:120 +#: rhodecode/templates/changeset/diff_block.html:86 +msgid "Raw Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:123 +msgid "Patch diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:124 +msgid "Patch Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:127 +#: rhodecode/templates/changeset/diff_block.html:90 +msgid "Download diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:128 +#: rhodecode/templates/changeset/diff_block.html:91 +msgid "Download Diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:145 +#: rhodecode/templates/changeset/changeset.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:217 +#, python-format +msgid "%d Commit comment" +msgid_plural "%d Commit comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset.html:151 +#: rhodecode/templates/changeset/changeset.html:153 +#: rhodecode/templates/pullrequests/pullrequest_show.html:145 +#: rhodecode/templates/pullrequests/pullrequest_show.html:147 +#: rhodecode/tests/functional/test_changeset_comments.py:224 +#, python-format +msgid "%d Inline Comment" +msgid_plural "%d Inline Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files at current commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:177 +msgid "Browse files" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Expand All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:179 +#: rhodecode/templates/changeset/changeset_range.html:59 +#: rhodecode/templates/compare/compare_diff.html:255 +#: rhodecode/templates/files/file_diff.html:77 +#: rhodecode/templates/pullrequests/pullrequest_show.html:265 +msgid "Collapse All" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:190 +#: rhodecode/templates/compare/compare_diff.html:263 +#: rhodecode/templates/pullrequests/pullrequest_show.html:274 +msgid "No files" +msgstr "无文件" + +#: rhodecode/templates/changeset/changeset.html:227 +#: rhodecode/templates/files/file_diff.html:128 +msgid "Show comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:228 +#: rhodecode/templates/files/file_diff.html:129 +msgid "Hide comments" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Diff was truncated. File content available only in full diff." +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/changeset/diff_block.html:59 +#: rhodecode/templates/files/file_diff.html:146 +msgid "Showing a big diff might take some time and resources, continue?" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:245 +#: rhodecode/templates/changeset/diff_block.html:7 +#: rhodecode/templates/changeset/diff_block.html:10 +#: rhodecode/templates/changeset/diff_block.html:25 +#: rhodecode/templates/changeset/diff_block.html:46 +#: rhodecode/templates/files/file_diff.html:146 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Show full diff" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:314 +msgid "No Child Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset.html:350 +msgid "No Parent Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:21 +#, python-format +msgid "Vote on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:23 +#, python-format +msgid "Comment on pull request #%s" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:28 +msgid "Status change on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:30 +msgid "Comment on commit" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:58 +msgid "Previous comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:62 +msgid "Next comment" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:118 +msgid "Create a comment on line {1}." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:121 +#: rhodecode/templates/changeset/changeset_file_comment.html:251 +#, python-format +msgid "Comments parsed using %s syntax with %s support." +msgstr "评论使用%s语法并支持%s" + +#: rhodecode/templates/changeset/changeset_file_comment.html:123 +#: rhodecode/templates/changeset/changeset_file_comment.html:253 +msgid "" +"Use @username inside this text to send notification to this RhodeCode user" +msgstr "在文本中使用 @用户名 以发送通知到该RhodeCode用户" + +#: rhodecode/templates/changeset/changeset_file_comment.html:133 +#: rhodecode/templates/changeset/changeset_file_comment.html:264 +msgid "Comment preview" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:146 +#: rhodecode/templates/changeset/changeset_file_comment.html:293 +#: rhodecode/templates/compare/compare_diff.html:57 +msgid "Comment" +msgstr "评论" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "You need to be logged in to comment." +msgstr "必须登录才能评论" + +#: rhodecode/templates/changeset/changeset_file_comment.html:154 +msgid "Login now" +msgstr "现在登陆" + +#: rhodecode/templates/changeset/changeset_file_comment.html:158 +msgid "Hide" +msgstr "隐藏" + +#: rhodecode/templates/changeset/changeset_file_comment.html:171 +#, python-format +msgid "%d Pull Request Comment" +msgid_plural "%d Pull Request Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:173 +#, python-format +msgid "%d Commit Comment" +msgid_plural "%d Commit Comments" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:223 +msgid "Merge Pull Request" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:243 +msgid "Create a comment on this Pull Request." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:245 +msgid "Create comments on this Commit range." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.html:247 +msgid "Create a comment on this Commit." +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:5 +#, python-format +msgid "%s Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:9 +#: rhodecode/templates/changeset/changeset_range.html:20 +#, python-format +msgid "(%s commit)" +msgid_plural "(%s commits)" +msgstr[0] "" + +#: rhodecode/templates/changeset/changeset_range.html:16 +msgid "Commits" +msgstr "" + +#: rhodecode/templates/changeset/changeset_range.html:41 +msgid "Show combined compare" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:7 +msgid "The requested commit is too big and content was truncated." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:10 +msgid "The requested file is too big and its content is not shown." +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:64 +#, python-format +msgid "Show file at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:69 +#, python-format +msgid "File no longer present at commit: %(commit_id)s" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:75 +msgid "Show full diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:76 +msgid "Unified Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:80 +msgid "Show full side-by-side diff for this file" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:81 +#: rhodecode/templates/files/diff_2way.html:40 +msgid "Side-by-side Diff" +msgstr "" + +#: rhodecode/templates/changeset/diff_block.html:97 +#, python-format +msgid "%(num)s file changed" +msgid_plural "%(num)s files changed" +msgstr[0] "" + +#: rhodecode/templates/changeset/diff_block.html:99 +#, python-format +msgid "%(num)s file changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgid_plural "" +"%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted" +msgstr[0] "" + +#: rhodecode/templates/compare/compare_cs.html:5 +msgid "No Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:9 +msgid "Common Ancestor Commit" +msgstr "" + +#: rhodecode/templates/compare/compare_cs.html:20 +msgid "Time" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:6 +#: rhodecode/templates/compare/compare_diff.html:8 +#, python-format +msgid "%s Compare" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:16 +#, python-format +msgid "%s commit" +msgid_plural "%s commits" +msgstr[0] "" + +#: rhodecode/templates/compare/compare_diff.html:37 +#: rhodecode/templates/compare/compare_diff.html:55 +msgid "Compare Commits" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:46 +#: rhodecode/templates/files/file_diff.html:56 +#: rhodecode/templates/pullrequests/pullrequest_show.html:85 +msgid "Target" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:47 +#: rhodecode/templates/files/file_diff.html:62 +#: rhodecode/templates/files/files_source.html:18 +msgid "Source" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:53 +msgid "Swap" +msgstr "" + +#: rhodecode/templates/compare/compare_diff.html:245 +msgid "Compare commits, branches, bookmarks or tags." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:49 +msgid "Mercurial repository" +msgstr "Mercurial版本库" + +#: rhodecode/templates/data_table/_dt_elements.html:51 +msgid "Git repository" +msgstr "Git版本库" + +#: rhodecode/templates/data_table/_dt_elements.html:53 +msgid "Subversion repository" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:60 +msgid "Public repository" +msgstr "公共版本库" + +#: rhodecode/templates/data_table/_dt_elements.html:70 +msgid "Repository creating in progress..." +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:84 +msgid "No commits yet" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:91 +#: rhodecode/templates/data_table/_dt_elements.html:93 +#, python-format +msgid "Subscribe to %s rss feed" +msgstr "订阅%s的RSS" + +#: rhodecode/templates/data_table/_dt_elements.html:99 +#: rhodecode/templates/data_table/_dt_elements.html:101 +#, python-format +msgid "Subscribe to %s atom feed" +msgstr "订阅%s的Atom" + +#: rhodecode/templates/data_table/_dt_elements.html:127 +msgid "Creating" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:129 +msgid "Created" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:175 +#, python-format +msgid "Confirm to delete this group: %s with %s repository" +msgid_plural "Confirm to delete this group: %s with %s repositories" +msgstr[0] "确认删除这个版本库组:%s包含%s个版本库" + +#: rhodecode/templates/data_table/_dt_elements.html:201 +#, python-format +msgid "Confirm to delete this user group: %s" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:218 +msgid "User group" +msgstr "" + +#: rhodecode/templates/data_table/_dt_elements.html:262 +#: rhodecode/templates/forks/fork.html:81 +msgid "Private" +msgstr "私有" + +#: rhodecode/templates/data_table/_dt_elements.html:287 +#, python-format +msgid "Pull request #%(pr_number)s" +msgstr "" + +#: rhodecode/templates/debug_style/buttons.html:131 +msgid "Confirm to remove this field: Field" +msgstr "" + +#: rhodecode/templates/debug_style/form-elements.html:107 +msgid "Default" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:119 +msgid "Some text..." +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:122 +#: rhodecode/templates/debug_style/forms.html:255 +msgid "Variable Item" +msgstr "" + +#: rhodecode/templates/debug_style/forms.html:252 +msgid "Some example text..." +msgstr "" + +#: rhodecode/templates/debug_style/index.html:5 +msgid "Debug Style" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:54 +msgid "Index" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:55 +msgid "Typography" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:56 +msgid "Forms" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:57 +msgid "Buttons" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:58 +msgid "Labels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:59 +msgid "Tables" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:60 +msgid "Tables wide" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:61 +msgid "Collapsable Content" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:63 +msgid "Layout form with sidebar" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:64 +msgid "Login" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:65 +msgid "Login 2" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:66 +msgid "Code blocks" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:69 +msgid "Panels" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:72 +msgid "Form elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:73 +msgid "Form elements small" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:74 +msgid "Form inline elements" +msgstr "" + +#: rhodecode/templates/debug_style/index.html:75 +msgid "Form vertical" +msgstr "" + +#: rhodecode/templates/email_templates/base.mako:16 +#, python-format +msgid "This is a notification from RhodeCode. %(instance_url)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +msgid "[mention]" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:5 +#, python-format +msgid "%(user)s commented on commit of %(repo_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:14 +#: rhodecode/templates/email_templates/commit_comment.mako:41 +#: rhodecode/templates/email_templates/pull_request_comment.mako:15 +#: rhodecode/templates/email_templates/pull_request_comment.mako:51 +msgid "Comment link" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:19 +#: rhodecode/templates/email_templates/commit_comment.mako:43 +#: rhodecode/templates/email_templates/pull_request_comment.mako:20 +#: rhodecode/templates/email_templates/pull_request_comment.mako:54 +#, python-format +msgid "File: %(comment_file)s on line %(comment_line)s" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:28 +#: rhodecode/templates/email_templates/commit_comment.mako:56 +msgid "Commit status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:35 +#, python-format +msgid "%(user)s commented on a file in commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:37 +#, python-format +msgid "%(user)s commented on a commit of %(repo_url)s." +msgstr "" + +#: rhodecode/templates/email_templates/commit_comment.mako:47 +#: rhodecode/templates/files/files_detail.html:5 +#: rhodecode/templates/files/files_detail.html:12 +msgid "Commit Description" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:5 +#, python-format +msgid "%(user)s commented on pull request #%(pr_id)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:17 +#: rhodecode/templates/email_templates/pull_request_comment.mako:52 +msgid "Source repository" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:29 +#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +msgid "Pull request status was changed to" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:31 +#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +msgid "Pull request was closed with status" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:37 +#, python-format +msgid "%(user)s commented on a file on pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_comment.mako:43 +#, python-format +msgid "%(user)s commented on a pull request #%(pr_id)s \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:5 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_url)s: \"%(pr_title)s\"" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:17 +#: rhodecode/templates/email_templates/pull_request_review.mako:54 +#, python-format +msgid "" +"Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s " +"into %(target_ref_type)s:%(target_ref_name)s" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:26 +#: rhodecode/templates/email_templates/pull_request_review.mako:63 +msgid "Link" +msgstr "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:35 +#: rhodecode/templates/email_templates/pull_request_review.mako:72 +#, python-format +msgid "Commit (%(num)s)" +msgid_plural "Commits (%(num)s)" +msgstr[0] "" + +#: rhodecode/templates/email_templates/pull_request_review.mako:47 +#, python-format +msgid "%(user)s wants you to review pull request #%(pr_id)s: \"%(pr_title)s\"." +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:5 +msgid "hello \"world\"" +msgstr "" + +#: rhodecode/templates/email_templates/test.mako:21 +msgid "Translation" +msgstr "" + +#: rhodecode/templates/errors/error_document.html:39 +#, python-format +msgid "You will be redirected to %s in %s seconds" +msgstr "重定向到%s,于%s秒后" + +#: rhodecode/templates/feed/atom_feed_entry.mako:3 +#, python-format +msgid "%(user)s commited on %(date)s UTC" +msgstr "" + +#: rhodecode/templates/feed/atom_feed_entry.mako:26 +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Commit was too big and was cut off..." +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:15 +#, python-format +msgid "%s File side-by-side diff" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:79 +msgid "Enable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:80 +msgid "Disable editor mode" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:84 +msgid "Previous change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:85 +msgid "Next change" +msgstr "" + +#: rhodecode/templates/files/diff_2way.html:100 +msgid "mode" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:6 +msgid "Last Author" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:8 +#, python-format +msgid "File Author (%s)" +msgid_plural "File Authors (%s)" +msgstr[0] "" + +#: rhodecode/templates/files/file_authors_box.html:11 +msgid "Show All" +msgstr "" + +#: rhodecode/templates/files/file_authors_box.html:26 +msgid "last author" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:4 +#, python-format +msgid "%s File Diff" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:37 +msgid "for" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:53 +msgid "No commits" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:81 +msgid "Cannot diff binary files" +msgstr "" + +#: rhodecode/templates/files/file_diff.html:83 +msgid "File was not changed in this commit range" +msgstr "" + +#: rhodecode/templates/files/file_tree_author_box.html:5 +msgid "Commit Author" +msgstr "" + +#: rhodecode/templates/files/files.html:4 +#: rhodecode/templates/files/files_pjax.html:2 +#, python-format +msgid "%s Files" +msgstr "" + +#: rhodecode/templates/files/files.html:143 +msgid "Switch To Commit" +msgstr "" + +#: rhodecode/templates/files/files_add.html:4 +#, python-format +msgid "%s Files Add" +msgstr "" + +#: rhodecode/templates/files/files_add.html:15 +msgid "Add new file" +msgstr "新建文件" + +#: rhodecode/templates/files/files_add.html:34 +#: rhodecode/templates/files/files_delete.html:34 +#: rhodecode/templates/files/files_edit.html:34 +msgid "Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:39 +msgid "Specify Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:44 +msgid "Remove Custom Path" +msgstr "" + +#: rhodecode/templates/files/files_add.html:50 +msgid "Filename" +msgstr "" + +#: rhodecode/templates/files/files_add.html:54 +#: rhodecode/templates/files/files_add.html:65 +msgid "or" +msgstr "或者" + +#: rhodecode/templates/files/files_add.html:54 +msgid "Upload File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:59 +msgid "Upload file" +msgstr "" + +#: rhodecode/templates/files/files_add.html:63 +msgid "No file selected" +msgstr "" + +#: rhodecode/templates/files/files_add.html:65 +msgid "Create New File" +msgstr "" + +#: rhodecode/templates/files/files_add.html:75 +#: rhodecode/templates/files/files_edit.html:79 +msgid "line wraps" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "on" +msgstr "" + +#: rhodecode/templates/files/files_add.html:76 +#: rhodecode/templates/files/files_edit.html:80 +msgid "off" +msgstr "" + +#: rhodecode/templates/files/files_add.html:103 +#: rhodecode/templates/files/files_edit.html:106 +msgid "Commit changes" +msgstr "提交修改" + +#: rhodecode/templates/files/files_browser.html:9 +msgid "Previous commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:13 +msgid "Next commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:19 +msgid "Search File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:22 +msgid "Close File List" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:27 +msgid "Add File" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:34 +msgid "Loading file list..." +msgstr "加载文件列表..." + +#: rhodecode/templates/files/files_browser.html:50 +msgid "Size" +msgstr "大小" + +#: rhodecode/templates/files/files_browser.html:51 +msgid "Modified" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:52 +msgid "Last Commit" +msgstr "" + +#: rhodecode/templates/files/files_browser.html:89 +msgid "Loading..." +msgstr "载入中..." + +#: rhodecode/templates/files/files_delete.html:4 +#, python-format +msgid "%s Files Delete" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:15 +msgid "Delete file" +msgstr "" + +#: rhodecode/templates/files/files_delete.html:45 +#: rhodecode/templates/files/files_source.html:49 +#, python-format +msgid "Binary file (%s)" +msgstr "二进制文件(%s)" + +#: rhodecode/templates/files/files_delete.html:50 +#: rhodecode/templates/files/files_source.html:61 +msgid "File is too big to display" +msgstr "文件过大,不能显示" + +#: rhodecode/templates/files/files_delete.html:70 +msgid "Delete File" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:35 +msgid "File last commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:54 +msgid "Diff to Commit" +msgstr "" + +#: rhodecode/templates/files/files_detail.html:55 +msgid "Show at Commit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:4 +#, python-format +msgid "%s File Edit" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:15 +msgid "Edit file" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:55 +msgid "history" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:61 +msgid "source" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:63 +#: rhodecode/templates/files/files_pjax.html:19 +msgid "annotation" +msgstr "显示注释" + +#: rhodecode/templates/files/files_edit.html:65 +msgid "raw" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:67 +msgid "download" +msgstr "" + +#: rhodecode/templates/files/files_edit.html:74 +msgid "Editing file" +msgstr "编辑文件" + +#: rhodecode/templates/files/files_pjax.html:17 +msgid "Location" +msgstr "位置" + +#: rhodecode/templates/files/files_source.html:6 +#: rhodecode/templates/search/search_content.html:20 +msgid "line" +msgid_plural "lines" +msgstr[0] "" + +#: rhodecode/templates/files/files_source.html:12 +msgid "History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:15 +#: rhodecode/templates/search/search_content.html:31 +msgid "Show Full History" +msgstr "" + +#: rhodecode/templates/files/files_source.html:20 +#: rhodecode/templates/search/search_content.html:33 +msgid "Annotation" +msgstr "" + +#: rhodecode/templates/files/files_source.html:22 +#: rhodecode/templates/search/search_content.html:34 +msgid "Raw" +msgstr "" + +#: rhodecode/templates/files/files_source.html:24 +#: rhodecode/templates/search/search_content.html:36 +msgid "Download" +msgstr "下载" + +#: rhodecode/templates/files/files_source.html:31 +#, python-format +msgid "Edit on Branch:%s" +msgstr "" + +#: rhodecode/templates/files/files_source.html:36 +msgid "Editing binary files not allowed" +msgstr "" + +#: rhodecode/templates/files/files_source.html:39 +msgid "Editing files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/files/files_source.html:40 +msgid "Deleting files allowed only when on branch head commit" +msgstr "" + +#: rhodecode/templates/followers/followers.html:5 +#: rhodecode/templates/followers/followers.html:27 +#, python-format +msgid "%s Followers" +msgstr "%s个关注者" + +#: rhodecode/templates/followers/followers.html:12 +msgid "Followers" +msgstr "关注者" + +#: rhodecode/templates/followers/followers_data.html:5 +msgid "Follower Name" +msgstr "" + +#: rhodecode/templates/followers/followers_data.html:6 +msgid "Following Since" +msgstr "" + +#: rhodecode/templates/forks/fork.html:5 +#, python-format +msgid "Fork repository %s" +msgstr "" + +#: rhodecode/templates/forks/fork.html:12 +msgid "New Fork" +msgstr "" + +#: rhodecode/templates/forks/fork.html:37 +msgid "Fork name" +msgstr "复刻名称" + +#: rhodecode/templates/forks/fork.html:91 +msgid "Copy permissions" +msgstr "拷贝权限" + +#: rhodecode/templates/forks/fork.html:95 +msgid "Copy permissions from forked repository" +msgstr "从被复刻版本库拷贝权限" + +#: rhodecode/templates/forks/fork.html:100 +msgid "Fork this Repository" +msgstr "" + +#: rhodecode/templates/forks/forks.html:5 +#, python-format +msgid "%s Forks" +msgstr "%s个复刻" + +#: rhodecode/templates/forks/forks.html:12 +msgid "Forks" +msgstr "复刻" + +#: rhodecode/templates/forks/forks.html:32 +msgid "Create new fork" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:9 +msgid "Forked" +msgstr "" + +#: rhodecode/templates/forks/forks_data.html:46 +msgid "There are no forks yet" +msgstr "无复刻" + +#: rhodecode/templates/journal/journal.html:13 +msgid "Filter" +msgstr "" + +#: rhodecode/templates/journal/journal.html:23 +msgid "ATOM journal feed" +msgstr "订阅日志ATOM" + +#: rhodecode/templates/journal/journal.html:24 +msgid "RSS journal feed" +msgstr "订阅日志RSS" + +#: rhodecode/templates/journal/journal_data.html:53 +msgid "No entries yet" +msgstr "没有条目" + +#: rhodecode/templates/journal/public_journal.html:4 +#: rhodecode/templates/journal/public_journal.html:24 +msgid "Public Journal" +msgstr "公共日志" + +#: rhodecode/templates/journal/public_journal.html:16 +msgid "ATOM public journal feed" +msgstr "订阅公共日志ATOM" + +#: rhodecode/templates/journal/public_journal.html:17 +msgid "RSS public journal feed" +msgstr "订阅公共日志RSS" + +#: rhodecode/templates/pullrequests/pullrequest.html:4 +#: rhodecode/templates/pullrequests/pullrequest.html:8 +msgid "New pull request" +msgstr "新建拉取请求" + +#: rhodecode/templates/pullrequests/pullrequest.html:52 +msgid "Write a short description on this pull request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:59 +msgid "Commit flow" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:67 +msgid "Origin repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:85 +msgid "Loading refs..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:96 +msgid "Submit Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:109 +#: rhodecode/templates/pullrequests/pullrequest_show.html:182 +msgid "Pull request reviewers" +msgstr "拉取请求检视人员" + +#: rhodecode/templates/pullrequests/pullrequest.html:117 +#: rhodecode/templates/pullrequests/pullrequest_show.html:215 +msgid "Add reviewer" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:278 +#: rhodecode/templates/pullrequests/pullrequest.html:520 +msgid "Please select origin and destination" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:284 +msgid "Loading compare ..." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:331 +#: rhodecode/templates/pullrequests/pullrequest.html:333 +msgid "This pull request will consist of __COMMITS__ commit." +msgid_plural "This pull request will consist of __COMMITS__ commits." +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest.html:336 +msgid "Show detailed compare." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:343 +msgid "There are no commits to merge." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:450 +msgid "Destination repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest.html:461 +msgid "Select commit reference" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:4 +#, python-format +msgid "%s Pull Request #%s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:48 +msgid "From" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:51 +#: rhodecode/templates/pullrequests/pullrequest_show.html:185 +msgid "Close" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:58 +msgid "Origin" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:105 +msgid "Review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:116 +#, python-format +msgid "calculated based on %s reviewer vote" +msgid_plural "calculated based on %s reviewers votes" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:139 +#: rhodecode/templates/pullrequests/pullrequest_show.html:141 +#, python-format +msgid "%d Pull request comment" +msgid_plural "%d Pull request comments" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +#, python-format +msgid "%d Outdated Comment" +msgid_plural "%d Outdated Comments" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:151 +msgid "(Show)" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:160 +#: rhodecode/templates/pullrequests/pullrequest_show.html:219 +msgid "Save Changes" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:200 +msgid "reviewer" +msgstr "检视者" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:236 +msgid "Missing requirements:" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:237 +msgid "" +"These commits cannot be displayed, because this repository uses the " +"Mercurial largefiles extension, which was not enabled." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:245 +msgid "Missing commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:246 +msgid "" +"This pull request cannot be displayed, because one or more commits no longer" +" exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:247 +msgid "" +"Please update this pull request, push the commits back into the source " +"repository, or consider closing this pull request." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:254 +msgid "Update commits" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:257 +#, python-format +msgid "Compare View: %s commit" +msgid_plural "Compare View: %s commits" +msgstr[0] "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:330 +#: rhodecode/templates/pullrequests/pullrequest_show.html:365 +msgid "Outdated Inline Comments" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.html:386 +#: rhodecode/templates/pullrequests/pullrequest_show.html:392 +msgid "Showing a huge diff might take some time and resources" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:4 +#, python-format +msgid "%s Pull Requests" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:34 +msgid "Open new Pull Request" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:48 +msgid "Opened" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:49 +msgid "Opened by me" +msgstr "我创建的" + +#: rhodecode/templates/pullrequests/pullrequests.html:50 +msgid "Awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:52 +msgid "Awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:53 +msgid "From this repo" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:62 +#, python-format +msgid "Pull Requests from %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:64 +#, python-format +msgid "Closed Pull Requests to repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:66 +#, python-format +msgid "Pull Requests to %(repo_name)s repository opened by me" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:68 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:70 +#, python-format +msgid "Pull Requests to %(repo_name)s repository awaiting my review" +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequests.html:72 +#, python-format +msgid "Pull Requests to %(repo_name)s repository" +msgstr "" + +#: rhodecode/templates/search/search.html:6 +#: rhodecode/templates/search/search.html:17 +#, python-format +msgid "Search inside repository %(repo_name)s" +msgstr "" + +#: rhodecode/templates/search/search.html:8 +#: rhodecode/templates/search/search.html:19 +msgid "Search inside all accessible repositories" +msgstr "" + +#: rhodecode/templates/search/search.html:60 +msgid "Search item" +msgstr "" + +#: rhodecode/templates/search/search.html:63 +msgid "File contents" +msgstr "文件内容" + +#: rhodecode/templates/search/search.html:63 +msgid "Commit messages" +msgstr "提交信息" + +#: rhodecode/templates/search/search.html:63 +msgid "File names" +msgstr "文件名" + +#: rhodecode/templates/search/search_path.html:4 +msgid "File" +msgstr "" + +#: rhodecode/templates/summary/base.html:5 +#, python-format +msgid "%s Summary" +msgstr "%s概要" + +#: rhodecode/templates/summary/base.html:13 +#, python-format +msgid "%s ATOM feed" +msgstr "" + +#: rhodecode/templates/summary/base.html:14 +#, python-format +msgid "%s RSS feed" +msgstr "" + +#: rhodecode/templates/summary/components.html:5 +#, python-format +msgid "%(num)s Branch" +msgid_plural "%(num)s Branches" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:12 +#, python-format +msgid "%(num)s Closed Branch" +msgid_plural "%(num)s Closed Branches" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:19 +#, python-format +msgid "%(num)s Tag" +msgid_plural "%(num)s Tags" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:26 +#, python-format +msgid "%(num)s Bookmark" +msgid_plural "%(num)s Bookmarks" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:49 +msgid "Read-only url" +msgstr "" + +#: rhodecode/templates/summary/components.html:54 +#: rhodecode/templates/summary/components.html:65 +msgid "Show by Name" +msgstr "以名字显示" + +#: rhodecode/templates/summary/components.html:55 +#: rhodecode/templates/summary/components.html:66 +msgid "Show by ID" +msgstr "按ID显示" + +#: rhodecode/templates/summary/components.html:56 +msgid "SVN Protocol is disabled. To enable it, see the" +msgstr "" + +#: rhodecode/templates/summary/components.html:56 +msgid "documentation here" +msgstr "" + +#: rhodecode/templates/summary/components.html:60 +msgid "Clone url" +msgstr "克隆地址" + +#: rhodecode/templates/summary/components.html:86 +msgid "Information" +msgstr "" + +#: rhodecode/templates/summary/components.html:95 +#: rhodecode/templates/summary/components.html:98 +#, python-format +msgid "%(num)s Commit" +msgid_plural "%(num)s Commits" +msgstr[0] "" + +#: rhodecode/templates/summary/components.html:102 +msgid "Number of Repository Forks" +msgstr "" + +#: rhodecode/templates/summary/components.html:110 +msgid "Calculating Repository Size..." +msgstr "" + +#: rhodecode/templates/summary/components.html:141 +msgid "Calculating Code Statistics..." +msgstr "" + +#: rhodecode/templates/summary/components.html:145 +msgid "Statistics are disabled for this repository" +msgstr "该版本库统计功能已经禁用" + +#: rhodecode/templates/summary/components.html:148 +msgid "enable statistics" +msgstr "" + +#: rhodecode/templates/summary/components.html:159 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.html:165 +msgid "There are no downloads yet" +msgstr "无下载" + +#: rhodecode/templates/summary/components.html:169 +msgid "Downloads are disabled for this repository" +msgstr "这个版本库的下载已经禁用" + +#: rhodecode/templates/summary/components.html:172 +msgid "enable downloads" +msgstr "" + +#: rhodecode/templates/summary/summary.html:17 +#: rhodecode/templates/summary/summary.html:19 +msgid "RSS Feed" +msgstr "" + +#: rhodecode/templates/summary/summary.html:35 +msgid "Quick start" +msgstr "快速入门" + +#: rhodecode/templates/summary/summary.html:48 +#, python-format +msgid "Readme file from commit %s:%s" +msgstr "" + +#: rhodecode/templates/tags/tags.html:5 +#, python-format +msgid "%s Tags" +msgstr "%s标签" + +#: rhodecode/templates/tags/tags.html:13 +msgid "tags" +msgstr "" + +#: rhodecode/templates/tags/tags.html:31 +msgid "Compare Selected Tags" +msgstr "" + +#: rhodecode/templates/users/user.html:29 +#: rhodecode/templates/users/user_profile.html:5 +msgid "Profile" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:35 +msgid "First name" +msgstr "" + +#: rhodecode/templates/users/user_profile.html:43 +msgid "Last name" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:162 +msgid "hello" +msgstr "" + +#: rhodecode/tests/lib/test_ext_json.py:163 +msgid "singular" +msgid_plural "plural" +msgstr[0] "" diff --git a/rhodecode/lib/__init__.py b/rhodecode/lib/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode libs +""" diff --git a/rhodecode/lib/action_parser.py b/rhodecode/lib/action_parser.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/action_parser.py @@ -0,0 +1,314 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pylons import url +from pylons.i18n.translation import _ +from webhelpers.html.builder import literal +from webhelpers.html.tags import link_to + +from rhodecode.lib.utils2 import AttributeDict +from rhodecode.lib.vcs.backends.base import BaseCommit +from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError + + +log = logging.getLogger(__name__) + + +def action_parser(user_log, feed=False, parse_cs=False): + """ + This helper will action_map the specified string action into translated + fancy names with icons and links + + :param user_log: user log instance + :param feed: use output for feeds (no html and fancy icons) + :param parse_cs: parse Changesets into VCS instances + """ + ap = ActionParser(user_log, feed=False, parse_commits=False) + return ap.callbacks() + + +class ActionParser(object): + + commits_limit = 3 # display this amount always + commits_top_limit = 50 # show up to this amount of commits hidden + + def __init__(self, user_log, feed=False, parse_commits=False): + self.user_log = user_log + self.feed = feed + self.parse_commits = parse_commits + + self.action = user_log.action + self.action_params = ' ' + x = self.action.split(':', 1) + if len(x) > 1: + self.action, self.action_params = x + + def callbacks(self): + action_str = self.action_map.get(self.action, self.action) + if self.feed: + action = action_str[0].replace('[', '').replace(']', '') + else: + action = action_str[0]\ + .replace('[', '<span class="journal_highlight">')\ + .replace(']', '</span>') + + action_params_func = _no_params_func + if callable(action_str[1]): + action_params_func = action_str[1] + + # returned callbacks we need to call to get + return [ + lambda: literal(action), action_params_func, + self.action_parser_icon] + + @property + def action_map(self): + + # action : translated str, callback(extractor), icon + action_map = { + 'user_deleted_repo': ( + _('[deleted] repository'), + None, 'icon-trash'), + 'user_created_repo': ( + _('[created] repository'), + None, 'icon-plus icon-plus-colored'), + 'user_created_fork': ( + _('[created] repository as fork'), + None, 'icon-code-fork'), + 'user_forked_repo': ( + _('[forked] repository'), + self.get_fork_name, 'icon-code-fork'), + 'user_updated_repo': ( + _('[updated] repository'), + None, 'icon-pencil icon-pencil-colored'), + 'user_downloaded_archive': ( + _('[downloaded] archive from repository'), + self.get_archive_name, 'icon-download-alt'), + 'admin_deleted_repo': ( + _('[delete] repository'), + None, 'icon-trash'), + 'admin_created_repo': ( + _('[created] repository'), + None, 'icon-plus icon-plus-colored'), + 'admin_forked_repo': ( + _('[forked] repository'), + None, 'icon-code-fork icon-fork-colored'), + 'admin_updated_repo': ( + _('[updated] repository'), + None, 'icon-pencil icon-pencil-colored'), + 'admin_created_user': ( + _('[created] user'), + self.get_user_name, 'icon-user icon-user-colored'), + 'admin_updated_user': ( + _('[updated] user'), + self.get_user_name, 'icon-user icon-user-colored'), + 'admin_created_users_group': ( + _('[created] user group'), + self.get_users_group, 'icon-pencil icon-pencil-colored'), + 'admin_updated_users_group': ( + _('[updated] user group'), + self.get_users_group, 'icon-pencil icon-pencil-colored'), + 'user_commented_revision': ( + _('[commented] on commit in repository'), + self.get_cs_links, 'icon-comment icon-comment-colored'), + 'user_commented_pull_request': ( + _('[commented] on pull request for'), + self.get_pull_request, 'icon-comment icon-comment-colored'), + 'user_closed_pull_request': ( + _('[closed] pull request for'), + self.get_pull_request, 'icon-check'), + 'user_merged_pull_request': ( + _('[merged] pull request for'), + self.get_pull_request, 'icon-check'), + 'push': ( + _('[pushed] into'), + self.get_cs_links, 'icon-arrow-up'), + 'push_local': ( + _('[committed via RhodeCode] into repository'), + self.get_cs_links, 'icon-pencil icon-pencil-colored'), + 'push_remote': ( + _('[pulled from remote] into repository'), + self.get_cs_links, 'icon-arrow-up'), + 'pull': ( + _('[pulled] from'), + None, 'icon-arrow-down'), + 'started_following_repo': ( + _('[started following] repository'), + None, 'icon-heart icon-heart-colored'), + 'stopped_following_repo': ( + _('[stopped following] repository'), + None, 'icon-heart-empty icon-heart-colored'), + } + return action_map + + def get_fork_name(self): + repo_name = self.action_params + _url = url('summary_home', repo_name=repo_name) + return _('fork name %s') % link_to(self.action_params, _url) + + def get_user_name(self): + user_name = self.action_params + return user_name + + def get_users_group(self): + group_name = self.action_params + return group_name + + def get_pull_request(self): + pull_request_id = self.action_params + if self.is_deleted(): + repo_name = self.user_log.repository_name + else: + repo_name = self.user_log.repository.repo_name + return link_to( + _('Pull request #%s') % pull_request_id, + url('pullrequest_show', repo_name=repo_name, + pull_request_id=pull_request_id)) + + def get_archive_name(self): + archive_name = self.action_params + return archive_name + + def action_parser_icon(self): + tmpl = """<i class="%s" alt="%s"></i>""" + ico = self.action_map.get(self.action, ['', '', ''])[2] + return literal(tmpl % (ico, self.action)) + + def get_cs_links(self): + if self.is_deleted(): + return self.action_params + + repo_name = self.user_log.repository.repo_name + commit_ids = self.action_params.split(',') + commits = self.get_commits(commit_ids) + + link_generator = ( + self.lnk(commit, repo_name) + for commit in commits[:self.commits_limit]) + commit_links = [" " + ', '.join(link_generator)] + _op1, _name1 = _get_op(commit_ids[0]) + _op2, _name2 = _get_op(commit_ids[-1]) + + commit_id_range = '%s...%s' % (_name1, _name2) + + compare_view = ( + ' <div class="compare_view tooltip" title="%s">' + '<a href="%s">%s</a> </div>' % ( + _('Show all combined commits %s->%s') % ( + commit_ids[0][:12], commit_ids[-1][:12] + ), + url('changeset_home', repo_name=repo_name, + revision=commit_id_range), _('compare view') + ) + ) + + if len(commit_ids) > self.commits_limit: + more_count = len(commit_ids) - self.commits_limit + commit_links.append( + _(' and %(num)s more commits') % {'num': more_count} + ) + + if len(commits) > 1: + commit_links.append(compare_view) + return ''.join(commit_links) + + def get_commits(self, commit_ids): + commits = [] + if not filter(lambda v: v != '', commit_ids): + return commits + + repo = None + if self.parse_commits: + repo = self.user_log.repository.scm_instance() + + for commit_id in commit_ids[:self.commits_top_limit]: + _op, _name = _get_op(commit_id) + + # we want parsed commits, or new log store format is bad + if self.parse_commits: + try: + commit = repo.get_commit(commit_id=commit_id) + commits.append(commit) + except CommitDoesNotExistError: + log.error( + 'cannot find commit id %s in this repository', + commit_id) + commits.append(commit_id) + continue + else: + fake_commit = AttributeDict({ + 'short_id': commit_id[:12], + 'raw_id': commit_id, + 'message': '', + 'op': _op, + 'ref_name': _name + }) + commits.append(fake_commit) + + return commits + + def lnk(self, commit_or_id, repo_name): + from rhodecode.lib.helpers import tooltip + + if isinstance(commit_or_id, (BaseCommit, AttributeDict)): + lazy_cs = True + if (getattr(commit_or_id, 'op', None) and + getattr(commit_or_id, 'ref_name', None)): + lazy_cs = False + lbl = '?' + if commit_or_id.op == 'delete_branch': + lbl = '%s' % _('Deleted branch: %s') % commit_or_id.ref_name + title = '' + elif commit_or_id.op == 'tag': + lbl = '%s' % _('Created tag: %s') % commit_or_id.ref_name + title = '' + _url = '#' + + else: + lbl = '%s' % (commit_or_id.short_id[:8]) + _url = url('changeset_home', repo_name=repo_name, + revision=commit_or_id.raw_id) + title = tooltip(commit_or_id.message) + else: + # commit cannot be found/striped/removed etc. + lbl = ('%s' % commit_or_id)[:12] + _url = '#' + title = _('Commit not found') + if self.parse_commits: + return link_to(lbl, _url, title=title, class_='tooltip') + return link_to(lbl, _url, raw_id=commit_or_id.raw_id, repo_name=repo_name, + class_='lazy-cs' if lazy_cs else '') + + def is_deleted(self): + return self.user_log.repository is None + + +def _no_params_func(): + return "" + + +def _get_op(commit_id): + _op = None + _name = commit_id + if len(commit_id.split('=>')) == 2: + _op, _name = commit_id.split('=>') + return _op, _name diff --git a/rhodecode/lib/annotate.py b/rhodecode/lib/annotate.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/annotate.py @@ -0,0 +1,214 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Anontation library for usage in rhodecode, previously part of vcs +""" + +import StringIO + +from pygments import highlight +from pygments.formatters import HtmlFormatter + +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.nodes import FileNode + + +def annotate_highlight( + filenode, annotate_from_commit_func=None, + order=None, headers=None, **options): + """ + Returns html portion containing annotated table with 3 columns: line + numbers, commit information and pygmentized line of code. + + :param filenode: FileNode object + :param annotate_from_commit_func: function taking commit and + returning single annotate cell; needs break line at the end + :param order: ordered sequence of ``ls`` (line numbers column), + ``annotate`` (annotate column), ``code`` (code column); Default is + ``['ls', 'annotate', 'code']`` + :param headers: dictionary with headers (keys are whats in ``order`` + parameter) + """ + from rhodecode.lib.utils import get_custom_lexer + options['linenos'] = True + formatter = AnnotateHtmlFormatter( + filenode=filenode, order=order, headers=headers, + annotate_from_commit_func=annotate_from_commit_func, **options) + lexer = get_custom_lexer(filenode.extension) or filenode.lexer + highlighted = highlight(filenode.content, lexer, formatter) + return highlighted + + +class AnnotateHtmlFormatter(HtmlFormatter): + + def __init__( + self, filenode, annotate_from_commit_func=None, + order=None, **options): + """ + If ``annotate_from_commit_func`` is passed, it should be a function + which returns string from the given commit. For example, we may pass + following function as ``annotate_from_commit_func``:: + + def commit_to_anchor(commit): + return '<a href="/commits/%s/">%s</a>\n' %\ + (commit.id, commit.id) + + :param annotate_from_commit_func: see above + :param order: (default: ``['ls', 'annotate', 'code']``); order of + columns; + :param options: standard pygment's HtmlFormatter options, there is + extra option tough, ``headers``. For instance we can pass:: + + formatter = AnnotateHtmlFormatter(filenode, headers={ + 'ls': '#', + 'annotate': 'Annotate', + 'code': 'Code', + }) + + """ + super(AnnotateHtmlFormatter, self).__init__(**options) + self.annotate_from_commit_func = annotate_from_commit_func + self.order = order or ('ls', 'annotate', 'code') + headers = options.pop('headers', None) + if headers and not ( + 'ls' in headers and 'annotate' in headers and 'code' in headers): + raise ValueError( + "If headers option dict is specified it must " + "all 'ls', 'annotate' and 'code' keys") + self.headers = headers + if isinstance(filenode, FileNode): + self.filenode = filenode + else: + raise VCSError( + "This formatter expect FileNode parameter, not %r" % + type(filenode)) + + def annotate_from_commit(self, commit): + """ + Returns full html line for single commit per annotated line. + """ + if self.annotate_from_commit_func: + return self.annotate_from_commit_func(commit) + else: + return commit.id + '\n' + + def _wrap_tablelinenos(self, inner): + dummyoutfile = StringIO.StringIO() + lncount = 0 + for t, line in inner: + if t: + lncount += 1 + dummyoutfile.write(line) + + fl = self.linenostart + mw = len(str(lncount + fl - 1)) + sp = self.linenospecial + st = self.linenostep + la = self.lineanchors + aln = self.anchorlinenos + if sp: + lines = [] + + for i in range(fl, fl + lncount): + if i % st == 0: + if i % sp == 0: + if aln: + lines.append('<a href="#%s-%d" class="special">' + '%*d</a>' % + (la, i, mw, i)) + else: + lines.append('<span class="special">' + '%*d</span>' % (mw, i)) + else: + if aln: + lines.append('<a href="#%s-%d">' + '%*d</a>' % (la, i, mw, i)) + else: + lines.append('%*d' % (mw, i)) + else: + lines.append('') + ls = '\n'.join(lines) + else: + lines = [] + for i in range(fl, fl + lncount): + if i % st == 0: + if aln: + lines.append('<a href="#%s-%d">%*d</a>' \ + % (la, i, mw, i)) + else: + lines.append('%*d' % (mw, i)) + else: + lines.append('') + ls = '\n'.join(lines) + + cached = {} + annotate = [] + for el in self.filenode.annotate: + commit_id = el[1] + if commit_id in cached: + result = cached[commit_id] + else: + commit = el[2]() + result = self.annotate_from_commit(commit) + cached[commit_id] = result + annotate.append(result) + + annotate = ''.join(annotate) + + # in case you wonder about the seemingly redundant <div> here: + # since the content in the other cell also is wrapped in a div, + # some browsers in some configurations seem to mess up the formatting. + ''' + yield 0, ('<table class="%stable">' % self.cssclass + + '<tr><td class="linenos"><div class="linenodiv"><pre>' + + ls + '</pre></div></td>' + + '<td class="code">') + yield 0, dummyoutfile.getvalue() + yield 0, '</td></tr></table>' + + ''' + headers_row = [] + if self.headers: + headers_row = ['<tr class="annotate-header">'] + for key in self.order: + td = ''.join(('<td>', self.headers[key], '</td>')) + headers_row.append(td) + headers_row.append('</tr>') + + body_row_start = ['<tr>'] + for key in self.order: + if key == 'ls': + body_row_start.append( + '<td class="linenos"><div class="linenodiv"><pre>' + + ls + '</pre></div></td>') + elif key == 'annotate': + body_row_start.append( + '<td class="annotate"><div class="annotatediv"><pre>' + + annotate + '</pre></div></td>') + elif key == 'code': + body_row_start.append('<td class="code">') + yield 0, ('<table class="%stable">' % self.cssclass + + ''.join(headers_row) + + ''.join(body_row_start) + ) + yield 0, dummyoutfile.getvalue() + yield 0, '</td></tr></table>' diff --git a/rhodecode/lib/app_globals.py b/rhodecode/lib/app_globals.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/app_globals.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +The application's Globals object +""" + +from beaker.cache import CacheManager +from beaker.util import parse_cache_config_options + + +class Globals(object): + """ + Globals acts as a container for objects available throughout the + life of the application + """ + + def __init__(self, config): + """One instance of Globals is created during application + initialization and is available during requests via the + 'app_globals' variable + + """ + self.cache = CacheManager(**parse_cache_config_options(config)) + self.available_permissions = None # propagated after init_model diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/auth.py @@ -0,0 +1,1822 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +authentication and permission libraries +""" + +import inspect +import collections +import fnmatch +import hashlib +import itertools +import logging +import os +import random +import time +import traceback +from functools import wraps + +import ipaddress +from pylons import url, request +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _ +from sqlalchemy import or_ +from sqlalchemy.orm.exc import ObjectDeletedError +from sqlalchemy.orm import joinedload +from zope.cachedescriptors.property import Lazy as LazyProperty + +import rhodecode +from rhodecode.model import meta +from rhodecode.model.meta import Session +from rhodecode.model.user import UserModel +from rhodecode.model.db import ( + User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember, + UserIpMap, UserApiKeys) +from rhodecode.lib import caches +from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5 +from rhodecode.lib.utils import ( + get_repo_slug, get_repo_group_slug, get_user_group_slug) +from rhodecode.lib.caching_query import FromCache + + +if rhodecode.is_unix: + import bcrypt + +log = logging.getLogger(__name__) + +csrf_token_key = "csrf_token" + + +class PasswordGenerator(object): + """ + This is a simple class for generating password from different sets of + characters + usage:: + + passwd_gen = PasswordGenerator() + #print 8-letter password containing only big and small letters + of alphabet + passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL) + """ + ALPHABETS_NUM = r'''1234567890''' + ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm''' + ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM''' + ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' + ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \ + + ALPHABETS_NUM + ALPHABETS_SPECIAL + ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM + ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM + + def __init__(self, passwd=''): + self.passwd = passwd + + def gen_password(self, length, type_=None): + if type_ is None: + type_ = self.ALPHABETS_FULL + self.passwd = ''.join([random.choice(type_) for _ in xrange(length)]) + return self.passwd + + +class _RhodeCodeCryptoBase(object): + + def hash_create(self, str_): + """ + hash the string using + + :param str_: password to hash + """ + raise NotImplementedError + + def hash_check_with_upgrade(self, password, hashed): + """ + Returns tuple in which first element is boolean that states that + given password matches it's hashed version, and the second is new hash + of the password, in case this password should be migrated to new + cipher. + """ + checked_hash = self.hash_check(password, hashed) + return checked_hash, None + + def hash_check(self, password, hashed): + """ + Checks matching password with it's hashed value. + + :param password: password + :param hashed: password in hashed form + """ + raise NotImplementedError + + def _assert_bytes(self, value): + """ + Passing in an `unicode` object can lead to hard to detect issues + if passwords contain non-ascii characters. Doing a type check + during runtime, so that such mistakes are detected early on. + """ + if not isinstance(value, str): + raise TypeError( + "Bytestring required as input, got %r." % (value, )) + + +class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase): + + def hash_create(self, str_): + self._assert_bytes(str_) + return bcrypt.hashpw(str_, bcrypt.gensalt(10)) + + def hash_check_with_upgrade(self, password, hashed): + """ + Returns tuple in which first element is boolean that states that + given password matches it's hashed version, and the second is new hash + of the password, in case this password should be migrated to new + cipher. + + This implements special upgrade logic which works like that: + - check if the given password == bcrypted hash, if yes then we + properly used password and it was already in bcrypt. Proceed + without any changes + - if bcrypt hash check is not working try with sha256. If hash compare + is ok, it means we using correct but old hashed password. indicate + hash change and proceed + """ + + new_hash = None + + # regular pw check + password_match_bcrypt = self.hash_check(password, hashed) + + # now we want to know if the password was maybe from sha256 + # basically calling _RhodeCodeCryptoSha256().hash_check() + if not password_match_bcrypt: + if _RhodeCodeCryptoSha256().hash_check(password, hashed): + new_hash = self.hash_create(password) # make new bcrypt hash + password_match_bcrypt = True + + return password_match_bcrypt, new_hash + + def hash_check(self, password, hashed): + """ + Checks matching password with it's hashed value. + + :param password: password + :param hashed: password in hashed form + """ + self._assert_bytes(password) + try: + return bcrypt.hashpw(password, hashed) == hashed + except ValueError as e: + # we're having a invalid salt here probably, we should not crash + # just return with False as it would be a wrong password. + log.debug('Failed to check password hash using bcrypt %s', + safe_str(e)) + + return False + + +class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase): + + def hash_create(self, str_): + self._assert_bytes(str_) + return hashlib.sha256(str_).hexdigest() + + def hash_check(self, password, hashed): + """ + Checks matching password with it's hashed value. + + :param password: password + :param hashed: password in hashed form + """ + self._assert_bytes(password) + return hashlib.sha256(password).hexdigest() == hashed + + +class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase): + + def hash_create(self, str_): + self._assert_bytes(str_) + return hashlib.md5(str_).hexdigest() + + def hash_check(self, password, hashed): + """ + Checks matching password with it's hashed value. + + :param password: password + :param hashed: password in hashed form + """ + self._assert_bytes(password) + return hashlib.md5(password).hexdigest() == hashed + + +def crypto_backend(): + """ + Return the matching crypto backend. + + Selection is based on if we run tests or not, we pick md5 backend to run + tests faster since BCRYPT is expensive to calculate + """ + if rhodecode.is_test: + RhodeCodeCrypto = _RhodeCodeCryptoMd5() + else: + RhodeCodeCrypto = _RhodeCodeCryptoBCrypt() + + return RhodeCodeCrypto + + +def get_crypt_password(password): + """ + Create the hash of `password` with the active crypto backend. + + :param password: The cleartext password. + :type password: unicode + """ + password = safe_str(password) + return crypto_backend().hash_create(password) + + +def check_password(password, hashed): + """ + Check if the value in `password` matches the hash in `hashed`. + + :param password: The cleartext password. + :type password: unicode + + :param hashed: The expected hashed version of the password. + :type hashed: The hash has to be passed in in text representation. + """ + password = safe_str(password) + return crypto_backend().hash_check(password, hashed) + + +def generate_auth_token(data, salt=None): + """ + Generates API KEY from given string + """ + + if salt is None: + salt = os.urandom(16) + return hashlib.sha1(safe_str(data) + salt).hexdigest() + + +class CookieStoreWrapper(object): + + def __init__(self, cookie_store): + self.cookie_store = cookie_store + + def __repr__(self): + return 'CookieStore<%s>' % (self.cookie_store) + + def get(self, key, other=None): + if isinstance(self.cookie_store, dict): + return self.cookie_store.get(key, other) + elif isinstance(self.cookie_store, AuthUser): + return self.cookie_store.__dict__.get(key, other) + + +def _cached_perms_data(user_id, scope, user_is_admin, + user_inherit_default_permissions, explicit, algo): + + permissions = PermissionCalculator( + user_id, scope, user_is_admin, user_inherit_default_permissions, + explicit, algo) + return permissions.calculate() + + +class PermissionCalculator(object): + + def __init__( + self, user_id, scope, user_is_admin, + user_inherit_default_permissions, explicit, algo): + self.user_id = user_id + self.user_is_admin = user_is_admin + self.inherit_default_permissions = user_inherit_default_permissions + self.explicit = explicit + self.algo = algo + + scope = scope or {} + self.scope_repo_id = scope.get('repo_id') + self.scope_repo_group_id = scope.get('repo_group_id') + self.scope_user_group_id = scope.get('user_group_id') + + self.default_user_id = User.get_default_user(cache=True).user_id + + self.permissions_repositories = {} + self.permissions_repository_groups = {} + self.permissions_user_groups = {} + self.permissions_global = set() + + self.default_repo_perms = Permission.get_default_repo_perms( + self.default_user_id, self.scope_repo_id) + self.default_repo_groups_perms = Permission.get_default_group_perms( + self.default_user_id, self.scope_repo_group_id) + self.default_user_group_perms = \ + Permission.get_default_user_group_perms( + self.default_user_id, self.scope_user_group_id) + + def calculate(self): + if self.user_is_admin: + return self._admin_permissions() + + self._calculate_global_default_permissions() + self._calculate_global_permissions() + self._calculate_default_permissions() + self._calculate_repository_permissions() + self._calculate_repository_group_permissions() + self._calculate_user_group_permissions() + return self._permission_structure() + + def _admin_permissions(self): + """ + admin user have all default rights for repositories + and groups set to admin + """ + self.permissions_global.add('hg.admin') + self.permissions_global.add('hg.create.write_on_repogroup.true') + + # repositories + for perm in self.default_repo_perms: + r_k = perm.UserRepoToPerm.repository.repo_name + p = 'repository.admin' + self.permissions_repositories[r_k] = p + + # repository groups + for perm in self.default_repo_groups_perms: + rg_k = perm.UserRepoGroupToPerm.group.group_name + p = 'group.admin' + self.permissions_repository_groups[rg_k] = p + + # user groups + for perm in self.default_user_group_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = 'usergroup.admin' + self.permissions_user_groups[u_k] = p + + return self._permission_structure() + + def _calculate_global_default_permissions(self): + """ + global permissions taken from the default user + """ + default_global_perms = UserToPerm.query()\ + .filter(UserToPerm.user_id == self.default_user_id)\ + .options(joinedload(UserToPerm.permission)) + + for perm in default_global_perms: + self.permissions_global.add(perm.permission.permission_name) + + def _calculate_global_permissions(self): + """ + Set global system permissions with user permissions or permissions + taken from the user groups of the current user. + + The permissions include repo creating, repo group creating, forking + etc. + """ + + # now we read the defined permissions and overwrite what we have set + # before those can be configured from groups or users explicitly. + + # TODO: johbo: This seems to be out of sync, find out the reason + # for the comment below and update it. + + # In case we want to extend this list we should be always in sync with + # User.DEFAULT_USER_PERMISSIONS definitions + _configurable = frozenset([ + 'hg.fork.none', 'hg.fork.repository', + 'hg.create.none', 'hg.create.repository', + 'hg.usergroup.create.false', 'hg.usergroup.create.true', + 'hg.repogroup.create.false', 'hg.repogroup.create.true', + 'hg.create.write_on_repogroup.false', + 'hg.create.write_on_repogroup.true', + 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true' + ]) + + # USER GROUPS comes first user group global permissions + user_perms_from_users_groups = Session().query(UserGroupToPerm)\ + .options(joinedload(UserGroupToPerm.permission))\ + .join((UserGroupMember, UserGroupToPerm.users_group_id == + UserGroupMember.users_group_id))\ + .filter(UserGroupMember.user_id == self.user_id)\ + .order_by(UserGroupToPerm.users_group_id)\ + .all() + + # need to group here by groups since user can be in more than + # one group, so we get all groups + _explicit_grouped_perms = [ + [x, list(y)] for x, y in + itertools.groupby(user_perms_from_users_groups, + lambda _x: _x.users_group)] + + for gr, perms in _explicit_grouped_perms: + # since user can be in multiple groups iterate over them and + # select the lowest permissions first (more explicit) + # TODO: marcink: do this^^ + + # group doesn't inherit default permissions so we actually set them + if not gr.inherit_default_permissions: + # NEED TO IGNORE all previously set configurable permissions + # and replace them with explicitly set from this user + # group permissions + self.permissions_global = self.permissions_global.difference( + _configurable) + for perm in perms: + self.permissions_global.add( + perm.permission.permission_name) + + # user explicit global permissions + user_perms = Session().query(UserToPerm)\ + .options(joinedload(UserToPerm.permission))\ + .filter(UserToPerm.user_id == self.user_id).all() + + if not self.inherit_default_permissions: + # NEED TO IGNORE all configurable permissions and + # replace them with explicitly set from this user permissions + self.permissions_global = self.permissions_global.difference( + _configurable) + for perm in user_perms: + self.permissions_global.add(perm.permission.permission_name) + + def _calculate_default_permissions(self): + """ + Set default user permissions for repositories, repository groups + taken from the default user. + + Calculate inheritance of object permissions based on what we have now + in GLOBAL permissions. We check if .false is in GLOBAL since this is + explicitly set. Inherit is the opposite of .false being there. + + .. note:: + + the syntax is little bit odd but what we need to check here is + the opposite of .false permission being in the list so even for + inconsistent state when both .true/.false is there + .false is more important + + """ + user_inherit_object_permissions = not ('hg.inherit_default_perms.false' + in self.permissions_global) + + # defaults for repositories, taken from `default` user permissions + # on given repo + for perm in self.default_repo_perms: + r_k = perm.UserRepoToPerm.repository.repo_name + if perm.Repository.private and not ( + perm.Repository.user_id == self.user_id): + # disable defaults for private repos, + p = 'repository.none' + elif perm.Repository.user_id == self.user_id: + # set admin if owner + p = 'repository.admin' + else: + p = perm.Permission.permission_name + # if we decide this user isn't inheriting permissions from + # default user we set him to .none so only explicit + # permissions work + if not user_inherit_object_permissions: + p = 'repository.none' + self.permissions_repositories[r_k] = p + + # defaults for repository groups taken from `default` user permission + # on given group + for perm in self.default_repo_groups_perms: + rg_k = perm.UserRepoGroupToPerm.group.group_name + if perm.RepoGroup.user_id == self.user_id: + # set admin if owner + p = 'group.admin' + else: + p = perm.Permission.permission_name + + # if we decide this user isn't inheriting permissions from default + # user we set him to .none so only explicit permissions work + if not user_inherit_object_permissions: + p = 'group.none' + self.permissions_repository_groups[rg_k] = p + + # defaults for user groups taken from `default` user permission + # on given user group + for perm in self.default_user_group_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = perm.Permission.permission_name + # if we decide this user isn't inheriting permissions from default + # user we set him to .none so only explicit permissions work + if not user_inherit_object_permissions: + p = 'usergroup.none' + self.permissions_user_groups[u_k] = p + + def _calculate_repository_permissions(self): + """ + Repository permissions for the current user. + + Check if the user is part of user groups for this repository and + fill in the permission from it. `_choose_permission` decides of which + permission should be selected based on selected method. + """ + + # user group for repositories permissions + user_repo_perms_from_user_group = Permission\ + .get_default_repo_perms_from_user_group( + self.user_id, self.scope_repo_id) + + multiple_counter = collections.defaultdict(int) + for perm in user_repo_perms_from_user_group: + r_k = perm.UserGroupRepoToPerm.repository.repo_name + multiple_counter[r_k] += 1 + p = perm.Permission.permission_name + + if perm.Repository.user_id == self.user_id: + # set admin if owner + p = 'repository.admin' + else: + if multiple_counter[r_k] > 1: + cur_perm = self.permissions_repositories[r_k] + p = self._choose_permission(p, cur_perm) + self.permissions_repositories[r_k] = p + + # user explicit permissions for repositories, overrides any specified + # by the group permission + user_repo_perms = Permission.get_default_repo_perms( + self.user_id, self.scope_repo_id) + for perm in user_repo_perms: + r_k = perm.UserRepoToPerm.repository.repo_name + # set admin if owner + if perm.Repository.user_id == self.user_id: + p = 'repository.admin' + else: + p = perm.Permission.permission_name + if not self.explicit: + cur_perm = self.permissions_repositories.get( + r_k, 'repository.none') + p = self._choose_permission(p, cur_perm) + self.permissions_repositories[r_k] = p + + def _calculate_repository_group_permissions(self): + """ + Repository group permissions for the current user. + + Check if the user is part of user groups for repository groups and + fill in the permissions from it. `_choose_permmission` decides of which + permission should be selected based on selected method. + """ + # user group for repo groups permissions + user_repo_group_perms_from_user_group = Permission\ + .get_default_group_perms_from_user_group( + self.user_id, self.scope_repo_group_id) + + multiple_counter = collections.defaultdict(int) + for perm in user_repo_group_perms_from_user_group: + g_k = perm.UserGroupRepoGroupToPerm.group.group_name + multiple_counter[g_k] += 1 + p = perm.Permission.permission_name + if perm.RepoGroup.user_id == self.user_id: + # set admin if owner + p = 'group.admin' + else: + if multiple_counter[g_k] > 1: + cur_perm = self.permissions_repository_groups[g_k] + p = self._choose_permission(p, cur_perm) + self.permissions_repository_groups[g_k] = p + + # user explicit permissions for repository groups + user_repo_groups_perms = Permission.get_default_group_perms( + self.user_id, self.scope_repo_group_id) + for perm in user_repo_groups_perms: + rg_k = perm.UserRepoGroupToPerm.group.group_name + if perm.RepoGroup.user_id == self.user_id: + # set admin if owner + p = 'group.admin' + else: + p = perm.Permission.permission_name + if not self.explicit: + cur_perm = self.permissions_repository_groups.get( + rg_k, 'group.none') + p = self._choose_permission(p, cur_perm) + self.permissions_repository_groups[rg_k] = p + + def _calculate_user_group_permissions(self): + """ + User group permissions for the current user. + """ + # user group for user group permissions + user_group_from_user_group = Permission\ + .get_default_user_group_perms_from_user_group( + self.user_id, self.scope_repo_group_id) + + multiple_counter = collections.defaultdict(int) + for perm in user_group_from_user_group: + g_k = perm.UserGroupUserGroupToPerm\ + .target_user_group.users_group_name + multiple_counter[g_k] += 1 + p = perm.Permission.permission_name + if multiple_counter[g_k] > 1: + cur_perm = self.permissions_user_groups[g_k] + p = self._choose_permission(p, cur_perm) + self.permissions_user_groups[g_k] = p + + # user explicit permission for user groups + user_user_groups_perms = Permission.get_default_user_group_perms( + self.user_id, self.scope_user_group_id) + for perm in user_user_groups_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = perm.Permission.permission_name + if not self.explicit: + cur_perm = self.permissions_user_groups.get( + u_k, 'usergroup.none') + p = self._choose_permission(p, cur_perm) + self.permissions_user_groups[u_k] = p + + def _choose_permission(self, new_perm, cur_perm): + new_perm_val = Permission.PERM_WEIGHTS[new_perm] + cur_perm_val = Permission.PERM_WEIGHTS[cur_perm] + if self.algo == 'higherwin': + if new_perm_val > cur_perm_val: + return new_perm + return cur_perm + elif self.algo == 'lowerwin': + if new_perm_val < cur_perm_val: + return new_perm + return cur_perm + + def _permission_structure(self): + return { + 'global': self.permissions_global, + 'repositories': self.permissions_repositories, + 'repositories_groups': self.permissions_repository_groups, + 'user_groups': self.permissions_user_groups, + } + + +def allowed_auth_token_access(controller_name, whitelist=None, auth_token=None): + """ + Check if given controller_name is in whitelist of auth token access + """ + if not whitelist: + from rhodecode import CONFIG + whitelist = aslist( + CONFIG.get('api_access_controllers_whitelist'), sep=',') + log.debug( + 'Allowed controllers for AUTH TOKEN access: %s' % (whitelist,)) + + auth_token_access_valid = False + for entry in whitelist: + if fnmatch.fnmatch(controller_name, entry): + auth_token_access_valid = True + break + + if auth_token_access_valid: + log.debug('controller:%s matches entry in whitelist' + % (controller_name,)) + else: + msg = ('controller: %s does *NOT* match any entry in whitelist' + % (controller_name,)) + if auth_token: + # if we use auth token key and don't have access it's a warning + log.warning(msg) + else: + log.debug(msg) + + return auth_token_access_valid + + +class AuthUser(object): + """ + A simple object that handles all attributes of user in RhodeCode + + It does lookup based on API key,given user, or user present in session + Then it fills all required information for such user. It also checks if + anonymous access is enabled and if so, it returns default user as logged in + """ + GLOBAL_PERMS = [x[0] for x in Permission.PERMS] + + def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None): + + self.user_id = user_id + self._api_key = api_key + + self.api_key = None + self.feed_token = '' + self.username = username + self.ip_addr = ip_addr + self.name = '' + self.lastname = '' + self.email = '' + self.is_authenticated = False + self.admin = False + self.inherit_default_permissions = False + self.password = '' + + self.anonymous_user = None # propagated on propagate_data + self.propagate_data() + self._instance = None + self._permissions_scoped_cache = {} # used to bind scoped calculation + + @LazyProperty + def permissions(self): + return self.get_perms(user=self, cache=False) + + def permissions_with_scope(self, scope): + """ + Call the get_perms function with scoped data. The scope in that function + narrows the SQL calls to the given ID of objects resulting in fetching + Just particular permission we want to obtain. If scope is an empty dict + then it basically narrows the scope to GLOBAL permissions only. + + :param scope: dict + """ + if 'repo_name' in scope: + obj = Repository.get_by_repo_name(scope['repo_name']) + if obj: + scope['repo_id'] = obj.repo_id + _scope = { + 'repo_id': -1, + 'user_group_id': -1, + 'repo_group_id': -1, + } + _scope.update(scope) + cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b, + _scope.items()))) + if cache_key not in self._permissions_scoped_cache: + # store in cache to mimic how the @LazyProperty works, + # the difference here is that we use the unique key calculated + # from params and values + res = self.get_perms(user=self, cache=False, scope=_scope) + self._permissions_scoped_cache[cache_key] = res + return self._permissions_scoped_cache[cache_key] + + @property + def auth_tokens(self): + return self.get_auth_tokens() + + def get_instance(self): + return User.get(self.user_id) + + def update_lastactivity(self): + if self.user_id: + User.get(self.user_id).update_lastactivity() + + def propagate_data(self): + """ + Fills in user data and propagates values to this instance. Maps fetched + user attributes to this class instance attributes + """ + + user_model = UserModel() + anon_user = self.anonymous_user = User.get_default_user(cache=True) + is_user_loaded = False + + # lookup by userid + if self.user_id is not None and self.user_id != anon_user.user_id: + log.debug('Trying Auth User lookup by USER ID %s' % self.user_id) + is_user_loaded = user_model.fill_data(self, user_id=self.user_id) + + # try go get user by api key + elif self._api_key and self._api_key != anon_user.api_key: + log.debug('Trying Auth User lookup by API KEY %s' % self._api_key) + is_user_loaded = user_model.fill_data(self, api_key=self._api_key) + + # lookup by username + elif self.username: + log.debug('Trying Auth User lookup by USER NAME %s' % self.username) + is_user_loaded = user_model.fill_data(self, username=self.username) + else: + log.debug('No data in %s that could been used to log in' % self) + + if not is_user_loaded: + log.debug('Failed to load user. Fallback to default user') + # if we cannot authenticate user try anonymous + if anon_user.active: + user_model.fill_data(self, user_id=anon_user.user_id) + # then we set this user is logged in + self.is_authenticated = True + else: + # in case of disabled anonymous user we reset some of the + # parameters so such user is "corrupted", skipping the fill_data + for attr in ['user_id', 'username', 'admin', 'active']: + setattr(self, attr, None) + self.is_authenticated = False + + if not self.username: + self.username = 'None' + + log.debug('Auth User is now %s' % self) + + def get_perms(self, user, scope=None, explicit=True, algo='higherwin', + cache=False): + """ + Fills user permission attribute with permissions taken from database + works for permissions given for repositories, and for permissions that + are granted to groups + + :param user: instance of User object from database + :param explicit: In case there are permissions both for user and a group + that user is part of, explicit flag will defiine if user will + explicitly override permissions from group, if it's False it will + make decision based on the algo + :param algo: algorithm to decide what permission should be choose if + it's multiple defined, eg user in two different groups. It also + decides if explicit flag is turned off how to specify the permission + for case when user is in a group + have defined separate permission + """ + user_id = user.user_id + user_is_admin = user.is_admin + + # inheritance of global permissions like create repo/fork repo etc + user_inherit_default_permissions = user.inherit_default_permissions + + log.debug('Computing PERMISSION tree for scope %s' % (scope, )) + compute = caches.conditional_cache( + 'short_term', 'cache_desc', + condition=cache, func=_cached_perms_data) + result = compute(user_id, scope, user_is_admin, + user_inherit_default_permissions, explicit, algo) + + result_repr = [] + for k in result: + result_repr.append((k, len(result[k]))) + + log.debug('PERMISSION tree computed %s' % (result_repr,)) + return result + + def get_auth_tokens(self): + auth_tokens = [self.api_key] + for api_key in UserApiKeys.query()\ + .filter(UserApiKeys.user_id == self.user_id)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time())).all(): + auth_tokens.append(api_key.api_key) + + return auth_tokens + + @property + def is_admin(self): + return self.admin + + @property + def is_user_object(self): + return self.user_id is not None + + @property + def repositories_admin(self): + """ + Returns list of repositories you're an admin of + """ + return [x[0] for x in self.permissions['repositories'].iteritems() + if x[1] == 'repository.admin'] + + @property + def repository_groups_admin(self): + """ + Returns list of repository groups you're an admin of + """ + return [x[0] + for x in self.permissions['repositories_groups'].iteritems() + if x[1] == 'group.admin'] + + @property + def user_groups_admin(self): + """ + Returns list of user groups you're an admin of + """ + return [x[0] for x in self.permissions['user_groups'].iteritems() + if x[1] == 'usergroup.admin'] + + @property + def ip_allowed(self): + """ + Checks if ip_addr used in constructor is allowed from defined list of + allowed ip_addresses for user + + :returns: boolean, True if ip is in allowed ip range + """ + # check IP + inherit = self.inherit_default_permissions + return AuthUser.check_ip_allowed(self.user_id, self.ip_addr, + inherit_from_default=inherit) + + @classmethod + def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default): + allowed_ips = AuthUser.get_allowed_ips( + user_id, cache=True, inherit_from_default=inherit_from_default) + if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips): + log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips)) + return True + else: + log.info('Access for IP:%s forbidden, ' + 'not in %s' % (ip_addr, allowed_ips)) + return False + + def __repr__(self): + return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\ + % (self.user_id, self.username, self.ip_addr, self.is_authenticated) + + def set_authenticated(self, authenticated=True): + if self.user_id != self.anonymous_user.user_id: + self.is_authenticated = authenticated + + def get_cookie_store(self): + return { + 'username': self.username, + 'password': md5(self.password), + 'user_id': self.user_id, + 'is_authenticated': self.is_authenticated + } + + @classmethod + def from_cookie_store(cls, cookie_store): + """ + Creates AuthUser from a cookie store + + :param cls: + :param cookie_store: + """ + user_id = cookie_store.get('user_id') + username = cookie_store.get('username') + api_key = cookie_store.get('api_key') + return AuthUser(user_id, api_key, username) + + @classmethod + def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False): + _set = set() + + if inherit_from_default: + default_ips = UserIpMap.query().filter( + UserIpMap.user == User.get_default_user(cache=True)) + if cache: + default_ips = default_ips.options(FromCache("sql_cache_short", + "get_user_ips_default")) + + # populate from default user + for ip in default_ips: + try: + _set.add(ip.ip_addr) + except ObjectDeletedError: + # since we use heavy caching sometimes it happens that + # we get deleted objects here, we just skip them + pass + + user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id) + if cache: + user_ips = user_ips.options(FromCache("sql_cache_short", + "get_user_ips_%s" % user_id)) + + for ip in user_ips: + try: + _set.add(ip.ip_addr) + except ObjectDeletedError: + # since we use heavy caching sometimes it happens that we get + # deleted objects here, we just skip them + pass + return _set or set(['0.0.0.0/0', '::/0']) + + +def set_available_permissions(config): + """ + This function will propagate pylons globals with all available defined + permission given in db. We don't want to check each time from db for new + permissions since adding a new permission also requires application restart + ie. to decorate new views with the newly created permission + + :param config: current pylons config instance + + """ + log.info('getting information about all available permissions') + try: + sa = meta.Session + all_perms = sa.query(Permission).all() + config['available_permissions'] = [x.permission_name for x in all_perms] + except Exception: + log.error(traceback.format_exc()) + finally: + meta.Session.remove() + + +def get_csrf_token(session=None, force_new=False, save_if_missing=True): + """ + Return the current authentication token, creating one if one doesn't + already exist and the save_if_missing flag is present. + + :param session: pass in the pylons session, else we use the global ones + :param force_new: force to re-generate the token and store it in session + :param save_if_missing: save the newly generated token if it's missing in + session + """ + if not session: + from pylons import session + + if (csrf_token_key not in session and save_if_missing) or force_new: + token = hashlib.sha1(str(random.getrandbits(128))).hexdigest() + session[csrf_token_key] = token + if hasattr(session, 'save'): + session.save() + return session.get(csrf_token_key) + + +# CHECK DECORATORS +class CSRFRequired(object): + """ + Decorator for authenticating a form + + This decorator uses an authorization token stored in the client's + session for prevention of certain Cross-site request forgery (CSRF) + attacks (See + http://en.wikipedia.org/wiki/Cross-site_request_forgery for more + information). + + For use with the ``webhelpers.secure_form`` helper functions. + + """ + def __init__(self, token=csrf_token_key, header='X-CSRF-Token'): + self.token = token + self.header = header + + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def _get_csrf(self, _request): + return _request.POST.get(self.token, _request.headers.get(self.header)) + + def check_csrf(self, _request, cur_token): + supplied_token = self._get_csrf(_request) + return supplied_token and supplied_token == cur_token + + def __wrapper(self, func, *fargs, **fkwargs): + cur_token = get_csrf_token(save_if_missing=False) + if self.check_csrf(request, cur_token): + if request.POST.get(self.token): + del request.POST[self.token] + return func(*fargs, **fkwargs) + else: + reason = 'token-missing' + supplied_token = self._get_csrf(request) + if supplied_token and cur_token != supplied_token: + reason = 'token-mismatch [%s:%s]' % (cur_token or ''[:6], + supplied_token or ''[:6]) + + csrf_message = \ + ("Cross-site request forgery detected, request denied. See " + "http://en.wikipedia.org/wiki/Cross-site_request_forgery for " + "more information.") + log.warn('Cross-site request forgery detected, request %r DENIED: %s ' + 'REMOTE_ADDR:%s, HEADERS:%s' % ( + request, reason, request.remote_addr, request.headers)) + + abort(403, detail=csrf_message) + + +class LoginRequired(object): + """ + Must be logged in to execute this function else + redirect to login page + + :param api_access: if enabled this checks only for valid auth token + and grants access based on valid token + """ + def __init__(self, auth_token_access=False): + self.auth_token_access = auth_token_access + + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + cls = fargs[0] + user = cls._rhodecode_user + loc = "%s:%s" % (cls.__class__.__name__, func.__name__) + log.debug('Starting login restriction checks for user: %s' % (user,)) + # check if our IP is allowed + ip_access_valid = True + if not user.ip_allowed: + from rhodecode.lib import helpers as h + h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))), + category='warning') + ip_access_valid = False + + # check if we used an APIKEY and it's a valid one + # defined whitelist of controllers which API access will be enabled + _auth_token = request.GET.get( + 'auth_token', '') or request.GET.get('api_key', '') + auth_token_access_valid = allowed_auth_token_access( + loc, auth_token=_auth_token) + + # explicit controller is enabled or API is in our whitelist + if self.auth_token_access or auth_token_access_valid: + log.debug('Checking AUTH TOKEN access for %s' % (cls,)) + + if _auth_token and _auth_token in user.auth_tokens: + auth_token_access_valid = True + log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],)) + else: + auth_token_access_valid = False + if not _auth_token: + log.debug("AUTH TOKEN *NOT* present in request") + else: + log.warning( + "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:]) + + log.debug('Checking if %s is authenticated @ %s' % (user.username, loc)) + reason = 'RHODECODE_AUTH' if user.is_authenticated \ + else 'AUTH_TOKEN_AUTH' + + if ip_access_valid and ( + user.is_authenticated or auth_token_access_valid): + log.info( + 'user %s authenticating with:%s IS authenticated on func %s' + % (user, reason, loc)) + + # update user data to check last activity + user.update_lastactivity() + Session().commit() + return func(*fargs, **fkwargs) + else: + log.warning( + 'user %s authenticating with:%s NOT authenticated on ' + 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s' + % (user, reason, loc, ip_access_valid, + auth_token_access_valid)) + # we preserve the get PARAM + came_from = request.path_qs + + log.debug('redirecting to login page with %s' % (came_from,)) + return redirect( + url('login_home', came_from=came_from)) + + +class NotAnonymous(object): + """ + Must be logged in to execute this function else + redirect to login page""" + + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + cls = fargs[0] + self.user = cls._rhodecode_user + + log.debug('Checking if user is not anonymous @%s' % cls) + + anonymous = self.user.username == User.DEFAULT_USER + + if anonymous: + came_from = request.path_qs + + import rhodecode.lib.helpers as h + h.flash(_('You need to be a registered user to ' + 'perform this action'), + category='warning') + return redirect(url('login_home', came_from=came_from)) + else: + return func(*fargs, **fkwargs) + + +class XHRRequired(object): + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + log.debug('Checking if request is XMLHttpRequest (XHR)') + xhr_message = 'This is not a valid XMLHttpRequest (XHR) request' + if not request.is_xhr: + abort(400, detail=xhr_message) + + return func(*fargs, **fkwargs) + + +class HasAcceptedRepoType(object): + """ + Check if requested repo is within given repo type aliases + + TODO: anderson: not sure where to put this decorator + """ + + def __init__(self, *repo_type_list): + self.repo_type_list = set(repo_type_list) + + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + cls = fargs[0] + rhodecode_repo = cls.rhodecode_repo + + log.debug('%s checking repo type for %s in %s', + self.__class__.__name__, + rhodecode_repo.alias, self.repo_type_list) + + if rhodecode_repo.alias in self.repo_type_list: + return func(*fargs, **fkwargs) + else: + import rhodecode.lib.helpers as h + h.flash(h.literal( + _('Action not supported for %s.' % rhodecode_repo.alias)), + category='warning') + return redirect( + url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name)) + + +class PermsDecorator(object): + """ + Base class for controller decorators, we extract the current user from + the class itself, which has it stored in base controllers + """ + + def __init__(self, *required_perms): + self.required_perms = set(required_perms) + + def __call__(self, func): + return get_cython_compat_decorator(self.__wrapper, func) + + def __wrapper(self, func, *fargs, **fkwargs): + cls = fargs[0] + _user = cls._rhodecode_user + + log.debug('checking %s permissions %s for %s %s', + self.__class__.__name__, self.required_perms, cls, _user) + + if self.check_permissions(_user): + log.debug('Permission granted for %s %s', cls, _user) + return func(*fargs, **fkwargs) + + else: + log.debug('Permission denied for %s %s', cls, _user) + anonymous = _user.username == User.DEFAULT_USER + + if anonymous: + came_from = request.path_qs + + import rhodecode.lib.helpers as h + h.flash(_('You need to be signed in to view this page'), + category='warning') + return redirect(url('login_home', came_from=came_from)) + + else: + # redirect with forbidden ret code + return abort(403) + + def check_permissions(self, user): + """Dummy function for overriding""" + raise NotImplementedError( + 'You have to write this function in child class') + + +class HasPermissionAllDecorator(PermsDecorator): + """ + Checks for access permission for all given predicates. All of them + have to be meet in order to fulfill the request + """ + + def check_permissions(self, user): + perms = user.permissions_with_scope({}) + if self.required_perms.issubset(perms['global']): + return True + return False + + +class HasPermissionAnyDecorator(PermsDecorator): + """ + Checks for access permission for any of given predicates. In order to + fulfill the request any of predicates must be meet + """ + + def check_permissions(self, user): + perms = user.permissions_with_scope({}) + if self.required_perms.intersection(perms['global']): + return True + return False + + +class HasRepoPermissionAllDecorator(PermsDecorator): + """ + Checks for access permission for all given predicates for specific + repository. All of them have to be meet in order to fulfill the request + """ + + def check_permissions(self, user): + perms = user.permissions + repo_name = get_repo_slug(request) + try: + user_perms = set([perms['repositories'][repo_name]]) + except KeyError: + return False + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasRepoPermissionAnyDecorator(PermsDecorator): + """ + Checks for access permission for any of given predicates for specific + repository. In order to fulfill the request any of predicates must be meet + """ + + def check_permissions(self, user): + perms = user.permissions + repo_name = get_repo_slug(request) + try: + user_perms = set([perms['repositories'][repo_name]]) + except KeyError: + return False + + if self.required_perms.intersection(user_perms): + return True + return False + + +class HasRepoGroupPermissionAllDecorator(PermsDecorator): + """ + Checks for access permission for all given predicates for specific + repository group. All of them have to be meet in order to + fulfill the request + """ + + def check_permissions(self, user): + perms = user.permissions + group_name = get_repo_group_slug(request) + try: + user_perms = set([perms['repositories_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasRepoGroupPermissionAnyDecorator(PermsDecorator): + """ + Checks for access permission for any of given predicates for specific + repository group. In order to fulfill the request any + of predicates must be met + """ + + def check_permissions(self, user): + perms = user.permissions + group_name = get_repo_group_slug(request) + try: + user_perms = set([perms['repositories_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.intersection(user_perms): + return True + return False + + +class HasUserGroupPermissionAllDecorator(PermsDecorator): + """ + Checks for access permission for all given predicates for specific + user group. All of them have to be meet in order to fulfill the request + """ + + def check_permissions(self, user): + perms = user.permissions + group_name = get_user_group_slug(request) + try: + user_perms = set([perms['user_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasUserGroupPermissionAnyDecorator(PermsDecorator): + """ + Checks for access permission for any of given predicates for specific + user group. In order to fulfill the request any of predicates must be meet + """ + + def check_permissions(self, user): + perms = user.permissions + group_name = get_user_group_slug(request) + try: + user_perms = set([perms['user_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.intersection(user_perms): + return True + return False + + +# CHECK FUNCTIONS +class PermsFunction(object): + """Base function for other check functions""" + + def __init__(self, *perms): + self.required_perms = set(perms) + self.repo_name = None + self.repo_group_name = None + self.user_group_name = None + + def __bool__(self): + frame = inspect.currentframe() + stack_trace = traceback.format_stack(frame) + log.error('Checking bool value on a class instance of perm ' + 'function is not allowed: %s' % ''.join(stack_trace)) + # rather than throwing errors, here we always return False so if by + # accident someone checks truth for just an instance it will always end + # up in returning False + return False + __nonzero__ = __bool__ + + def __call__(self, check_location='', user=None): + if not user: + log.debug('Using user attribute from global request') + # TODO: remove this someday,put as user as attribute here + user = request.user + + # init auth user if not already given + if not isinstance(user, AuthUser): + log.debug('Wrapping user %s into AuthUser', user) + user = AuthUser(user.user_id) + + cls_name = self.__class__.__name__ + check_scope = self._get_check_scope(cls_name) + check_location = check_location or 'unspecified location' + + log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name, + self.required_perms, user, check_scope, check_location) + if not user: + log.warning('Empty user given for permission check') + return False + + if self.check_permissions(user): + log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s', + check_scope, user, check_location) + return True + + else: + log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s', + check_scope, user, check_location) + return False + + def _get_check_scope(self, cls_name): + return { + 'HasPermissionAll': 'GLOBAL', + 'HasPermissionAny': 'GLOBAL', + 'HasRepoPermissionAll': 'repo:%s' % self.repo_name, + 'HasRepoPermissionAny': 'repo:%s' % self.repo_name, + 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name, + 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name, + 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name, + 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name, + }.get(cls_name, '?:%s' % cls_name) + + def check_permissions(self, user): + """Dummy function for overriding""" + raise Exception('You have to write this function in child class') + + +class HasPermissionAll(PermsFunction): + def check_permissions(self, user): + perms = user.permissions_with_scope({}) + if self.required_perms.issubset(perms.get('global')): + return True + return False + + +class HasPermissionAny(PermsFunction): + def check_permissions(self, user): + perms = user.permissions_with_scope({}) + if self.required_perms.intersection(perms.get('global')): + return True + return False + + +class HasRepoPermissionAll(PermsFunction): + def __call__(self, repo_name=None, check_location='', user=None): + self.repo_name = repo_name + return super(HasRepoPermissionAll, self).__call__(check_location, user) + + def check_permissions(self, user): + if not self.repo_name: + self.repo_name = get_repo_slug(request) + + perms = user.permissions + try: + user_perms = set([perms['repositories'][self.repo_name]]) + except KeyError: + return False + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasRepoPermissionAny(PermsFunction): + def __call__(self, repo_name=None, check_location='', user=None): + self.repo_name = repo_name + return super(HasRepoPermissionAny, self).__call__(check_location, user) + + def check_permissions(self, user): + if not self.repo_name: + self.repo_name = get_repo_slug(request) + + perms = user.permissions + try: + user_perms = set([perms['repositories'][self.repo_name]]) + except KeyError: + return False + if self.required_perms.intersection(user_perms): + return True + return False + + +class HasRepoGroupPermissionAny(PermsFunction): + def __call__(self, group_name=None, check_location='', user=None): + self.repo_group_name = group_name + return super(HasRepoGroupPermissionAny, self).__call__( + check_location, user) + + def check_permissions(self, user): + perms = user.permissions + try: + user_perms = set( + [perms['repositories_groups'][self.repo_group_name]]) + except KeyError: + return False + if self.required_perms.intersection(user_perms): + return True + return False + + +class HasRepoGroupPermissionAll(PermsFunction): + def __call__(self, group_name=None, check_location='', user=None): + self.repo_group_name = group_name + return super(HasRepoGroupPermissionAll, self).__call__( + check_location, user) + + def check_permissions(self, user): + perms = user.permissions + try: + user_perms = set( + [perms['repositories_groups'][self.repo_group_name]]) + except KeyError: + return False + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasUserGroupPermissionAny(PermsFunction): + def __call__(self, user_group_name=None, check_location='', user=None): + self.user_group_name = user_group_name + return super(HasUserGroupPermissionAny, self).__call__( + check_location, user) + + def check_permissions(self, user): + perms = user.permissions + try: + user_perms = set([perms['user_groups'][self.user_group_name]]) + except KeyError: + return False + if self.required_perms.intersection(user_perms): + return True + return False + + +class HasUserGroupPermissionAll(PermsFunction): + def __call__(self, user_group_name=None, check_location='', user=None): + self.user_group_name = user_group_name + return super(HasUserGroupPermissionAll, self).__call__( + check_location, user) + + def check_permissions(self, user): + perms = user.permissions + try: + user_perms = set([perms['user_groups'][self.user_group_name]]) + except KeyError: + return False + if self.required_perms.issubset(user_perms): + return True + return False + + +# SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH +class HasPermissionAnyMiddleware(object): + def __init__(self, *perms): + self.required_perms = set(perms) + + def __call__(self, user, repo_name): + # repo_name MUST be unicode, since we handle keys in permission + # dict by unicode + repo_name = safe_unicode(repo_name) + user = AuthUser(user.user_id) + log.debug( + 'Checking VCS protocol permissions %s for user:%s repo:`%s`', + self.required_perms, user, repo_name) + + if self.check_permissions(user, repo_name): + log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s', + repo_name, user, 'PermissionMiddleware') + return True + + else: + log.debug('Permission to repo:`%s` DENIED for user:%s @ %s', + repo_name, user, 'PermissionMiddleware') + return False + + def check_permissions(self, user, repo_name): + perms = user.permissions_with_scope({'repo_name': repo_name}) + + try: + user_perms = set([perms['repositories'][repo_name]]) + except Exception: + log.exception('Error while accessing user permissions') + return False + + if self.required_perms.intersection(user_perms): + return True + return False + + +# SPECIAL VERSION TO HANDLE API AUTH +class _BaseApiPerm(object): + def __init__(self, *perms): + self.required_perms = set(perms) + + def __call__(self, check_location=None, user=None, repo_name=None, + group_name=None, user_group_name=None): + cls_name = self.__class__.__name__ + check_scope = 'global:%s' % (self.required_perms,) + if repo_name: + check_scope += ', repo_name:%s' % (repo_name,) + + if group_name: + check_scope += ', repo_group_name:%s' % (group_name,) + + if user_group_name: + check_scope += ', user_group_name:%s' % (user_group_name,) + + log.debug( + 'checking cls:%s %s %s @ %s' + % (cls_name, self.required_perms, check_scope, check_location)) + if not user: + log.debug('Empty User passed into arguments') + return False + + # process user + if not isinstance(user, AuthUser): + user = AuthUser(user.user_id) + if not check_location: + check_location = 'unspecified' + if self.check_permissions(user.permissions, repo_name, group_name, + user_group_name): + log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s', + check_scope, user, check_location) + return True + + else: + log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s', + check_scope, user, check_location) + return False + + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + """ + implement in child class should return True if permissions are ok, + False otherwise + + :param perm_defs: dict with permission definitions + :param repo_name: repo name + """ + raise NotImplementedError() + + +class HasPermissionAllApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + if self.required_perms.issubset(perm_defs.get('global')): + return True + return False + + +class HasPermissionAnyApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + if self.required_perms.intersection(perm_defs.get('global')): + return True + return False + + +class HasRepoPermissionAllApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + try: + _user_perms = set([perm_defs['repositories'][repo_name]]) + except KeyError: + log.warning(traceback.format_exc()) + return False + if self.required_perms.issubset(_user_perms): + return True + return False + + +class HasRepoPermissionAnyApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + try: + _user_perms = set([perm_defs['repositories'][repo_name]]) + except KeyError: + log.warning(traceback.format_exc()) + return False + if self.required_perms.intersection(_user_perms): + return True + return False + + +class HasRepoGroupPermissionAnyApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + try: + _user_perms = set([perm_defs['repositories_groups'][group_name]]) + except KeyError: + log.warning(traceback.format_exc()) + return False + if self.required_perms.intersection(_user_perms): + return True + return False + + +class HasRepoGroupPermissionAllApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + try: + _user_perms = set([perm_defs['repositories_groups'][group_name]]) + except KeyError: + log.warning(traceback.format_exc()) + return False + if self.required_perms.issubset(_user_perms): + return True + return False + + +class HasUserGroupPermissionAnyApi(_BaseApiPerm): + def check_permissions(self, perm_defs, repo_name=None, group_name=None, + user_group_name=None): + try: + _user_perms = set([perm_defs['user_groups'][user_group_name]]) + except KeyError: + log.warning(traceback.format_exc()) + return False + if self.required_perms.intersection(_user_perms): + return True + return False + + +def check_ip_access(source_ip, allowed_ips=None): + """ + Checks if source_ip is a subnet of any of allowed_ips. + + :param source_ip: + :param allowed_ips: list of allowed ips together with mask + """ + log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips)) + source_ip_address = ipaddress.ip_address(source_ip) + if isinstance(allowed_ips, (tuple, list, set)): + for ip in allowed_ips: + try: + network_address = ipaddress.ip_network(ip, strict=False) + if source_ip_address in network_address: + log.debug('IP %s is network %s' % + (source_ip_address, network_address)) + return True + # for any case we cannot determine the IP, don't crash just + # skip it and log as error, we want to say forbidden still when + # sending bad IP + except Exception: + log.error(traceback.format_exc()) + continue + return False + + +def get_cython_compat_decorator(wrapper, func): + """ + Creates a cython compatible decorator. The previously used + decorator.decorator() function seems to be incompatible with cython. + + :param wrapper: __wrapper method of the decorator class + :param func: decorated function + """ + @wraps(func) + def local_wrapper(*args, **kwds): + return wrapper(func, *args, **kwds) + local_wrapper.__wrapped__ = func + return local_wrapper diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/base.py @@ -0,0 +1,551 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +The base Controller API +Provides the BaseController class for subclassing. And usage in different +controllers +""" + +import logging +import socket + +import ipaddress + +from paste.auth.basic import AuthBasicAuthenticator +from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception +from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION +from pylons import config, tmpl_context as c, request, session, url +from pylons.controllers import WSGIController +from pylons.controllers.util import redirect +from pylons.i18n import translation +# marcink: don't remove this import +from pylons.templating import render_mako as render # noqa +from pylons.i18n.translation import _ +from webob.exc import HTTPFound + + +import rhodecode +from rhodecode.authentication.base import VCS_TYPE +from rhodecode.lib import auth, utils2 +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import AuthUser, CookieStoreWrapper +from rhodecode.lib.exceptions import UserCreationError +from rhodecode.lib.utils import ( + get_repo_slug, set_rhodecode_config, password_changed, + get_enabled_hook_classes) +from rhodecode.lib.utils2 import ( + str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist) +from rhodecode.lib.vcs.exceptions import RepositoryRequirementError +from rhodecode.model import meta +from rhodecode.model.db import Repository, User +from rhodecode.model.notification import NotificationModel +from rhodecode.model.scm import ScmModel +from rhodecode.model.settings import VcsSettingsModel, SettingsModel + + +log = logging.getLogger(__name__) + + +def _filter_proxy(ip): + """ + Passed in IP addresses in HEADERS can be in a special format of multiple + ips. Those comma separated IPs are passed from various proxies in the + chain of request processing. The left-most being the original client. + We only care about the first IP which came from the org. client. + + :param ip: ip string from headers + """ + if ',' in ip: + _ips = ip.split(',') + _first_ip = _ips[0].strip() + log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip) + return _first_ip + return ip + + +def _filter_port(ip): + """ + Removes a port from ip, there are 4 main cases to handle here. + - ipv4 eg. 127.0.0.1 + - ipv6 eg. ::1 + - ipv4+port eg. 127.0.0.1:8080 + - ipv6+port eg. [::1]:8080 + + :param ip: + """ + def is_ipv6(ip_addr): + if hasattr(socket, 'inet_pton'): + try: + socket.inet_pton(socket.AF_INET6, ip_addr) + except socket.error: + return False + else: + # fallback to ipaddress + try: + ipaddress.IPv6Address(ip_addr) + except Exception: + return False + return True + + if ':' not in ip: # must be ipv4 pure ip + return ip + + if '[' in ip and ']' in ip: # ipv6 with port + return ip.split(']')[0][1:].lower() + + # must be ipv6 or ipv4 with port + if is_ipv6(ip): + return ip + else: + ip, _port = ip.split(':')[:2] # means ipv4+port + return ip + + +def get_ip_addr(environ): + proxy_key = 'HTTP_X_REAL_IP' + proxy_key2 = 'HTTP_X_FORWARDED_FOR' + def_key = 'REMOTE_ADDR' + _filters = lambda x: _filter_port(_filter_proxy(x)) + + ip = environ.get(proxy_key) + if ip: + return _filters(ip) + + ip = environ.get(proxy_key2) + if ip: + return _filters(ip) + + ip = environ.get(def_key, '0.0.0.0') + return _filters(ip) + + +def get_server_ip_addr(environ, log_errors=True): + hostname = environ.get('SERVER_NAME') + try: + return socket.gethostbyname(hostname) + except Exception as e: + if log_errors: + # in some cases this lookup is not possible, and we don't want to + # make it an exception in logs + log.exception('Could not retrieve server ip address: %s', e) + return hostname + + +def get_server_port(environ): + return environ.get('SERVER_PORT') + + +def get_access_path(environ): + path = environ.get('PATH_INFO') + org_req = environ.get('pylons.original_request') + if org_req: + path = org_req.environ.get('PATH_INFO') + return path + + +def vcs_operation_context( + environ, repo_name, username, action, scm, check_locking=True): + """ + Generate the context for a vcs operation, e.g. push or pull. + + This context is passed over the layers so that hooks triggered by the + vcs operation know details like the user, the user's IP address etc. + + :param check_locking: Allows to switch of the computation of the locking + data. This serves mainly the need of the simplevcs middleware to be + able to disable this for certain operations. + + """ + # Tri-state value: False: unlock, None: nothing, True: lock + make_lock = None + locked_by = [None, None, None] + is_anonymous = username == User.DEFAULT_USER + if not is_anonymous and check_locking: + log.debug('Checking locking on repository "%s"', repo_name) + user = User.get_by_username(username) + repo = Repository.get_by_repo_name(repo_name) + make_lock, __, locked_by = repo.get_locking_state( + action, user.user_id) + + settings_model = VcsSettingsModel(repo=repo_name) + ui_settings = settings_model.get_ui_settings() + + extras = { + 'ip': get_ip_addr(environ), + 'username': username, + 'action': action, + 'repository': repo_name, + 'scm': scm, + 'config': rhodecode.CONFIG['__file__'], + 'make_lock': make_lock, + 'locked_by': locked_by, + 'server_url': utils2.get_server_url(environ), + 'hooks': get_enabled_hook_classes(ui_settings), + } + return extras + + +class BasicAuth(AuthBasicAuthenticator): + + def __init__(self, realm, authfunc, auth_http_code=None, + initial_call_detection=False): + self.realm = realm + self.initial_call = initial_call_detection + self.authfunc = authfunc + self._rc_auth_http_code = auth_http_code + + def _get_response_from_code(self, http_code): + try: + return get_exception(safe_int(http_code)) + except Exception: + log.exception('Failed to fetch response for code %s' % http_code) + return HTTPForbidden + + def build_authentication(self): + head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm) + if self._rc_auth_http_code and not self.initial_call: + # return alternative HTTP code if alternative http return code + # is specified in RhodeCode config, but ONLY if it's not the + # FIRST call + custom_response_klass = self._get_response_from_code( + self._rc_auth_http_code) + return custom_response_klass(headers=head) + return HTTPUnauthorized(headers=head) + + def authenticate(self, environ): + authorization = AUTHORIZATION(environ) + if not authorization: + return self.build_authentication() + (authmeth, auth) = authorization.split(' ', 1) + if 'basic' != authmeth.lower(): + return self.build_authentication() + auth = auth.strip().decode('base64') + _parts = auth.split(':', 1) + if len(_parts) == 2: + username, password = _parts + if self.authfunc( + username, password, environ, VCS_TYPE): + return username + if username and password: + # we mark that we actually executed authentication once, at + # that point we can use the alternative auth code + self.initial_call = False + + return self.build_authentication() + + __call__ = authenticate + + +def attach_context_attributes(context): + rc_config = SettingsModel().get_all_settings() + + context.rhodecode_version = rhodecode.__version__ + context.rhodecode_edition = config.get('rhodecode.edition') + # unique secret + version does not leak the version but keep consistency + context.rhodecode_version_hash = md5( + config.get('beaker.session.secret', '') + + rhodecode.__version__)[:8] + + # Default language set for the incoming request + context.language = translation.get_lang()[0] + + # Visual options + context.visual = AttributeDict({}) + + # DB store + context.visual.show_public_icon = str2bool( + rc_config.get('rhodecode_show_public_icon')) + context.visual.show_private_icon = str2bool( + rc_config.get('rhodecode_show_private_icon')) + context.visual.stylify_metatags = str2bool( + rc_config.get('rhodecode_stylify_metatags')) + context.visual.dashboard_items = safe_int( + rc_config.get('rhodecode_dashboard_items', 100)) + context.visual.admin_grid_items = safe_int( + rc_config.get('rhodecode_admin_grid_items', 100)) + context.visual.repository_fields = str2bool( + rc_config.get('rhodecode_repository_fields')) + context.visual.show_version = str2bool( + rc_config.get('rhodecode_show_version')) + context.visual.use_gravatar = str2bool( + rc_config.get('rhodecode_use_gravatar')) + context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url') + context.visual.default_renderer = rc_config.get( + 'rhodecode_markup_renderer', 'rst') + context.visual.rhodecode_support_url = \ + rc_config.get('rhodecode_support_url') or url('rhodecode_support') + + context.pre_code = rc_config.get('rhodecode_pre_code') + context.post_code = rc_config.get('rhodecode_post_code') + context.rhodecode_name = rc_config.get('rhodecode_title') + context.default_encodings = aslist(config.get('default_encoding'), sep=',') + # if we have specified default_encoding in the request, it has more + # priority + if request.GET.get('default_encoding'): + context.default_encodings.insert(0, request.GET.get('default_encoding')) + context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl') + + # INI stored + context.labs_active = str2bool( + config.get('labs_settings_active', 'false')) + context.visual.allow_repo_location_change = str2bool( + config.get('allow_repo_location_change', True)) + context.visual.allow_custom_hooks_settings = str2bool( + config.get('allow_custom_hooks_settings', True)) + context.debug_style = str2bool(config.get('debug_style', False)) + + context.rhodecode_instanceid = config.get('instance_id') + + # AppEnlight + context.appenlight_enabled = str2bool(config.get('appenlight', 'false')) + context.appenlight_api_public_key = config.get( + 'appenlight.api_public_key', '') + context.appenlight_server_url = config.get('appenlight.server_url', '') + + # END CONFIG VARS + + # TODO: This dosn't work when called from pylons compatibility tween. + # Fix this and remove it from base controller. + # context.repo_name = get_repo_slug(request) # can be empty + + context.csrf_token = auth.get_csrf_token() + context.backends = rhodecode.BACKENDS.keys() + context.backends.sort() + context.unread_notifications = NotificationModel().get_unread_cnt_for_user( + context.rhodecode_user.user_id) + + +def get_auth_user(environ): + ip_addr = get_ip_addr(environ) + # make sure that we update permissions each time we call controller + _auth_token = (request.GET.get('auth_token', '') or + request.GET.get('api_key', '')) + + if _auth_token: + # when using API_KEY we are sure user exists. + auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr) + authenticated = False + else: + cookie_store = CookieStoreWrapper(session.get('rhodecode_user')) + try: + auth_user = AuthUser(user_id=cookie_store.get('user_id', None), + ip_addr=ip_addr) + except UserCreationError as e: + h.flash(e, 'error') + # container auth or other auth functions that create users + # on the fly can throw this exception signaling that there's + # issue with user creation, explanation should be provided + # in Exception itself. We then create a simple blank + # AuthUser + auth_user = AuthUser(ip_addr=ip_addr) + + if password_changed(auth_user, session): + session.invalidate() + cookie_store = CookieStoreWrapper( + session.get('rhodecode_user')) + auth_user = AuthUser(ip_addr=ip_addr) + + authenticated = cookie_store.get('is_authenticated') + + if not auth_user.is_authenticated and auth_user.is_user_object: + # user is not authenticated and not empty + auth_user.set_authenticated(authenticated) + + return auth_user + + +class BaseController(WSGIController): + + def __before__(self): + """ + __before__ is called before controller methods and after __call__ + """ + # on each call propagate settings calls into global settings. + set_rhodecode_config(config) + attach_context_attributes(c) + + # TODO: Remove this when fixed in attach_context_attributes() + c.repo_name = get_repo_slug(request) # can be empty + + self.cut_off_limit_diff = safe_int(config.get('cut_off_limit_diff')) + self.cut_off_limit_file = safe_int(config.get('cut_off_limit_file')) + self.sa = meta.Session + self.scm_model = ScmModel(self.sa) + + default_lang = c.language + user_lang = c.language + try: + user_obj = self._rhodecode_user.get_instance() + if user_obj: + user_lang = user_obj.user_data.get('language') + except Exception: + log.exception('Failed to fetch user language for user %s', + self._rhodecode_user) + + if user_lang and user_lang != default_lang: + log.debug('set language to %s for user %s', user_lang, + self._rhodecode_user) + translation.set_lang(user_lang) + + def _dispatch_redirect(self, with_url, environ, start_response): + resp = HTTPFound(with_url) + environ['SCRIPT_NAME'] = '' # handle prefix middleware + environ['PATH_INFO'] = with_url + return resp(environ, start_response) + + def __call__(self, environ, start_response): + """Invoke the Controller""" + # WSGIController.__call__ dispatches to the Controller method + # the request is routed to. This routing information is + # available in environ['pylons.routes_dict'] + from rhodecode.lib import helpers as h + + # Provide the Pylons context to Pyramid's debugtoolbar if it asks + if environ.get('debugtoolbar.wants_pylons_context', False): + environ['debugtoolbar.pylons_context'] = c._current_obj() + + _route_name = '.'.join([environ['pylons.routes_dict']['controller'], + environ['pylons.routes_dict']['action']]) + + self.rc_config = SettingsModel().get_all_settings() + self.ip_addr = get_ip_addr(environ) + + # The rhodecode auth user is looked up and passed through the + # environ by the pylons compatibility tween in pyramid. + # So we can just grab it from there. + auth_user = environ['rc_auth_user'] + + # set globals for auth user + request.user = auth_user + c.rhodecode_user = self._rhodecode_user = auth_user + + log.info('IP: %s User: %s accessed %s [%s]' % ( + self.ip_addr, auth_user, safe_unicode(get_access_path(environ)), + _route_name) + ) + + # TODO: Maybe this should be move to pyramid to cover all views. + # check user attributes for password change flag + user_obj = auth_user.get_instance() + if user_obj and user_obj.user_data.get('force_password_change'): + h.flash('You are required to change your password', 'warning', + ignore_duplicate=True) + + skip_user_check_urls = [ + 'error.document', 'login.logout', 'login.index', + 'admin/my_account.my_account_password', + 'admin/my_account.my_account_password_update' + ] + if _route_name not in skip_user_check_urls: + return self._dispatch_redirect( + url('my_account_password'), environ, start_response) + + return WSGIController.__call__(self, environ, start_response) + + +class BaseRepoController(BaseController): + """ + Base class for controllers responsible for loading all needed data for + repository loaded items are + + c.rhodecode_repo: instance of scm repository + c.rhodecode_db_repo: instance of db + c.repository_requirements_missing: shows that repository specific data + could not be displayed due to the missing requirements + c.repository_pull_requests: show number of open pull requests + """ + + def __before__(self): + super(BaseRepoController, self).__before__() + if c.repo_name: # extracted from routes + db_repo = Repository.get_by_repo_name(c.repo_name) + if not db_repo: + return + + log.debug( + 'Found repository in database %s with state `%s`', + safe_unicode(db_repo), safe_unicode(db_repo.repo_state)) + route = getattr(request.environ.get('routes.route'), 'name', '') + + # allow to delete repos that are somehow damages in filesystem + if route in ['delete_repo']: + return + + if db_repo.repo_state in [Repository.STATE_PENDING]: + if route in ['repo_creating_home']: + return + check_url = url('repo_creating_home', repo_name=c.repo_name) + return redirect(check_url) + + self.rhodecode_db_repo = db_repo + + missing_requirements = False + try: + self.rhodecode_repo = self.rhodecode_db_repo.scm_instance() + except RepositoryRequirementError as e: + missing_requirements = True + self._handle_missing_requirements(e) + + if self.rhodecode_repo is None and not missing_requirements: + log.error('%s this repository is present in database but it ' + 'cannot be created as an scm instance', c.repo_name) + + h.flash(_( + "The repository at %(repo_name)s cannot be located.") % + {'repo_name': c.repo_name}, + category='error', ignore_duplicate=True) + redirect(url('home')) + + # update last change according to VCS data + if not missing_requirements: + commit = db_repo.get_commit( + pre_load=["author", "date", "message", "parents"]) + db_repo.update_commit_cache(commit) + + # Prepare context + c.rhodecode_db_repo = db_repo + c.rhodecode_repo = self.rhodecode_repo + c.repository_requirements_missing = missing_requirements + + self._update_global_counters(self.scm_model, db_repo) + + def _update_global_counters(self, scm_model, db_repo): + """ + Base variables that are exposed to every page of repository + """ + c.repository_pull_requests = scm_model.get_pull_requests(db_repo) + + def _handle_missing_requirements(self, error): + self.rhodecode_repo = None + log.error( + 'Requirements are missing for repository %s: %s', + c.repo_name, error.message) + + summary_url = url('summary_home', repo_name=c.repo_name) + statistics_url = url('edit_repo_statistics', repo_name=c.repo_name) + settings_update_url = url('repo', repo_name=c.repo_name) + path = request.path + should_redirect = ( + path not in (summary_url, settings_update_url) + and '/settings' not in path or path == statistics_url + ) + if should_redirect: + redirect(summary_url) diff --git a/rhodecode/lib/caches.py b/rhodecode/lib/caches.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/caches.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2015-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import beaker +import logging + +from beaker.cache import _cache_decorate, cache_regions, region_invalidate + +from rhodecode.lib.utils import safe_str, md5 +from rhodecode.model.db import Session, CacheKey, IntegrityError + +log = logging.getLogger(__name__) + +FILE_TREE = 'cache_file_tree' +FILE_TREE_META = 'cache_file_tree_metadata' +FILE_SEARCH_TREE_META = 'cache_file_search_metadata' +SUMMARY_STATS = 'cache_summary_stats' + +# This list of caches gets purged when invalidation happens +USED_REPO_CACHES = (FILE_TREE, FILE_TREE_META, FILE_TREE_META) + +DEFAULT_CACHE_MANAGER_CONFIG = { + 'type': 'memorylru_base', + 'max_items': 10240, + 'key_length': 256, + 'enabled': True +} + + +def configure_cache_region( + region_name, region_kw, default_cache_kw, default_expire=60): + default_type = default_cache_kw.get('type', 'memory') + default_lock_dir = default_cache_kw.get('lock_dir') + default_data_dir = default_cache_kw.get('data_dir') + + region_kw['lock_dir'] = region_kw.get('lock_dir', default_lock_dir) + region_kw['data_dir'] = region_kw.get('data_dir', default_data_dir) + region_kw['type'] = region_kw.get('type', default_type) + region_kw['expire'] = int(region_kw.get('expire', default_expire)) + + beaker.cache.cache_regions[region_name] = region_kw + + +def get_cache_manager(region_name, cache_name, custom_ttl=None): + """ + Creates a Beaker cache manager. Such instance can be used like that:: + + _namespace = caches.get_repo_namespace_key(caches.XXX, repo_name) + cache_manager = caches.get_cache_manager('repo_cache_long', _namespace) + _cache_key = caches.compute_key_from_params(repo_name, commit.raw_id) + def heavy_compute(): + ... + result = cache_manager.get(_cache_key, createfunc=heavy_compute) + + :param region_name: region from ini file + :param cache_name: custom cache name, usually prefix+repo_name. eg + file_switcher_repo1 + :param custom_ttl: override .ini file timeout on this cache + :return: instance of cache manager + """ + + cache_config = cache_regions.get(region_name, DEFAULT_CACHE_MANAGER_CONFIG) + if custom_ttl: + log.debug('Updating region %s with custom ttl: %s', + region_name, custom_ttl) + cache_config.update({'expire': custom_ttl}) + + return beaker.cache.Cache._get_cache(cache_name, cache_config) + + +def clear_cache_manager(cache_manager): + log.debug('Clearing all values for cache manager %s', cache_manager) + cache_manager.clear() + + +def clear_repo_caches(repo_name): + # invalidate cache manager for this repo + for prefix in USED_REPO_CACHES: + namespace = get_repo_namespace_key(prefix, repo_name) + cache_manager = get_cache_manager('repo_cache_long', namespace) + clear_cache_manager(cache_manager) + + +def compute_key_from_params(*args): + """ + Helper to compute key from given params to be used in cache manager + """ + return md5("_".join(map(safe_str, args))) + + +def get_repo_namespace_key(prefix, repo_name): + return '{0}_{1}'.format(prefix, compute_key_from_params(repo_name)) + + +def conditional_cache(region, prefix, condition, func): + """ + Conditional caching function use like:: + def _c(arg): + # heavy computation function + return data + + # depending on the condition the compute is wrapped in cache or not + compute = conditional_cache('short_term', 'cache_desc', + condition=True, func=func) + return compute(arg) + + :param region: name of cache region + :param prefix: cache region prefix + :param condition: condition for cache to be triggered, and + return data cached + :param func: wrapped heavy function to compute + + """ + wrapped = func + if condition: + log.debug('conditional_cache: True, wrapping call of ' + 'func: %s into %s region cache', region, func) + cached_region = _cache_decorate((prefix,), None, None, region) + wrapped = cached_region(func) + return wrapped + + +class ActiveRegionCache(object): + def __init__(self, context): + self.context = context + + def invalidate(self, *args, **kwargs): + return False + + def compute(self): + log.debug('Context cache: getting obj %s from cache', self.context) + return self.context.compute_func(self.context.cache_key) + + +class FreshRegionCache(ActiveRegionCache): + def invalidate(self): + log.debug('Context cache: invalidating cache for %s', self.context) + region_invalidate( + self.context.compute_func, None, self.context.cache_key) + return True + + +class InvalidationContext(object): + def __repr__(self): + return '<InvalidationContext:{}[{}]>'.format( + self.repo_name, self.cache_type) + + def __init__(self, compute_func, repo_name, cache_type, + raise_exception=False): + self.compute_func = compute_func + self.repo_name = repo_name + self.cache_type = cache_type + self.cache_key = compute_key_from_params( + repo_name, cache_type) + self.raise_exception = raise_exception + + def get_cache_obj(self): + cache_key = CacheKey.get_cache_key( + self.repo_name, self.cache_type) + cache_obj = CacheKey.get_active_cache(cache_key) + if not cache_obj: + cache_obj = CacheKey(cache_key, self.repo_name) + return cache_obj + + def __enter__(self): + """ + Test if current object is valid, and return CacheRegion function + that does invalidation and calculation + """ + + self.cache_obj = self.get_cache_obj() + if self.cache_obj.cache_active: + # means our cache obj is existing and marked as it's + # cache is not outdated, we return BaseInvalidator + self.skip_cache_active_change = True + return ActiveRegionCache(self) + + # the key is either not existing or set to False, we return + # the real invalidator which re-computes value. We additionally set + # the flag to actually update the Database objects + self.skip_cache_active_change = False + return FreshRegionCache(self) + + def __exit__(self, exc_type, exc_val, exc_tb): + + if self.skip_cache_active_change: + return + + try: + self.cache_obj.cache_active = True + Session().add(self.cache_obj) + Session().commit() + except IntegrityError: + # if we catch integrity error, it means we inserted this object + # assumption is that's really an edge race-condition case and + # it's safe is to skip it + Session().rollback() + except Exception: + log.exception('Failed to commit on cache key update') + Session().rollback() + if self.raise_exception: + raise diff --git a/rhodecode/lib/caching_query.py b/rhodecode/lib/caching_query.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/caching_query.py @@ -0,0 +1,322 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +caching_query.py + +Represent persistence structures which allow the usage of +Beaker caching with SQLAlchemy. + +The three new concepts introduced here are: + + * CachingQuery - a Query subclass that caches and + retrieves results in/from Beaker. + * FromCache - a query option that establishes caching + parameters on a Query + * RelationshipCache - a variant of FromCache which is specific + to a query invoked during a lazy load. + * _params_from_query - extracts value parameters from + a Query. + +The rest of what's here are standard SQLAlchemy and +Beaker constructs. + +""" +import beaker +from beaker.exceptions import BeakerException + +from sqlalchemy.orm.interfaces import MapperOption +from sqlalchemy.orm.query import Query +from sqlalchemy.sql import visitors + +from rhodecode.lib.utils2 import safe_str + + +class CachingQuery(Query): + """A Query subclass which optionally loads full results from a Beaker + cache region. + + The CachingQuery stores additional state that allows it to consult + a Beaker cache before accessing the database: + + * A "region", which is a cache region argument passed to a + Beaker CacheManager, specifies a particular cache configuration + (including backend implementation, expiration times, etc.) + * A "namespace", which is a qualifying name that identifies a + group of keys within the cache. A query that filters on a name + might use the name "by_name", a query that filters on a date range + to a joined table might use the name "related_date_range". + + When the above state is present, a Beaker cache is retrieved. + + The "namespace" name is first concatenated with + a string composed of the individual entities and columns the Query + requests, i.e. such as ``Query(User.id, User.name)``. + + The Beaker cache is then loaded from the cache manager based + on the region and composed namespace. The key within the cache + itself is then constructed against the bind parameters specified + by this query, which are usually literals defined in the + WHERE clause. + + The FromCache and RelationshipCache mapper options below represent + the "public" method of configuring this state upon the CachingQuery. + + """ + + def __init__(self, manager, *args, **kw): + self.cache_manager = manager + Query.__init__(self, *args, **kw) + + def __iter__(self): + """override __iter__ to pull results from Beaker + if particular attributes have been configured. + + Note that this approach does *not* detach the loaded objects from + the current session. If the cache backend is an in-process cache + (like "memory") and lives beyond the scope of the current session's + transaction, those objects may be expired. The method here can be + modified to first expunge() each loaded item from the current + session before returning the list of items, so that the items + in the cache are not the same ones in the current Session. + + """ + if hasattr(self, '_cache_parameters'): + return self.get_value(createfunc=lambda: + list(Query.__iter__(self))) + else: + return Query.__iter__(self) + + def invalidate(self): + """Invalidate the value represented by this Query.""" + + cache, cache_key = _get_cache_parameters(self) + cache.remove(cache_key) + + def get_value(self, merge=True, createfunc=None): + """Return the value from the cache for this query. + + Raise KeyError if no value present and no + createfunc specified. + + """ + cache, cache_key = _get_cache_parameters(self) + ret = cache.get_value(cache_key, createfunc=createfunc) + if merge: + ret = self.merge_result(ret, load=False) + return ret + + def set_value(self, value): + """Set the value in the cache for this query.""" + + cache, cache_key = _get_cache_parameters(self) + cache.put(cache_key, value) + + +def query_callable(manager, query_cls=CachingQuery): + def query(*arg, **kw): + return query_cls(manager, *arg, **kw) + return query + + +def get_cache_region(name, region): + if region not in beaker.cache.cache_regions: + raise BeakerException('Cache region `%s` not configured ' + 'Check if proper cache settings are in the .ini files' % region) + kw = beaker.cache.cache_regions[region] + return beaker.cache.Cache._get_cache(name, kw) + + +def _get_cache_parameters(query): + """For a query with cache_region and cache_namespace configured, + return the correspoinding Cache instance and cache key, based + on this query's current criterion and parameter values. + + """ + if not hasattr(query, '_cache_parameters'): + raise ValueError("This Query does not have caching " + "parameters configured.") + + region, namespace, cache_key = query._cache_parameters + + namespace = _namespace_from_query(namespace, query) + + if cache_key is None: + # cache key - the value arguments from this query's parameters. + args = [safe_str(x) for x in _params_from_query(query)] + args.extend(filter(lambda k: k not in ['None', None, u'None'], + [str(query._limit), str(query._offset)])) + + cache_key = " ".join(args) + + if cache_key is None: + raise Exception('Cache key cannot be None') + + # get cache + #cache = query.cache_manager.get_cache_region(namespace, region) + cache = get_cache_region(namespace, region) + # optional - hash the cache_key too for consistent length + # import uuid + # cache_key= str(uuid.uuid5(uuid.NAMESPACE_DNS, cache_key)) + + return cache, cache_key + + +def _namespace_from_query(namespace, query): + # cache namespace - the token handed in by the + # option + class we're querying against + namespace = " ".join([namespace] + [str(x) for x in query._entities]) + + # memcached wants this + namespace = namespace.replace(' ', '_') + + return namespace + + +def _set_cache_parameters(query, region, namespace, cache_key): + + if hasattr(query, '_cache_parameters'): + region, namespace, cache_key = query._cache_parameters + raise ValueError("This query is already configured " + "for region %r namespace %r" % + (region, namespace)) + query._cache_parameters = region, namespace, cache_key + + +class FromCache(MapperOption): + """Specifies that a Query should load results from a cache.""" + + propagate_to_loaders = False + + def __init__(self, region, namespace, cache_key=None): + """Construct a new FromCache. + + :param region: the cache region. Should be a + region configured in the Beaker CacheManager. + + :param namespace: the cache namespace. Should + be a name uniquely describing the target Query's + lexical structure. + + :param cache_key: optional. A string cache key + that will serve as the key to the query. Use this + if your query has a huge amount of parameters (such + as when using in_()) which correspond more simply to + some other identifier. + + """ + self.region = region + self.namespace = namespace + self.cache_key = cache_key + + def process_query(self, query): + """Process a Query during normal loading operation.""" + + _set_cache_parameters(query, self.region, self.namespace, + self.cache_key) + + +class RelationshipCache(MapperOption): + """Specifies that a Query as called within a "lazy load" + should load results from a cache.""" + + propagate_to_loaders = True + + def __init__(self, region, namespace, attribute): + """Construct a new RelationshipCache. + + :param region: the cache region. Should be a + region configured in the Beaker CacheManager. + + :param namespace: the cache namespace. Should + be a name uniquely describing the target Query's + lexical structure. + + :param attribute: A Class.attribute which + indicates a particular class relationship() whose + lazy loader should be pulled from the cache. + + """ + self.region = region + self.namespace = namespace + self._relationship_options = { + (attribute.property.parent.class_, attribute.property.key): self + } + + def process_query_conditionally(self, query): + """Process a Query that is used within a lazy loader. + + (the process_query_conditionally() method is a SQLAlchemy + hook invoked only within lazyload.) + + """ + if query._current_path: + mapper, key = query._current_path[-2:] + + for cls in mapper.class_.__mro__: + if (cls, key) in self._relationship_options: + relationship_option = \ + self._relationship_options[(cls, key)] + _set_cache_parameters( + query, + relationship_option.region, + relationship_option.namespace, + None) + + def and_(self, option): + """Chain another RelationshipCache option to this one. + + While many RelationshipCache objects can be specified on a single + Query separately, chaining them together allows for a more efficient + lookup during load. + + """ + self._relationship_options.update(option._relationship_options) + return self + + +def _params_from_query(query): + """Pull the bind parameter values from a query. + + This takes into account any scalar attribute bindparam set up. + + E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7))) + would return [5, 7]. + + """ + v = [] + def visit_bindparam(bind): + + if bind.key in query._params: + value = query._params[bind.key] + elif bind.callable: + # lazyloader may dig a callable in here, intended + # to late-evaluate params after autoflush is called. + # convert to a scalar value. + value = bind.callable() + else: + value = bind.value + + v.append(value) + if query._criterion is not None: + visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam}) + for f in query._from_obj: + visitors.traverse(f, {}, {'bindparam':visit_bindparam}) + return v diff --git a/rhodecode/lib/celerylib/__init__.py b/rhodecode/lib/celerylib/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/celerylib/__init__.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ +""" +celery libs for RhodeCode +""" + + +import socket +import logging + +import rhodecode + +from os.path import join as jn +from pylons import config + +from decorator import decorator + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode import CELERY_ENABLED, CELERY_EAGER +from rhodecode.config import utils +from rhodecode.lib.utils2 import safe_str, md5_safe, aslist +from rhodecode.lib.pidlock import DaemonLock, LockHeld +from rhodecode.lib.vcs import connect_vcs +from rhodecode.model import meta + +log = logging.getLogger(__name__) + + +class ResultWrapper(object): + def __init__(self, task): + self.task = task + + @LazyProperty + def result(self): + return self.task + + +def run_task(task, *args, **kwargs): + global CELERY_ENABLED + if CELERY_ENABLED: + try: + t = task.apply_async(args=args, kwargs=kwargs) + log.info('running task %s:%s', t.task_id, task) + return t + + except socket.error as e: + if isinstance(e, IOError) and e.errno == 111: + log.debug('Unable to connect to celeryd. Sync execution') + CELERY_ENABLED = False + else: + log.exception("Exception while connecting to celeryd.") + except KeyError as e: + log.debug('Unable to connect to celeryd. Sync execution') + except Exception as e: + log.exception( + "Exception while trying to run task asynchronous. " + "Fallback to sync execution.") + + log.debug('executing task %s in sync mode', task) + return ResultWrapper(task(*args, **kwargs)) + + +def __get_lockkey(func, *fargs, **fkwargs): + params = list(fargs) + params.extend(['%s-%s' % ar for ar in fkwargs.items()]) + + func_name = str(func.__name__) if hasattr(func, '__name__') else str(func) + _lock_key = func_name + '-' + '-'.join(map(safe_str, params)) + return 'task_%s.lock' % (md5_safe(_lock_key),) + + +def locked_task(func): + def __wrapper(func, *fargs, **fkwargs): + lockkey = __get_lockkey(func, *fargs, **fkwargs) + lockkey_path = config['app_conf']['cache_dir'] + + log.info('running task with lockkey %s' % lockkey) + try: + l = DaemonLock(file_=jn(lockkey_path, lockkey)) + ret = func(*fargs, **fkwargs) + l.release() + return ret + except LockHeld: + log.info('LockHeld') + return 'Task with key %s already running' % lockkey + + return decorator(__wrapper, func) + + +def get_session(): + if CELERY_ENABLED: + utils.initialize_database(config) + sa = meta.Session() + return sa + + +def dbsession(func): + def __wrapper(func, *fargs, **fkwargs): + try: + ret = func(*fargs, **fkwargs) + return ret + finally: + if CELERY_ENABLED and not CELERY_EAGER: + meta.Session.remove() + + return decorator(__wrapper, func) + + +def vcsconnection(func): + def __wrapper(func, *fargs, **fkwargs): + if CELERY_ENABLED and not CELERY_EAGER: + backends = config['vcs.backends'] = aslist( + config.get('vcs.backends', 'hg,git'), sep=',') + for alias in rhodecode.BACKENDS.keys(): + if alias not in backends: + del rhodecode.BACKENDS[alias] + utils.configure_pyro4(config) + utils.configure_vcs(config) + connect_vcs( + config['vcs.server'], + utils.get_vcs_server_protocol(config)) + ret = func(*fargs, **fkwargs) + return ret + + return decorator(__wrapper, func) diff --git a/rhodecode/lib/celerylib/tasks.py b/rhodecode/lib/celerylib/tasks.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/celerylib/tasks.py @@ -0,0 +1,284 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +RhodeCode task modules, containing all task that suppose to be run +by celery daemon +""" + + +import os +import logging + +from celery.task import task +from pylons import config + +from rhodecode import CELERY_ENABLED +from rhodecode.lib.celerylib import ( + run_task, dbsession, __get_lockkey, LockHeld, DaemonLock, + get_session, vcsconnection) +from rhodecode.lib.hooks_base import log_create_repository +from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer +from rhodecode.lib.utils import add_cache, action_logger +from rhodecode.lib.utils2 import safe_int, str2bool +from rhodecode.model.db import Repository, User + + +add_cache(config) # pragma: no cover + + +def get_logger(cls): + if CELERY_ENABLED: + try: + log = cls.get_logger() + except Exception: + log = logging.getLogger(__name__) + else: + log = logging.getLogger(__name__) + + return log + + +@task(ignore_result=True) +@dbsession +def send_email(recipients, subject, body='', html_body='', email_config=None): + """ + Sends an email with defined parameters from the .ini files. + + :param recipients: list of recipients, it this is empty the defined email + address from field 'email_to' is used instead + :param subject: subject of the mail + :param body: body of the mail + :param html_body: html version of body + """ + log = get_logger(send_email) + + email_config = email_config or config + subject = "%s %s" % (email_config.get('email_prefix', ''), subject) + if not recipients: + # if recipients are not defined we send to email_config + all admins + admins = [ + u.email for u in User.query().filter(User.admin == True).all()] + recipients = [email_config.get('email_to')] + admins + + mail_server = email_config.get('smtp_server') or None + if mail_server is None: + log.error("SMTP server information missing. Sending email failed. " + "Make sure that `smtp_server` variable is configured " + "inside the .ini file") + return False + + mail_from = email_config.get('app_email_from', 'RhodeCode') + user = email_config.get('smtp_username') + passwd = email_config.get('smtp_password') + mail_port = email_config.get('smtp_port') + tls = str2bool(email_config.get('smtp_use_tls')) + ssl = str2bool(email_config.get('smtp_use_ssl')) + debug = str2bool(email_config.get('debug')) + smtp_auth = email_config.get('smtp_auth') + + try: + m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth, + mail_port, ssl, tls, debug=debug) + m.send(recipients, subject, body, html_body) + except Exception: + log.exception('Mail sending failed') + return False + return True + + +@task(ignore_result=False) +@dbsession +@vcsconnection +def create_repo(form_data, cur_user): + from rhodecode.model.repo import RepoModel + from rhodecode.model.user import UserModel + from rhodecode.model.settings import SettingsModel + + log = get_logger(create_repo) + DBS = get_session() + + cur_user = UserModel(DBS)._get_user(cur_user) + owner = cur_user + + repo_name = form_data['repo_name'] + repo_name_full = form_data['repo_name_full'] + repo_type = form_data['repo_type'] + description = form_data['repo_description'] + private = form_data['repo_private'] + clone_uri = form_data.get('clone_uri') + repo_group = safe_int(form_data['repo_group']) + landing_rev = form_data['repo_landing_rev'] + copy_fork_permissions = form_data.get('copy_permissions') + copy_group_permissions = form_data.get('repo_copy_permissions') + fork_of = form_data.get('fork_parent_id') + state = form_data.get('repo_state', Repository.STATE_PENDING) + + # repo creation defaults, private and repo_type are filled in form + defs = SettingsModel().get_default_repo_settings(strip_prefix=True) + enable_statistics = form_data.get( + 'enable_statistics', defs.get('repo_enable_statistics')) + enable_locking = form_data.get( + 'enable_locking', defs.get('repo_enable_locking')) + enable_downloads = form_data.get( + 'enable_downloads', defs.get('repo_enable_downloads')) + + try: + RepoModel(DBS)._create_repo( + repo_name=repo_name_full, + repo_type=repo_type, + description=description, + owner=owner, + private=private, + clone_uri=clone_uri, + repo_group=repo_group, + landing_rev=landing_rev, + fork_of=fork_of, + copy_fork_permissions=copy_fork_permissions, + copy_group_permissions=copy_group_permissions, + enable_statistics=enable_statistics, + enable_locking=enable_locking, + enable_downloads=enable_downloads, + state=state + ) + + action_logger(cur_user, 'user_created_repo', + repo_name_full, '', DBS) + DBS.commit() + + # now create this repo on Filesystem + RepoModel(DBS)._create_filesystem_repo( + repo_name=repo_name, + repo_type=repo_type, + repo_group=RepoModel(DBS)._get_repo_group(repo_group), + clone_uri=clone_uri, + ) + repo = Repository.get_by_repo_name(repo_name_full) + log_create_repository(created_by=owner.username, **repo.get_dict()) + + # update repo commit caches initially + repo.update_commit_cache() + + # set new created state + repo.set_state(Repository.STATE_CREATED) + DBS.commit() + except Exception as e: + log.warning('Exception %s occurred when creating repository, ' + 'doing cleanup...', e) + # rollback things manually ! + repo = Repository.get_by_repo_name(repo_name_full) + if repo: + Repository.delete(repo.repo_id) + DBS.commit() + RepoModel(DBS)._delete_filesystem_repo(repo) + raise + + # it's an odd fix to make celery fail task when exception occurs + def on_failure(self, *args, **kwargs): + pass + + return True + + +@task(ignore_result=False) +@dbsession +@vcsconnection +def create_repo_fork(form_data, cur_user): + """ + Creates a fork of repository using internal VCS methods + + :param form_data: + :param cur_user: + """ + from rhodecode.model.repo import RepoModel + from rhodecode.model.user import UserModel + + log = get_logger(create_repo_fork) + DBS = get_session() + + cur_user = UserModel(DBS)._get_user(cur_user) + owner = cur_user + + repo_name = form_data['repo_name'] # fork in this case + repo_name_full = form_data['repo_name_full'] + repo_type = form_data['repo_type'] + description = form_data['description'] + private = form_data['private'] + clone_uri = form_data.get('clone_uri') + repo_group = safe_int(form_data['repo_group']) + landing_rev = form_data['landing_rev'] + copy_fork_permissions = form_data.get('copy_permissions') + fork_id = safe_int(form_data.get('fork_parent_id')) + + try: + fork_of = RepoModel(DBS)._get_repo(fork_id) + RepoModel(DBS)._create_repo( + repo_name=repo_name_full, + repo_type=repo_type, + description=description, + owner=owner, + private=private, + clone_uri=clone_uri, + repo_group=repo_group, + landing_rev=landing_rev, + fork_of=fork_of, + copy_fork_permissions=copy_fork_permissions + ) + action_logger(cur_user, 'user_forked_repo:%s' % repo_name_full, + fork_of.repo_name, '', DBS) + DBS.commit() + + base_path = Repository.base_path() + source_repo_path = os.path.join(base_path, fork_of.repo_name) + + # now create this repo on Filesystem + RepoModel(DBS)._create_filesystem_repo( + repo_name=repo_name, + repo_type=repo_type, + repo_group=RepoModel(DBS)._get_repo_group(repo_group), + clone_uri=source_repo_path, + ) + repo = Repository.get_by_repo_name(repo_name_full) + log_create_repository(created_by=owner.username, **repo.get_dict()) + + # update repo commit caches initially + config = repo._config + config.set('extensions', 'largefiles', '') + repo.update_commit_cache(config=config) + + # set new created state + repo.set_state(Repository.STATE_CREATED) + DBS.commit() + except Exception as e: + log.warning('Exception %s occurred when forking repository, ' + 'doing cleanup...', e) + # rollback things manually ! + repo = Repository.get_by_repo_name(repo_name_full) + if repo: + Repository.delete(repo.repo_id) + DBS.commit() + RepoModel(DBS)._delete_filesystem_repo(repo) + raise + + # it's an odd fix to make celery fail task when exception occurs + def on_failure(self, *args, **kwargs): + pass + + return True diff --git a/rhodecode/lib/celerypylons/__init__.py b/rhodecode/lib/celerypylons/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/celerypylons/__init__.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Automatically sets the environment variable `CELERY_LOADER` to +`celerypylons.loader:PylonsLoader`. This ensures the loader is +specified when accessing the rest of this package, and allows celery +to be installed in a webapp just by importing celerypylons:: + + import celerypylons + +""" + +import os +import warnings + +CELERYPYLONS_LOADER = 'rhodecode.lib.celerypylons.loader.PylonsLoader' +if os.environ.get('CELERY_LOADER', CELERYPYLONS_LOADER) != CELERYPYLONS_LOADER: + warnings.warn("'CELERY_LOADER' environment variable will be overridden by celery-pylons.") +os.environ['CELERY_LOADER'] = CELERYPYLONS_LOADER diff --git a/rhodecode/lib/celerypylons/commands.py b/rhodecode/lib/celerypylons/commands.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/celerypylons/commands.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import rhodecode +from rhodecode.lib.utils import BasePasterCommand, Command, load_rcextensions +from celery.app import app_or_default +from celery.bin import camqadm, celerybeat, celeryd, celeryev + +from rhodecode.lib.utils2 import str2bool + +__all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand', + 'CAMQPAdminCommand', 'CeleryEventCommand'] + + +class CeleryCommand(BasePasterCommand): + """Abstract class implements run methods needed for celery + + Starts the celery worker that uses a paste.deploy configuration + file. + """ + + def update_parser(self): + """ + Abstract method. Allows for the class's parser to be updated + before the superclass's `run` method is called. Necessary to + allow options/arguments to be passed through to the underlying + celery command. + """ + + cmd = self.celery_command(app_or_default()) + for x in cmd.get_options(): + self.parser.add_option(x) + + def command(self): + from pylons import config + try: + CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery')) + except KeyError: + CELERY_ENABLED = False + + if not CELERY_ENABLED: + raise Exception('Please set use_celery = true in .ini config ' + 'file before running celeryd') + rhodecode.CELERY_ENABLED = CELERY_ENABLED + load_rcextensions(config['here']) + cmd = self.celery_command(app_or_default()) + return cmd.run(**vars(self.options)) + + +class CeleryDaemonCommand(CeleryCommand): + """Start the celery worker + + Starts the celery worker that uses a paste.deploy configuration + file. + """ + usage = 'CONFIG_FILE [celeryd options...]' + summary = __doc__.splitlines()[0] + description = "".join(__doc__.splitlines()[2:]) + + parser = Command.standard_parser(quiet=True) + celery_command = celeryd.WorkerCommand + + +class CeleryBeatCommand(CeleryCommand): + """Start the celery beat server + + Starts the celery beat server using a paste.deploy configuration + file. + """ + usage = 'CONFIG_FILE [celerybeat options...]' + summary = __doc__.splitlines()[0] + description = "".join(__doc__.splitlines()[2:]) + + parser = Command.standard_parser(quiet=True) + celery_command = celerybeat.BeatCommand + + +class CAMQPAdminCommand(CeleryCommand): + """CAMQP Admin + + CAMQP celery admin tool. + """ + usage = 'CONFIG_FILE [camqadm options...]' + summary = __doc__.splitlines()[0] + description = "".join(__doc__.splitlines()[2:]) + + parser = Command.standard_parser(quiet=True) + celery_command = camqadm.AMQPAdminCommand + + +class CeleryEventCommand(CeleryCommand): + """Celery event command. + + Capture celery events. + """ + usage = 'CONFIG_FILE [celeryev options...]' + summary = __doc__.splitlines()[0] + description = "".join(__doc__.splitlines()[2:]) + + parser = Command.standard_parser(quiet=True) + celery_command = celeryev.EvCommand diff --git a/rhodecode/lib/celerypylons/loader.py b/rhodecode/lib/celerypylons/loader.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/celerypylons/loader.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from celery.loaders.base import BaseLoader +from pylons import config + +to_pylons = lambda x: x.replace('_', '.').lower() +to_celery = lambda x: x.replace('.', '_').upper() + +LIST_PARAMS = """CELERY_IMPORTS ADMINS ROUTES""".split() + + +class PylonsSettingsProxy(object): + """Pylons Settings Proxy + + Proxies settings from pylons.config + + """ + def __getattr__(self, key): + pylons_key = to_pylons(key) + try: + value = config[pylons_key] + if key in LIST_PARAMS:return value.split() + return self.type_converter(value) + except KeyError: + raise AttributeError(pylons_key) + + def get(self, key): + try: + return self.__getattr__(key) + except AttributeError: + return None + + def __getitem__(self, key): + try: + return self.__getattr__(key) + except AttributeError: + raise KeyError() + + def __setattr__(self, key, value): + pylons_key = to_pylons(key) + config[pylons_key] = value + + def __setitem__(self, key, value): + self.__setattr__(key, value) + + def type_converter(self, value): + #cast to int + if value.isdigit(): + return int(value) + + #cast to bool + if value.lower() in ['true', 'false']: + return value.lower() == 'true' + return value + +class PylonsLoader(BaseLoader): + """Pylons celery loader + + Maps the celery config onto pylons.config + + """ + def read_configuration(self): + self.configured = True + return PylonsSettingsProxy() + + def on_worker_init(self): + """ + Import task modules. + """ + self.import_default_modules() diff --git a/rhodecode/lib/colored_formatter.py b/rhodecode/lib/colored_formatter.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/colored_formatter.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Legacy support for old logging formatter names. + +.. deprecated:: 3.2.0 + + Got replaced by rhodecode.lib.logging_formatter. This module stays for a + few versions to ease the migration of INI files. + +""" + +import warnings + +from rhodecode.lib import logging_formatter + + +def _deprecated_formatter(name): + BaseFormatter = getattr(logging_formatter, name) + + class LegacyFormatter(BaseFormatter): + + def __init__(self, *args, **kwargs): + warnings.warn( + "Use rhodecode.lib.logging_formatter.%s instead." % name, + DeprecationWarning) + BaseFormatter.__init__(self, *args, **kwargs) + + return LegacyFormatter + + +ColorFormatter = _deprecated_formatter('ColorFormatter') +ColorFormatterSql = _deprecated_formatter('ColorFormatterSql') diff --git a/rhodecode/lib/compat.py b/rhodecode/lib/compat.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/compat.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Python backward compatibility functions and common libs +""" + + +import os +import sys + +import rhodecode + + +# ============================================================================== +# kill FUNCTIONS +# ============================================================================== +if rhodecode.is_windows: + import ctypes + + def kill(pid, sig): + """Kill function for Win32.""" + kernel32 = ctypes.windll.kernel32 + handle = kernel32.OpenProcess(1, 0, pid) + return kernel32.TerminateProcess(handle, 0) != 0 +else: + kill = os.kill + + +# ============================================================================== +# OrderedDict +# ============================================================================== +from collections import OrderedDict diff --git a/rhodecode/lib/datelib.py b/rhodecode/lib/datelib.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/datelib.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Provides utilities around date and time handling +""" + +import datetime +import time + + +def makedate(): + lt = time.localtime() + if lt[8] == 1 and time.daylight: + tz = time.altzone + else: + tz = time.timezone + return time.mktime(lt), tz + + +def date_fromtimestamp(unixts, tzoffset=0): + """ + Makes a local datetime object out of unix timestamp + + :param unixts: + :param tzoffset: + """ + + return datetime.datetime.fromtimestamp(float(unixts)) + + +def date_astimestamp(value): + """ + Convert a given `datetime.datetime` into a `float` like `time.time` + """ + return time.mktime(value.timetuple()) + value.microsecond / 1E6 + + +def date_to_timestamp_plus_offset(value): + """ + Convert a given `datetime.datetime` into a unix timestamp and offset. + """ + # TODO: johbo: The time handling looks quite fragile here since we mix + # system time zones with naive datetime instances. + if value is None: + value = time.time() + elif isinstance(value, datetime.datetime): + assert not is_aware(value), ( + "This code is not prepared to handle aware datetime instances") + value = date_astimestamp(value) + return (value, time.timezone) + + +def is_aware(value): + """ + Determines if a given datetime.time is aware. + + The logic is described in Python's docs: + http://docs.python.org/library/datetime.html#datetime.tzinfo + """ + return (value.tzinfo is not None + and value.tzinfo.utcoffset(value) is not None) diff --git a/rhodecode/lib/db_manage.py b/rhodecode/lib/db_manage.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/db_manage.py @@ -0,0 +1,598 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Database creation, and setup module for RhodeCode Enterprise. Used for creation +of database as well as for migration operations +""" + +import os +import sys +import time +import uuid +import logging +import getpass +from os.path import dirname as dn, join as jn + +from sqlalchemy.engine import create_engine + +from rhodecode import __dbversion__ +from rhodecode.model import init_model +from rhodecode.model.user import UserModel +from rhodecode.model.db import ( + User, Permission, RhodeCodeUi, RhodeCodeSetting, UserToPerm, + DbMigrateVersion, RepoGroup, UserRepoGroupToPerm, CacheKey, Repository) +from rhodecode.model.meta import Session, Base +from rhodecode.model.permission import PermissionModel +from rhodecode.model.repo import RepoModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.settings import SettingsModel + + +log = logging.getLogger(__name__) + + +def notify(msg): + """ + Notification for migrations messages + """ + ml = len(msg) + (4 * 2) + print('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)).upper() + + +class DbManage(object): + + def __init__(self, log_sql, dbconf, root, tests=False, + SESSION=None, cli_args={}): + self.dbname = dbconf.split('/')[-1] + self.tests = tests + self.root = root + self.dburi = dbconf + self.log_sql = log_sql + self.db_exists = False + self.cli_args = cli_args + self.init_db(SESSION=SESSION) + self.ask_ok = self.get_ask_ok_func(self.cli_args.get('force_ask')) + + def get_ask_ok_func(self, param): + if param not in [None]: + # return a function lambda that has a default set to param + return lambda *args, **kwargs: param + else: + from rhodecode.lib.utils import ask_ok + return ask_ok + + def init_db(self, SESSION=None): + if SESSION: + self.sa = SESSION + else: + # init new sessions + engine = create_engine(self.dburi, echo=self.log_sql) + init_model(engine) + self.sa = Session() + + def create_tables(self, override=False): + """ + Create a auth database + """ + + log.info("Existing database with the same name is going to be destroyed.") + log.info("Setup command will run DROP ALL command on that database.") + if self.tests: + destroy = True + else: + destroy = self.ask_ok('Are you sure that you want to destroy the old database? [y/n]') + if not destroy: + log.info('Nothing done.') + sys.exit(0) + if destroy: + Base.metadata.drop_all() + + checkfirst = not override + Base.metadata.create_all(checkfirst=checkfirst) + log.info('Created tables for %s' % self.dbname) + + def set_db_version(self): + ver = DbMigrateVersion() + ver.version = __dbversion__ + ver.repository_id = 'rhodecode_db_migrations' + ver.repository_path = 'versions' + self.sa.add(ver) + log.info('db version set to: %s' % __dbversion__) + + def run_pre_migration_tasks(self): + """ + Run various tasks before actually doing migrations + """ + # delete cache keys on each upgrade + total = CacheKey.query().count() + log.info("Deleting (%s) cache keys now...", total) + CacheKey.delete_all_cache() + + def upgrade(self): + """ + Upgrades given database schema to given revision following + all needed steps, to perform the upgrade + + """ + + from rhodecode.lib.dbmigrate.migrate.versioning import api + from rhodecode.lib.dbmigrate.migrate.exceptions import \ + DatabaseNotControlledError + + if 'sqlite' in self.dburi: + print ( + '********************** WARNING **********************\n' + 'Make sure your version of sqlite is at least 3.7.X. \n' + 'Earlier versions are known to fail on some migrations\n' + '*****************************************************\n') + + upgrade = self.ask_ok( + 'You are about to perform a database upgrade. Make ' + 'sure you have backed up your database. ' + 'Continue ? [y/n]') + if not upgrade: + log.info('No upgrade performed') + sys.exit(0) + + repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))), + 'rhodecode/lib/dbmigrate') + db_uri = self.dburi + + try: + curr_version = api.db_version(db_uri, repository_path) + msg = ('Found current database under version ' + 'control with version %s' % curr_version) + + except (RuntimeError, DatabaseNotControlledError): + curr_version = 1 + msg = ('Current database is not under version control. Setting ' + 'as version %s' % curr_version) + api.version_control(db_uri, repository_path, curr_version) + + notify(msg) + + self.run_pre_migration_tasks() + + if curr_version == __dbversion__: + log.info('This database is already at the newest version') + sys.exit(0) + + upgrade_steps = range(curr_version + 1, __dbversion__ + 1) + notify('attempting to upgrade database from ' + 'version %s to version %s' % (curr_version, __dbversion__)) + + # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE + _step = None + for step in upgrade_steps: + notify('performing upgrade step %s' % step) + time.sleep(0.5) + + api.upgrade(db_uri, repository_path, step) + self.sa.rollback() + notify('schema upgrade for step %s completed' % (step,)) + + _step = step + + notify('upgrade to version %s successful' % _step) + + def fix_repo_paths(self): + """ + Fixes an old RhodeCode version path into new one without a '*' + """ + + paths = self.sa.query(RhodeCodeUi)\ + .filter(RhodeCodeUi.ui_key == '/')\ + .scalar() + + paths.ui_value = paths.ui_value.replace('*', '') + + try: + self.sa.add(paths) + self.sa.commit() + except Exception: + self.sa.rollback() + raise + + def fix_default_user(self): + """ + Fixes an old default user with some 'nicer' default values, + used mostly for anonymous access + """ + def_user = self.sa.query(User)\ + .filter(User.username == User.DEFAULT_USER)\ + .one() + + def_user.name = 'Anonymous' + def_user.lastname = 'User' + def_user.email = User.DEFAULT_USER_EMAIL + + try: + self.sa.add(def_user) + self.sa.commit() + except Exception: + self.sa.rollback() + raise + + def fix_settings(self): + """ + Fixes rhodecode settings and adds ga_code key for google analytics + """ + + hgsettings3 = RhodeCodeSetting('ga_code', '') + + try: + self.sa.add(hgsettings3) + self.sa.commit() + except Exception: + self.sa.rollback() + raise + + def create_admin_and_prompt(self): + + # defaults + defaults = self.cli_args + username = defaults.get('username') + password = defaults.get('password') + email = defaults.get('email') + + if username is None: + username = raw_input('Specify admin username:') + if password is None: + password = self._get_admin_password() + if not password: + # second try + password = self._get_admin_password() + if not password: + sys.exit() + if email is None: + email = raw_input('Specify admin email:') + api_key = self.cli_args.get('api_key') + self.create_user(username, password, email, True, + strict_creation_check=False, + api_key=api_key) + + def _get_admin_password(self): + password = getpass.getpass('Specify admin password ' + '(min 6 chars):') + confirm = getpass.getpass('Confirm password:') + + if password != confirm: + log.error('passwords mismatch') + return False + if len(password) < 6: + log.error('password is too short - use at least 6 characters') + return False + + return password + + def create_test_admin_and_users(self): + log.info('creating admin and regular test users') + from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \ + TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \ + TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \ + TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \ + TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL + + self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, + TEST_USER_ADMIN_EMAIL, True) + + self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, + TEST_USER_REGULAR_EMAIL, False) + + self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS, + TEST_USER_REGULAR2_EMAIL, False) + + def create_ui_settings(self, repo_store_path): + """ + Creates ui settings, fills out hooks + and disables dotencode + """ + settings_model = SettingsModel(sa=self.sa) + + # Build HOOKS + hooks = [ + (RhodeCodeUi.HOOK_REPO_SIZE, 'python:vcsserver.hooks.repo_size'), + + # HG + (RhodeCodeUi.HOOK_PRE_PULL, 'python:vcsserver.hooks.pre_pull'), + (RhodeCodeUi.HOOK_PULL, 'python:vcsserver.hooks.log_pull_action'), + (RhodeCodeUi.HOOK_PRE_PUSH, 'python:vcsserver.hooks.pre_push'), + (RhodeCodeUi.HOOK_PUSH, 'python:vcsserver.hooks.log_push_action'), + + ] + + for key, value in hooks: + hook_obj = settings_model.get_ui_by_key(key) + hooks2 = hook_obj if hook_obj else RhodeCodeUi() + hooks2.ui_section = 'hooks' + hooks2.ui_key = key + hooks2.ui_value = value + self.sa.add(hooks2) + + # enable largefiles + largefiles = RhodeCodeUi() + largefiles.ui_section = 'extensions' + largefiles.ui_key = 'largefiles' + largefiles.ui_value = '' + self.sa.add(largefiles) + + # set default largefiles cache dir, defaults to + # /repo location/.cache/largefiles + largefiles = RhodeCodeUi() + largefiles.ui_section = 'largefiles' + largefiles.ui_key = 'usercache' + largefiles.ui_value = os.path.join(repo_store_path, '.cache', + 'largefiles') + self.sa.add(largefiles) + + # enable hgsubversion disabled by default + hgsubversion = RhodeCodeUi() + hgsubversion.ui_section = 'extensions' + hgsubversion.ui_key = 'hgsubversion' + hgsubversion.ui_value = '' + hgsubversion.ui_active = False + self.sa.add(hgsubversion) + + # enable hggit disabled by default + hggit = RhodeCodeUi() + hggit.ui_section = 'extensions' + hggit.ui_key = 'hggit' + hggit.ui_value = '' + hggit.ui_active = False + self.sa.add(hggit) + + # set svn branch defaults + branches = ["/branches/*", "/trunk"] + tags = ["/tags/*"] + + for branch in branches: + settings_model.create_ui_section_value( + RhodeCodeUi.SVN_BRANCH_ID, branch) + + for tag in tags: + settings_model.create_ui_section_value(RhodeCodeUi.SVN_TAG_ID, tag) + + def create_auth_plugin_options(self, skip_existing=False): + """ + Create default auth plugin settings, and make it active + + :param skip_existing: + """ + + for k, v, t in [('auth_plugins', 'egg:rhodecode-enterprise-ce#rhodecode', 'list'), + ('auth_rhodecode_enabled', 'True', 'bool')]: + if (skip_existing and + SettingsModel().get_setting_by_name(k) is not None): + log.debug('Skipping option %s' % k) + continue + setting = RhodeCodeSetting(k, v, t) + self.sa.add(setting) + + def create_default_options(self, skip_existing=False): + """Creates default settings""" + + for k, v, t in [ + ('default_repo_enable_locking', False, 'bool'), + ('default_repo_enable_downloads', False, 'bool'), + ('default_repo_enable_statistics', False, 'bool'), + ('default_repo_private', False, 'bool'), + ('default_repo_type', 'hg', 'unicode')]: + + if (skip_existing and + SettingsModel().get_setting_by_name(k) is not None): + log.debug('Skipping option %s' % k) + continue + setting = RhodeCodeSetting(k, v, t) + self.sa.add(setting) + + def fixup_groups(self): + def_usr = User.get_default_user() + for g in RepoGroup.query().all(): + g.group_name = g.get_new_name(g.name) + self.sa.add(g) + # get default perm + default = UserRepoGroupToPerm.query()\ + .filter(UserRepoGroupToPerm.group == g)\ + .filter(UserRepoGroupToPerm.user == def_usr)\ + .scalar() + + if default is None: + log.debug('missing default permission for group %s adding' % g) + perm_obj = RepoGroupModel()._create_default_perms(g) + self.sa.add(perm_obj) + + def reset_permissions(self, username): + """ + Resets permissions to default state, useful when old systems had + bad permissions, we must clean them up + + :param username: + """ + default_user = User.get_by_username(username) + if not default_user: + return + + u2p = UserToPerm.query()\ + .filter(UserToPerm.user == default_user).all() + fixed = False + if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS): + for p in u2p: + Session().delete(p) + fixed = True + self.populate_default_permissions() + return fixed + + def update_repo_info(self): + RepoModel.update_repoinfo() + + def config_prompt(self, test_repo_path='', retries=3): + defaults = self.cli_args + _path = defaults.get('repos_location') + if retries == 3: + log.info('Setting up repositories config') + + if _path is not None: + path = _path + elif not self.tests and not test_repo_path: + path = raw_input( + 'Enter a valid absolute path to store repositories. ' + 'All repositories in that path will be added automatically:' + ) + else: + path = test_repo_path + path_ok = True + + # check proper dir + if not os.path.isdir(path): + path_ok = False + log.error('Given path %s is not a valid directory' % (path,)) + + elif not os.path.isabs(path): + path_ok = False + log.error('Given path %s is not an absolute path' % (path,)) + + # check if path is at least readable. + if not os.access(path, os.R_OK): + path_ok = False + log.error('Given path %s is not readable' % (path,)) + + # check write access, warn user about non writeable paths + elif not os.access(path, os.W_OK) and path_ok: + log.warning('No write permission to given path %s' % (path,)) + + q = ('Given path %s is not writeable, do you want to ' + 'continue with read only mode ? [y/n]' % (path,)) + if not self.ask_ok(q): + log.error('Canceled by user') + sys.exit(-1) + + if retries == 0: + sys.exit('max retries reached') + if not path_ok: + retries -= 1 + return self.config_prompt(test_repo_path, retries) + + real_path = os.path.normpath(os.path.realpath(path)) + + if real_path != os.path.normpath(path): + q = ('Path looks like a symlink, RhodeCode Enterprise will store ' + 'given path as %s ? [y/n]') % (real_path,) + if not self.ask_ok(q): + log.error('Canceled by user') + sys.exit(-1) + + return real_path + + def create_settings(self, path): + + self.create_ui_settings(path) + + ui_config = [ + ('web', 'push_ssl', 'false'), + ('web', 'allow_archive', 'gz zip bz2'), + ('web', 'allow_push', '*'), + ('web', 'baseurl', '/'), + ('paths', '/', path), + ('phases', 'publish', 'true') + ] + for section, key, value in ui_config: + ui_conf = RhodeCodeUi() + setattr(ui_conf, 'ui_section', section) + setattr(ui_conf, 'ui_key', key) + setattr(ui_conf, 'ui_value', value) + self.sa.add(ui_conf) + + # rhodecode app settings + settings = [ + ('realm', 'RhodeCode', 'unicode'), + ('title', '', 'unicode'), + ('pre_code', '', 'unicode'), + ('post_code', '', 'unicode'), + ('show_public_icon', True, 'bool'), + ('show_private_icon', True, 'bool'), + ('stylify_metatags', False, 'bool'), + ('dashboard_items', 100, 'int'), + ('admin_grid_items', 25, 'int'), + ('show_version', True, 'bool'), + ('use_gravatar', False, 'bool'), + ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'), + ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'), + ('support_url', '', 'unicode'), + ('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'), + ('license_key', '', 'unicode'), + ('show_revision_number', True, 'bool'), + ('show_sha_length', 12, 'int'), + ] + + for key, val, type_ in settings: + sett = RhodeCodeSetting(key, val, type_) + self.sa.add(sett) + + self.create_auth_plugin_options() + self.create_default_options() + + log.info('created ui config') + + def create_user(self, username, password, email='', admin=False, + strict_creation_check=True, api_key=None): + log.info('creating user %s' % username) + user = UserModel().create_or_update( + username, password, email, firstname='RhodeCode', lastname='Admin', + active=True, admin=admin, extern_type="rhodecode", + strict_creation_check=strict_creation_check) + + if api_key: + log.info('setting a provided api key for the user %s', username) + user.api_key = api_key + + def create_default_user(self): + log.info('creating default user') + # create default user for handling default permissions. + user = UserModel().create_or_update(username=User.DEFAULT_USER, + password=str(uuid.uuid1())[:20], + email=User.DEFAULT_USER_EMAIL, + firstname='Anonymous', + lastname='User', + strict_creation_check=False) + # based on configuration options activate/deactive this user which + # controlls anonymous access + if self.cli_args.get('public_access') is False: + log.info('Public access disabled') + user.active = False + Session().add(user) + Session().commit() + + def create_permissions(self): + """ + Creates all permissions defined in the system + """ + # module.(access|create|change|delete)_[name] + # module.(none|read|write|admin) + log.info('creating permissions') + PermissionModel(self.sa).create_permissions() + + def populate_default_permissions(self): + """ + Populate default permissions. It will create only the default + permissions that are missing, and not alter already defined ones + """ + log.info('creating default user permissions') + PermissionModel(self.sa).create_default_user_permissions(user=User.DEFAULT_USER) diff --git a/rhodecode/lib/dbmigrate/__init__.py b/rhodecode/lib/dbmigrate/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/__init__.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Database migration modules +""" + +import logging + +from rhodecode.lib.utils import BasePasterCommand, Command, add_cache +from rhodecode.lib.db_manage import DbManage + +log = logging.getLogger(__name__) + + +class UpgradeDb(BasePasterCommand): + """Command used for paster to upgrade our database to newer version + """ + + max_args = 1 + min_args = 1 + + usage = "CONFIG_FILE" + summary = "Upgrades current db to newer version" + group_name = "RhodeCode" + + parser = Command.standard_parser(verbose=True) + + def command(self): + from pylons import config + add_cache(config) + self.logging_file_config(self.path_to_ini_file) + + db_uri = config['sqlalchemy.db1.url'] + dbmanage = DbManage(log_sql=True, dbconf=db_uri, + root=config['here'], tests=False, + cli_args=self.options.__dict__) + dbmanage.upgrade() + + def update_parser(self): + self.parser.add_option('--sql', + action='store_true', + dest='just_sql', + help="Prints upgrade sql for further investigation", + default=False) + + self.parser.add_option('--force-yes', + action='store_true', + dest='force_ask', + default=None, + help='Force yes to every question') + self.parser.add_option('--force-no', + action='store_false', + dest='force_ask', + default=None, + help='Force no to every question') diff --git a/rhodecode/lib/dbmigrate/migrate.cfg b/rhodecode/lib/dbmigrate/migrate.cfg new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate.cfg @@ -0,0 +1,20 @@ +[db_settings] +# Used to identify which repository this database is versioned under. +# You can use the name of your project. +repository_id=rhodecode_db_migrations + +# The name of the database table used to track the schema version. +# This name shouldn't already be used by your project. +# If this is changed once a database is under version control, you'll need to +# change the table name in each database too. +version_table=db_migrate_version + +# When committing a change script, Migrate will attempt to generate the +# sql for all supported databases; normally, if one of them fails - probably +# because you don't have that database installed - it is ignored and the +# commit continues, perhaps ending successfully. +# Databases in this list MUST compile successfully during a commit, or the +# entire commit will fail. List the databases your application will actually +# be using to ensure your updates to that database work properly. +# This must be a list; example: ['postgres','sqlite'] +required_dbs=['sqlite'] diff --git a/rhodecode/lib/dbmigrate/migrate/__init__.py b/rhodecode/lib/dbmigrate/migrate/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/__init__.py @@ -0,0 +1,11 @@ +""" + SQLAlchemy migrate provides two APIs :mod:`migrate.versioning` for + database schema version and repository management and + :mod:`migrate.changeset` that allows to define database schema changes + using Python. +""" + +from rhodecode.lib.dbmigrate.migrate.versioning import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +__version__ = '0.7.3.dev' diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/__init__.py b/rhodecode/lib/dbmigrate/migrate/changeset/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/__init__.py @@ -0,0 +1,30 @@ +""" + This module extends SQLAlchemy and provides additional DDL [#]_ + support. + + .. [#] SQL Data Definition Language +""" +import re +import warnings + +import sqlalchemy +from sqlalchemy import __version__ as _sa_version + +warnings.simplefilter('always', DeprecationWarning) + +_sa_version = tuple(int(re.match("\d+", x).group(0)) + for x in _sa_version.split(".")) +SQLA_07 = _sa_version >= (0, 7) +SQLA_08 = _sa_version >= (0, 8) + +del re +del _sa_version + +from rhodecode.lib.dbmigrate.migrate.changeset.schema import * +from rhodecode.lib.dbmigrate.migrate.changeset.constraint import * + +sqlalchemy.schema.Table.__bases__ += (ChangesetTable,) +sqlalchemy.schema.Column.__bases__ += (ChangesetColumn,) +sqlalchemy.schema.Index.__bases__ += (ChangesetIndex,) + +sqlalchemy.schema.DefaultClause.__bases__ += (ChangesetDefaultClause,) diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py b/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py @@ -0,0 +1,315 @@ +""" + Extensions to SQLAlchemy for altering existing tables. + + At the moment, this isn't so much based off of ANSI as much as + things that just happen to work with multiple databases. +""" +import StringIO + +import sqlalchemy as sa +from sqlalchemy.schema import SchemaVisitor +from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.sql import ClauseElement +from sqlalchemy.schema import (ForeignKeyConstraint, + PrimaryKeyConstraint, + CheckConstraint, + UniqueConstraint, + Index) + +import sqlalchemy.sql.compiler +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import constraint +from rhodecode.lib.dbmigrate.migrate.changeset import util + +from sqlalchemy.schema import AddConstraint, DropConstraint +from sqlalchemy.sql.compiler import DDLCompiler +SchemaGenerator = SchemaDropper = DDLCompiler + + +class AlterTableVisitor(SchemaVisitor): + """Common operations for ``ALTER TABLE`` statements.""" + + # engine.Compiler looks for .statement + # when it spawns off a new compiler + statement = ClauseElement() + + def append(self, s): + """Append content to the SchemaIterator's query buffer.""" + + self.buffer.write(s) + + def execute(self): + """Execute the contents of the SchemaIterator's buffer.""" + try: + return self.connection.execute(self.buffer.getvalue()) + finally: + self.buffer.seek(0) + self.buffer.truncate() + + def __init__(self, dialect, connection, **kw): + self.connection = connection + self.buffer = StringIO.StringIO() + self.preparer = dialect.identifier_preparer + self.dialect = dialect + + def traverse_single(self, elem): + ret = super(AlterTableVisitor, self).traverse_single(elem) + if ret: + # adapt to 0.6 which uses a string-returning + # object + self.append(" %s" % ret) + + def _to_table(self, param): + """Returns the table object for the given param object.""" + if isinstance(param, (sa.Column, sa.Index, sa.schema.Constraint)): + ret = param.table + else: + ret = param + return ret + + def start_alter_table(self, param): + """Returns the start of an ``ALTER TABLE`` SQL-Statement. + + Use the param object to determine the table name and use it + for building the SQL statement. + + :param param: object to determine the table from + :type param: :class:`sqlalchemy.Column`, :class:`sqlalchemy.Index`, + :class:`sqlalchemy.schema.Constraint`, :class:`sqlalchemy.Table`, + or string (table name) + """ + table = self._to_table(param) + self.append('\nALTER TABLE %s ' % self.preparer.format_table(table)) + return table + + +class ANSIColumnGenerator(AlterTableVisitor, SchemaGenerator): + """Extends ansisql generator for column creation (alter table add col)""" + + def visit_column(self, column): + """Create a column (table already exists). + + :param column: column object + :type column: :class:`sqlalchemy.Column` instance + """ + if column.default is not None: + self.traverse_single(column.default) + + table = self.start_alter_table(column) + self.append("ADD ") + + self.append(self.get_column_specification(column)) + + for cons in column.constraints: + self.traverse_single(cons) + self.execute() + + # ALTER TABLE STATEMENTS + + # add indexes and unique constraints + if column.index_name: + Index(column.index_name,column).create() + elif column.unique_name: + constraint.UniqueConstraint(column, + name=column.unique_name).create() + + # SA bounds FK constraints to table, add manually + for fk in column.foreign_keys: + self.add_foreignkey(fk.constraint) + + # add primary key constraint if needed + if column.primary_key_name: + cons = constraint.PrimaryKeyConstraint(column, + name=column.primary_key_name) + cons.create() + + def add_foreignkey(self, fk): + self.connection.execute(AddConstraint(fk)) + +class ANSIColumnDropper(AlterTableVisitor, SchemaDropper): + """Extends ANSI SQL dropper for column dropping (``ALTER TABLE + DROP COLUMN``). + """ + + def visit_column(self, column): + """Drop a column from its table. + + :param column: the column object + :type column: :class:`sqlalchemy.Column` + """ + table = self.start_alter_table(column) + self.append('DROP COLUMN %s' % self.preparer.format_column(column)) + self.execute() + + +class ANSISchemaChanger(AlterTableVisitor, SchemaGenerator): + """Manages changes to existing schema elements. + + Note that columns are schema elements; ``ALTER TABLE ADD COLUMN`` + is in SchemaGenerator. + + All items may be renamed. Columns can also have many of their properties - + type, for example - changed. + + Each function is passed a tuple, containing (object, name); where + object is a type of object you'd expect for that function + (ie. table for visit_table) and name is the object's new + name. NONE means the name is unchanged. + """ + + def visit_table(self, table): + """Rename a table. Other ops aren't supported.""" + self.start_alter_table(table) + q = util.safe_quote(table) + self.append("RENAME TO %s" % self.preparer.quote(table.new_name, q)) + self.execute() + + def visit_index(self, index): + """Rename an index""" + if hasattr(self, '_validate_identifier'): + # SA <= 0.6.3 + self.append("ALTER INDEX %s RENAME TO %s" % ( + self.preparer.quote( + self._validate_identifier( + index.name, True), index.quote), + self.preparer.quote( + self._validate_identifier( + index.new_name, True), index.quote))) + elif hasattr(self, '_index_identifier'): + # SA >= 0.6.5, < 0.8 + self.append("ALTER INDEX %s RENAME TO %s" % ( + self.preparer.quote( + self._index_identifier( + index.name), index.quote), + self.preparer.quote( + self._index_identifier( + index.new_name), index.quote))) + else: + # SA >= 0.8 + class NewName(object): + """Map obj.name -> obj.new_name""" + def __init__(self, index): + self.name = index.new_name + self._obj = index + + def __getattr__(self, attr): + if attr == 'name': + return getattr(self, attr) + return getattr(self._obj, attr) + + self.append("ALTER INDEX %s RENAME TO %s" % ( + self._prepared_index_name(index), + self._prepared_index_name(NewName(index)))) + + self.execute() + + def visit_column(self, delta): + """Rename/change a column.""" + # ALTER COLUMN is implemented as several ALTER statements + keys = delta.keys() + if 'type' in keys: + self._run_subvisit(delta, self._visit_column_type) + if 'nullable' in keys: + self._run_subvisit(delta, self._visit_column_nullable) + if 'server_default' in keys: + # Skip 'default': only handle server-side defaults, others + # are managed by the app, not the db. + self._run_subvisit(delta, self._visit_column_default) + if 'name' in keys: + self._run_subvisit(delta, self._visit_column_name, start_alter=False) + + def _run_subvisit(self, delta, func, start_alter=True): + """Runs visit method based on what needs to be changed on column""" + table = self._to_table(delta.table) + col_name = delta.current_name + if start_alter: + self.start_alter_column(table, col_name) + ret = func(table, delta.result_column, delta) + self.execute() + + def start_alter_column(self, table, col_name): + """Starts ALTER COLUMN""" + self.start_alter_table(table) + q = util.safe_quote(table) + self.append("ALTER COLUMN %s " % self.preparer.quote(col_name, q)) + + def _visit_column_nullable(self, table, column, delta): + nullable = delta['nullable'] + if nullable: + self.append("DROP NOT NULL") + else: + self.append("SET NOT NULL") + + def _visit_column_default(self, table, column, delta): + default_text = self.get_column_default_string(column) + if default_text is not None: + self.append("SET DEFAULT %s" % default_text) + else: + self.append("DROP DEFAULT") + + def _visit_column_type(self, table, column, delta): + type_ = delta['type'] + type_text = str(type_.compile(dialect=self.dialect)) + self.append("TYPE %s" % type_text) + + def _visit_column_name(self, table, column, delta): + self.start_alter_table(table) + q = util.safe_quote(table) + col_name = self.preparer.quote(delta.current_name, q) + new_name = self.preparer.format_column(delta.result_column) + self.append('RENAME COLUMN %s TO %s' % (col_name, new_name)) + + +class ANSIConstraintCommon(AlterTableVisitor): + """ + Migrate's constraints require a separate creation function from + SA's: Migrate's constraints are created independently of a table; + SA's are created at the same time as the table. + """ + + def get_constraint_name(self, cons): + """Gets a name for the given constraint. + + If the name is already set it will be used otherwise the + constraint's :meth:`autoname <migrate.changeset.constraint.ConstraintChangeset.autoname>` + method is used. + + :param cons: constraint object + """ + if cons.name is not None: + ret = cons.name + else: + ret = cons.name = cons.autoname() + return self.preparer.quote(ret, cons.quote) + + def visit_migrate_primary_key_constraint(self, *p, **k): + self._visit_constraint(*p, **k) + + def visit_migrate_foreign_key_constraint(self, *p, **k): + self._visit_constraint(*p, **k) + + def visit_migrate_check_constraint(self, *p, **k): + self._visit_constraint(*p, **k) + + def visit_migrate_unique_constraint(self, *p, **k): + self._visit_constraint(*p, **k) + +class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator): + def _visit_constraint(self, constraint): + constraint.name = self.get_constraint_name(constraint) + self.append(self.process(AddConstraint(constraint))) + self.execute() + +class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper): + def _visit_constraint(self, constraint): + constraint.name = self.get_constraint_name(constraint) + self.append(self.process(DropConstraint(constraint, cascade=constraint.cascade))) + self.execute() + + +class ANSIDialect(DefaultDialect): + columngenerator = ANSIColumnGenerator + columndropper = ANSIColumnDropper + schemachanger = ANSISchemaChanger + constraintgenerator = ANSIConstraintGenerator + constraintdropper = ANSIConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py b/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py @@ -0,0 +1,200 @@ +""" + This module defines standalone schema constraint classes. +""" +from sqlalchemy import schema + +from rhodecode.lib.dbmigrate.migrate.exceptions import * + + +class ConstraintChangeset(object): + """Base class for Constraint classes.""" + + def _normalize_columns(self, cols, table_name=False): + """Given: column objects or names; return col names and + (maybe) a table""" + colnames = [] + table = None + for col in cols: + if isinstance(col, schema.Column): + if col.table is not None and table is None: + table = col.table + if table_name: + col = '.'.join((col.table.name, col.name)) + else: + col = col.name + colnames.append(col) + return colnames, table + + def __do_imports(self, visitor_name, *a, **kw): + engine = kw.pop('engine', self.table.bind) + from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import ( + get_engine_visitor, run_single_visitor) + visitorcallable = get_engine_visitor(engine, visitor_name) + run_single_visitor(engine, visitorcallable, self, *a, **kw) + + def create(self, *a, **kw): + """Create the constraint in the database. + + :param engine: the database engine to use. If this is \ + :keyword:`None` the instance's engine will be used + :type engine: :class:`sqlalchemy.engine.base.Engine` + :param connection: reuse connection istead of creating new one. + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + """ + # TODO: set the parent here instead of in __init__ + self.__do_imports('constraintgenerator', *a, **kw) + + def drop(self, *a, **kw): + """Drop the constraint from the database. + + :param engine: the database engine to use. If this is + :keyword:`None` the instance's engine will be used + :param cascade: Issue CASCADE drop if database supports it + :type engine: :class:`sqlalchemy.engine.base.Engine` + :type cascade: bool + :param connection: reuse connection istead of creating new one. + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + :returns: Instance with cleared columns + """ + self.cascade = kw.pop('cascade', False) + self.__do_imports('constraintdropper', *a, **kw) + # the spirit of Constraint objects is that they + # are immutable (just like in a DB. they're only ADDed + # or DROPped). + #self.columns.clear() + return self + + +class PrimaryKeyConstraint(ConstraintChangeset, schema.PrimaryKeyConstraint): + """Construct PrimaryKeyConstraint + + Migrate's additional parameters: + + :param cols: Columns in constraint. + :param table: If columns are passed as strings, this kw is required + :type table: Table instance + :type cols: strings or Column instances + """ + + __migrate_visit_name__ = 'migrate_primary_key_constraint' + + def __init__(self, *cols, **kwargs): + colnames, table = self._normalize_columns(cols) + table = kwargs.pop('table', table) + super(PrimaryKeyConstraint, self).__init__(*colnames, **kwargs) + if table is not None: + self._set_parent(table) + + def autoname(self): + """Mimic the database's automatic constraint names""" + return "%s_pkey" % self.table.name + + +class ForeignKeyConstraint(ConstraintChangeset, schema.ForeignKeyConstraint): + """Construct ForeignKeyConstraint + + Migrate's additional parameters: + + :param columns: Columns in constraint + :param refcolumns: Columns that this FK reffers to in another table. + :param table: If columns are passed as strings, this kw is required + :type table: Table instance + :type columns: list of strings or Column instances + :type refcolumns: list of strings or Column instances + """ + + __migrate_visit_name__ = 'migrate_foreign_key_constraint' + + def __init__(self, columns, refcolumns, *args, **kwargs): + colnames, table = self._normalize_columns(columns) + table = kwargs.pop('table', table) + refcolnames, reftable = self._normalize_columns(refcolumns, + table_name=True) + super(ForeignKeyConstraint, self).__init__( + colnames, refcolnames, *args,**kwargs + ) + if table is not None: + self._set_parent(table) + + @property + def referenced(self): + return [e.column for e in self.elements] + + @property + def reftable(self): + return self.referenced[0].table + + def autoname(self): + """Mimic the database's automatic constraint names""" + if hasattr(self.columns, 'keys'): + # SA <= 0.5 + firstcol = self.columns[self.columns.keys()[0]] + ret = "%(table)s_%(firstcolumn)s_fkey" % { + 'table': firstcol.table.name, + 'firstcolumn': firstcol.name,} + else: + # SA >= 0.6 + ret = "%(table)s_%(firstcolumn)s_fkey" % { + 'table': self.table.name, + 'firstcolumn': self.columns[0],} + return ret + + +class CheckConstraint(ConstraintChangeset, schema.CheckConstraint): + """Construct CheckConstraint + + Migrate's additional parameters: + + :param sqltext: Plain SQL text to check condition + :param columns: If not name is applied, you must supply this kw\ + to autoname constraint + :param table: If columns are passed as strings, this kw is required + :type table: Table instance + :type columns: list of Columns instances + :type sqltext: string + """ + + __migrate_visit_name__ = 'migrate_check_constraint' + + def __init__(self, sqltext, *args, **kwargs): + cols = kwargs.pop('columns', []) + if not cols and not kwargs.get('name', False): + raise InvalidConstraintError('You must either set "name"' + 'parameter or "columns" to autogenarate it.') + colnames, table = self._normalize_columns(cols) + table = kwargs.pop('table', table) + schema.CheckConstraint.__init__(self, sqltext, *args, **kwargs) + if table is not None: + self._set_parent(table) + self.colnames = colnames + + def autoname(self): + return "%(table)s_%(cols)s_check" % \ + {'table': self.table.name, 'cols': "_".join(self.colnames)} + + +class UniqueConstraint(ConstraintChangeset, schema.UniqueConstraint): + """Construct UniqueConstraint + + Migrate's additional parameters: + + :param cols: Columns in constraint. + :param table: If columns are passed as strings, this kw is required + :type table: Table instance + :type cols: strings or Column instances + + .. versionadded:: 0.6.0 + """ + + __migrate_visit_name__ = 'migrate_unique_constraint' + + def __init__(self, *cols, **kwargs): + self.colnames, table = self._normalize_columns(cols) + table = kwargs.pop('table', table) + super(UniqueConstraint, self).__init__(*self.colnames, **kwargs) + if table is not None: + self._set_parent(table) + + def autoname(self): + """Mimic the database's automatic constraint names""" + return "%s_%s_key" % (self.table.name, '_'.join(self.colnames)) diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/__init__.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/__init__.py @@ -0,0 +1,11 @@ +""" + This module contains database dialect specific changeset + implementations. +""" +__all__ = [ + 'postgres', + 'sqlite', + 'mysql', + 'oracle', + 'ibmdb2', +] diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py @@ -0,0 +1,93 @@ +""" + Firebird database specific implementations of changeset classes. +""" +from sqlalchemy.databases import firebird as sa_base +from sqlalchemy.schema import PrimaryKeyConstraint +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql + + +FBSchemaGenerator = sa_base.FBDDLCompiler + +class FBColumnGenerator(FBSchemaGenerator, ansisql.ANSIColumnGenerator): + """Firebird column generator implementation.""" + + +class FBColumnDropper(ansisql.ANSIColumnDropper): + """Firebird column dropper implementation.""" + + def visit_column(self, column): + """Firebird supports 'DROP col' instead of 'DROP COLUMN col' syntax + + Drop primary key and unique constraints if dropped column is referencing it.""" + if column.primary_key: + if column.table.primary_key.columns.contains_column(column): + column.table.primary_key.drop() + # TODO: recreate primary key if it references more than this column + + for index in column.table.indexes: + # "column in index.columns" causes problems as all + # column objects compare equal and return a SQL expression + if column.name in [col.name for col in index.columns]: + index.drop() + # TODO: recreate index if it references more than this column + + for cons in column.table.constraints: + if isinstance(cons,PrimaryKeyConstraint): + # will be deleted only when the column its on + # is deleted! + continue + + should_drop = column.name in cons.columns + if should_drop: + self.start_alter_table(column) + self.append("DROP CONSTRAINT ") + self.append(self.preparer.format_constraint(cons)) + self.execute() + # TODO: recreate unique constraint if it refenrences more than this column + + self.start_alter_table(column) + self.append('DROP %s' % self.preparer.format_column(column)) + self.execute() + + +class FBSchemaChanger(ansisql.ANSISchemaChanger): + """Firebird schema changer implementation.""" + + def visit_table(self, table): + """Rename table not supported""" + raise exceptions.NotSupportedError( + "Firebird does not support renaming tables.") + + def _visit_column_name(self, table, column, delta): + self.start_alter_table(table) + col_name = self.preparer.quote(delta.current_name, table.quote) + new_name = self.preparer.format_column(delta.result_column) + self.append('ALTER COLUMN %s TO %s' % (col_name, new_name)) + + def _visit_column_nullable(self, table, column, delta): + """Changing NULL is not supported""" + # TODO: http://www.firebirdfaq.org/faq103/ + raise exceptions.NotSupportedError( + "Firebird does not support altering NULL bevahior.") + + +class FBConstraintGenerator(ansisql.ANSIConstraintGenerator): + """Firebird constraint generator implementation.""" + + +class FBConstraintDropper(ansisql.ANSIConstraintDropper): + """Firebird constaint dropper implementation.""" + + def cascade_constraint(self, constraint): + """Cascading constraints is not supported""" + raise exceptions.NotSupportedError( + "Firebird does not support cascading constraints") + + +class FBDialect(ansisql.ANSIDialect): + columngenerator = FBColumnGenerator + columndropper = FBColumnDropper + schemachanger = FBSchemaChanger + constraintgenerator = FBConstraintGenerator + constraintdropper = FBConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py @@ -0,0 +1,69 @@ +""" + MySQL database specific implementations of changeset classes. +""" + +import sqlalchemy +from sqlalchemy.databases import mysql as sa_base +from sqlalchemy import types as sqltypes + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql +from rhodecode.lib.dbmigrate.migrate.changeset import util + + + +MySQLSchemaGenerator = sa_base.MySQLDDLCompiler + +class MySQLColumnGenerator(MySQLSchemaGenerator, ansisql.ANSIColumnGenerator): + pass + + +class MySQLColumnDropper(ansisql.ANSIColumnDropper): + pass + + +class MySQLSchemaChanger(MySQLSchemaGenerator, ansisql.ANSISchemaChanger): + + def visit_column(self, delta): + table = delta.table + colspec = self.get_column_specification(delta.result_column) + if delta.result_column.autoincrement: + primary_keys = [c for c in table.primary_key.columns + if (c.autoincrement and + isinstance(c.type, sqltypes.Integer) and + not c.foreign_keys)] + + if primary_keys: + first = primary_keys.pop(0) + if first.name == delta.current_name: + colspec += " AUTO_INCREMENT" + q = util.safe_quote(table) + old_col_name = self.preparer.quote(delta.current_name, q) + + self.start_alter_table(table) + + self.append("CHANGE COLUMN %s " % old_col_name) + self.append(colspec) + self.execute() + + def visit_index(self, param): + # If MySQL can do this, I can't find how + raise exceptions.NotSupportedError("MySQL cannot rename indexes") + + +class MySQLConstraintGenerator(ansisql.ANSIConstraintGenerator): + pass + + +class MySQLConstraintDropper(MySQLSchemaGenerator, ansisql.ANSIConstraintDropper): + def visit_migrate_check_constraint(self, *p, **k): + raise exceptions.NotSupportedError("MySQL does not support CHECK" + " constraints, use triggers instead.") + + +class MySQLDialect(ansisql.ANSIDialect): + columngenerator = MySQLColumnGenerator + columndropper = MySQLColumnDropper + schemachanger = MySQLSchemaChanger + constraintgenerator = MySQLConstraintGenerator + constraintdropper = MySQLConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/oracle.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/oracle.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/oracle.py @@ -0,0 +1,108 @@ +""" + Oracle database specific implementations of changeset classes. +""" +import sqlalchemy as sa +from sqlalchemy.databases import oracle as sa_base + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql + + +OracleSchemaGenerator = sa_base.OracleDDLCompiler + + +class OracleColumnGenerator(OracleSchemaGenerator, ansisql.ANSIColumnGenerator): + pass + + +class OracleColumnDropper(ansisql.ANSIColumnDropper): + pass + + +class OracleSchemaChanger(OracleSchemaGenerator, ansisql.ANSISchemaChanger): + + def get_column_specification(self, column, **kwargs): + # Ignore the NOT NULL generated + override_nullable = kwargs.pop('override_nullable', None) + if override_nullable: + orig = column.nullable + column.nullable = True + ret = super(OracleSchemaChanger, self).get_column_specification( + column, **kwargs) + if override_nullable: + column.nullable = orig + return ret + + def visit_column(self, delta): + keys = delta.keys() + + if 'name' in keys: + self._run_subvisit(delta, + self._visit_column_name, + start_alter=False) + + if len(set(('type', 'nullable', 'server_default')).intersection(keys)): + self._run_subvisit(delta, + self._visit_column_change, + start_alter=False) + + def _visit_column_change(self, table, column, delta): + # Oracle cannot drop a default once created, but it can set it + # to null. We'll do that if default=None + # http://forums.oracle.com/forums/message.jspa?messageID=1273234#1273234 + dropdefault_hack = (column.server_default is None \ + and 'server_default' in delta.keys()) + # Oracle apparently doesn't like it when we say "not null" if + # the column's already not null. Fudge it, so we don't need a + # new function + notnull_hack = ((not column.nullable) \ + and ('nullable' not in delta.keys())) + # We need to specify NULL if we're removing a NOT NULL + # constraint + null_hack = (column.nullable and ('nullable' in delta.keys())) + + if dropdefault_hack: + column.server_default = sa.PassiveDefault(sa.sql.null()) + if notnull_hack: + column.nullable = True + colspec = self.get_column_specification(column, + override_nullable=null_hack) + if null_hack: + colspec += ' NULL' + if notnull_hack: + column.nullable = False + if dropdefault_hack: + column.server_default = None + + self.start_alter_table(table) + self.append("MODIFY (") + self.append(colspec) + self.append(")") + + +class OracleConstraintCommon(object): + + def get_constraint_name(self, cons): + # Oracle constraints can't guess their name like other DBs + if not cons.name: + raise exceptions.NotSupportedError( + "Oracle constraint names must be explicitly stated") + return cons.name + + +class OracleConstraintGenerator(OracleConstraintCommon, + ansisql.ANSIConstraintGenerator): + pass + + +class OracleConstraintDropper(OracleConstraintCommon, + ansisql.ANSIConstraintDropper): + pass + + +class OracleDialect(ansisql.ANSIDialect): + columngenerator = OracleColumnGenerator + columndropper = OracleColumnDropper + schemachanger = OracleSchemaChanger + constraintgenerator = OracleConstraintGenerator + constraintdropper = OracleConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py @@ -0,0 +1,43 @@ +""" + `PostgreSQL`_ database specific implementations of changeset classes. + + .. _`PostgreSQL`: http://www.postgresql.org/ +""" +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql + + +from sqlalchemy.databases import postgresql as sa_base +PGSchemaGenerator = sa_base.PGDDLCompiler + + +class PGColumnGenerator(PGSchemaGenerator, ansisql.ANSIColumnGenerator): + """PostgreSQL column generator implementation.""" + pass + + +class PGColumnDropper(ansisql.ANSIColumnDropper): + """PostgreSQL column dropper implementation.""" + pass + + +class PGSchemaChanger(ansisql.ANSISchemaChanger): + """PostgreSQL schema changer implementation.""" + pass + + +class PGConstraintGenerator(ansisql.ANSIConstraintGenerator): + """PostgreSQL constraint generator implementation.""" + pass + + +class PGConstraintDropper(ansisql.ANSIConstraintDropper): + """PostgreSQL constaint dropper implementation.""" + pass + + +class PGDialect(ansisql.ANSIDialect): + columngenerator = PGColumnGenerator + columndropper = PGColumnDropper + schemachanger = PGSchemaChanger + constraintgenerator = PGConstraintGenerator + constraintdropper = PGConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py @@ -0,0 +1,199 @@ +""" + `SQLite`_ database specific implementations of changeset classes. + + .. _`SQLite`: http://www.sqlite.org/ +""" +from UserDict import DictMixin +from copy import copy +import re + +from sqlalchemy.databases import sqlite as sa_base +from sqlalchemy.schema import UniqueConstraint + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql + + +SQLiteSchemaGenerator = sa_base.SQLiteDDLCompiler + + +class SQLiteCommon(object): + + def _not_supported(self, op): + raise exceptions.NotSupportedError("SQLite does not support " + "%s; see http://www.sqlite.org/lang_altertable.html" % op) + + +class SQLiteHelper(SQLiteCommon): + + def _get_unique_constraints(self, table): + """Retrieve information about existing unique constraints of the table + + This feature is needed for recreate_table() to work properly. + """ + + data = table.metadata.bind.execute( + """SELECT sql + FROM sqlite_master + WHERE + type='table' AND + name=:table_name""", + table_name=table.name + ).fetchone()[0] + + UNIQUE_PATTERN = "CONSTRAINT (\w+) UNIQUE \(([^\)]+)\)" + constraints = [] + for name, cols in re.findall(UNIQUE_PATTERN, data): + # Filter out any columns that were dropped from the table. + columns = [] + for c in cols.split(","): + if c in table.columns: + # There was a bug in reflection of SQLite columns with + # reserved identifiers as names (SQLite can return them + # wrapped with double quotes), so strip double quotes. + columns.extend(c.strip(' "')) + if columns: + constraints.extend(UniqueConstraint(*columns, name=name)) + return constraints + + def recreate_table(self, table, column=None, delta=None, + omit_uniques=None): + table_name = self.preparer.format_table(table) + + # we remove all indexes so as not to have + # problems during copy and re-create + for index in table.indexes: + index.drop() + + # reflect existing unique constraints + for uc in self._get_unique_constraints(table): + table.append_constraint(uc) + # omit given unique constraints when creating a new table if required + table.constraints = set([ + cons for cons in table.constraints + if omit_uniques is None or cons.name not in omit_uniques + ]) + + self.append('ALTER TABLE %s RENAME TO migration_tmp' % table_name) + self.execute() + + insertion_string = self._modify_table(table, column, delta) + + table.create(bind=self.connection) + self.append(insertion_string % {'table_name': table_name}) + self.execute() + self.append('DROP TABLE migration_tmp') + self.execute() + + def visit_column(self, delta): + if isinstance(delta, DictMixin): + column = delta.result_column + table = self._to_table(delta.table) + else: + column = delta + table = self._to_table(column.table) + + self.recreate_table(table,column,delta) + +class SQLiteColumnGenerator(SQLiteSchemaGenerator, + ansisql.ANSIColumnGenerator, + # at the end so we get the normal + # visit_column by default + SQLiteHelper, + SQLiteCommon + ): + """SQLite ColumnGenerator""" + + def _modify_table(self, table, column, delta): + columns = ' ,'.join(map( + self.preparer.format_column, + [c for c in table.columns if c.name!=column.name])) + return ('INSERT INTO %%(table_name)s (%(cols)s) ' + 'SELECT %(cols)s from migration_tmp')%{'cols':columns} + + def visit_column(self,column): + if column.foreign_keys: + SQLiteHelper.visit_column(self,column) + else: + super(SQLiteColumnGenerator,self).visit_column(column) + +class SQLiteColumnDropper(SQLiteHelper, ansisql.ANSIColumnDropper): + """SQLite ColumnDropper""" + + def _modify_table(self, table, column, delta): + + columns = ' ,'.join(map(self.preparer.format_column, table.columns)) + return 'INSERT INTO %(table_name)s SELECT ' + columns + \ + ' from migration_tmp' + + def visit_column(self,column): + # For SQLite, we *have* to remove the column here so the table + # is re-created properly. + column.remove_from_table(column.table,unset_table=False) + super(SQLiteColumnDropper,self).visit_column(column) + + +class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger): + """SQLite SchemaChanger""" + + def _modify_table(self, table, column, delta): + return 'INSERT INTO %(table_name)s SELECT * from migration_tmp' + + def visit_index(self, index): + """Does not support ALTER INDEX""" + self._not_supported('ALTER INDEX') + + +class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteHelper, SQLiteCommon): + + def visit_migrate_primary_key_constraint(self, constraint): + tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )" + cols = ', '.join(map(self.preparer.format_column, constraint.columns)) + tname = self.preparer.format_table(constraint.table) + name = self.get_constraint_name(constraint) + msg = tmpl % (name, tname, cols) + self.append(msg) + self.execute() + + def _modify_table(self, table, column, delta): + return 'INSERT INTO %(table_name)s SELECT * from migration_tmp' + + def visit_migrate_foreign_key_constraint(self, *p, **k): + self.recreate_table(p[0].table) + + def visit_migrate_unique_constraint(self, *p, **k): + self.recreate_table(p[0].table) + + +class SQLiteConstraintDropper(ansisql.ANSIColumnDropper, + SQLiteHelper, + ansisql.ANSIConstraintCommon): + + def _modify_table(self, table, column, delta): + return 'INSERT INTO %(table_name)s SELECT * from migration_tmp' + + def visit_migrate_primary_key_constraint(self, constraint): + tmpl = "DROP INDEX %s " + name = self.get_constraint_name(constraint) + msg = tmpl % (name) + self.append(msg) + self.execute() + + def visit_migrate_foreign_key_constraint(self, *p, **k): + self._not_supported('ALTER TABLE DROP CONSTRAINT') + + def visit_migrate_check_constraint(self, *p, **k): + self._not_supported('ALTER TABLE DROP CONSTRAINT') + + def visit_migrate_unique_constraint(self, *p, **k): + self.recreate_table(p[0].table, omit_uniques=[p[0].name]) + + +# TODO: technically primary key is a NOT NULL + UNIQUE constraint, should add NOT NULL to index + +class SQLiteDialect(ansisql.ANSIDialect): + columngenerator = SQLiteColumnGenerator + columndropper = SQLiteColumnDropper + schemachanger = SQLiteSchemaChanger + constraintgenerator = SQLiteConstraintGenerator + constraintdropper = SQLiteConstraintDropper diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/databases/visitor.py b/rhodecode/lib/dbmigrate/migrate/changeset/databases/visitor.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/visitor.py @@ -0,0 +1,88 @@ +""" + Module for visitor class mapping. +""" +import sqlalchemy as sa + +from rhodecode.lib.dbmigrate.migrate.changeset import ansisql +from rhodecode.lib.dbmigrate.migrate.changeset.databases import (sqlite, + postgres, + mysql, + oracle, + firebird) + + +# Map SA dialects to the corresponding Migrate extensions +DIALECTS = { + "default": ansisql.ANSIDialect, + "sqlite": sqlite.SQLiteDialect, + "postgres": postgres.PGDialect, + "postgresql": postgres.PGDialect, + "mysql": mysql.MySQLDialect, + "oracle": oracle.OracleDialect, + "firebird": firebird.FBDialect, +} + + +# NOTE(mriedem): We have to conditionally check for DB2 in case ibm_db_sa +# isn't available since ibm_db_sa is not packaged in sqlalchemy like the +# other dialects. +try: + from rhodecode.lib.dbmigrate.migrate.changeset.databases import ibmdb2 + DIALECTS["ibm_db_sa"] = ibmdb2.IBMDBDialect +except ImportError: + pass + + +def get_engine_visitor(engine, name): + """ + Get the visitor implementation for the given database engine. + + :param engine: SQLAlchemy Engine + :param name: Name of the visitor + :type name: string + :type engine: Engine + :returns: visitor + """ + # TODO: link to supported visitors + return get_dialect_visitor(engine.dialect, name) + + +def get_dialect_visitor(sa_dialect, name): + """ + Get the visitor implementation for the given dialect. + + Finds the visitor implementation based on the dialect class and + returns and instance initialized with the given name. + + Binds dialect specific preparer to visitor. + """ + + # map sa dialect to migrate dialect and return visitor + sa_dialect_name = getattr(sa_dialect, 'name', 'default') + migrate_dialect_cls = DIALECTS[sa_dialect_name] + visitor = getattr(migrate_dialect_cls, name) + + # bind preparer + visitor.preparer = sa_dialect.preparer(sa_dialect) + + return visitor + +def run_single_visitor(engine, visitorcallable, element, + connection=None, **kwargs): + """Taken from :meth:`sqlalchemy.engine.base.Engine._run_single_visitor` + with support for migrate visitors. + """ + if connection is None: + conn = engine.contextual_connect(close_with_result=False) + else: + conn = connection + visitor = visitorcallable(engine.dialect, conn) + try: + if hasattr(element, '__migrate_visit_name__'): + fn = getattr(visitor, 'visit_' + element.__migrate_visit_name__) + else: + fn = getattr(visitor, 'visit_' + element.__visit_name__) + fn(element, **kwargs) + finally: + if connection is None: + conn.close() diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/schema.py b/rhodecode/lib/dbmigrate/migrate/changeset/schema.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/schema.py @@ -0,0 +1,665 @@ +""" + Schema module providing common schema operations. +""" +import warnings + +from UserDict import DictMixin + +import sqlalchemy + +from sqlalchemy.schema import ForeignKeyConstraint +from sqlalchemy.schema import UniqueConstraint + +from rhodecode.lib.dbmigrate.migrate.exceptions import * +from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_07, SQLA_08 +from rhodecode.lib.dbmigrate.migrate.changeset import util +from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import ( + get_engine_visitor, run_single_visitor) + + +__all__ = [ + 'create_column', + 'drop_column', + 'alter_column', + 'rename_table', + 'rename_index', + 'ChangesetTable', + 'ChangesetColumn', + 'ChangesetIndex', + 'ChangesetDefaultClause', + 'ColumnDelta', +] + +def create_column(column, table=None, *p, **kw): + """Create a column, given the table. + + API to :meth:`ChangesetColumn.create`. + """ + if table is not None: + return table.create_column(column, *p, **kw) + return column.create(*p, **kw) + + +def drop_column(column, table=None, *p, **kw): + """Drop a column, given the table. + + API to :meth:`ChangesetColumn.drop`. + """ + if table is not None: + return table.drop_column(column, *p, **kw) + return column.drop(*p, **kw) + + +def rename_table(table, name, engine=None, **kw): + """Rename a table. + + If Table instance is given, engine is not used. + + API to :meth:`ChangesetTable.rename`. + + :param table: Table to be renamed. + :param name: New name for Table. + :param engine: Engine instance. + :type table: string or Table instance + :type name: string + :type engine: obj + """ + table = _to_table(table, engine) + table.rename(name, **kw) + + +def rename_index(index, name, table=None, engine=None, **kw): + """Rename an index. + + If Index instance is given, + table and engine are not used. + + API to :meth:`ChangesetIndex.rename`. + + :param index: Index to be renamed. + :param name: New name for index. + :param table: Table to which Index is reffered. + :param engine: Engine instance. + :type index: string or Index instance + :type name: string + :type table: string or Table instance + :type engine: obj + """ + index = _to_index(index, table, engine) + index.rename(name, **kw) + + +def alter_column(*p, **k): + """Alter a column. + + This is a helper function that creates a :class:`ColumnDelta` and + runs it. + + :argument column: + The name of the column to be altered or a + :class:`ChangesetColumn` column representing it. + + :param table: + A :class:`~sqlalchemy.schema.Table` or table name to + for the table where the column will be changed. + + :param engine: + The :class:`~sqlalchemy.engine.base.Engine` to use for table + reflection and schema alterations. + + :returns: A :class:`ColumnDelta` instance representing the change. + + + """ + + if 'table' not in k and isinstance(p[0], sqlalchemy.Column): + k['table'] = p[0].table + if 'engine' not in k: + k['engine'] = k['table'].bind + + # deprecation + if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column): + warnings.warn( + "Passing a Column object to alter_column is deprecated." + " Just pass in keyword parameters instead.", + MigrateDeprecationWarning + ) + engine = k['engine'] + + # enough tests seem to break when metadata is always altered + # that this crutch has to be left in until they can be sorted + # out + k['alter_metadata']=True + + delta = ColumnDelta(*p, **k) + + visitorcallable = get_engine_visitor(engine, 'schemachanger') + engine._run_visitor(visitorcallable, delta) + + return delta + + +def _to_table(table, engine=None): + """Return if instance of Table, else construct new with metadata""" + if isinstance(table, sqlalchemy.Table): + return table + + # Given: table name, maybe an engine + meta = sqlalchemy.MetaData() + if engine is not None: + meta.bind = engine + return sqlalchemy.Table(table, meta) + + +def _to_index(index, table=None, engine=None): + """Return if instance of Index, else construct new with metadata""" + if isinstance(index, sqlalchemy.Index): + return index + + # Given: index name; table name required + table = _to_table(table, engine) + ret = sqlalchemy.Index(index) + ret.table = table + return ret + + +class ColumnDelta(DictMixin, sqlalchemy.schema.SchemaItem): + """Extracts the differences between two columns/column-parameters + + May receive parameters arranged in several different ways: + + * **current_column, new_column, \*p, \*\*kw** + Additional parameters can be specified to override column + differences. + + * **current_column, \*p, \*\*kw** + Additional parameters alter current_column. Table name is extracted + from current_column object. + Name is changed to current_column.name from current_name, + if current_name is specified. + + * **current_col_name, \*p, \*\*kw** + Table kw must specified. + + :param table: Table at which current Column should be bound to.\ + If table name is given, reflection will be used. + :type table: string or Table instance + + :param metadata: A :class:`MetaData` instance to store + reflected table names + + :param engine: When reflecting tables, either engine or metadata must \ + be specified to acquire engine object. + :type engine: :class:`Engine` instance + :returns: :class:`ColumnDelta` instance provides interface for altered attributes to \ + `result_column` through :func:`dict` alike object. + + * :class:`ColumnDelta`.result_column is altered column with new attributes + + * :class:`ColumnDelta`.current_name is current name of column in db + + + """ + + # Column attributes that can be altered + diff_keys = ('name', 'type', 'primary_key', 'nullable', + 'server_onupdate', 'server_default', 'autoincrement') + diffs = dict() + __visit_name__ = 'column' + + def __init__(self, *p, **kw): + # 'alter_metadata' is not a public api. It exists purely + # as a crutch until the tests that fail when 'alter_metadata' + # behaviour always happens can be sorted out + self.alter_metadata = kw.pop("alter_metadata", False) + + self.meta = kw.pop("metadata", None) + self.engine = kw.pop("engine", None) + + # Things are initialized differently depending on how many column + # parameters are given. Figure out how many and call the appropriate + # method. + if len(p) >= 1 and isinstance(p[0], sqlalchemy.Column): + # At least one column specified + if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column): + # Two columns specified + diffs = self.compare_2_columns(*p, **kw) + else: + # Exactly one column specified + diffs = self.compare_1_column(*p, **kw) + else: + # Zero columns specified + if not len(p) or not isinstance(p[0], basestring): + raise ValueError("First argument must be column name") + diffs = self.compare_parameters(*p, **kw) + + self.apply_diffs(diffs) + + def __repr__(self): + return '<ColumnDelta altermetadata=%r, %s>' % ( + self.alter_metadata, + super(ColumnDelta, self).__repr__() + ) + + def __getitem__(self, key): + if key not in self.keys(): + raise KeyError("No such diff key, available: %s" % self.diffs ) + return getattr(self.result_column, key) + + def __setitem__(self, key, value): + if key not in self.keys(): + raise KeyError("No such diff key, available: %s" % self.diffs ) + setattr(self.result_column, key, value) + + def __delitem__(self, key): + raise NotImplementedError + + def __len__(self): + raise NotImplementedError + + def __iter__(self): + raise NotImplementedError + + def keys(self): + return self.diffs.keys() + + def compare_parameters(self, current_name, *p, **k): + """Compares Column objects with reflection""" + self.table = k.pop('table') + self.result_column = self._table.c.get(current_name) + if len(p): + k = self._extract_parameters(p, k, self.result_column) + return k + + def compare_1_column(self, col, *p, **k): + """Compares one Column object""" + self.table = k.pop('table', None) + if self.table is None: + self.table = col.table + self.result_column = col + if len(p): + k = self._extract_parameters(p, k, self.result_column) + return k + + def compare_2_columns(self, old_col, new_col, *p, **k): + """Compares two Column objects""" + self.process_column(new_col) + self.table = k.pop('table', None) + # we cannot use bool() on table in SA06 + if self.table is None: + self.table = old_col.table + if self.table is None: + new_col.table + self.result_column = old_col + + # set differences + # leave out some stuff for later comp + for key in (set(self.diff_keys) - set(('type',))): + val = getattr(new_col, key, None) + if getattr(self.result_column, key, None) != val: + k.setdefault(key, val) + + # inspect types + if not self.are_column_types_eq(self.result_column.type, new_col.type): + k.setdefault('type', new_col.type) + + if len(p): + k = self._extract_parameters(p, k, self.result_column) + return k + + def apply_diffs(self, diffs): + """Populate dict and column object with new values""" + self.diffs = diffs + for key in self.diff_keys: + if key in diffs: + setattr(self.result_column, key, diffs[key]) + + self.process_column(self.result_column) + + # create an instance of class type if not yet + if 'type' in diffs and callable(self.result_column.type): + self.result_column.type = self.result_column.type() + + # add column to the table + if self.table is not None and self.alter_metadata: + self.result_column.add_to_table(self.table) + + def are_column_types_eq(self, old_type, new_type): + """Compares two types to be equal""" + ret = old_type.__class__ == new_type.__class__ + + # String length is a special case + if ret and isinstance(new_type, sqlalchemy.types.String): + ret = (getattr(old_type, 'length', None) == \ + getattr(new_type, 'length', None)) + return ret + + def _extract_parameters(self, p, k, column): + """Extracts data from p and modifies diffs""" + p = list(p) + while len(p): + if isinstance(p[0], basestring): + k.setdefault('name', p.pop(0)) + elif isinstance(p[0], sqlalchemy.types.TypeEngine): + k.setdefault('type', p.pop(0)) + elif callable(p[0]): + p[0] = p[0]() + else: + break + + if len(p): + new_col = column.copy_fixed() + new_col._init_items(*p) + k = self.compare_2_columns(column, new_col, **k) + return k + + def process_column(self, column): + """Processes default values for column""" + # XXX: this is a snippet from SA processing of positional parameters + toinit = list() + + if column.server_default is not None: + if isinstance(column.server_default, sqlalchemy.FetchedValue): + toinit.append(column.server_default) + else: + toinit.append(sqlalchemy.DefaultClause(column.server_default)) + if column.server_onupdate is not None: + if isinstance(column.server_onupdate, FetchedValue): + toinit.append(column.server_default) + else: + toinit.append(sqlalchemy.DefaultClause(column.server_onupdate, + for_update=True)) + if toinit: + column._init_items(*toinit) + + def _get_table(self): + return getattr(self, '_table', None) + + def _set_table(self, table): + if isinstance(table, basestring): + if self.alter_metadata: + if not self.meta: + raise ValueError("metadata must be specified for table" + " reflection when using alter_metadata") + meta = self.meta + if self.engine: + meta.bind = self.engine + else: + if not self.engine and not self.meta: + raise ValueError("engine or metadata must be specified" + " to reflect tables") + if not self.engine: + self.engine = self.meta.bind + meta = sqlalchemy.MetaData(bind=self.engine) + self._table = sqlalchemy.Table(table, meta, autoload=True) + elif isinstance(table, sqlalchemy.Table): + self._table = table + if not self.alter_metadata: + self._table.meta = sqlalchemy.MetaData(bind=self._table.bind) + def _get_result_column(self): + return getattr(self, '_result_column', None) + + def _set_result_column(self, column): + """Set Column to Table based on alter_metadata evaluation.""" + self.process_column(column) + if not hasattr(self, 'current_name'): + self.current_name = column.name + if self.alter_metadata: + self._result_column = column + else: + self._result_column = column.copy_fixed() + + table = property(_get_table, _set_table) + result_column = property(_get_result_column, _set_result_column) + + +class ChangesetTable(object): + """Changeset extensions to SQLAlchemy tables.""" + + def create_column(self, column, *p, **kw): + """Creates a column. + + The column parameter may be a column definition or the name of + a column in this table. + + API to :meth:`ChangesetColumn.create` + + :param column: Column to be created + :type column: Column instance or string + """ + if not isinstance(column, sqlalchemy.Column): + # It's a column name + column = getattr(self.c, str(column)) + column.create(table=self, *p, **kw) + + def drop_column(self, column, *p, **kw): + """Drop a column, given its name or definition. + + API to :meth:`ChangesetColumn.drop` + + :param column: Column to be droped + :type column: Column instance or string + """ + if not isinstance(column, sqlalchemy.Column): + # It's a column name + try: + column = getattr(self.c, str(column)) + except AttributeError: + # That column isn't part of the table. We don't need + # its entire definition to drop the column, just its + # name, so create a dummy column with the same name. + column = sqlalchemy.Column(str(column), sqlalchemy.Integer()) + column.drop(table=self, *p, **kw) + + def rename(self, name, connection=None, **kwargs): + """Rename this table. + + :param name: New name of the table. + :type name: string + :param connection: reuse connection istead of creating new one. + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + """ + engine = self.bind + self.new_name = name + visitorcallable = get_engine_visitor(engine, 'schemachanger') + run_single_visitor(engine, visitorcallable, self, connection, **kwargs) + + # Fix metadata registration + self.name = name + self.deregister() + self._set_parent(self.metadata) + + def _meta_key(self): + """Get the meta key for this table.""" + return sqlalchemy.schema._get_table_key(self.name, self.schema) + + def deregister(self): + """Remove this table from its metadata""" + if SQLA_07: + self.metadata._remove_table(self.name, self.schema) + else: + key = self._meta_key() + meta = self.metadata + if key in meta.tables: + del meta.tables[key] + + +class ChangesetColumn(object): + """Changeset extensions to SQLAlchemy columns.""" + + def alter(self, *p, **k): + """Makes a call to :func:`alter_column` for the column this + method is called on. + """ + if 'table' not in k: + k['table'] = self.table + if 'engine' not in k: + k['engine'] = k['table'].bind + return alter_column(self, *p, **k) + + def create(self, table=None, index_name=None, unique_name=None, + primary_key_name=None, populate_default=True, connection=None, **kwargs): + """Create this column in the database. + + Assumes the given table exists. ``ALTER TABLE ADD COLUMN``, + for most databases. + + :param table: Table instance to create on. + :param index_name: Creates :class:`ChangesetIndex` on this column. + :param unique_name: Creates :class:\ +`~migrate.changeset.constraint.UniqueConstraint` on this column. + :param primary_key_name: Creates :class:\ +`~migrate.changeset.constraint.PrimaryKeyConstraint` on this column. + :param populate_default: If True, created column will be \ +populated with defaults + :param connection: reuse connection istead of creating new one. + :type table: Table instance + :type index_name: string + :type unique_name: string + :type primary_key_name: string + :type populate_default: bool + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + + :returns: self + """ + self.populate_default = populate_default + self.index_name = index_name + self.unique_name = unique_name + self.primary_key_name = primary_key_name + for cons in ('index_name', 'unique_name', 'primary_key_name'): + self._check_sanity_constraints(cons) + + self.add_to_table(table) + engine = self.table.bind + visitorcallable = get_engine_visitor(engine, 'columngenerator') + engine._run_visitor(visitorcallable, self, connection, **kwargs) + + # TODO: reuse existing connection + if self.populate_default and self.default is not None: + stmt = table.update().values({self: engine._execute_default(self.default)}) + engine.execute(stmt) + + return self + + def drop(self, table=None, connection=None, **kwargs): + """Drop this column from the database, leaving its table intact. + + ``ALTER TABLE DROP COLUMN``, for most databases. + + :param connection: reuse connection istead of creating new one. + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + """ + if table is not None: + self.table = table + engine = self.table.bind + visitorcallable = get_engine_visitor(engine, 'columndropper') + engine._run_visitor(visitorcallable, self, connection, **kwargs) + self.remove_from_table(self.table, unset_table=False) + self.table = None + return self + + def add_to_table(self, table): + if table is not None and self.table is None: + if SQLA_07: + table.append_column(self) + else: + self._set_parent(table) + + def _col_name_in_constraint(self,cons,name): + return False + + def remove_from_table(self, table, unset_table=True): + # TODO: remove primary keys, constraints, etc + if unset_table: + self.table = None + + to_drop = set() + for index in table.indexes: + columns = [] + for col in index.columns: + if col.name!=self.name: + columns.append(col) + if columns: + index.columns = columns + if SQLA_08: + index.expressions = columns + else: + to_drop.add(index) + table.indexes = table.indexes - to_drop + + to_drop = set() + for cons in table.constraints: + # TODO: deal with other types of constraint + if isinstance(cons,(ForeignKeyConstraint, + UniqueConstraint)): + for col_name in cons.columns: + if not isinstance(col_name,basestring): + col_name = col_name.name + if self.name==col_name: + to_drop.add(cons) + table.constraints = table.constraints - to_drop + + if table.c.contains_column(self): + if SQLA_07: + table._columns.remove(self) + else: + table.c.remove(self) + + # TODO: this is fixed in 0.6 + def copy_fixed(self, **kw): + """Create a copy of this ``Column``, with all attributes.""" + q = util.safe_quote(self) + return sqlalchemy.Column(self.name, self.type, self.default, + key=self.key, + primary_key=self.primary_key, + nullable=self.nullable, + quote=q, + index=self.index, + unique=self.unique, + onupdate=self.onupdate, + autoincrement=self.autoincrement, + server_default=self.server_default, + server_onupdate=self.server_onupdate, + *[c.copy(**kw) for c in self.constraints]) + + def _check_sanity_constraints(self, name): + """Check if constraints names are correct""" + obj = getattr(self, name) + if (getattr(self, name[:-5]) and not obj): + raise InvalidConstraintError("Column.create() accepts index_name," + " primary_key_name and unique_name to generate constraints") + if not isinstance(obj, basestring) and obj is not None: + raise InvalidConstraintError( + "%s argument for column must be constraint name" % name) + + +class ChangesetIndex(object): + """Changeset extensions to SQLAlchemy Indexes.""" + + __visit_name__ = 'index' + + def rename(self, name, connection=None, **kwargs): + """Change the name of an index. + + :param name: New name of the Index. + :type name: string + :param connection: reuse connection istead of creating new one. + :type connection: :class:`sqlalchemy.engine.base.Connection` instance + """ + engine = self.table.bind + self.new_name = name + visitorcallable = get_engine_visitor(engine, 'schemachanger') + engine._run_visitor(visitorcallable, self, connection, **kwargs) + self.name = name + + +class ChangesetDefaultClause(object): + """Implements comparison between :class:`DefaultClause` instances""" + + def __eq__(self, other): + if isinstance(other, self.__class__): + if self.arg == other.arg: + return True + + def __ne__(self, other): + return not self.__eq__(other) diff --git a/rhodecode/lib/dbmigrate/migrate/changeset/util.py b/rhodecode/lib/dbmigrate/migrate/changeset/util.py new file mode 100755 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/changeset/util.py @@ -0,0 +1,10 @@ +""" +Safe quoting method +""" + +def safe_quote(obj): + # this is the SQLA 0.9 approach + if hasattr(obj, 'name') and hasattr(obj.name, 'quote'): + return obj.name.quote + else: + return obj.quote diff --git a/rhodecode/lib/dbmigrate/migrate/exceptions.py b/rhodecode/lib/dbmigrate/migrate/exceptions.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/exceptions.py @@ -0,0 +1,87 @@ +""" + Provide exception classes for :mod:`migrate` +""" + + +class Error(Exception): + """Error base class.""" + + +class ApiError(Error): + """Base class for API errors.""" + + +class KnownError(ApiError): + """A known error condition.""" + + +class UsageError(ApiError): + """A known error condition where help should be displayed.""" + + +class ControlledSchemaError(Error): + """Base class for controlled schema errors.""" + + +class InvalidVersionError(ControlledSchemaError): + """Invalid version number.""" + + +class DatabaseNotControlledError(ControlledSchemaError): + """Database should be under version control, but it's not.""" + + +class DatabaseAlreadyControlledError(ControlledSchemaError): + """Database shouldn't be under version control, but it is""" + + +class WrongRepositoryError(ControlledSchemaError): + """This database is under version control by another repository.""" + + +class NoSuchTableError(ControlledSchemaError): + """The table does not exist.""" + + +class PathError(Error): + """Base class for path errors.""" + + +class PathNotFoundError(PathError): + """A path with no file was required; found a file.""" + + +class PathFoundError(PathError): + """A path with a file was required; found no file.""" + + +class RepositoryError(Error): + """Base class for repository errors.""" + + +class InvalidRepositoryError(RepositoryError): + """Invalid repository error.""" + + +class ScriptError(Error): + """Base class for script errors.""" + + +class InvalidScriptError(ScriptError): + """Invalid script error.""" + + +class InvalidVersionError(Error): + """Invalid version error.""" + +# migrate.changeset + +class NotSupportedError(Error): + """Not supported error""" + + +class InvalidConstraintError(Error): + """Invalid constraint error""" + +class MigrateDeprecationWarning(DeprecationWarning): + """Warning for deprecated features in Migrate""" diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/__init__.py b/rhodecode/lib/dbmigrate/migrate/versioning/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/__init__.py @@ -0,0 +1,5 @@ +""" + This package provides functionality to create and manage + repositories of database schema changesets and to apply these + changesets to databases. +""" diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/api.py b/rhodecode/lib/dbmigrate/migrate/versioning/api.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/api.py @@ -0,0 +1,386 @@ +""" + This module provides an external API to the versioning system. + + .. versionchanged:: 0.6.0 + :func:`migrate.versioning.api.test` and schema diff functions + changed order of positional arguments so all accept `url` and `repository` + as first arguments. + + .. versionchanged:: 0.5.4 + ``--preview_sql`` displays source file when using SQL scripts. + If Python script is used, it runs the action with mocked engine and + returns captured SQL statements. + + .. versionchanged:: 0.5.4 + Deprecated ``--echo`` parameter in favour of new + :func:`migrate.versioning.util.construct_engine` behavior. +""" + +# Dear migrate developers, +# +# please do not comment this module using sphinx syntax because its +# docstrings are presented as user help and most users cannot +# interpret sphinx annotated ReStructuredText. +# +# Thanks, +# Jan Dittberner + +import sys +import inspect +import logging + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning import ( + repository, schema, version, + script as script_ # command name conflict +) +from rhodecode.lib.dbmigrate.migrate.versioning.util import ( + catch_known_errors, with_engine) + + +log = logging.getLogger(__name__) +command_desc = { + 'help': 'displays help on a given command', + 'create': 'create an empty repository at the specified path', + 'script': 'create an empty change Python script', + 'script_sql': 'create empty change SQL scripts for given database', + 'version': 'display the latest version available in a repository', + 'db_version': 'show the current version of the repository under version control', + 'source': 'display the Python code for a particular version in this repository', + 'version_control': 'mark a database as under this repository\'s version control', + 'upgrade': 'upgrade a database to a later version', + 'downgrade': 'downgrade a database to an earlier version', + 'drop_version_control': 'removes version control from a database', + 'manage': 'creates a Python script that runs Migrate with a set of default values', + 'test': 'performs the upgrade and downgrade command on the given database', + 'compare_model_to_db': 'compare MetaData against the current database state', + 'create_model': 'dump the current database as a Python model to stdout', + 'make_update_script_for_model': 'create a script changing the old MetaData to the new (current) MetaData', + 'update_db_from_model': 'modify the database to match the structure of the current MetaData', +} +__all__ = command_desc.keys() + +Repository = repository.Repository +ControlledSchema = schema.ControlledSchema +VerNum = version.VerNum +PythonScript = script_.PythonScript +SqlScript = script_.SqlScript + + +# deprecated +def help(cmd=None, **opts): + """%prog help COMMAND + + Displays help on a given command. + """ + if cmd is None: + raise exceptions.UsageError(None) + try: + func = globals()[cmd] + except: + raise exceptions.UsageError( + "'%s' isn't a valid command. Try 'help COMMAND'" % cmd) + ret = func.__doc__ + if sys.argv[0]: + ret = ret.replace('%prog', sys.argv[0]) + return ret + +@catch_known_errors +def create(repository, name, **opts): + """%prog create REPOSITORY_PATH NAME [--table=TABLE] + + Create an empty repository at the specified path. + + You can specify the version_table to be used; by default, it is + 'migrate_version'. This table is created in all version-controlled + databases. + """ + repo_path = Repository.create(repository, name, **opts) + + +@catch_known_errors +def script(description, repository, **opts): + """%prog script DESCRIPTION REPOSITORY_PATH + + Create an empty change script using the next unused version number + appended with the given description. + + For instance, manage.py script "Add initial tables" creates: + repository/versions/001_Add_initial_tables.py + """ + repo = Repository(repository) + repo.create_script(description, **opts) + + +@catch_known_errors +def script_sql(database, description, repository, **opts): + """%prog script_sql DATABASE DESCRIPTION REPOSITORY_PATH + + Create empty change SQL scripts for given DATABASE, where DATABASE + is either specific ('postgresql', 'mysql', 'oracle', 'sqlite', etc.) + or generic ('default'). + + For instance, manage.py script_sql postgresql description creates: + repository/versions/001_description_postgresql_upgrade.sql and + repository/versions/001_description_postgresql_downgrade.sql + """ + repo = Repository(repository) + repo.create_script_sql(database, description, **opts) + + +def version(repository, **opts): + """%prog version REPOSITORY_PATH + + Display the latest version available in a repository. + """ + repo = Repository(repository) + return repo.latest + + +@with_engine +def db_version(url, repository, **opts): + """%prog db_version URL REPOSITORY_PATH + + Show the current version of the repository with the given + connection string, under version control of the specified + repository. + + The url should be any valid SQLAlchemy connection string. + """ + engine = opts.pop('engine') + schema = ControlledSchema(engine, repository) + return schema.version + + +def source(version, dest=None, repository=None, **opts): + """%prog source VERSION [DESTINATION] --repository=REPOSITORY_PATH + + Display the Python code for a particular version in this + repository. Save it to the file at DESTINATION or, if omitted, + send to stdout. + """ + if repository is None: + raise exceptions.UsageError("A repository must be specified") + repo = Repository(repository) + ret = repo.version(version).script().source() + if dest is not None: + with open(dest, 'w') as f: + f.write(ret) + ret = None + return ret + + +def upgrade(url, repository, version=None, **opts): + """%prog upgrade URL REPOSITORY_PATH [VERSION] [--preview_py|--preview_sql] + + Upgrade a database to a later version. + + This runs the upgrade() function defined in your change scripts. + + By default, the database is updated to the latest available + version. You may specify a version instead, if you wish. + + You may preview the Python or SQL code to be executed, rather than + actually executing it, using the appropriate 'preview' option. + """ + err = "Cannot upgrade a database of version %s to version %s. "\ + "Try 'downgrade' instead." + return _migrate(url, repository, version, upgrade=True, err=err, **opts) + + +def downgrade(url, repository, version, **opts): + """%prog downgrade URL REPOSITORY_PATH VERSION [--preview_py|--preview_sql] + + Downgrade a database to an earlier version. + + This is the reverse of upgrade; this runs the downgrade() function + defined in your change scripts. + + You may preview the Python or SQL code to be executed, rather than + actually executing it, using the appropriate 'preview' option. + """ + err = "Cannot downgrade a database of version %s to version %s. "\ + "Try 'upgrade' instead." + return _migrate(url, repository, version, upgrade=False, err=err, **opts) + +@with_engine +def test(url, repository, **opts): + """%prog test URL REPOSITORY_PATH [VERSION] + + Performs the upgrade and downgrade option on the given + database. This is not a real test and may leave the database in a + bad state. You should therefore better run the test on a copy of + your database. + """ + engine = opts.pop('engine') + repos = Repository(repository) + + # Upgrade + log.info("Upgrading...") + script = repos.version(None).script(engine.name, 'upgrade') + script.run(engine, 1) + log.info("done") + + log.info("Downgrading...") + script = repos.version(None).script(engine.name, 'downgrade') + script.run(engine, -1) + log.info("done") + log.info("Success") + + +@with_engine +def version_control(url, repository, version=None, **opts): + """%prog version_control URL REPOSITORY_PATH [VERSION] + + Mark a database as under this repository's version control. + + Once a database is under version control, schema changes should + only be done via change scripts in this repository. + + This creates the table version_table in the database. + + The url should be any valid SQLAlchemy connection string. + + By default, the database begins at version 0 and is assumed to be + empty. If the database is not empty, you may specify a version at + which to begin instead. No attempt is made to verify this + version's correctness - the database schema is expected to be + identical to what it would be if the database were created from + scratch. + """ + engine = opts.pop('engine') + ControlledSchema.create(engine, repository, version) + + +@with_engine +def drop_version_control(url, repository, **opts): + """%prog drop_version_control URL REPOSITORY_PATH + + Removes version control from a database. + """ + engine = opts.pop('engine') + schema = ControlledSchema(engine, repository) + schema.drop() + + +def manage(file, **opts): + """%prog manage FILENAME [VARIABLES...] + + Creates a script that runs Migrate with a set of default values. + + For example:: + + %prog manage manage.py --repository=/path/to/repository \ +--url=sqlite:///project.db + + would create the script manage.py. The following two commands + would then have exactly the same results:: + + python manage.py version + %prog version --repository=/path/to/repository + """ + Repository.create_manage_file(file, **opts) + + +@with_engine +def compare_model_to_db(url, repository, model, **opts): + """%prog compare_model_to_db URL REPOSITORY_PATH MODEL + + Compare the current model (assumed to be a module level variable + of type sqlalchemy.MetaData) against the current database. + + NOTE: This is EXPERIMENTAL. + """ # TODO: get rid of EXPERIMENTAL label + engine = opts.pop('engine') + return ControlledSchema.compare_model_to_db(engine, model, repository) + + +@with_engine +def create_model(url, repository, **opts): + """%prog create_model URL REPOSITORY_PATH [DECLERATIVE=True] + + Dump the current database as a Python model to stdout. + + NOTE: This is EXPERIMENTAL. + """ # TODO: get rid of EXPERIMENTAL label + engine = opts.pop('engine') + declarative = opts.get('declarative', False) + return ControlledSchema.create_model(engine, repository, declarative) + + +@catch_known_errors +@with_engine +def make_update_script_for_model(url, repository, oldmodel, model, **opts): + """%prog make_update_script_for_model URL OLDMODEL MODEL REPOSITORY_PATH + + Create a script changing the old Python model to the new (current) + Python model, sending to stdout. + + NOTE: This is EXPERIMENTAL. + """ # TODO: get rid of EXPERIMENTAL label + engine = opts.pop('engine') + return PythonScript.make_update_script_for_model( + engine, oldmodel, model, repository, **opts) + + +@with_engine +def update_db_from_model(url, repository, model, **opts): + """%prog update_db_from_model URL REPOSITORY_PATH MODEL + + Modify the database to match the structure of the current Python + model. This also sets the db_version number to the latest in the + repository. + + NOTE: This is EXPERIMENTAL. + """ # TODO: get rid of EXPERIMENTAL label + engine = opts.pop('engine') + schema = ControlledSchema(engine, repository) + schema.update_db_from_model(model) + +@with_engine +def _migrate(url, repository, version, upgrade, err, **opts): + engine = opts.pop('engine') + url = str(engine.url) + schema = ControlledSchema(engine, repository) + version = _migrate_version(schema, version, upgrade, err) + + changeset = schema.changeset(version) + for ver, change in changeset: + nextver = ver + changeset.step + log.info('%s -> %s... ', ver, nextver) + + if opts.get('preview_sql'): + if isinstance(change, PythonScript): + log.info(change.preview_sql(url, changeset.step, **opts)) + elif isinstance(change, SqlScript): + log.info(change.source()) + + elif opts.get('preview_py'): + if not isinstance(change, PythonScript): + raise exceptions.UsageError("Python source can be only displayed" + " for python migration files") + source_ver = max(ver, nextver) + module = schema.repository.version(source_ver).script().module + funcname = upgrade and "upgrade" or "downgrade" + func = getattr(module, funcname) + log.info(inspect.getsource(func)) + else: + schema.runchange(ver, change, changeset.step) + log.info('done') + + +def _migrate_version(schema, version, upgrade, err): + if version is None: + return version + # Version is specified: ensure we're upgrading in the right direction + # (current version < target version for upgrading; reverse for down) + version = VerNum(version) + cur = schema.version + if upgrade is not None: + if upgrade: + direction = cur <= version + else: + direction = cur >= version + if not direction: + raise exceptions.KnownError(err % (cur, version)) + return version diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/cfgparse.py b/rhodecode/lib/dbmigrate/migrate/versioning/cfgparse.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/cfgparse.py @@ -0,0 +1,27 @@ +""" + Configuration parser module. +""" + +from ConfigParser import ConfigParser + +from rhodecode.lib.dbmigrate.migrate.versioning.config import * +from rhodecode.lib.dbmigrate.migrate.versioning import pathed + + +class Parser(ConfigParser): + """A project configuration file.""" + + def to_dict(self, sections=None): + """It's easier to access config values like dictionaries""" + return self._sections + + +class Config(pathed.Pathed, Parser): + """Configuration class.""" + + def __init__(self, path, *p, **k): + """Confirm the config file exists; read it.""" + self.require_found(path) + pathed.Pathed.__init__(self, path) + Parser.__init__(self, *p, **k) + self.read(path) diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/config.py b/rhodecode/lib/dbmigrate/migrate/versioning/config.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/config.py @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from sqlalchemy.util import OrderedDict + + +__all__ = ['databases', 'operations'] + +databases = ('sqlite', 'postgres', 'mysql', 'oracle', 'mssql', 'firebird') + +# Map operation names to function names +operations = OrderedDict() +operations['upgrade'] = 'upgrade' +operations['downgrade'] = 'downgrade' diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py b/rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py @@ -0,0 +1,302 @@ +""" +Code to generate a Python model from a database or differences +between a model and database. + +Some of this is borrowed heavily from the AutoCode project at: +http://code.google.com/p/sqlautocode/ +""" + +import sys +import logging + +import sqlalchemy + +import rhodecode.lib.dbmigrate.migrate +import rhodecode.lib.dbmigrate.migrate.changeset + + +log = logging.getLogger(__name__) +HEADER = """ +## File autogenerated by genmodel.py + +from sqlalchemy import * +""" + +META_DEFINITION = "meta = MetaData()" + +DECLARATIVE_DEFINITION = """ +from sqlalchemy.ext import declarative + +Base = declarative.declarative_base() +""" + + +class ModelGenerator(object): + """Various transformations from an A, B diff. + + In the implementation, A tends to be called the model and B + the database (although this is not true of all diffs). + The diff is directionless, but transformations apply the diff + in a particular direction, described in the method name. + """ + + def __init__(self, diff, engine, declarative=False): + self.diff = diff + self.engine = engine + self.declarative = declarative + + def column_repr(self, col): + kwarg = [] + if col.key != col.name: + kwarg.append('key') + if col.primary_key: + col.primary_key = True # otherwise it dumps it as 1 + kwarg.append('primary_key') + if not col.nullable: + kwarg.append('nullable') + if col.onupdate: + kwarg.append('onupdate') + if col.default: + if col.primary_key: + # I found that PostgreSQL automatically creates a + # default value for the sequence, but let's not show + # that. + pass + else: + kwarg.append('default') + args = ['%s=%r' % (k, getattr(col, k)) for k in kwarg] + + # crs: not sure if this is good idea, but it gets rid of extra + # u'' + name = col.name.encode('utf8') + + type_ = col.type + for cls in col.type.__class__.__mro__: + if cls.__module__ == 'sqlalchemy.types' and \ + not cls.__name__.isupper(): + if cls is not type_.__class__: + type_ = cls() + break + + type_repr = repr(type_) + if type_repr.endswith('()'): + type_repr = type_repr[:-2] + + constraints = [repr(cn) for cn in col.constraints] + + data = { + 'name': name, + 'commonStuff': ', '.join([type_repr] + constraints + args), + } + + if self.declarative: + return """%(name)s = Column(%(commonStuff)s)""" % data + else: + return """Column(%(name)r, %(commonStuff)s)""" % data + + def _getTableDefn(self, table, metaName='meta'): + out = [] + tableName = table.name + if self.declarative: + out.append("class %(table)s(Base):" % {'table': tableName}) + out.append(" __tablename__ = '%(table)s'\n" % + {'table': tableName}) + for col in table.columns: + out.append(" %s" % self.column_repr(col)) + out.append('\n') + else: + out.append("%(table)s = Table('%(table)s', %(meta)s," % + {'table': tableName, 'meta': metaName}) + for col in table.columns: + out.append(" %s," % self.column_repr(col)) + out.append(")\n") + return out + + def _get_tables(self,missingA=False,missingB=False,modified=False): + to_process = [] + for bool_,names,metadata in ( + (missingA,self.diff.tables_missing_from_A,self.diff.metadataB), + (missingB,self.diff.tables_missing_from_B,self.diff.metadataA), + (modified,self.diff.tables_different,self.diff.metadataA), + ): + if bool_: + for name in names: + yield metadata.tables.get(name) + + def _genModelHeader(self, tables): + out = [] + import_index = [] + + out.append(HEADER) + + for table in tables: + for col in table.columns: + if "dialects" in col.type.__module__ and \ + col.type.__class__ not in import_index: + out.append("from " + col.type.__module__ + + " import " + col.type.__class__.__name__) + import_index.append(col.type.__class__) + + out.append("") + + if self.declarative: + out.append(DECLARATIVE_DEFINITION) + else: + out.append(META_DEFINITION) + out.append("") + + return out + + def genBDefinition(self): + """Generates the source code for a definition of B. + + Assumes a diff where A is empty. + + Was: toPython. Assume database (B) is current and model (A) is empty. + """ + + out = [] + out.extend(self._genModelHeader(self._get_tables(missingA=True))) + for table in self._get_tables(missingA=True): + out.extend(self._getTableDefn(table)) + return '\n'.join(out) + + def genB2AMigration(self, indent=' '): + """Generate a migration from B to A. + + Was: toUpgradeDowngradePython + Assume model (A) is most current and database (B) is out-of-date. + """ + + decls = ['from rhodecode.lib.dbmigrate.migrate.changeset import schema', + 'pre_meta = MetaData()', + 'post_meta = MetaData()', + ] + upgradeCommands = ['pre_meta.bind = migrate_engine', + 'post_meta.bind = migrate_engine'] + downgradeCommands = list(upgradeCommands) + + for tn in self.diff.tables_missing_from_A: + pre_table = self.diff.metadataB.tables[tn] + decls.extend(self._getTableDefn(pre_table, metaName='pre_meta')) + upgradeCommands.append( + "pre_meta.tables[%(table)r].drop()" % {'table': tn}) + downgradeCommands.append( + "pre_meta.tables[%(table)r].create()" % {'table': tn}) + + for tn in self.diff.tables_missing_from_B: + post_table = self.diff.metadataA.tables[tn] + decls.extend(self._getTableDefn(post_table, metaName='post_meta')) + upgradeCommands.append( + "post_meta.tables[%(table)r].create()" % {'table': tn}) + downgradeCommands.append( + "post_meta.tables[%(table)r].drop()" % {'table': tn}) + + for (tn, td) in self.diff.tables_different.iteritems(): + if td.columns_missing_from_A or td.columns_different: + pre_table = self.diff.metadataB.tables[tn] + decls.extend(self._getTableDefn( + pre_table, metaName='pre_meta')) + if td.columns_missing_from_B or td.columns_different: + post_table = self.diff.metadataA.tables[tn] + decls.extend(self._getTableDefn( + post_table, metaName='post_meta')) + + for col in td.columns_missing_from_A: + upgradeCommands.append( + 'pre_meta.tables[%r].columns[%r].drop()' % (tn, col)) + downgradeCommands.append( + 'pre_meta.tables[%r].columns[%r].create()' % (tn, col)) + for col in td.columns_missing_from_B: + upgradeCommands.append( + 'post_meta.tables[%r].columns[%r].create()' % (tn, col)) + downgradeCommands.append( + 'post_meta.tables[%r].columns[%r].drop()' % (tn, col)) + for modelCol, databaseCol, modelDecl, databaseDecl in td.columns_different: + upgradeCommands.append( + 'assert False, "Can\'t alter columns: %s:%s=>%s"' % ( + tn, modelCol.name, databaseCol.name)) + downgradeCommands.append( + 'assert False, "Can\'t alter columns: %s:%s=>%s"' % ( + tn, modelCol.name, databaseCol.name)) + + return ( + '\n'.join(decls), + '\n'.join('%s%s' % (indent, line) for line in upgradeCommands), + '\n'.join('%s%s' % (indent, line) for line in downgradeCommands)) + + def _db_can_handle_this_change(self,td): + """Check if the database can handle going from B to A.""" + + if (td.columns_missing_from_B + and not td.columns_missing_from_A + and not td.columns_different): + # Even sqlite can handle column additions. + return True + else: + return not self.engine.url.drivername.startswith('sqlite') + + def runB2A(self): + """Goes from B to A. + + Was: applyModel. Apply model (A) to current database (B). + """ + + meta = sqlalchemy.MetaData(self.engine) + + for table in self._get_tables(missingA=True): + table = table.tometadata(meta) + table.drop() + for table in self._get_tables(missingB=True): + table = table.tometadata(meta) + table.create() + for modelTable in self._get_tables(modified=True): + tableName = modelTable.name + modelTable = modelTable.tometadata(meta) + dbTable = self.diff.metadataB.tables[tableName] + + td = self.diff.tables_different[tableName] + + if self._db_can_handle_this_change(td): + + for col in td.columns_missing_from_B: + modelTable.columns[col].create() + for col in td.columns_missing_from_A: + dbTable.columns[col].drop() + # XXX handle column changes here. + else: + # Sqlite doesn't support drop column, so you have to + # do more: create temp table, copy data to it, drop + # old table, create new table, copy data back. + # + # I wonder if this is guaranteed to be unique? + tempName = '_temp_%s' % modelTable.name + + def getCopyStatement(): + preparer = self.engine.dialect.preparer + commonCols = [] + for modelCol in modelTable.columns: + if modelCol.name in dbTable.columns: + commonCols.append(modelCol.name) + commonColsStr = ', '.join(commonCols) + return 'INSERT INTO %s (%s) SELECT %s FROM %s' % \ + (tableName, commonColsStr, commonColsStr, tempName) + + # Move the data in one transaction, so that we don't + # leave the database in a nasty state. + connection = self.engine.connect() + trans = connection.begin() + try: + connection.execute( + 'CREATE TEMPORARY TABLE %s as SELECT * from %s' % \ + (tempName, modelTable.name)) + # make sure the drop takes place inside our + # transaction with the bind parameter + modelTable.drop(bind=connection) + modelTable.create(bind=connection) + connection.execute(getCopyStatement()) + connection.execute('DROP TABLE %s' % tempName) + trans.commit() + except: + trans.rollback() + raise diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/migrate_repository.py b/rhodecode/lib/dbmigrate/migrate/versioning/migrate_repository.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/migrate_repository.py @@ -0,0 +1,100 @@ +""" + Script to migrate repository from sqlalchemy <= 0.4.4 to the new + repository schema. This shouldn't use any other migrate modules, so + that it can work in any version. +""" + +import os +import sys +import logging + +log = logging.getLogger(__name__) + + +def usage(): + """Gives usage information.""" + print """Usage: %(prog)s repository-to-migrate + + Upgrade your repository to the new flat format. + + NOTE: You should probably make a backup before running this. + """ % {'prog': sys.argv[0]} + + sys.exit(1) + + +def delete_file(filepath): + """Deletes a file and prints a message.""" + log.info('Deleting file: %s' % filepath) + os.remove(filepath) + + +def move_file(src, tgt): + """Moves a file and prints a message.""" + log.info('Moving file %s to %s' % (src, tgt)) + if os.path.exists(tgt): + raise Exception( + 'Cannot move file %s because target %s already exists' % \ + (src, tgt)) + os.rename(src, tgt) + + +def delete_directory(dirpath): + """Delete a directory and print a message.""" + log.info('Deleting directory: %s' % dirpath) + os.rmdir(dirpath) + + +def migrate_repository(repos): + """Does the actual migration to the new repository format.""" + log.info('Migrating repository at: %s to new format' % repos) + versions = '%s/versions' % repos + dirs = os.listdir(versions) + # Only use int's in list. + numdirs = [int(dirname) for dirname in dirs if dirname.isdigit()] + numdirs.sort() # Sort list. + for dirname in numdirs: + origdir = '%s/%s' % (versions, dirname) + log.info('Working on directory: %s' % origdir) + files = os.listdir(origdir) + files.sort() + for filename in files: + # Delete compiled Python files. + if filename.endswith('.pyc') or filename.endswith('.pyo'): + delete_file('%s/%s' % (origdir, filename)) + + # Delete empty __init__.py files. + origfile = '%s/__init__.py' % origdir + if os.path.exists(origfile) and len(open(origfile).read()) == 0: + delete_file(origfile) + + # Move sql upgrade scripts. + if filename.endswith('.sql'): + version, dbms, operation = filename.split('.', 3)[0:3] + origfile = '%s/%s' % (origdir, filename) + # For instance: 2.postgres.upgrade.sql -> + # 002_postgres_upgrade.sql + tgtfile = '%s/%03d_%s_%s.sql' % ( + versions, int(version), dbms, operation) + move_file(origfile, tgtfile) + + # Move Python upgrade script. + pyfile = '%s.py' % dirname + pyfilepath = '%s/%s' % (origdir, pyfile) + if os.path.exists(pyfilepath): + tgtfile = '%s/%03d.py' % (versions, int(dirname)) + move_file(pyfilepath, tgtfile) + + # Try to remove directory. Will fail if it's not empty. + delete_directory(origdir) + + +def main(): + """Main function to be called when using this script.""" + if len(sys.argv) != 2: + usage() + migrate_repository(sys.argv[1]) + + +if __name__ == '__main__': + main() diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/pathed.py b/rhodecode/lib/dbmigrate/migrate/versioning/pathed.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/pathed.py @@ -0,0 +1,75 @@ +""" + A path/directory class. +""" + +import os +import shutil +import logging + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning.config import * +from rhodecode.lib.dbmigrate.migrate.versioning.util import KeyedInstance + + +log = logging.getLogger(__name__) + +class Pathed(KeyedInstance): + """ + A class associated with a path/directory tree. + + Only one instance of this class may exist for a particular file; + __new__ will return an existing instance if possible + """ + parent = None + + @classmethod + def _key(cls, path): + return str(path) + + def __init__(self, path): + self.path = path + if self.__class__.parent is not None: + self._init_parent(path) + + def _init_parent(self, path): + """Try to initialize this object's parent, if it has one""" + parent_path = self.__class__._parent_path(path) + self.parent = self.__class__.parent(parent_path) + log.debug("Getting parent %r:%r" % (self.__class__.parent, parent_path)) + self.parent._init_child(path, self) + + def _init_child(self, child, path): + """Run when a child of this object is initialized. + + Parameters: the child object; the path to this object (its + parent) + """ + + @classmethod + def _parent_path(cls, path): + """ + Fetch the path of this object's parent from this object's path. + """ + # os.path.dirname(), but strip directories like files (like + # unix basename) + # + # Treat directories like files... + if path[-1] == '/': + path = path[:-1] + ret = os.path.dirname(path) + return ret + + @classmethod + def require_notfound(cls, path): + """Ensures a given path does not already exist""" + if os.path.exists(path): + raise exceptions.PathFoundError(path) + + @classmethod + def require_found(cls, path): + """Ensures a given path already exists""" + if not os.path.exists(path): + raise exceptions.PathNotFoundError(path) + + def __str__(self): + return self.path diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/repository.py b/rhodecode/lib/dbmigrate/migrate/versioning/repository.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/repository.py @@ -0,0 +1,243 @@ +""" + SQLAlchemy migrate repository management. +""" +import os +import shutil +import string +import logging + +from pkg_resources import resource_filename +from tempita import Template as TempitaTemplate + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning import version, pathed, cfgparse +from rhodecode.lib.dbmigrate.migrate.versioning.template import Template +from rhodecode.lib.dbmigrate.migrate.versioning.config import * + + +log = logging.getLogger(__name__) + +class Changeset(dict): + """A collection of changes to be applied to a database. + + Changesets are bound to a repository and manage a set of + scripts from that repository. + + Behaves like a dict, for the most part. Keys are ordered based on step value. + """ + + def __init__(self, start, *changes, **k): + """ + Give a start version; step must be explicitly stated. + """ + self.step = k.pop('step', 1) + self.start = version.VerNum(start) + self.end = self.start + for change in changes: + self.add(change) + + def __iter__(self): + return iter(self.items()) + + def keys(self): + """ + In a series of upgrades x -> y, keys are version x. Sorted. + """ + ret = super(Changeset, self).keys() + # Reverse order if downgrading + ret.sort(reverse=(self.step < 1)) + return ret + + def values(self): + return [self[k] for k in self.keys()] + + def items(self): + return zip(self.keys(), self.values()) + + def add(self, change): + """Add new change to changeset""" + key = self.end + self.end += self.step + self[key] = change + + def run(self, *p, **k): + """Run the changeset scripts""" + for version, script in self: + script.run(*p, **k) + + +class Repository(pathed.Pathed): + """A project's change script repository""" + + _config = 'migrate.cfg' + _versions = 'versions' + + def __init__(self, path): + log.debug('Loading repository %s...' % path) + self.verify(path) + super(Repository, self).__init__(path) + self.config = cfgparse.Config(os.path.join(self.path, self._config)) + self.versions = version.Collection(os.path.join(self.path, + self._versions)) + log.debug('Repository %s loaded successfully' % path) + log.debug('Config: %r' % self.config.to_dict()) + + @classmethod + def verify(cls, path): + """ + Ensure the target path is a valid repository. + + :raises: :exc:`InvalidRepositoryError <migrate.exceptions.InvalidRepositoryError>` + """ + # Ensure the existence of required files + try: + cls.require_found(path) + cls.require_found(os.path.join(path, cls._config)) + cls.require_found(os.path.join(path, cls._versions)) + except exceptions.PathNotFoundError as e: + raise exceptions.InvalidRepositoryError(path) + + @classmethod + def prepare_config(cls, tmpl_dir, name, options=None): + """ + Prepare a project configuration file for a new project. + + :param tmpl_dir: Path to Repository template + :param config_file: Name of the config file in Repository template + :param name: Repository name + :type tmpl_dir: string + :type config_file: string + :type name: string + :returns: Populated config file + """ + if options is None: + options = {} + options.setdefault('version_table', 'migrate_version') + options.setdefault('repository_id', name) + options.setdefault('required_dbs', []) + options.setdefault('use_timestamp_numbering', False) + + with open(os.path.join(tmpl_dir, cls._config)) as f: + tmpl = f.read() + ret = TempitaTemplate(tmpl).substitute(options) + + # cleanup + del options['__template_name__'] + + return ret + + @classmethod + def create(cls, path, name, **opts): + """Create a repository at a specified path""" + cls.require_notfound(path) + theme = opts.pop('templates_theme', None) + t_path = opts.pop('templates_path', None) + + # Create repository + tmpl_dir = Template(t_path).get_repository(theme=theme) + shutil.copytree(tmpl_dir, path) + + # Edit config defaults + config_text = cls.prepare_config(tmpl_dir, name, options=opts) + with open(os.path.join(path, cls._config), 'w') as fd: + fd.write(config_text) + + opts['repository_name'] = name + + # Create a management script + manager = os.path.join(path, 'manage.py') + Repository.create_manage_file(manager, templates_theme=theme, + templates_path=t_path, **opts) + + return cls(path) + + def create_script(self, description, **k): + """API to :meth:`migrate.versioning.version.Collection.create_new_python_version`""" + + k['use_timestamp_numbering'] = self.use_timestamp_numbering + self.versions.create_new_python_version(description, **k) + + def create_script_sql(self, database, description, **k): + """API to :meth:`migrate.versioning.version.Collection.create_new_sql_version`""" + k['use_timestamp_numbering'] = self.use_timestamp_numbering + self.versions.create_new_sql_version(database, description, **k) + + @property + def latest(self): + """API to :attr:`migrate.versioning.version.Collection.latest`""" + return self.versions.latest + + @property + def version_table(self): + """Returns version_table name specified in config""" + return self.config.get('db_settings', 'version_table') + + @property + def id(self): + """Returns repository id specified in config""" + return self.config.get('db_settings', 'repository_id') + + @property + def use_timestamp_numbering(self): + """Returns use_timestamp_numbering specified in config""" + if self.config.has_option('db_settings', 'use_timestamp_numbering'): + return self.config.getboolean('db_settings', 'use_timestamp_numbering') + return False + + def version(self, *p, **k): + """API to :attr:`migrate.versioning.version.Collection.version`""" + return self.versions.version(*p, **k) + + @classmethod + def clear(cls): + # TODO: deletes repo + super(Repository, cls).clear() + version.Collection.clear() + + def changeset(self, database, start, end=None): + """Create a changeset to migrate this database from ver. start to end/latest. + + :param database: name of database to generate changeset + :param start: version to start at + :param end: version to end at (latest if None given) + :type database: string + :type start: int + :type end: int + :returns: :class:`Changeset instance <migration.versioning.repository.Changeset>` + """ + start = version.VerNum(start) + + if end is None: + end = self.latest + else: + end = version.VerNum(end) + + if start <= end: + step = 1 + range_mod = 1 + op = 'upgrade' + else: + step = -1 + range_mod = 0 + op = 'downgrade' + + versions = range(int(start) + range_mod, int(end) + range_mod, step) + changes = [self.version(v).script(database, op) for v in versions] + ret = Changeset(start, step=step, *changes) + return ret + + @classmethod + def create_manage_file(cls, file_, **opts): + """Create a project management script (manage.py) + + :param file_: Destination file to be written + :param opts: Options that are passed to :func:`migrate.versioning.shell.main` + """ + mng_file = Template(opts.pop('templates_path', None))\ + .get_manage(theme=opts.pop('templates_theme', None)) + + with open(mng_file) as f: + tmpl = f.read() + + with open(file_, 'w') as fd: + fd.write(TempitaTemplate(tmpl).substitute(opts)) diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/schema.py b/rhodecode/lib/dbmigrate/migrate/versioning/schema.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/schema.py @@ -0,0 +1,221 @@ +""" + Database schema version management. +""" +import sys +import logging + +from sqlalchemy import (Table, Column, MetaData, String, Text, Integer, + create_engine) +from sqlalchemy.sql import and_ +from sqlalchemy import exc as sa_exceptions +from sqlalchemy.sql import bindparam + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_07 +from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff +from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository +from rhodecode.lib.dbmigrate.migrate.versioning.util import load_model +from rhodecode.lib.dbmigrate.migrate.versioning.version import VerNum + + +log = logging.getLogger(__name__) + + +class ControlledSchema(object): + """A database under version control""" + + def __init__(self, engine, repository): + if isinstance(repository, basestring): + repository = Repository(repository) + self.engine = engine + self.repository = repository + self.meta = MetaData(engine) + self.load() + + def __eq__(self, other): + """Compare two schemas by repositories and versions""" + return (self.repository is other.repository \ + and self.version == other.version) + + def load(self): + """Load controlled schema version info from DB""" + tname = self.repository.version_table + try: + if not hasattr(self, 'table') or self.table is None: + self.table = Table(tname, self.meta, autoload=True) + + result = self.engine.execute(self.table.select( + self.table.c.repository_id == str(self.repository.id))) + + data = list(result)[0] + except: + cls, exc, tb = sys.exc_info() + raise exceptions.DatabaseNotControlledError, exc.__str__(), tb + + self.version = data['version'] + return data + + def drop(self): + """ + Remove version control from a database. + """ + if SQLA_07: + try: + self.table.drop() + except sa_exceptions.DatabaseError: + raise exceptions.DatabaseNotControlledError(str(self.table)) + else: + try: + self.table.drop() + except (sa_exceptions.SQLError): + raise exceptions.DatabaseNotControlledError(str(self.table)) + + def changeset(self, version=None): + """API to Changeset creation. + + Uses self.version for start version and engine.name + to get database name. + """ + database = self.engine.name + start_ver = self.version + changeset = self.repository.changeset(database, start_ver, version) + return changeset + + def runchange(self, ver, change, step): + startver = ver + endver = ver + step + # Current database version must be correct! Don't run if corrupt! + if self.version != startver: + raise exceptions.InvalidVersionError("%s is not %s" % \ + (self.version, startver)) + # Run the change + change.run(self.engine, step) + + # Update/refresh database version + self.update_repository_table(startver, endver) + self.load() + + def update_repository_table(self, startver, endver): + """Update version_table with new information""" + update = self.table.update(and_(self.table.c.version == int(startver), + self.table.c.repository_id == str(self.repository.id))) + self.engine.execute(update, version=int(endver)) + + def upgrade(self, version=None): + """ + Upgrade (or downgrade) to a specified version, or latest version. + """ + changeset = self.changeset(version) + for ver, change in changeset: + self.runchange(ver, change, changeset.step) + + def update_db_from_model(self, model): + """ + Modify the database to match the structure of the current Python model. + """ + model = load_model(model) + + diff = schemadiff.getDiffOfModelAgainstDatabase( + model, self.engine, excludeTables=[self.repository.version_table] + ) + genmodel.ModelGenerator(diff,self.engine).runB2A() + + self.update_repository_table(self.version, int(self.repository.latest)) + + self.load() + + @classmethod + def create(cls, engine, repository, version=None): + """ + Declare a database to be under a repository's version control. + + :raises: :exc:`DatabaseAlreadyControlledError` + :returns: :class:`ControlledSchema` + """ + # Confirm that the version # is valid: positive, integer, + # exists in repos + if isinstance(repository, basestring): + repository = Repository(repository) + version = cls._validate_version(repository, version) + table = cls._create_table_version(engine, repository, version) + # TODO: history table + # Load repository information and return + return cls(engine, repository) + + @classmethod + def _validate_version(cls, repository, version): + """ + Ensures this is a valid version number for this repository. + + :raises: :exc:`InvalidVersionError` if invalid + :return: valid version number + """ + if version is None: + version = 0 + try: + version = VerNum(version) # raises valueerror + if version < 0 or version > repository.latest: + raise ValueError() + except ValueError: + raise exceptions.InvalidVersionError(version) + return version + + @classmethod + def _create_table_version(cls, engine, repository, version): + """ + Creates the versioning table in a database. + + :raises: :exc:`DatabaseAlreadyControlledError` + """ + # Create tables + tname = repository.version_table + meta = MetaData(engine) + + table = Table( + tname, meta, + Column('repository_id', String(250), primary_key=True), + Column('repository_path', Text), + Column('version', Integer), ) + + # there can be multiple repositories/schemas in the same db + if not table.exists(): + table.create() + + # test for existing repository_id + s = table.select(table.c.repository_id == bindparam("repository_id")) + result = engine.execute(s, repository_id=repository.id) + if result.fetchone(): + raise exceptions.DatabaseAlreadyControlledError + + # Insert data + engine.execute(table.insert().values( + repository_id=repository.id, + repository_path=repository.path, + version=int(version))) + return table + + @classmethod + def compare_model_to_db(cls, engine, model, repository): + """ + Compare the current model against the current database. + """ + if isinstance(repository, basestring): + repository = Repository(repository) + model = load_model(model) + + diff = schemadiff.getDiffOfModelAgainstDatabase( + model, engine, excludeTables=[repository.version_table]) + return diff + + @classmethod + def create_model(cls, engine, repository, declarative=False): + """ + Dump the current database as a Python model. + """ + if isinstance(repository, basestring): + repository = Repository(repository) + + diff = schemadiff.getDiffOfModelAgainstDatabase( + MetaData(), engine, excludeTables=[repository.version_table] + ) + return genmodel.ModelGenerator(diff, engine, declarative).genBDefinition() diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py b/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py @@ -0,0 +1,299 @@ +""" + Schema differencing support. +""" + +import logging +import sqlalchemy + +from sqlalchemy.types import Float + +log = logging.getLogger(__name__) + + +def getDiffOfModelAgainstDatabase(metadata, engine, excludeTables=None): + """ + Return differences of model against database. + + :return: object which will evaluate to :keyword:`True` if there \ + are differences else :keyword:`False`. + """ + db_metadata = sqlalchemy.MetaData(engine) + db_metadata.reflect() + + # sqlite will include a dynamically generated 'sqlite_sequence' table if + # there are autoincrement sequences in the database; this should not be + # compared. + if engine.dialect.name == 'sqlite': + if 'sqlite_sequence' in db_metadata.tables: + db_metadata.remove(db_metadata.tables['sqlite_sequence']) + + return SchemaDiff(metadata, db_metadata, + labelA='model', + labelB='database', + excludeTables=excludeTables) + + +def getDiffOfModelAgainstModel(metadataA, metadataB, excludeTables=None): + """ + Return differences of model against another model. + + :return: object which will evaluate to :keyword:`True` if there \ + are differences else :keyword:`False`. + """ + return SchemaDiff(metadataA, metadataB, excludeTables=excludeTables) + + +class ColDiff(object): + """ + Container for differences in one :class:`~sqlalchemy.schema.Column` + between two :class:`~sqlalchemy.schema.Table` instances, ``A`` + and ``B``. + + .. attribute:: col_A + + The :class:`~sqlalchemy.schema.Column` object for A. + + .. attribute:: col_B + + The :class:`~sqlalchemy.schema.Column` object for B. + + .. attribute:: type_A + + The most generic type of the :class:`~sqlalchemy.schema.Column` + object in A. + + .. attribute:: type_B + + The most generic type of the :class:`~sqlalchemy.schema.Column` + object in A. + + """ + + diff = False + + def __init__(self,col_A,col_B): + self.col_A = col_A + self.col_B = col_B + + self.type_A = col_A.type + self.type_B = col_B.type + + self.affinity_A = self.type_A._type_affinity + self.affinity_B = self.type_B._type_affinity + + if self.affinity_A is not self.affinity_B: + self.diff = True + return + + if isinstance(self.type_A,Float) or isinstance(self.type_B,Float): + if not (isinstance(self.type_A,Float) and isinstance(self.type_B,Float)): + self.diff=True + return + + for attr in ('precision','scale','length'): + A = getattr(self.type_A,attr,None) + B = getattr(self.type_B,attr,None) + if not (A is None or B is None) and A!=B: + self.diff=True + return + + def __nonzero__(self): + return self.diff + + __bool__ = __nonzero__ + + +class TableDiff(object): + """ + Container for differences in one :class:`~sqlalchemy.schema.Table` + between two :class:`~sqlalchemy.schema.MetaData` instances, ``A`` + and ``B``. + + .. attribute:: columns_missing_from_A + + A sequence of column names that were found in B but weren't in + A. + + .. attribute:: columns_missing_from_B + + A sequence of column names that were found in A but weren't in + B. + + .. attribute:: columns_different + + A dictionary containing information about columns that were + found to be different. + It maps column names to a :class:`ColDiff` objects describing the + differences found. + """ + __slots__ = ( + 'columns_missing_from_A', + 'columns_missing_from_B', + 'columns_different', + ) + + def __nonzero__(self): + return bool( + self.columns_missing_from_A or + self.columns_missing_from_B or + self.columns_different + ) + + __bool__ = __nonzero__ + +class SchemaDiff(object): + """ + Compute the difference between two :class:`~sqlalchemy.schema.MetaData` + objects. + + The string representation of a :class:`SchemaDiff` will summarise + the changes found between the two + :class:`~sqlalchemy.schema.MetaData` objects. + + The length of a :class:`SchemaDiff` will give the number of + changes found, enabling it to be used much like a boolean in + expressions. + + :param metadataA: + First :class:`~sqlalchemy.schema.MetaData` to compare. + + :param metadataB: + Second :class:`~sqlalchemy.schema.MetaData` to compare. + + :param labelA: + The label to use in messages about the first + :class:`~sqlalchemy.schema.MetaData`. + + :param labelB: + The label to use in messages about the second + :class:`~sqlalchemy.schema.MetaData`. + + :param excludeTables: + A sequence of table names to exclude. + + .. attribute:: tables_missing_from_A + + A sequence of table names that were found in B but weren't in + A. + + .. attribute:: tables_missing_from_B + + A sequence of table names that were found in A but weren't in + B. + + .. attribute:: tables_different + + A dictionary containing information about tables that were found + to be different. + It maps table names to a :class:`TableDiff` objects describing the + differences found. + """ + + def __init__(self, + metadataA, metadataB, + labelA='metadataA', + labelB='metadataB', + excludeTables=None): + + self.metadataA, self.metadataB = metadataA, metadataB + self.labelA, self.labelB = labelA, labelB + self.label_width = max(len(labelA),len(labelB)) + excludeTables = set(excludeTables or []) + + A_table_names = set(metadataA.tables.keys()) + B_table_names = set(metadataB.tables.keys()) + + self.tables_missing_from_A = sorted( + B_table_names - A_table_names - excludeTables + ) + self.tables_missing_from_B = sorted( + A_table_names - B_table_names - excludeTables + ) + + self.tables_different = {} + for table_name in A_table_names.intersection(B_table_names): + + td = TableDiff() + + A_table = metadataA.tables[table_name] + B_table = metadataB.tables[table_name] + + A_column_names = set(A_table.columns.keys()) + B_column_names = set(B_table.columns.keys()) + + td.columns_missing_from_A = sorted( + B_column_names - A_column_names + ) + + td.columns_missing_from_B = sorted( + A_column_names - B_column_names + ) + + td.columns_different = {} + + for col_name in A_column_names.intersection(B_column_names): + + cd = ColDiff( + A_table.columns.get(col_name), + B_table.columns.get(col_name) + ) + + if cd: + td.columns_different[col_name]=cd + + # XXX - index and constraint differences should + # be checked for here + + if td: + self.tables_different[table_name]=td + + def __str__(self): + """ Summarize differences. """ + out = [] + column_template =' %%%is: %%r' % self.label_width + + for names,label in ( + (self.tables_missing_from_A,self.labelA), + (self.tables_missing_from_B,self.labelB), + ): + if names: + out.append( + ' tables missing from %s: %s' % ( + label,', '.join(sorted(names)) + ) + ) + + for name,td in sorted(self.tables_different.items()): + out.append( + ' table with differences: %s' % name + ) + for names,label in ( + (td.columns_missing_from_A,self.labelA), + (td.columns_missing_from_B,self.labelB), + ): + if names: + out.append( + ' %s missing these columns: %s' % ( + label,', '.join(sorted(names)) + ) + ) + for name,cd in td.columns_different.items(): + out.append(' column with differences: %s' % name) + out.append(column_template % (self.labelA,cd.col_A)) + out.append(column_template % (self.labelB,cd.col_B)) + + if out: + out.insert(0, 'Schema diffs:') + return '\n'.join(out) + else: + return 'No schema diffs' + + def __len__(self): + """ + Used in bool evaluation, return of 0 means no diffs. + """ + return ( + len(self.tables_missing_from_A) + + len(self.tables_missing_from_B) + + len(self.tables_different) + ) diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/script/__init__.py b/rhodecode/lib/dbmigrate/migrate/versioning/script/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from rhodecode.lib.dbmigrate.migrate.versioning.script.base import BaseScript +from rhodecode.lib.dbmigrate.migrate.versioning.script.py import PythonScript +from rhodecode.lib.dbmigrate.migrate.versioning.script.sql import SqlScript diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/script/base.py b/rhodecode/lib/dbmigrate/migrate/versioning/script/base.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/base.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import logging + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning.config import operations +from rhodecode.lib.dbmigrate.migrate.versioning import pathed + + +log = logging.getLogger(__name__) + +class BaseScript(pathed.Pathed): + """Base class for other types of scripts. + All scripts have the following properties: + + source (script.source()) + The source code of the script + version (script.version()) + The version number of the script + operations (script.operations()) + The operations defined by the script: upgrade(), downgrade() or both. + Returns a tuple of operations. + Can also check for an operation with ex. script.operation(Script.ops.up) + """ # TODO: sphinxfy this and implement it correctly + + def __init__(self, path): + log.debug('Loading script %s...' % path) + self.verify(path) + super(BaseScript, self).__init__(path) + log.debug('Script %s loaded successfully' % path) + + @classmethod + def verify(cls, path): + """Ensure this is a valid script + This version simply ensures the script file's existence + + :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>` + """ + try: + cls.require_found(path) + except: + raise exceptions.InvalidScriptError(path) + + def source(self): + """:returns: source code of the script. + :rtype: string + """ + with open(self.path) as fd: + ret = fd.read() + return ret + + def run(self, engine): + """Core of each BaseScript subclass. + This method executes the script. + """ + raise NotImplementedError() diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/script/py.py b/rhodecode/lib/dbmigrate/migrate/versioning/script/py.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/py.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import shutil +import warnings +import logging +import inspect +from StringIO import StringIO + +from rhodecode.lib.dbmigrate import migrate +from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff +from rhodecode.lib.dbmigrate.migrate.versioning.config import operations +from rhodecode.lib.dbmigrate.migrate.versioning.template import Template +from rhodecode.lib.dbmigrate.migrate.versioning.script import base +from rhodecode.lib.dbmigrate.migrate.versioning.util import import_path, load_model, with_engine +from rhodecode.lib.dbmigrate.migrate.exceptions import MigrateDeprecationWarning, InvalidScriptError, ScriptError + +log = logging.getLogger(__name__) +__all__ = ['PythonScript'] + + +class PythonScript(base.BaseScript): + """Base for Python scripts""" + + @classmethod + def create(cls, path, **opts): + """Create an empty migration script at specified path + + :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`""" + cls.require_notfound(path) + + src = Template(opts.pop('templates_path', None)).get_script(theme=opts.pop('templates_theme', None)) + shutil.copy(src, path) + + return cls(path) + + @classmethod + def make_update_script_for_model(cls, engine, oldmodel, + model, repository, **opts): + """Create a migration script based on difference between two SA models. + + :param repository: path to migrate repository + :param oldmodel: dotted.module.name:SAClass or SAClass object + :param model: dotted.module.name:SAClass or SAClass object + :param engine: SQLAlchemy engine + :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>` + :type oldmodel: string or Class + :type model: string or Class + :type engine: Engine instance + :returns: Upgrade / Downgrade script + :rtype: string + """ + + if isinstance(repository, basestring): + # oh dear, an import cycle! + from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository + repository = Repository(repository) + + oldmodel = load_model(oldmodel) + model = load_model(model) + + # Compute differences. + diff = schemadiff.getDiffOfModelAgainstModel( + model, + oldmodel, + excludeTables=[repository.version_table]) + # TODO: diff can be False (there is no difference?) + decls, upgradeCommands, downgradeCommands = \ + genmodel.ModelGenerator(diff,engine).genB2AMigration() + + # Store differences into file. + src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None)) + with open(src) as f: + contents = f.read() + + # generate source + search = 'def upgrade(migrate_engine):' + contents = contents.replace(search, '\n\n'.join((decls, search)), 1) + if upgradeCommands: + contents = contents.replace(' pass', upgradeCommands, 1) + if downgradeCommands: + contents = contents.replace(' pass', downgradeCommands, 1) + return contents + + @classmethod + def verify_module(cls, path): + """Ensure path is a valid script + + :param path: Script location + :type path: string + :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>` + :returns: Python module + """ + # Try to import and get the upgrade() func + module = import_path(path) + try: + assert callable(module.upgrade) + except Exception as e: + raise InvalidScriptError(path + ': %s' % str(e)) + return module + + def preview_sql(self, url, step, **args): + """Mocks SQLAlchemy Engine to store all executed calls in a string + and runs :meth:`PythonScript.run <migrate.versioning.script.py.PythonScript.run>` + + :returns: SQL file + """ + buf = StringIO() + args['engine_arg_strategy'] = 'mock' + args['engine_arg_executor'] = lambda s, p = '': buf.write(str(s) + p) + + @with_engine + def go(url, step, **kw): + engine = kw.pop('engine') + self.run(engine, step) + return buf.getvalue() + + return go(url, step, **args) + + def run(self, engine, step): + """Core method of Script file. + Exectues :func:`update` or :func:`downgrade` functions + + :param engine: SQLAlchemy Engine + :param step: Operation to run + :type engine: string + :type step: int + """ + if step > 0: + op = 'upgrade' + elif step < 0: + op = 'downgrade' + else: + raise ScriptError("%d is not a valid step" % step) + + funcname = base.operations[op] + script_func = self._func(funcname) + + # check for old way of using engine + if not inspect.getargspec(script_func)[0]: + raise TypeError("upgrade/downgrade functions must accept engine" + " parameter (since version 0.5.4)") + + script_func(engine) + + @property + def module(self): + """Calls :meth:`migrate.versioning.script.py.verify_module` + and returns it. + """ + if not hasattr(self, '_module'): + self._module = self.verify_module(self.path) + return self._module + + def _func(self, funcname): + if not hasattr(self.module, funcname): + msg = "Function '%s' is not defined in this script" + raise ScriptError(msg % funcname) + return getattr(self.module, funcname) diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py b/rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import logging +import shutil + +from rhodecode.lib.dbmigrate.migrate.versioning.script import base +from rhodecode.lib.dbmigrate.migrate.versioning.template import Template + + +log = logging.getLogger(__name__) + +class SqlScript(base.BaseScript): + """A file containing plain SQL statements.""" + + @classmethod + def create(cls, path, **opts): + """Create an empty migration script at specified path + + :returns: :class:`SqlScript instance <migrate.versioning.script.sql.SqlScript>`""" + cls.require_notfound(path) + + src = Template(opts.pop('templates_path', None)).get_sql_script(theme=opts.pop('templates_theme', None)) + shutil.copy(src, path) + return cls(path) + + # TODO: why is step parameter even here? + def run(self, engine, step=None, executemany=True): + """Runs SQL script through raw dbapi execute call""" + text = self.source() + # Don't rely on SA's autocommit here + # (SA uses .startswith to check if a commit is needed. What if script + # starts with a comment?) + conn = engine.connect() + try: + trans = conn.begin() + try: + # HACK: SQLite doesn't allow multiple statements through + # its execute() method, but it provides executescript() instead + dbapi = conn.engine.raw_connection() + if executemany and getattr(dbapi, 'executescript', None): + dbapi.executescript(text) + else: + conn.execute(text) + trans.commit() + except: + trans.rollback() + raise + finally: + conn.close() diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/shell.py b/rhodecode/lib/dbmigrate/migrate/versioning/shell.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/shell.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""The migrate command-line tool.""" + +import sys +import inspect +import logging +from optparse import OptionParser, BadOptionError + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning import api +from rhodecode.lib.dbmigrate.migrate.versioning.config import * +from rhodecode.lib.dbmigrate.migrate.versioning.util import asbool + + +alias = { + 's': api.script, + 'vc': api.version_control, + 'dbv': api.db_version, + 'v': api.version, +} + +def alias_setup(): + global alias + for key, val in alias.iteritems(): + setattr(api, key, val) +alias_setup() + + +class PassiveOptionParser(OptionParser): + + def _process_args(self, largs, rargs, values): + """little hack to support all --some_option=value parameters""" + + while rargs: + arg = rargs[0] + if arg == "--": + del rargs[0] + return + elif arg[0:2] == "--": + # if parser does not know about the option + # pass it along (make it anonymous) + try: + opt = arg.split('=', 1)[0] + self._match_long_opt(opt) + except BadOptionError: + largs.append(arg) + del rargs[0] + else: + self._process_long_opt(rargs, values) + elif arg[:1] == "-" and len(arg) > 1: + self._process_short_opts(rargs, values) + elif self.allow_interspersed_args: + largs.append(arg) + del rargs[0] + +def main(argv=None, **kwargs): + """Shell interface to :mod:`migrate.versioning.api`. + + kwargs are default options that can be overriden with passing + --some_option as command line option + + :param disable_logging: Let migrate configure logging + :type disable_logging: bool + """ + if argv is not None: + argv = argv + else: + argv = list(sys.argv[1:]) + commands = list(api.__all__) + commands.sort() + + usage = """%%prog COMMAND ... + + Available commands: + %s + + Enter "%%prog help COMMAND" for information on a particular command. + """ % '\n\t'.join(["%s - %s" % (command.ljust(28), api.command_desc.get(command)) for command in commands]) + + parser = PassiveOptionParser(usage=usage) + parser.add_option("-d", "--debug", + action="store_true", + dest="debug", + default=False, + help="Shortcut to turn on DEBUG mode for logging") + parser.add_option("-q", "--disable_logging", + action="store_true", + dest="disable_logging", + default=False, + help="Use this option to disable logging configuration") + help_commands = ['help', '-h', '--help'] + HELP = False + + try: + command = argv.pop(0) + if command in help_commands: + HELP = True + command = argv.pop(0) + except IndexError: + parser.print_help() + return + + command_func = getattr(api, command, None) + if command_func is None or command.startswith('_'): + parser.error("Invalid command %s" % command) + + parser.set_usage(inspect.getdoc(command_func)) + f_args, f_varargs, f_kwargs, f_defaults = inspect.getargspec(command_func) + for arg in f_args: + parser.add_option( + "--%s" % arg, + dest=arg, + action='store', + type="string") + + # display help of the current command + if HELP: + parser.print_help() + return + + options, args = parser.parse_args(argv) + + # override kwargs with anonymous parameters + override_kwargs = {} + for arg in list(args): + if arg.startswith('--'): + args.remove(arg) + if '=' in arg: + opt, value = arg[2:].split('=', 1) + else: + opt = arg[2:] + value = True + override_kwargs[opt] = value + + # override kwargs with options if user is overwriting + for key, value in options.__dict__.iteritems(): + if value is not None: + override_kwargs[key] = value + + # arguments that function accepts without passed kwargs + f_required = list(f_args) + candidates = dict(kwargs) + candidates.update(override_kwargs) + for key, value in candidates.iteritems(): + if key in f_args: + f_required.remove(key) + + # map function arguments to parsed arguments + for arg in args: + try: + kw = f_required.pop(0) + except IndexError: + parser.error("Too many arguments for command %s: %s" % (command, + arg)) + kwargs[kw] = arg + + # apply overrides + kwargs.update(override_kwargs) + + # configure options + for key, value in options.__dict__.iteritems(): + kwargs.setdefault(key, value) + + # configure logging + if not asbool(kwargs.pop('disable_logging', False)): + # filter to log =< INFO into stdout and rest to stderr + class SingleLevelFilter(logging.Filter): + def __init__(self, min=None, max=None): + self.min = min or 0 + self.max = max or 100 + + def filter(self, record): + return self.min <= record.levelno <= self.max + + logger = logging.getLogger() + h1 = logging.StreamHandler(sys.stdout) + f1 = SingleLevelFilter(max=logging.INFO) + h1.addFilter(f1) + h2 = logging.StreamHandler(sys.stderr) + f2 = SingleLevelFilter(min=logging.WARN) + h2.addFilter(f2) + logger.addHandler(h1) + logger.addHandler(h2) + + if options.debug: + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.INFO) + + log = logging.getLogger(__name__) + + # check if all args are given + try: + num_defaults = len(f_defaults) + except TypeError: + num_defaults = 0 + f_args_default = f_args[len(f_args) - num_defaults:] + required = list(set(f_required) - set(f_args_default)) + required.sort() + if required: + parser.error("Not enough arguments for command %s: %s not specified" \ + % (command, ', '.join(required))) + + # handle command + try: + ret = command_func(**kwargs) + if ret is not None: + log.info(ret) + except (exceptions.UsageError, exceptions.KnownError) as e: + parser.error(e.args[0]) + +if __name__ == "__main__": + main() diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/template.py b/rhodecode/lib/dbmigrate/migrate/versioning/template.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/template.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import shutil +import sys + +from pkg_resources import resource_filename + +from rhodecode.lib.dbmigrate.migrate.versioning.config import * +from rhodecode.lib.dbmigrate.migrate.versioning import pathed + + +class Collection(pathed.Pathed): + """A collection of templates of a specific type""" + _mask = None + + def get_path(self, file): + return os.path.join(self.path, str(file)) + + +class RepositoryCollection(Collection): + _mask = '%s' + +class ScriptCollection(Collection): + _mask = '%s.py_tmpl' + +class ManageCollection(Collection): + _mask = '%s.py_tmpl' + +class SQLScriptCollection(Collection): + _mask = '%s.py_tmpl' + +class Template(pathed.Pathed): + """Finds the paths/packages of various Migrate templates. + + :param path: Templates are loaded from rhodecode.lib.dbmigrate.migrate package + if `path` is not provided. + """ + pkg = 'rhodecode.lib.dbmigrate.migrate.versioning.templates' + + def __new__(cls, path=None): + if path is None: + path = cls._find_path(cls.pkg) + return super(Template, cls).__new__(cls, path) + + def __init__(self, path=None): + if path is None: + path = Template._find_path(self.pkg) + super(Template, self).__init__(path) + self.repository = RepositoryCollection(os.path.join(path, 'repository')) + self.script = ScriptCollection(os.path.join(path, 'script')) + self.manage = ManageCollection(os.path.join(path, 'manage')) + self.sql_script = SQLScriptCollection(os.path.join(path, 'sql_script')) + + @classmethod + def _find_path(cls, pkg): + """Returns absolute path to dotted python package.""" + tmp_pkg = pkg.rsplit('.', 1) + + if len(tmp_pkg) != 1: + return resource_filename(tmp_pkg[0], tmp_pkg[1]) + else: + return resource_filename(tmp_pkg[0], '') + + def _get_item(self, collection, theme=None): + """Locates and returns collection. + + :param collection: name of collection to locate + :param type_: type of subfolder in collection (defaults to "_default") + :returns: (package, source) + :rtype: str, str + """ + item = getattr(self, collection) + theme_mask = getattr(item, '_mask') + theme = theme_mask % (theme or 'default') + return item.get_path(theme) + + def get_repository(self, *a, **kw): + """Calls self._get_item('repository', *a, **kw)""" + return self._get_item('repository', *a, **kw) + + def get_script(self, *a, **kw): + """Calls self._get_item('script', *a, **kw)""" + return self._get_item('script', *a, **kw) + + def get_sql_script(self, *a, **kw): + """Calls self._get_item('sql_script', *a, **kw)""" + return self._get_item('sql_script', *a, **kw) + + def get_manage(self, *a, **kw): + """Calls self._get_item('manage', *a, **kw)""" + return self._get_item('manage', *a, **kw) diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py b/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""".. currentmodule:: migrate.versioning.util""" + +import warnings +import logging +from decorator import decorator +from pkg_resources import EntryPoint + +from sqlalchemy import create_engine +from sqlalchemy.engine import Engine +from sqlalchemy.pool import StaticPool + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning.util.keyedinstance import KeyedInstance +from rhodecode.lib.dbmigrate.migrate.versioning.util.importpath import import_path + + +log = logging.getLogger(__name__) + +def load_model(dotted_name): + """Import module and use module-level variable". + + :param dotted_name: path to model in form of string: ``some.python.module:Class`` + + .. versionchanged:: 0.5.4 + + """ + if isinstance(dotted_name, basestring): + if ':' not in dotted_name: + # backwards compatibility + warnings.warn('model should be in form of module.model:User ' + 'and not module.model.User', exceptions.MigrateDeprecationWarning) + dotted_name = ':'.join(dotted_name.rsplit('.', 1)) + return EntryPoint.parse('x=%s' % dotted_name).load(False) + else: + # Assume it's already loaded. + return dotted_name + +def asbool(obj): + """Do everything to use object as bool""" + if isinstance(obj, basestring): + obj = obj.strip().lower() + if obj in ['true', 'yes', 'on', 'y', 't', '1']: + return True + elif obj in ['false', 'no', 'off', 'n', 'f', '0']: + return False + else: + raise ValueError("String is not true/false: %r" % obj) + if obj in (True, False): + return bool(obj) + else: + raise ValueError("String is not true/false: %r" % obj) + +def guess_obj_type(obj): + """Do everything to guess object type from string + + Tries to convert to `int`, `bool` and finally returns if not succeded. + + .. versionadded: 0.5.4 + """ + + result = None + + try: + result = int(obj) + except: + pass + + if result is None: + try: + result = asbool(obj) + except: + pass + + if result is not None: + return result + else: + return obj + +@decorator +def catch_known_errors(f, *a, **kw): + """Decorator that catches known api errors + + .. versionadded: 0.5.4 + """ + + try: + return f(*a, **kw) + except exceptions.PathFoundError as e: + raise exceptions.KnownError("The path %s already exists" % e.args[0]) + +def construct_engine(engine, **opts): + """.. versionadded:: 0.5.4 + + Constructs and returns SQLAlchemy engine. + + Currently, there are 2 ways to pass create_engine options to :mod:`migrate.versioning.api` functions: + + :param engine: connection string or a existing engine + :param engine_dict: python dictionary of options to pass to `create_engine` + :param engine_arg_*: keyword parameters to pass to `create_engine` (evaluated with :func:`migrate.versioning.util.guess_obj_type`) + :type engine_dict: dict + :type engine: string or Engine instance + :type engine_arg_*: string + :returns: SQLAlchemy Engine + + .. note:: + + keyword parameters override ``engine_dict`` values. + + """ + if isinstance(engine, Engine): + return engine + elif not isinstance(engine, basestring): + raise ValueError("you need to pass either an existing engine or a database uri") + + # get options for create_engine + if opts.get('engine_dict') and isinstance(opts['engine_dict'], dict): + kwargs = opts['engine_dict'] + else: + kwargs = {} + + # DEPRECATED: handle echo the old way + echo = asbool(opts.get('echo', False)) + if echo: + warnings.warn('echo=True parameter is deprecated, pass ' + 'engine_arg_echo=True or engine_dict={"echo": True}', + exceptions.MigrateDeprecationWarning) + kwargs['echo'] = echo + + # parse keyword arguments + for key, value in opts.iteritems(): + if key.startswith('engine_arg_'): + kwargs[key[11:]] = guess_obj_type(value) + + log.debug('Constructing engine') + # TODO: return create_engine(engine, poolclass=StaticPool, **kwargs) + # seems like 0.5.x branch does not work with engine.dispose and staticpool + return create_engine(engine, **kwargs) + +@decorator +def with_engine(f, *a, **kw): + """Decorator for :mod:`migrate.versioning.api` functions + to safely close resources after function usage. + + Passes engine parameters to :func:`construct_engine` and + resulting parameter is available as kw['engine']. + + Engine is disposed after wrapped function is executed. + + .. versionadded: 0.6.0 + """ + url = a[0] + engine = construct_engine(url, **kw) + + try: + kw['engine'] = engine + return f(*a, **kw) + finally: + if isinstance(engine, Engine) and engine is not url: + log.debug('Disposing SQLAlchemy engine %s', engine) + engine.dispose() + + +class Memoize: + """Memoize(fn) - an instance which acts like fn but memoizes its arguments + Will only work on functions with non-mutable arguments + + ActiveState Code 52201 + """ + def __init__(self, fn): + self.fn = fn + self.memo = {} + + def __call__(self, *args): + if args not in self.memo: + self.memo[args] = self.fn(*args) + return self.memo[args] diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/util/importpath.py b/rhodecode/lib/dbmigrate/migrate/versioning/util/importpath.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/importpath.py @@ -0,0 +1,15 @@ +import os +import sys + +def import_path(fullpath): + """ Import a file with full path specification. Allows one to + import from anywhere, something __import__ does not do. + """ + # http://zephyrfalcon.org/weblog/arch_d7_2002_08_31.html + path, filename = os.path.split(fullpath) + filename, ext = os.path.splitext(filename) + sys.path.append(path) + module = __import__(filename) + reload(module) # Might be out of date during tests + del sys.path[-1] + return module diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/util/keyedinstance.py b/rhodecode/lib/dbmigrate/migrate/versioning/util/keyedinstance.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/keyedinstance.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +class KeyedInstance(object): + """A class whose instances have a unique identifier of some sort + No two instances with the same unique ID should exist - if we try to create + a second instance, the first should be returned. + """ + + _instances = {} + + def __new__(cls, *p, **k): + instances = cls._instances + clskey = str(cls) + if clskey not in instances: + instances[clskey] = {} + instances = instances[clskey] + + key = cls._key(*p, **k) + if key not in instances: + instances[key] = super(KeyedInstance, cls).__new__(cls) + return instances[key] + + @classmethod + def _key(cls, *p, **k): + """Given a unique identifier, return a dictionary key + This should be overridden by child classes, to specify which parameters + should determine an object's uniqueness + """ + raise NotImplementedError() + + @classmethod + def clear(cls): + # Allow cls.clear() as well as uniqueInstance.clear(cls) + if str(cls) in cls._instances: + del cls._instances[str(cls)] diff --git a/rhodecode/lib/dbmigrate/migrate/versioning/version.py b/rhodecode/lib/dbmigrate/migrate/versioning/version.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/migrate/versioning/version.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import re +import shutil +import logging + +from rhodecode.lib.dbmigrate.migrate import exceptions +from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script +from datetime import datetime + + +log = logging.getLogger(__name__) + +class VerNum(object): + """A version number that behaves like a string and int at the same time""" + + _instances = {} + + def __new__(cls, value): + val = str(value) + if val not in cls._instances: + cls._instances[val] = super(VerNum, cls).__new__(cls) + ret = cls._instances[val] + return ret + + def __init__(self,value): + self.value = str(int(value)) + if self < 0: + raise ValueError("Version number cannot be negative") + + def __add__(self, value): + ret = int(self) + int(value) + return VerNum(ret) + + def __sub__(self, value): + return self + (int(value) * -1) + + def __eq__(self, value): + return int(self) == int(value) + + def __ne__(self, value): + return int(self) != int(value) + + def __lt__(self, value): + return int(self) < int(value) + + def __gt__(self, value): + return int(self) > int(value) + + def __ge__(self, value): + return int(self) >= int(value) + + def __le__(self, value): + return int(self) <= int(value) + + def __repr__(self): + return "<VerNum(%s)>" % self.value + + def __str__(self): + return str(self.value) + + def __int__(self): + return int(self.value) + + +class Collection(pathed.Pathed): + """A collection of versioning scripts in a repository""" + + FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*') + + def __init__(self, path): + """Collect current version scripts in repository + and store them in self.versions + """ + super(Collection, self).__init__(path) + + # Create temporary list of files, allowing skipped version numbers. + files = os.listdir(path) + if '1' in files: + # deprecation + raise Exception('It looks like you have a repository in the old ' + 'format (with directories for each version). ' + 'Please convert repository before proceeding.') + + tempVersions = {} + for filename in files: + match = self.FILENAME_WITH_VERSION.match(filename) + if match: + num = int(match.group(1)) + tempVersions.setdefault(num, []).append(filename) + else: + pass # Must be a helper file or something, let's ignore it. + + # Create the versions member where the keys + # are VerNum's and the values are Version's. + self.versions = {} + for num, files in tempVersions.items(): + self.versions[VerNum(num)] = Version(num, path, files) + + @property + def latest(self): + """:returns: Latest version in Collection""" + return max([VerNum(0)] + self.versions.keys()) + + def _next_ver_num(self, use_timestamp_numbering): + if use_timestamp_numbering == True: + return VerNum(int(datetime.utcnow().strftime('%Y%m%d%H%M%S'))) + else: + return self.latest + 1 + + def create_new_python_version(self, description, **k): + """Create Python files for new version""" + ver = self._next_ver_num(k.pop('use_timestamp_numbering', False)) + extra = str_to_filename(description) + + if extra: + if extra == '_': + extra = '' + elif not extra.startswith('_'): + extra = '_%s' % extra + + filename = '%03d%s.py' % (ver, extra) + filepath = self._version_path(filename) + + script.PythonScript.create(filepath, **k) + self.versions[ver] = Version(ver, self.path, [filename]) + + def create_new_sql_version(self, database, description, **k): + """Create SQL files for new version""" + ver = self._next_ver_num(k.pop('use_timestamp_numbering', False)) + self.versions[ver] = Version(ver, self.path, []) + + extra = str_to_filename(description) + + if extra: + if extra == '_': + extra = '' + elif not extra.startswith('_'): + extra = '_%s' % extra + + # Create new files. + for op in ('upgrade', 'downgrade'): + filename = '%03d%s_%s_%s.sql' % (ver, extra, database, op) + filepath = self._version_path(filename) + script.SqlScript.create(filepath, **k) + self.versions[ver].add_script(filepath) + + def version(self, vernum=None): + """Returns latest Version if vernum is not given. + Otherwise, returns wanted version""" + if vernum is None: + vernum = self.latest + return self.versions[VerNum(vernum)] + + @classmethod + def clear(cls): + super(Collection, cls).clear() + + def _version_path(self, ver): + """Returns path of file in versions repository""" + return os.path.join(self.path, str(ver)) + + +class Version(object): + """A single version in a collection + :param vernum: Version Number + :param path: Path to script files + :param filelist: List of scripts + :type vernum: int, VerNum + :type path: string + :type filelist: list + """ + + def __init__(self, vernum, path, filelist): + self.version = VerNum(vernum) + + # Collect scripts in this folder + self.sql = {} + self.python = None + + for script in filelist: + self.add_script(os.path.join(path, script)) + + def script(self, database=None, operation=None): + """Returns SQL or Python Script""" + for db in (database, 'default'): + # Try to return a .sql script first + try: + return self.sql[db][operation] + except KeyError: + continue # No .sql script exists + + # TODO: maybe add force Python parameter? + ret = self.python + + assert ret is not None, \ + "There is no script for %d version" % self.version + return ret + + def add_script(self, path): + """Add script to Collection/Version""" + if path.endswith(Extensions.py): + self._add_script_py(path) + elif path.endswith(Extensions.sql): + self._add_script_sql(path) + + SQL_FILENAME = re.compile(r'^.*\.sql') + + def _add_script_sql(self, path): + basename = os.path.basename(path) + match = self.SQL_FILENAME.match(basename) + + if match: + basename = basename.replace('.sql', '') + parts = basename.split('_') + if len(parts) < 3: + raise exceptions.ScriptError( + "Invalid SQL script name %s " % basename + \ + "(needs to be ###_description_database_operation.sql)") + version = parts[0] + op = parts[-1] + # NOTE(mriedem): check for ibm_db_sa as the database in the name + if 'ibm_db_sa' in basename: + if len(parts) == 6: + dbms = '_'.join(parts[-4: -1]) + else: + raise exceptions.ScriptError( + "Invalid ibm_db_sa SQL script name '%s'; " + "(needs to be " + "###_description_ibm_db_sa_operation.sql)" % basename) + else: + dbms = parts[-2] + else: + raise exceptions.ScriptError( + "Invalid SQL script name %s " % basename + \ + "(needs to be ###_description_database_operation.sql)") + + # File the script into a dictionary + self.sql.setdefault(dbms, {})[op] = script.SqlScript(path) + + def _add_script_py(self, path): + if self.python is not None: + raise exceptions.ScriptError('You can only have one Python script ' + 'per version, but you have: %s and %s' % (self.python, path)) + self.python = script.PythonScript(path) + + +class Extensions: + """A namespace for file extensions""" + py = 'py' + sql = 'sql' + +def str_to_filename(s): + """Replaces spaces, (double and single) quotes + and double underscores to underscores + """ + + s = s.replace(' ', '_').replace('"', '_').replace("'", '_').replace(".", "_") + while '__' in s: + s = s.replace('__', '_') + return s diff --git a/rhodecode/lib/dbmigrate/schema/__init__.py b/rhodecode/lib/dbmigrate/schema/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/dbmigrate/schema/db_1_1_0.py b/rhodecode/lib/dbmigrate/schema/db_1_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_1_0.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session +from rhodecode.model.meta import Base + +class BaseModel(object): + """Base Model for all classess + + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session.query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def getAll(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session.delete(obj) + Session.commit() + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id') + , {'useexisting':True}) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None) + + user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relation('Repository') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True}) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(None), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(None), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + def __repr__(self): + return "<CacheKey('%s:%s')>" % (self.cache_id, self.cache_key) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py @@ -0,0 +1,1054 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import logging +import datetime +import traceback +from datetime import date + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from beaker.cache import cache_region, region_invalidate + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.auth import generate_auth_token +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, safe_unicode +from rhodecode.lib.exceptions import UserGroupAssignedException +from rhodecode.lib.ext_json import json + +from rhodecode.model.meta import Base, Session +from rhodecode.lib.caching_query import FromCache + + +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +class ModelSerializer(json.JSONEncoder): + """ + Simple Serializer for JSON, + + usage:: + + to make object customized for serialization implement a __json__ + method that will return a dict for serialization into json + + example:: + + class Task(object): + + def __init__(self, name, value): + self.name = name + self.value = value + + def __json__(self): + return dict(name=self.name, + value=self.value) + + """ + + def default(self, obj): + + if hasattr(obj, '__json__'): + return obj.__json__() + else: + return json.JSONEncoder.default(self, obj) + +class BaseModel(object): + """Base Model for all classess + + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session.query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def getAll(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session.delete(obj) + Session.commit() + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True}) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if v == 'ldap_active': + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __repr__(self): + return "<%s('%s:%s')>" % (self.__class__.__name__, + self.app_settings_name, self.app_settings_value) + + + @classmethod + def get_by_name(cls, ldap_key): + return cls.query()\ + .filter(cls.app_settings_name == ldap_key).scalar() + + @classmethod + def get_app_settings(cls, cache=False): + + ret = cls.query() + + if cache: + ret = ret.options(FromCache("sql_cache_short", "get_hg_settings")) + + if not ret: + raise Exception('Could not get application settings !') + settings = {} + for each in ret: + settings['rhodecode_' + each.app_settings_name] = \ + each.app_settings_value + + return settings + + @classmethod + def get_ldap_settings(cls, cache=False): + ret = cls.query()\ + .filter(cls.app_settings_name.startswith('ldap_')).all() + fd = {} + for row in ret: + fd.update({row.app_settings_name:row.app_settings_value}) + + return fd + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True}) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'pretxnchangegroup.push_logger' + HOOK_PULL = 'preoutgoing.pull_logger' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.ui_key == key) + + + @classmethod + def get_builtin_hooks(cls): + q = cls.query() + q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE, + cls.HOOK_PUSH, cls.HOOK_PULL])) + return q.all() + + @classmethod + def get_custom_hooks(cls): + q = cls.query() + q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE, + cls.HOOK_PUSH, cls.HOOK_PULL])) + q = q.filter(cls.ui_section == 'hooks') + return q.all() + + @classmethod + def create_or_update_hook(cls, key, val): + new_ui = cls.get_by_key(key).scalar() or cls() + new_ui.ui_section = 'hooks' + new_ui.ui_active = True + new_ui.ui_key = key + new_ui.ui_value = val + + Session.add(new_ui) + Session.commit() + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True}) + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=None) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("name", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + + user_log = relationship('UserLog', cascade='all') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + @property + def full_contact(self): + return '%s %s <%s>' % (self.name, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.name, self.lastname) + + @property + def is_admin(self): + return self.admin + + def __repr__(self): + try: + return "<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + except: + return self.__class__.__name__ + + @classmethod + def get_by_username(cls, username, case_insensitive=False): + if case_insensitive: + return Session.query(cls).filter(cls.username.ilike(username)).scalar() + else: + return Session.query(cls).filter(cls.username == username).scalar() + + @classmethod + def get_by_auth_token(cls, auth_token): + return cls.query().filter(cls.api_key == auth_token).one() + + def update_lastlogin(self): + """Update user lastlogin""" + + self.last_login = datetime.datetime.now() + Session.add(self) + Session.commit() + log.debug('updated user %s lastlogin' % self.username) + + @classmethod + def create(cls, form_data): + from rhodecode.lib.auth import get_crypt_password + + try: + new_user = cls() + for k, v in form_data.items(): + if k == 'password': + v = get_crypt_password(v) + setattr(new_user, k, v) + + new_user.api_key = generate_auth_token(form_data['username']) + Session.add(new_user) + Session.commit() + return new_user + except: + log.error(traceback.format_exc()) + Session.rollback() + raise + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = {'extend_existing':True} + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + @property + def action_as_day(self): + return date(*self.action_date.timetuple()[:3]) + + user = relationship('User') + repository = relationship('Repository') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = {'extend_existing':True} + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + + def __repr__(self): + return '<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.users_group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.users_group_name == group_name) + if cache: + gr = gr.options(FromCache("sql_cache_short", + "get_user_%s" % group_name)) + return gr.scalar() + + + @classmethod + def get(cls, users_group_id, cache=False): + users_group = cls.query() + if cache: + users_group = users_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return users_group.get(users_group_id) + + @classmethod + def create(cls, form_data): + try: + new_users_group = cls() + for k, v in form_data.items(): + setattr(new_users_group, k, v) + + Session.add(new_users_group) + Session.commit() + return new_users_group + except: + log.error(traceback.format_exc()) + Session.rollback() + raise + + @classmethod + def update(cls, users_group_id, form_data): + + try: + users_group = cls.get(users_group_id, cache=False) + + for k, v in form_data.items(): + if k == 'users_group_members': + users_group.members = [] + Session.flush() + members_list = [] + if v: + v = [v] if isinstance(v, basestring) else v + for u_id in set(v): + member = UserGroupMember(users_group_id, u_id) + members_list.append(member) + setattr(users_group, 'members', members_list) + setattr(users_group, k, v) + + Session.add(users_group) + Session.commit() + except: + log.error(traceback.format_exc()) + Session.rollback() + raise + + @classmethod + def delete(cls, user_group_id): + try: + + # check if this group is not assigned to repo + assigned_groups = UserGroupRepoToPerm.query()\ + .filter(UserGroupRepoToPerm.users_group_id == + user_group_id).all() + + if assigned_groups: + raise UserGroupAssignedException( + 'UserGroup assigned to %s' % assigned_groups) + + users_group = cls.get(user_group_id, cache=False) + Session.delete(users_group) + Session.commit() + except: + log.error(traceback.format_exc()) + Session.rollback() + raise + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = {'extend_existing':True} + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + @staticmethod + def add_user_to_group(group, user): + ugm = UserGroupMember() + ugm.users_group = group + ugm.user = user + Session.add(ugm) + Session.commit() + return ugm + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg') + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') + + logs = relationship('UserLog', cascade='all') + + def __repr__(self): + return "<%s('%s:%s')>" % (self.__class__.__name__, + self.repo_id, self.repo_name) + + @classmethod + def url_sep(cls): + return '/' + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session.query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.one() + + @classmethod + def get_repo_forks(cls, repo_id): + return cls.query().filter(Repository.fork_id == repo_id) + + @classmethod + def base_path(cls): + """ + Returns base path when all repos are stored + + :param cls: + """ + q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == + cls.url_sep()) + q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @property + def just_name(self): + return self.repo_name.split(Repository.url_sep())[-1] + + @property + def groups_with_parents(self): + groups = [] + if self.group is None: + return groups + + cur_gr = self.group + groups.insert(0, cur_gr) + while 1: + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + groups.insert(0, gr) + + return groups + + @property + def groups_and_repo(self): + return self.groups_with_parents, self.just_name + + @LazyProperty + def repo_path(self): + """ + Returns base full path for that repository means where it actually + exists on a filesystem + """ + q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == + Repository.url_sep()) + q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @property + def repo_full_path(self): + p = [self.repo_path] + # we need to split the name by / since this is how we store the + # names in the database, but that eventually needs to be converted + # into a valid system path + p += self.repo_name.split(Repository.url_sep()) + return os.path.join(*p) + + def get_new_name(self, repo_name): + """ + returns new full repository name based on assigned group and new new + + :param group_name: + """ + path_prefix = self.group.full_path_splitted if self.group else [] + return Repository.url_sep().join(path_prefix + [repo_name]) + + @property + def _config(self): + """ + Returns db based config object. + """ + from rhodecode.lib.utils import make_db_config + return make_db_config(clear_session=False) + + @classmethod + def is_valid(cls, repo_name): + """ + returns True if given repo name is a valid filesystem repository + + :param cls: + :param repo_name: + """ + from rhodecode.lib.utils import is_valid_repo + + return is_valid_repo(repo_name, cls.base_path()) + + + #========================================================================== + # SCM PROPERTIES + #========================================================================== + + def get_commit(self, rev): + return get_commit_safe(self.scm_instance, rev) + + @property + def tip(self): + return self.get_commit('tip') + + @property + def author(self): + return self.tip.author + + @property + def last_change(self): + return self.scm_instance.last_change + + #========================================================================== + # SCM CACHE INSTANCE + #========================================================================== + + @property + def invalidate(self): + return CacheInvalidation.invalidate(self.repo_name) + + def set_invalidate(self): + """ + set a cache for invalidation for this instance + """ + CacheInvalidation.set_invalidate(self.repo_name) + + @LazyProperty + def scm_instance(self): + return self.__get_instance() + + @property + def scm_instance_cached(self): + @cache_region('long_term') + def _c(repo_name): + return self.__get_instance() + rn = self.repo_name + + inv = self.invalidate + if inv is not None: + region_invalidate(_c, None, rn) + # update our cache + CacheInvalidation.set_valid(inv.cache_key) + return _c(rn) + + def __get_instance(self): + + repo_full_path = self.repo_full_path + + try: + alias = get_scm(repo_full_path)[0] + log.debug('Creating instance of %s repository' % alias) + backend = get_backend(alias) + except VCSError: + log.error(traceback.format_exc()) + log.error('Perhaps this repository is in db and not in ' + 'filesystem run rescan repositories with ' + '"destroy old data " option from admin panel') + return + + if alias == 'hg': + + repo = backend(safe_str(repo_full_path), create=False, + config=self._config) + + else: + repo = backend(repo_full_path, create=False) + + return repo + + +class Group(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},) + __mapper_args__ = {'order_by':'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + + parent_group = relationship('Group', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __repr__(self): + return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return '/' + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache("sql_cache_short", + "get_group_%s" % group_name)) + return gr.scalar() + + @property + def parents(self): + parents_recursion_limit = 5 + groups = [] + if self.parent_group is None: + return groups + cur_gr = self.parent_group + groups.insert(0, cur_gr) + cnt = 0 + while 1: + cnt += 1 + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + if cnt == parents_recursion_limit: + # this will prevent accidental infinit loops + log.error('group nested more than %s' % + parents_recursion_limit) + break + + groups.insert(0, gr) + return groups + + @property + def children(self): + return Group.query().filter(Group.parent_group == self) + + @property + def name(self): + return self.group_name.split(Group.url_sep())[-1] + + @property + def full_path(self): + return self.group_name + + @property + def full_path_splitted(self): + return self.group_name.split(Group.url_sep()) + + @property + def repositories(self): + return Repository.query().filter(Repository.group == self) + + @property + def repositories_recursive_count(self): + cnt = self.repositories.count() + + def children_count(group): + cnt = 0 + for child in group.children: + cnt += child.repositories.count() + cnt += children_count(child) + return cnt + + return cnt + children_count(self) + + + def get_new_name(self, group_name): + """ + returns new full group name based on parent and new name + + :param group_name: + """ + path_prefix = (self.parent_group.full_path_splitted if + self.parent_group else []) + return Group.url_sep().join(path_prefix + [group_name]) + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = {'extend_existing':True} + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __repr__(self): + return "<%s('%s:%s')>" % (self.__class__.__name__, + self.permission_id, self.permission_name) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True}) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission') + repository = relationship('Repository') + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True}) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission') + + @classmethod + def has_perm(cls, user_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + return cls.query().filter(cls.user_id == user_id)\ + .filter(cls.permission == perm).scalar() is not None + + @classmethod + def grant_perm(cls, user_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + new = cls() + new.user_id = user_id + new.permission = perm + try: + Session.add(new) + Session.commit() + except: + Session.rollback() + + + @classmethod + def revoke_perm(cls, user_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + try: + cls.query().filter(cls.user_id == user_id) \ + .filter(cls.permission == perm).delete() + Session.commit() + except: + Session.rollback() + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True}) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __repr__(self): + return '<userGroup:%s => %s >' % (self.users_group, self.repository) + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = {'extend_existing':True} + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + + @classmethod + def has_perm(cls, users_group_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + return cls.query().filter(cls.users_group_id == + users_group_id)\ + .filter(cls.permission == perm)\ + .scalar() is not None + + @classmethod + def grant_perm(cls, users_group_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + new = cls() + new.users_group_id = users_group_id + new.permission = perm + try: + Session.add(new) + Session.commit() + except: + Session.rollback() + + + @classmethod + def revoke_perm(cls, users_group_id, perm): + if not isinstance(perm, Permission): + raise Exception('perm needs to be an instance of Permission class') + + try: + cls.query().filter(cls.users_group_id == users_group_id) \ + .filter(cls.permission == perm).delete() + Session.commit() + except: + Session.rollback() + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'group_to_perm' + __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True}) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission') + group = relationship('RepoGroup') + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True}) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id') + , {'extend_existing':True}) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + + @classmethod + def get_repo_followers(cls, repo_id): + return cls.query().filter(cls.follows_repo_id == repo_id) + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True}) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + def __repr__(self): + return "<%s('%s:%s')>" % (self.__class__.__name__, + self.cache_id, self.cache_key) + + @classmethod + def invalidate(cls, key): + """ + Returns Invalidation object if this given key should be invalidated + None otherwise. `cache_active = False` means that this cache + state is not valid and needs to be invalidated + + :param key: + """ + return cls.query()\ + .filter(CacheInvalidation.cache_key == key)\ + .filter(CacheInvalidation.cache_active == False)\ + .scalar() + + @classmethod + def set_invalidate(cls, key): + """ + Mark this Cache key for invalidation + + :param key: + """ + + log.debug('marking %s for invalidation' % key) + inv_obj = Session.query(cls)\ + .filter(cls.cache_key == key).scalar() + if inv_obj: + inv_obj.cache_active = False + else: + log.debug('cache key not found in invalidation db -> creating one') + inv_obj = CacheInvalidation(key) + + try: + Session.add(inv_obj) + Session.commit() + except Exception: + log.error(traceback.format_exc()) + Session.rollback() + + @classmethod + def set_valid(cls, key): + """ + Mark this cache key as active and currently cached + + :param key: + """ + inv_obj = Session.query(CacheInvalidation)\ + .filter(CacheInvalidation.cache_key == key).scalar() + inv_obj.cache_active = True + Session.add(inv_obj) + Session.commit() + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = {'extend_existing':True} + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_3_0.py b/rhodecode/lib/dbmigrate/schema/db_1_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_3_0.py @@ -0,0 +1,1276 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import logging +import datetime +import traceback +from collections import defaultdict + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from beaker.cache import cache_region, region_invalidate + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session +import hashlib + + +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class ModelSerializer(json.JSONEncoder): + """ + Simple Serializer for JSON, + + usage:: + + to make object customized for serialization implement a __json__ + method that will return a dict for serialization into json + + example:: + + class Task(object): + + def __init__(self, name, value): + self.name = name + self.value = value + + def __json__(self): + return dict(name=self.name, + value=self.value) + + """ + + def default(self, obj): + + if hasattr(obj, '__json__'): + return obj.__json__() + else: + return json.JSONEncoder.default(self, obj) + + +class BaseModel(object): + """ + Base Model for all classess + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + for k, val in getattr(self, '__json__', lambda: {})().iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session.query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def getAll(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session.delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name == 'ldap_active': + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + @classmethod + def get_by_name(cls, ldap_key): + return cls.query()\ + .filter(cls.app_settings_name == ldap_key).scalar() + + @classmethod + def get_app_settings(cls, cache=False): + + ret = cls.query() + + if cache: + ret = ret.options(FromCache("sql_cache_short", "get_hg_settings")) + + if not ret: + raise Exception('Could not get application settings !') + settings = {} + for each in ret: + settings['rhodecode_' + each.app_settings_name] = \ + each.app_settings_value + + return settings + + @classmethod + def get_ldap_settings(cls, cache=False): + ret = cls.query()\ + .filter(cls.app_settings_name.startswith('ldap_')).all() + fd = {} + for row in ret: + fd.update({row.app_settings_name:row.app_settings_value}) + + return fd + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'pretxnchangegroup.push_logger' + HOOK_PULL = 'preoutgoing.pull_logger' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.ui_key == key) + + @classmethod + def get_builtin_hooks(cls): + q = cls.query() + q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE, + cls.HOOK_PUSH, cls.HOOK_PULL])) + return q.all() + + @classmethod + def get_custom_hooks(cls): + q = cls.query() + q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE, + cls.HOOK_PUSH, cls.HOOK_PULL])) + q = q.filter(cls.ui_section == 'hooks') + return q.all() + + @classmethod + def create_or_update_hook(cls, key, val): + new_ui = cls.get_by_key(key).scalar() or cls() + new_ui.ui_section = 'hooks' + new_ui.ui_active = True + new_ui.ui_key = key + new_ui.ui_value = val + + Session.add(new_ui) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=None) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("name", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + + user_log = relationship('UserLog', cascade='all') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def full_name(self): + return '%s %s' % (self.name, self.lastname) + + @property + def full_name_or_username(self): + return ('%s %s' % (self.name, self.lastname) + if (self.name and self.lastname) else self.username) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.name, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.name, self.lastname) + + @property + def is_admin(self): + return self.admin + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % email)) + return q.scalar() + + def update_lastlogin(self): + """Update user lastlogin""" + self.last_login = datetime.datetime.now() + Session.add(self) + log.debug('updated user %s lastlogin' % self.username) + + def __json__(self): + return dict( + user_id=self.user_id, + first_name=self.name, + last_name=self.lastname, + email=self.email, + full_name=self.full_name, + full_name_or_username=self.full_name_or_username, + short_contact=self.short_contact, + full_contact=self.full_contact + ) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + @property + def action_as_day(self): + return datetime.date(*self.action_date.timetuple()[:3]) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + + def __unicode__(self): + return u'<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + users_group = cls.query() + if cache: + users_group = users_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return users_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg') + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') + + logs = relationship('UserLog') + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id, + self.repo_name) + + @classmethod + def url_sep(cls): + return '/' + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session.query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + @classmethod + def get_repo_forks(cls, repo_id): + return cls.query().filter(Repository.fork_id == repo_id) + + @classmethod + def base_path(cls): + """ + Returns base path when all repos are stored + + :param cls: + """ + q = Session.query(RhodeCodeUi)\ + .filter(RhodeCodeUi.ui_key == cls.url_sep()) + q = q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @property + def just_name(self): + return self.repo_name.split(Repository.url_sep())[-1] + + @property + def groups_with_parents(self): + groups = [] + if self.group is None: + return groups + + cur_gr = self.group + groups.insert(0, cur_gr) + while 1: + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + groups.insert(0, gr) + + return groups + + @property + def groups_and_repo(self): + return self.groups_with_parents, self.just_name + + @LazyProperty + def repo_path(self): + """ + Returns base full path for that repository means where it actually + exists on a filesystem + """ + q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == + Repository.url_sep()) + q = q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @property + def repo_full_path(self): + p = [self.repo_path] + # we need to split the name by / since this is how we store the + # names in the database, but that eventually needs to be converted + # into a valid system path + p += self.repo_name.split(Repository.url_sep()) + return os.path.join(*p) + + def get_new_name(self, repo_name): + """ + returns new full repository name based on assigned group and new new + + :param group_name: + """ + path_prefix = self.group.full_path_splitted if self.group else [] + return Repository.url_sep().join(path_prefix + [repo_name]) + + @property + def _config(self): + """ + Returns db based config object. + """ + from rhodecode.lib.utils import make_db_config + return make_db_config(clear_session=False) + + @classmethod + def is_valid(cls, repo_name): + """ + returns True if given repo name is a valid filesystem repository + + :param cls: + :param repo_name: + """ + from rhodecode.lib.utils import is_valid_repo + + return is_valid_repo(repo_name, cls.base_path()) + + #========================================================================== + # SCM PROPERTIES + #========================================================================== + + def get_commit(self, rev): + return get_commit_safe(self.scm_instance, rev) + + @property + def tip(self): + return self.get_commit('tip') + + @property + def author(self): + return self.tip.author + + @property + def last_change(self): + return self.scm_instance.last_change + + def comments(self, revisions=None): + """ + Returns comments for this repository grouped by revisions + + :param revisions: filter query by revisions only + """ + cmts = ChangesetComment.query()\ + .filter(ChangesetComment.repo == self) + if revisions: + cmts = cmts.filter(ChangesetComment.revision.in_(revisions)) + grouped = defaultdict(list) + for cmt in cmts.all(): + grouped[cmt.revision].append(cmt) + return grouped + + #========================================================================== + # SCM CACHE INSTANCE + #========================================================================== + + @property + def invalidate(self): + return CacheInvalidation.invalidate(self.repo_name) + + def set_invalidate(self): + """ + set a cache for invalidation for this instance + """ + CacheInvalidation.set_invalidate(self.repo_name) + + @LazyProperty + def scm_instance(self): + return self.__get_instance() + + @property + def scm_instance_cached(self): + @cache_region('long_term') + def _c(repo_name): + return self.__get_instance() + rn = self.repo_name + log.debug('Getting cached instance of repo') + inv = self.invalidate + if inv is not None: + region_invalidate(_c, None, rn) + # update our cache + CacheInvalidation.set_valid(inv.cache_key) + return _c(rn) + + def __get_instance(self): + repo_full_path = self.repo_full_path + try: + alias = get_scm(repo_full_path)[0] + log.debug('Creating instance of %s repository' % alias) + backend = get_backend(alias) + except VCSError: + log.error(traceback.format_exc()) + log.error('Perhaps this repository is in db and not in ' + 'filesystem run rescan repositories with ' + '"destroy old data " option from admin panel') + return + + if alias == 'hg': + + repo = backend(safe_str(repo_full_path), create=False, + config=self._config) + else: + repo = backend(repo_full_path, create=False) + + return repo + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + + parent_group = relationship('RepoGroup', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return '/' + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + @property + def parents(self): + parents_recursion_limit = 5 + groups = [] + if self.parent_group is None: + return groups + cur_gr = self.parent_group + groups.insert(0, cur_gr) + cnt = 0 + while 1: + cnt += 1 + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + if cnt == parents_recursion_limit: + # this will prevent accidental infinit loops + log.error('group nested more than %s' % + parents_recursion_limit) + break + + groups.insert(0, gr) + return groups + + @property + def children(self): + return RepoGroup.query().filter(RepoGroup.parent_group == self) + + @property + def name(self): + return self.group_name.split(RepoGroup.url_sep())[-1] + + @property + def full_path(self): + return self.group_name + + @property + def full_path_splitted(self): + return self.group_name.split(RepoGroup.url_sep()) + + @property + def repositories(self): + return Repository.query()\ + .filter(Repository.group == self)\ + .order_by(Repository.repo_name) + + @property + def repositories_recursive_count(self): + cnt = self.repositories.count() + + def children_count(group): + cnt = 0 + for child in group.children: + cnt += child.repositories.count() + cnt += children_count(child) + return cnt + + return cnt + children_count(self) + + def get_new_name(self, group_name): + """ + returns new full group name based on parent and new name + + :param group_name: + """ + path_prefix = (self.parent_group.full_path_splitted if + self.parent_group else []) + return RepoGroup.url_sep().join(path_prefix + [group_name]) + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + @classmethod + def get_default_repo_perms(cls, default_user_id): + q = Session.query(UserRepoToPerm, Repository, cls)\ + .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\ + .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\ + .filter(UserRepoToPerm.user_id == default_user_id) + + return q.all() + + @classmethod + def get_default_group_perms(cls, default_user_id): + q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\ + .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ + .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\ + .filter(UserRepoGroupToPerm.user_id == default_user_id) + + return q.all() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + @classmethod + def create(cls, user, repository, permission): + n = cls() + n.user = user + n.repository = repository + n.permission = permission + Session.add(n) + return n + + def __unicode__(self): + return u'<user:%s => %s >' % (self.user, self.repository) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + @classmethod + def create(cls, users_group, repository, permission): + n = cls() + n.users_group = users_group + n.repository = repository + n.permission = permission + Session.add(n) + return n + + def __unicode__(self): + return u'<userGroup:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + @classmethod + def get_repo_followers(cls, repo_id): + return cls.query().filter(cls.follows_repo_id == repo_id) + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, + self.cache_id, self.cache_key) + + @classmethod + def _get_key(cls, key): + """ + Wrapper for generating a key, together with a prefix + + :param key: + """ + import rhodecode + prefix = '' + iid = rhodecode.CONFIG.get('instance_id') + if iid: + prefix = iid + return "%s%s" % (prefix, key), prefix, key.rstrip('_README') + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.cache_key == key).scalar() + + @classmethod + def _get_or_create_key(cls, key, prefix, org_key): + inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar() + if not inv_obj: + try: + inv_obj = CacheInvalidation(key, org_key) + Session.add(inv_obj) + Session.commit() + except Exception: + log.error(traceback.format_exc()) + Session.rollback() + return inv_obj + + @classmethod + def invalidate(cls, key): + """ + Returns Invalidation object if this given key should be invalidated + None otherwise. `cache_active = False` means that this cache + state is not valid and needs to be invalidated + + :param key: + """ + + key, _prefix, _org_key = cls._get_key(key) + inv = cls._get_or_create_key(key, _prefix, _org_key) + + if inv and inv.cache_active is False: + return inv + + @classmethod + def set_invalidate(cls, key): + """ + Mark this Cache key for invalidation + + :param key: + """ + + key, _prefix, _org_key = cls._get_key(key) + inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all() + log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs), + _org_key)) + try: + for inv_obj in inv_objs: + if inv_obj: + inv_obj.cache_active = False + + Session.add(inv_obj) + Session.commit() + except Exception: + log.error(traceback.format_exc()) + Session.rollback() + + @classmethod + def set_valid(cls, key): + """ + Mark this cache key as active and currently cached + + :param key: + """ + inv_obj = cls.get_by_key(key) + inv_obj.cache_active = True + Session.add(inv_obj) + Session.commit() + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=False) + line_no = Column('line_no', Unicode(10), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + + @classmethod + def get_users(cls, revision): + """ + Returns user associated with this changesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + return Session.query(User)\ + .filter(cls.revision == revision)\ + .join(ChangesetComment.author).all() + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + @property + def recipients(self): + return [x.user for x in UserNotification.query()\ + .filter(UserNotification.notification == self).all()] + + @classmethod + def create(cls, created_by, subject, body, recipients, type_=None): + if type_ is None: + type_ = Notification.TYPE_MESSAGE + + notification = cls() + notification.created_by_user = created_by + notification.subject = subject + notification.body = body + notification.type_ = type_ + notification.created_on = datetime.datetime.now() + + for u in recipients: + assoc = UserNotification() + assoc.notification = notification + u.notifications.append(assoc) + Session.add(notification) + return notification + + @property + def description(self): + from rhodecode.model.notification import NotificationModel + return NotificationModel().make_description(self) + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + def mark_as_read(self): + self.read = True + Session.add(self) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine':'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) + +## this is migration from 1_4_0, but now it's here to overcome a problem of +## attaching a FK to this from 1_3_0 ! + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) # 500 revisions max + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_4_0.py b/rhodecode/lib/dbmigrate/schema/db_1_4_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_4_0.py @@ -0,0 +1,973 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name == 'ldap_active': + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + DEFAULT_USER = 'default' + DEFAULT_PERMISSIONS = [ + 'hg.register.manual_activate', 'hg.create.repository', + 'hg.fork.repository', 'repository.read', 'group.read' + ] + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog', cascade='all') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + + def __unicode__(self): + return u'<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return user_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + self.repo_name) + + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PERMS = [ + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repositories Group no access')), + ('group.read', _('Repositories Group read access')), + ('group.write', _('Repositories Group write access')), + ('group.admin', _('Repositories Group admin access')), + + ('hg.admin', _('RhodeCode Administrator')), + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + ('hg.register.none', _('Register disabled')), + ('hg.register.manual_activate', _('Register new user with RhodeCode ' + 'with manual activation')), + + ('hg.register.auto_activate', _('Register new user with RhodeCode ' + 'with auto activation')), + ] + + # defines which permissions are more important higher the more important + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository':1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<user:%s => %s >' % (self.user, self.repository) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<userGroup:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + @classmethod + def get_users(cls, revision=None, pull_request_id=None): + """ + Returns user associated with this ChangesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + q = Session().query(User)\ + .join(ChangesetComment.author) + if revision: + q = q.filter(cls.revision == revision) + elif pull_request_id: + q = q.filter(cls.pull_request_id == pull_request_id) + return q.all() + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_5_0.py b/rhodecode/lib/dbmigrate/schema/db_1_5_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_5_0.py @@ -0,0 +1,993 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix, remove_prefix +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name in ["ldap_active", + "default_repo_enable_statistics", + "default_repo_enable_locking", + "default_repo_private", + "default_repo_enable_downloads"]: + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + DEFAULT_USER = 'default' + DEFAULT_PERMISSIONS = [ + 'hg.register.manual_activate', 'hg.create.repository', + 'hg.fork.repository', 'repository.read', 'group.read' + ] + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + + def __unicode__(self): + return u'<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return user_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + self.repo_name) + + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PERMS = [ + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repositories Group no access')), + ('group.read', _('Repositories Group read access')), + ('group.write', _('Repositories Group write access')), + ('group.admin', _('Repositories Group admin access')), + + ('hg.admin', _('RhodeCode Administrator')), + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + ('hg.register.none', _('Register disabled')), + ('hg.register.manual_activate', _('Register new user with RhodeCode ' + 'with manual activation')), + + ('hg.register.auto_activate', _('Register new user with RhodeCode ' + 'with auto activation')), + ] + + # defines which permissions are more important higher the more important + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository':1 + } + + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + ] + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<user:%s => %s >' % (self.user, self.repository) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<userGroup:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + @classmethod + def get_users(cls, revision=None, pull_request_id=None): + """ + Returns user associated with this ChangesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + q = Session().query(User)\ + .join(ChangesetComment.author) + if revision: + q = q.filter(cls.revision == revision) + elif pull_request_id: + q = q.filter(cls.pull_request_id == pull_request_id) + return q.all() + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_5_2.py b/rhodecode/lib/dbmigrate/schema/db_1_5_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_5_2.py @@ -0,0 +1,1002 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix, remove_prefix +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name in ["ldap_active", + "default_repo_enable_statistics", + "default_repo_enable_locking", + "default_repo_private", + "default_repo_enable_downloads"]: + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + DEFAULT_USER = 'default' + DEFAULT_PERMISSIONS = [ + 'hg.register.manual_activate', 'hg.create.repository', + 'hg.fork.repository', 'repository.read', 'group.read' + ] + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + + def __unicode__(self): + return u'<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return user_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PERMS = [ + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repositories Group no access')), + ('group.read', _('Repositories Group read access')), + ('group.write', _('Repositories Group write access')), + ('group.admin', _('Repositories Group admin access')), + + ('hg.admin', _('RhodeCode Administrator')), + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + ('hg.register.none', _('Register disabled')), + ('hg.register.manual_activate', _('Register new user with RhodeCode ' + 'with manual activation')), + + ('hg.register.auto_activate', _('Register new user with RhodeCode ' + 'with auto activation')), + ] + + # defines which permissions are more important higher the more important + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository':1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<user:%s => %s >' % (self.user, self.repository) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<userGroup:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + @classmethod + def get_users(cls, revision=None, pull_request_id=None): + """ + Returns user associated with this ChangesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + q = Session().query(User)\ + .join(ChangesetComment.author) + if revision: + q = q.filter(cls.revision == revision) + elif pull_request_id: + q = q.filter(cls.pull_request_id == pull_request_id) + return q.all() + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_6_0.py b/rhodecode/lib/dbmigrate/schema/db_1_6_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_6_0.py @@ -0,0 +1,1087 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix, remove_prefix, time_to_datetime +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name in ["ldap_active", + "default_repo_enable_statistics", + "default_repo_enable_locking", + "default_repo_private", + "default_repo_enable_downloads"]: + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + DEFAULT_USER = 'default' + DEFAULT_PERMISSIONS = [ + 'hg.register.manual_activate', 'hg.create.repository', + 'hg.fork.repository', 'repository.read', 'group.read' + ] + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + + def __unicode__(self): + return u'<userGroup(%s)>' % (self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return user_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + #NOTE for this migration we are required tio have it + @hybrid_property + def changeset_cache(self): + from rhodecode.lib.vcs.backends.base import EmptyCommit + dummy = EmptyCommit().__json__() + if not self._changeset_cache: + return dummy + try: + return json.loads(self._changeset_cache) + except TypeError: + return dummy + + @changeset_cache.setter + def changeset_cache(self, val): + try: + self._changeset_cache = json.dumps(val) + except Exception: + log.error(traceback.format_exc()) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + #NOTE this is required for this migration to work + def update_commit_cache(self, cs_cache=None): + """ + Update cache of last changeset for repository, keys should be:: + + short_id + raw_id + revision + message + date + author + + :param cs_cache: + """ + from rhodecode.lib.vcs.backends.base import BaseChangeset + if cs_cache is None: + cs_cache = EmptyCommit() + # Note: Using always the empty commit here in case we are + # upgrading towards version 3.0 and above. Reason is that in this + # case the vcsclient connection is not available and things + # would explode here. + + if isinstance(cs_cache, BaseChangeset): + cs_cache = cs_cache.__json__() + + if (cs_cache != self.changeset_cache or not self.changeset_cache): + _default = datetime.datetime.fromtimestamp(0) + last_change = cs_cache.get('date') or _default + log.debug('updated repo %s with new cs cache %s' + % (self.repo_name, cs_cache)) + self.updated_on = last_change + self.changeset_cache = cs_cache + Session().add(self) + Session().commit() + else: + log.debug('Skipping repo:%s already with latest changes' + % self.repo_name) + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PERMS = [ + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('hg.admin', _('RhodeCode Administrator')), + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + ('hg.register.none', _('Register disabled')), + ('hg.register.manual_activate', _('Register new user with RhodeCode ' + 'with manual activation')), + + ('hg.register.auto_activate', _('Register new user with RhodeCode ' + 'with auto activation')), + ] + + # defines which permissions are more important higher the more important + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository':1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<user:%s => %s >' % (self.user, self.repository) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<userGroup:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + @classmethod + def get_users(cls, revision=None, pull_request_id=None): + """ + Returns user associated with this ChangesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + q = Session().query(User)\ + .join(ChangesetComment.author) + if revision: + q = q.filter(cls.revision == revision) + elif pull_request_id: + q = q.filter(cls.pull_request_id == pull_request_id) + return q.all() + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_7_0.py b/rhodecode/lib/dbmigrate/schema/db_1_7_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_7_0.py @@ -0,0 +1,1146 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix, remove_prefix, time_to_datetime +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + + def __init__(self, k='', v=''): + self.app_settings_name = k + self.app_settings_value = v + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name in ["ldap_active", + "default_repo_enable_statistics", + "default_repo_enable_locking", + "default_repo_private", + "default_repo_enable_downloads"]: + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + DEFAULT_USER = 'default' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, users_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % users_group_id)) + return user_group.get(users_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_1_8_0.py b/rhodecode/lib/dbmigrate/schema/db_1_8_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_1_8_0.py @@ -0,0 +1,1148 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_suffix, remove_prefix, time_to_datetime +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + if self.app_settings_name in ["ldap_active", + "default_repo_enable_statistics", + "default_repo_enable_locking", + "default_repo_private", + "default_repo_enable_downloads"]: + v = str2bool(v) + return v + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_0_0.py b/rhodecode/lib/dbmigrate/schema/db_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_0_0.py @@ -0,0 +1,1171 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + return safe_str(self.__unicode__()) + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + #for migration reasons, this is going to be later deleted + ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None) + + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + # don't trigger lazy load for migrations + #members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_0_1.py b/rhodecode/lib/dbmigrate/schema/db_2_0_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_0_1.py @@ -0,0 +1,1172 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + #TODO: create this field in migrations + #created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_0_2.py b/rhodecode/lib/dbmigrate/schema/db_2_0_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_0_2.py @@ -0,0 +1,1189 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + return q.scalar() + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + #NOTE: marcink, DO NOT REMOVE THOSE + @hybrid_property + def landing_rev(self): + # always should return [rev_type, rev] + if self._landing_revision: + _rev_info = self._landing_revision.split(':') + if len(_rev_info) < 2: + _rev_info.insert(0, 'rev') + return [_rev_info[0], _rev_info[1]] + return [None, None] + + @landing_rev.setter + def landing_rev(self, val): + if ':' not in val: + raise ValueError('value must be delimited with `:` and consist ' + 'of <rev_type>:<rev>, got %s instead' % val) + self._landing_revision = val + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_1_0.py b/rhodecode/lib/dbmigrate/schema/db_2_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_1_0.py @@ -0,0 +1,1206 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_2_0.py b/rhodecode/lib/dbmigrate/schema/db_2_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_2_0.py @@ -0,0 +1,1226 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int, \ + get_clone_url +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + #_user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_2_3.py b/rhodecode/lib/dbmigrate/schema/db_2_2_3.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_2_3.py @@ -0,0 +1,1232 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int, \ + get_clone_url +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username) + ) + ) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name) + ) + ) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name) + ) + ) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py b/rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py @@ -0,0 +1,1243 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int, \ + get_clone_url +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py b/rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py @@ -0,0 +1,1246 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import traceback +import hashlib +import collections +import functools + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \ + safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int, \ + get_clone_url +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + HOOK_PUSH = 'changegroup.push_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(cls.username.ilike(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(cls.email.ilike(email)) + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(UserEmailMap.email.ilike(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(cls.users_group_name.ilike(group_name)) + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(256), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query()\ + .filter(cls.group_name.ilike(group_name)) + else: + gr = cls.query()\ + .filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheInvalidation(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(256), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(256), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(256), nullable=False) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(256)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py b/rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py @@ -0,0 +1,1279 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import sys +import collections +import datetime +import functools +import logging +import os +import traceback +import time +import warnings +import itertools + +import ipaddress +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit + +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # GIT + HOOK_PRE_PULL_GIT = "preupload" + HOOK_PULL_GIT = "postupload" + HOOK_PRE_PUSH_GIT = "prereceive" + HOOK_PUSH_GIT = "postreceive" + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ] + + #definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(255), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(255), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(255), nullable=False) + + def __repr__(self): + return '<PullRequest #%s>' % (self.pull_request_id,) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py @@ -0,0 +1,1297 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import sys +import collections +import datetime +import functools +import hashlib +import logging +import os +import traceback +import time +import warnings +import itertools + +import ipaddress +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.backends.base import MergeFailureReason +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from zope.cachedescriptors.property import Lazy as LazyProperty +from rhodecode.lib.vcs.backends.base import EmptyCommit, Reference + +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # GIT + HOOK_PRE_PULL_GIT = "preupload" + HOOK_PULL_GIT = "postupload" + HOOK_PRE_PUSH_GIT = "prereceive" + HOOK_PUSH_GIT = "postreceive" + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(255), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(255), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column('last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column('last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + def __repr__(self): + return '<PullRequest #%s>' % (self.pull_request_id,) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py b/rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py @@ -0,0 +1,1340 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import base64 +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import itertools +import collections + + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from Crypto.Cipher import AES +from Crypto import Random +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(255), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(255), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column('last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column('last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + def __repr__(self): + return '<PullRequest #%s>' % (self.pull_request_id,) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py @@ -0,0 +1,1348 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import itertools +import collections + + +from sqlalchemy import * +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class PullRequest(Base, BaseModel): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True) + title = Column('title', Unicode(255), nullable=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True) + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + org_ref = Column('org_ref', Unicode(255), nullable=False) + other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column('last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column('last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + def __repr__(self): + return '<PullRequest #%s>' % (self.pull_request_id,) + + author = relationship('User', lazy='joined') + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id') + other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id') + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + ACL_LEVEL_PUBLIC = u'acl_public' + ACL_LEVEL_PRIVATE = u'acl_private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + acl_level = Column('acl_level', Unicode(128), nullable=True) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py b/rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py @@ -0,0 +1,1425 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import itertools +import collections + + +from sqlalchemy import * +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def org_repo_id(cls): + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + org_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def other_repo_id(cls): + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column('pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column('pull_request_id', Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py @@ -0,0 +1,1433 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import itertools +import collections + + +from sqlalchemy import * +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import OperationalError +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", String(1200000), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def org_repo_id(cls): + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + org_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def other_repo_id(cls): + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column( + 'pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column( + 'pull_request_id', Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column( + 'pull_requests_reviewers_id', Integer(), nullable=False, + primary_key=True) + pull_request_id = Column( + "pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py @@ -0,0 +1,1447 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import collections + + +from sqlalchemy import * +from sqlalchemy.exc import OperationalError +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import ( + relationship, joinedload, class_mapper, validates, aliased) +from sqlalchemy.sql.expression import true +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def username_or_name_or_email(self): + full_name = self.full_name if self.full_name is not ' ' else None + return self.username or full_name or self.email + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship('UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship('RepositoryField', + cascade="all, delete, delete-orphan") + + logs = relationship('UserLog') + comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan") + + pull_requests_org = relationship('PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + pull_requests_other = relationship('PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + COMMENT_OUTDATED = u'comment_outdated' + + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + display_state = Column('display_state', Unicode(128), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def org_repo_id(cls): + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + org_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def other_repo_id(cls): + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column( + 'pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column( + 'pull_request_id', Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column( + 'pull_requests_reviewers_id', Integer(), nullable=False, + primary_key=True) + pull_request_id = Column( + "pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + ACL_LEVEL_PUBLIC = u'acl_public' + ACL_LEVEL_PRIVATE = u'acl_private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + acl_level = Column('acl_level', Unicode(128), nullable=True) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py @@ -0,0 +1,1569 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import collections + + +from sqlalchemy import * +from sqlalchemy.exc import OperationalError +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import ( + relationship, joinedload, class_mapper, validates, aliased) +from sqlalchemy.sql.expression import true +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tuples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class RepoRhodeCodeSetting(Base, BaseModel): + __tablename__ = 'repo_rhodecode_settings' + __table_args__ = ( + UniqueConstraint( + 'app_settings_name', 'repository_id', + name='uq_repo_rhodecode_setting_name_repo_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + # TODO: Move it to some common place with RhodeCodeSetting + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + app_settings_id = Column( + "app_settings_id", Integer(), nullable=False, unique=True, + default=None, primary_key=True) + app_settings_name = Column( + "app_settings_name", String(255), nullable=True, unique=None, + default=None) + _app_settings_value = Column( + "app_settings_value", String(4096), nullable=True, unique=None, + default=None) + _app_settings_type = Column( + "app_settings_type", String(255), nullable=True, unique=None, + default=None) + + repository = relationship('Repository') + + def __init__(self, repository_id, key='', val='', type='unicode'): + self.repository_id = repository_id + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + type_ = self.app_settings_type + converter = ( + self.SETTINGS_TYPES.get(type_) or self.SETTINGS_TYPES['unicode']) + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s:%s[%s]')>" % ( + self.__class__.__name__, self.repository.repo_name, + self.app_settings_name, self.app_settings_value, + self.app_settings_type + ) + + +class RepoRhodeCodeUi(Base, BaseModel): + __tablename__ = 'repo_rhodecode_ui' + __table_args__ = ( + UniqueConstraint( + 'repository_id', 'ui_section', 'ui_key', + name='uq_repo_rhodecode_ui_repository_id_section_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + ui_id = Column( + "ui_id", Integer(), nullable=False, unique=True, default=None, + primary_key=True) + ui_section = Column( + "ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column( + "ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column( + "ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column( + "ui_active", Boolean(), nullable=True, unique=None, default=True) + + repository = relationship('Repository') + + def __repr__(self): + return '<%s[%s:%s]%s=>%s]>' % ( + self.__class__.__name__, self.repository.repo_name, + self.ui_section, self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def username_or_name_or_email(self): + full_name = self.full_name if self.full_name is not ' ' else None + return self.username or full_name or self.email + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship( + 'UserRepoToPerm', cascade='all', + order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship( + 'UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship( + 'RepositoryField', cascade="all, delete, delete-orphan") + logs = relationship('UserLog') + comments = relationship( + 'ChangesetComment', cascade="all, delete, delete-orphan") + pull_requests_org = relationship( + 'PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + pull_requests_other = relationship( + 'PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + ui = relationship('RepoRhodeCodeUi', cascade="all") + settings = relationship('RepoRhodeCodeSetting', cascade="all") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + COMMENT_OUTDATED = u'comment_outdated' + + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + display_state = Column('display_state', Unicode(128), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def org_repo_id(cls): + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + org_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def other_repo_id(cls): + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column( + 'pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column( + 'pull_request_id', Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column( + 'pull_requests_reviewers_id', Integer(), nullable=False, + primary_key=True) + pull_request_id = Column( + "pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + ACL_LEVEL_PUBLIC = u'acl_public' + ACL_LEVEL_PRIVATE = u'acl_private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + acl_level = Column('acl_level', Unicode(128), nullable=True) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py b/rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py @@ -0,0 +1,1594 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import collections + + +from sqlalchemy import * +from sqlalchemy.exc import OperationalError +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import ( + relationship, joinedload, class_mapper, validates, aliased) +from sqlalchemy.sql.expression import true +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +#============================================================================== +# BASE CLASSES +#============================================================================== + +_hash_key = lambda k: md5_safe(k) + + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + +# used to sort permissions by types, '#' used here is not allowed to be in +# usernames, and it's very early in sorted string.printable table. +PERMISSION_TYPE_SORT = { + 'admin': '####', + 'write': '###', + 'read': '##', + 'none': '#', +} + + +def display_sort(obj): + """ + Sort function used to sort permissions in .permissions() function of + Repository, RepoGroup, UserGroup. Also it put the default user in front + of all other resources + """ + + if obj.username == User.DEFAULT_USER: + return '#####' + prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '') + return prefix + obj.username + + +class EncryptedValue(TypeDecorator): + """ + Special column for encrypted data, use like:: + + value = Column("encrypted_value", EncryptedValue(40), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = String + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tuples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class RepoRhodeCodeSetting(Base, BaseModel): + __tablename__ = 'repo_rhodecode_settings' + __table_args__ = ( + UniqueConstraint( + 'app_settings_name', 'repository_id', + name='uq_repo_rhodecode_setting_name_repo_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + # TODO: Move it to some common place with RhodeCodeSetting + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + app_settings_id = Column( + "app_settings_id", Integer(), nullable=False, unique=True, + default=None, primary_key=True) + app_settings_name = Column( + "app_settings_name", String(255), nullable=True, unique=None, + default=None) + _app_settings_value = Column( + "app_settings_value", String(4096), nullable=True, unique=None, + default=None) + _app_settings_type = Column( + "app_settings_type", String(255), nullable=True, unique=None, + default=None) + + repository = relationship('Repository') + + def __init__(self, repository_id, key='', val='', type='unicode'): + self.repository_id = repository_id + self.app_settings_name = key + self.app_settings_value = val + self.app_settings_type = type + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + type_ = self.app_settings_type + converter = ( + self.SETTINGS_TYPES.get(type_) or self.SETTINGS_TYPES['unicode']) + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s:%s[%s]')>" % ( + self.__class__.__name__, self.repository.repo_name, + self.app_settings_name, self.app_settings_value, + self.app_settings_type + ) + + +class RepoRhodeCodeUi(Base, BaseModel): + __tablename__ = 'repo_rhodecode_ui' + __table_args__ = ( + UniqueConstraint( + 'repository_id', 'ui_section', 'ui_key', + name='uq_repo_rhodecode_ui_repository_id_section_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + ui_id = Column( + "ui_id", Integer(), nullable=False, unique=True, default=None, + primary_key=True) + ui_section = Column( + "ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column( + "ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column( + "ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column( + "ui_active", Boolean(), nullable=True, unique=None, default=True) + + repository = relationship('Repository') + + def __repr__(self): + return '<%s[%s:%s]%s=>%s]>' % ( + self.__class__.__name__, self.repository.repo_name, + self.ui_section, self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + user_emails = relationship('UserEmailMap', cascade='all') + user_ip_map = relationship('UserIpMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def username_or_name_or_email(self): + full_name = self.full_name if self.full_name is not ' ' else None + return self.username or full_name or self.email + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + UniqueConstraint('repo_name'), + Index('r_repo_name_idx', 'repo_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + NAME_SEP = URL_SEP + + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None) + repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + _locked = Column("locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data + + fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship( + 'UserRepoToPerm', cascade='all', + order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship( + 'UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship( + 'RepositoryField', cascade="all, delete, delete-orphan") + logs = relationship('UserLog') + comments = relationship( + 'ChangesetComment', cascade="all, delete, delete-orphan") + pull_requests_org = relationship( + 'PullRequest', + primaryjoin='PullRequest.org_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + pull_requests_other = relationship( + 'PullRequest', + primaryjoin='PullRequest.other_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + ui = relationship('RepoRhodeCodeUi', cascade="all") + settings = relationship('RepoRhodeCodeSetting', cascade="all") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + COMMENT_OUTDATED = u'comment_outdated' + + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + display_state = Column('display_state', Unicode(128), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def org_repo_id(cls): + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + org_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def other_repo_id(cls): + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + other_ref = Column('other_ref', Unicode(255), nullable=False) + _last_merge_org_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column( + 'pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column( + 'pull_request_id', Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column( + 'pull_requests_reviewers_id', Integer(), nullable=False, + primary_key=True) + pull_request_id = Column( + "pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + ACL_LEVEL_PUBLIC = u'acl_public' + ACL_LEVEL_PRIVATE = u'acl_private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + acl_level = Column('acl_level', Unicode(128), nullable=True) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) diff --git a/rhodecode/lib/dbmigrate/versions/001_initial_release.py b/rhodecode/lib/dbmigrate/versions/001_initial_release.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/001_initial_release.py @@ -0,0 +1,205 @@ +#============================================================================== +# DB INITIAL MODEL +#============================================================================== +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session +from rhodecode.model.meta import Base + +from rhodecode.lib.dbmigrate.migrate import * + +log = logging.getLogger(__name__) + +class RhodeCodeSetting(Base): + __tablename__ = 'rhodecode_settings' + __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True}) + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + + def __init__(self, k, v): + self.app_settings_name = k + self.app_settings_value = v + + def __repr__(self): + return "<RhodeCodeSetting('%s:%s')>" % (self.app_settings_name, + self.app_settings_value) + +class RhodeCodeUi(Base): + __tablename__ = 'rhodecode_ui' + __table_args__ = {'useexisting':True} + ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + ui_section = Column("ui_section", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) + + +class User(Base): + __tablename__ = 'users' + __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True}) + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + password = Column("password", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=None) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("name", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + email = Column("email", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False) + + user_log = relation('UserLog', cascade='all') + user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relation('Repository') + user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + + @property + def full_contact(self): + return '%s %s <%s>' % (self.name, self.lastname, self.email) + + def __repr__(self): + return "<User('id:%s:%s')>" % (self.user_id, self.username) + + def update_lastlogin(self): + """Update user lastlogin""" + + try: + session = Session.object_session(self) + self.last_login = datetime.datetime.now() + session.add(self) + session.commit() + log.debug('updated user %s lastlogin' % self.username) + except (DatabaseError,): + session.rollback() + + +class UserLog(Base): + __tablename__ = 'user_logs' + __table_args__ = {'useexisting':True} + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, ), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) + repository_name = Column("repository_name", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + action = Column("action", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + user = relation('User') + repository = relation('Repository') + +class Repository(Base): + __tablename__ = 'repositories' + __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},) + repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repo_name = Column("repo_name", String(length=None, convert_unicode=False, ), nullable=False, unique=True, default=None) + repo_type = Column("repo_type", String(length=None, convert_unicode=False, ), nullable=False, unique=False, default=None) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None) + private = Column("private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + fork_id = Column("fork_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None) + + user = relation('User') + fork = relation('Repository', remote_side=repo_id) + repo_to_perm = relation('UserRepoToPerm', cascade='all') + stats = relation('Statistics', cascade='all', uselist=False) + + repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') + + + def __repr__(self): + return "<Repository('%s:%s')>" % (self.repo_id, self.repo_name) + +class Permission(Base): + __tablename__ = 'permissions' + __table_args__ = {'useexisting':True} + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, ), nullable=True, unique=None, default=None) + + def __repr__(self): + return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name) + +class UserRepoToPerm(Base): + __tablename__ = 'repo_to_perm' + __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True}) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relation('User') + permission = relation('Permission') + repository = relation('Repository') + +class UserToPerm(Base): + __tablename__ = 'user_to_perm' + __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True}) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relation('User') + permission = relation('Permission') + +class Statistics(Base): + __tablename__ = 'statistics' + __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True}) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(), nullable=False)#JSON data + + repository = relation('Repository', single_parent=True) + +class UserFollowing(Base): + __tablename__ = 'user_followings' + __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id') + , {'useexisting':True}) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None) + + user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relation('Repository') + + +class CacheInvalidation(Base): + __tablename__ = 'cache_invalidation' + __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True}) + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(length=None, convert_unicode=False), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(length=None, convert_unicode=False), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + def __repr__(self): + return "<CacheKey('%s:%s')>" % (self.cache_id, self.cache_key) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; bind migrate_engine + # to your metadata + Base.metadata.create_all(bind=migrate_engine, checkfirst=False) + +def downgrade(migrate_engine): + # Operations to reverse the above upgrade go here. + Base.metadata.drop_all(bind=migrate_engine, checkfirst=False) diff --git a/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py b/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py @@ -0,0 +1,84 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session +from rhodecode.model.meta import Base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + + #========================================================================== + # Upgrade of `users` table + #========================================================================== + tblname = 'users' + tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + + #ADD is_ldap column + is_ldap = Column("is_ldap", Boolean(), nullable=True, + unique=None, default=False) + is_ldap.create(tbl, populate_default=True) + is_ldap.alter(nullable=False) + + #========================================================================== + # Upgrade of `user_logs` table + #========================================================================== + + tblname = 'users' + tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + + #ADD revision column + revision = Column('revision', TEXT(length=None, convert_unicode=False, + ), + nullable=True, unique=None, default=None) + revision.create(tbl) + + #========================================================================== + # Upgrade of `repositories` table + #========================================================================== + tblname = 'repositories' + tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + + #ADD repo_type column# + repo_type = Column("repo_type", String(length=None, convert_unicode=False), + nullable=True, unique=False, default='hg') + + repo_type.create(tbl, populate_default=True) + #repo_type.alter(nullable=False) + + #ADD statistics column# + enable_statistics = Column("statistics", Boolean(), nullable=True, + unique=None, default=True) + enable_statistics.create(tbl) + + #========================================================================== + # Add table `user_followings` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_1_0 import UserFollowing + UserFollowing().__table__.create() + + #========================================================================== + # Add table `cache_invalidation` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_1_0 import CacheInvalidation + CacheInvalidation().__table__.create() + + return + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py b/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py @@ -0,0 +1,117 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + + #========================================================================== + # Add table `groups`` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import Group as Group + Group().__table__.create() + + #========================================================================== + # Add table `group_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserRepoGroupToPerm + UserRepoGroupToPerm().__table__.create() + + #========================================================================== + # Add table `users_groups` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroup + UserGroup().__table__.create() + + #========================================================================== + # Add table `users_groups_members` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupMember + UserGroupMember().__table__.create() + + #========================================================================== + # Add table `users_group_repo_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupRepoToPerm + UserGroupRepoToPerm().__table__.create() + + #========================================================================== + # Add table `users_group_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupToPerm + UserGroupToPerm().__table__.create() + + #========================================================================== + # Upgrade of `users` table + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import User + + #add column + ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, ), nullable=True, unique=None, default=None) + ldap_dn.create(User().__table__) + + api_key = Column("api_key", String(length=255, convert_unicode=False, ), nullable=True, unique=None, default=None) + api_key.create(User().__table__) + + #remove old column + is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False) + is_ldap.drop(User().__table__) + + #========================================================================== + # Upgrade of `repositories` table + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import Repository + + #ADD clone_uri column# + + clone_uri = Column("clone_uri", String(length=255, convert_unicode=False), + nullable=True, unique=False, default=None) + + clone_uri.create(Repository().__table__) + + #ADD downloads column# + enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) + enable_downloads.create(Repository().__table__) + + #ADD column created_on + created_on = Column('created_on', DateTime(timezone=False), nullable=True, + unique=None, default=datetime.datetime.now) + created_on.create(Repository().__table__) + + #ADD group_id column# + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), + nullable=True, unique=False, default=None) + + group_id.create(Repository().__table__) + + #========================================================================== + # Upgrade of `user_followings` table + #========================================================================== + + from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserFollowing + + follows_from = Column('follows_from', DateTime(timezone=False), + nullable=True, unique=None, + default=datetime.datetime.now) + follows_from.create(UserFollowing().__table__) + + return + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py b/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py @@ -0,0 +1,74 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + #========================================================================== + # Add table `users_group_repo_group_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroupRepoGroupToPerm + UserGroupRepoGroupToPerm().__table__.create() + + #========================================================================== + # Add table `changeset_comments` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import ChangesetComment + ChangesetComment().__table__.create() + + #========================================================================== + # Add table `notifications` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import Notification + Notification().__table__.create() + + #========================================================================== + # Add table `user_to_notification` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserNotification + UserNotification().__table__.create() + + #========================================================================== + # Add unique to table `users_group_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroupToPerm + tbl = UserGroupToPerm().__table__ + cons = UniqueConstraint('users_group_id', 'permission_id', table=tbl) + cons.create() + + #========================================================================== + # Fix unique constrain on table `user_logs` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserLog + tbl = UserLog().__table__ + col = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False, unique=None, default=None) + col.alter(nullable=True, table=tbl) + + #========================================================================== + # Rename table `group_to_perm` to `user_repo_group_to_perm` + #========================================================================== + tbl = Table('group_to_perm', MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + tbl.rename('user_repo_group_to_perm') + + return + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/005_version_1_3_0.py b/rhodecode/lib/dbmigrate/versions/005_version_1_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/005_version_1_3_0.py @@ -0,0 +1,79 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + + #========================================================================== + # Change unique constraints of table `repo_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserRepoToPerm + tbl = UserRepoToPerm().__table__ + new_cons = UniqueConstraint('user_id', 'repository_id', 'permission_id', table=tbl) + new_cons.create() + old_cons = None + if migrate_engine.name in ['mysql']: + old_cons = UniqueConstraint('user_id', 'repository_id', table=tbl, name="user_id") + elif migrate_engine.name in ['postgresql']: + old_cons = UniqueConstraint('user_id', 'repository_id', table=tbl) + else: + # sqlite doesn't support dropping constraints... + print """Please manually drop UniqueConstraint('user_id', 'repository_id')""" + + if old_cons: + try: + old_cons.drop() + except Exception as e: + # we don't care if this fails really... better to pass migration than + # leave this in intermidiate state + print 'Failed to remove Unique for user_id, repository_id reason %s' % e + + + #========================================================================== + # fix uniques of table `user_repo_group_to_perm` + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserRepoGroupToPerm + tbl = UserRepoGroupToPerm().__table__ + new_cons = UniqueConstraint('group_id', 'permission_id', 'user_id', table=tbl) + new_cons.create() + old_cons = None + + # fix uniqueConstraints + if migrate_engine.name in ['mysql']: + #mysql is givinig troubles here... + old_cons = UniqueConstraint('group_id', 'permission_id', table=tbl, name="group_id") + elif migrate_engine.name in ['postgresql']: + old_cons = UniqueConstraint('group_id', 'permission_id', table=tbl, name='group_to_perm_group_id_permission_id_key') + else: + # sqlite doesn't support dropping constraints... + print """Please manually drop UniqueConstraint('group_id', 'permission_id')""" + + if old_cons: + try: + old_cons.drop() + except Exception as e: + # we don't care if this fails really... better to pass migration than + # leave this in intermidiate state + print 'Failed to remove Unique for user_id, repository_id reason %s' % e + + return + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py b/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py @@ -0,0 +1,177 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + + #========================================================================== + # USEREMAILMAP + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import UserEmailMap + tbl = UserEmailMap.__table__ + tbl.create() + #========================================================================== + # PULL REQUEST + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import PullRequest + tbl = PullRequest.__table__ + tbl.create() + + #========================================================================== + # PULL REQUEST REVIEWERS + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import PullRequestReviewers + tbl = PullRequestReviewers.__table__ + tbl.create() + + #========================================================================== + # CHANGESET STATUS + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import ChangesetStatus + tbl = ChangesetStatus.__table__ + tbl.create() + + _reset_base(migrate_engine) + + #========================================================================== + # USERS TABLE + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import User + tbl = User.__table__ + + # change column name -> firstname + col = User.__table__.columns.name + col.alter(index=Index('u_username_idx', 'username')) + col.alter(index=Index('u_email_idx', 'email')) + col.alter(name="firstname", table=tbl) + + # add inherit_default_permission column + inherit_default_permissions = Column("inherit_default_permissions", + Boolean(), nullable=True, unique=None, + default=True) + inherit_default_permissions.create(table=tbl) + inherit_default_permissions.alter(nullable=False, default=True, table=tbl) + + #========================================================================== + # USERS GROUP TABLE + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroup + tbl = UserGroup.__table__ + # add inherit_default_permission column + gr_inherit_default_permissions = Column( + "users_group_inherit_default_permissions", + Boolean(), nullable=True, unique=None, + default=True) + gr_inherit_default_permissions.create(table=tbl) + gr_inherit_default_permissions.alter(nullable=False, default=True, table=tbl) + + #========================================================================== + # REPOSITORIES + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import Repository + tbl = Repository.__table__ + + # add enable locking column + enable_locking = Column("enable_locking", Boolean(), nullable=True, + unique=None, default=False) + enable_locking.create(table=tbl) + enable_locking.alter(nullable=False, default=False, table=tbl) + + # add locked column + _locked = Column("locked", String(255), nullable=True, unique=False, + default=None) + _locked.create(table=tbl) + + #add langing revision column + landing_rev = Column("landing_revision", String(255), nullable=True, + unique=False, default='tip') + landing_rev.create(table=tbl) + landing_rev.alter(nullable=False, default='tip', table=tbl) + + #========================================================================== + # GROUPS + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import RepoGroup + tbl = RepoGroup.__table__ + + # add enable locking column + enable_locking = Column("enable_locking", Boolean(), nullable=True, + unique=None, default=False) + enable_locking.create(table=tbl) + enable_locking.alter(nullable=False, default=False) + + #========================================================================== + # CACHE INVALIDATION + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import CacheInvalidation + tbl = CacheInvalidation.__table__ + + # add INDEX for cache keys + col = CacheInvalidation.__table__.columns.cache_key + col.alter(index=Index('key_idx', 'cache_key')) + + #========================================================================== + # NOTIFICATION + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import Notification + tbl = Notification.__table__ + + # add index for notification type + col = Notification.__table__.columns.type + col.alter(index=Index('notification_type_idx', 'type'),) + + #========================================================================== + # CHANGESET_COMMENTS + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_3_0 import ChangesetComment + + tbl = ChangesetComment.__table__ + col = ChangesetComment.__table__.columns.revision + + # add index for revisions + col.alter(index=Index('cc_revision_idx', 'revision'),) + + # add hl_lines column + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + hl_lines.create(table=tbl) + + # add created_on column + created_on = Column('created_on', DateTime(timezone=False), nullable=True, + default=datetime.datetime.now) + created_on.create(table=tbl) + created_on.alter(nullable=False, default=datetime.datetime.now) + + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + modified_at.alter(type=DateTime(timezone=False), table=tbl) + + # add FK to pull_request + pull_request_id = Column("pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), + nullable=True) + pull_request_id.create(table=tbl) + _reset_base(migrate_engine) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/007_version_1_4_0.py b/rhodecode/lib/dbmigrate/versions/007_version_1_4_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/007_version_1_4_0.py @@ -0,0 +1,51 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + + #========================================================================== + # CHANGESET_COMMENTS + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import ChangesetComment + tbl_name = ChangesetComment.__tablename__ + tbl = Table(tbl_name, + MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + col = tbl.columns.revision + + # remove nullability from revision field + col.alter(nullable=True) + + #========================================================================== + # REPOSITORY + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_4_0 import Repository + tbl = Repository.__table__ + updated_on = Column('updated_on', DateTime(timezone=False), + nullable=True, unique=None) + # create created on column for future lightweight main page + updated_on.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/008_version_1_5_0.py b/rhodecode/lib/dbmigrate/versions/008_version_1_5_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/008_version_1_5_0.py @@ -0,0 +1,135 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_5_0 + #========================================================================== + # USER LOGS + #========================================================================== + + tbl = db_1_5_0.UserLog.__table__ + username = Column("username", String(255, convert_unicode=False), + nullable=True, unique=None, default=None) + # create username column + username.create(table=tbl) + + _Session = meta.Session() + ## after adding that column fix all usernames + users_log = _Session.query(db_1_5_0.UserLog)\ + .options(joinedload(db_1_5_0.UserLog.user))\ + .options(joinedload(db_1_5_0.UserLog.repository)).all() + + for entry in users_log: + entry.username = entry.user.username + _Session.add(entry) + _Session.commit() + + #alter username to not null + tbl_name = db_1_5_0.UserLog.__tablename__ + tbl = Table(tbl_name, + MetaData(bind=migrate_engine), autoload=True, + autoload_with=migrate_engine) + col = tbl.columns.username + + # remove nullability from revision field + col.alter(nullable=False) + + # issue fixups + fixups(db_1_5_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def fixups(models, _SESSION): + # ** create default permissions ** # + #===================================== + for p in models.Permission.PERMS: + if not get_by_key(models.Permission, p[0]): + new_perm = models.Permission() + new_perm.permission_name = p[0] + new_perm.permission_longname = p[0] #translation err with p[1] + print 'Creating new permission %s' % p[0] + _SESSION().add(new_perm) + + _SESSION().commit() + + # ** populate default permissions ** # + #===================================== + + user = models.User.query().filter(models.User.username == 'default').scalar() + + def _make_perm(perm): + new_perm = models.UserToPerm() + new_perm.user = user + new_perm.permission = get_by_key(models.Permission, perm) + return new_perm + + def _get_group(perm_name): + return '.'.join(perm_name.split('.')[:1]) + + perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all() + defined_perms_groups = map( + _get_group, (x.permission.permission_name for x in perms)) + log.debug('GOT ALREADY DEFINED:%s' % perms) + DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS + + # for every default permission that needs to be created, we check if + # it's group is already defined, if it's not we create default perm + for perm_name in DEFAULT_PERMS: + gr = _get_group(perm_name) + if gr not in defined_perms_groups: + log.debug('GR:%s not found, creating permission %s' + % (gr, perm_name)) + new_perm = _make_perm(perm_name) + _SESSION().add(new_perm) + _SESSION().commit() + + # ** create default options ** # + #=============================== + skip_existing = True + for k, v in [ + ('default_repo_enable_locking', False), + ('default_repo_enable_downloads', False), + ('default_repo_enable_statistics', False), + ('default_repo_private', False), + ('default_repo_type', 'hg')]: + + if skip_existing and get_by_name(models.RhodeCodeSetting, k) is not None: + log.debug('Skipping option %s' % k) + continue + setting = models.RhodeCodeSetting(k, v) + _SESSION().add(setting) + + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/009_version_1_5_1.py b/rhodecode/lib/dbmigrate/versions/009_version_1_5_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/009_version_1_5_1.py @@ -0,0 +1,28 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + pass + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/010_version_1_5_2.py b/rhodecode/lib/dbmigrate/versions/010_version_1_5_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/010_version_1_5_2.py @@ -0,0 +1,46 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_5_2 + #========================================================================== + # USER LOGS + #========================================================================== + tbl = db_1_5_2.UserIpMap.__table__ + tbl.create() + + #========================================================================== + # REPOSITORIES + #========================================================================== + tbl = db_1_5_2.Repository.__table__ + changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) + # create username column + changeset_cache.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + diff --git a/rhodecode/lib/dbmigrate/versions/011_version_1_6_0.py b/rhodecode/lib/dbmigrate/versions/011_version_1_6_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/011_version_1_6_0.py @@ -0,0 +1,49 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_6_0 + + #========================================================================== + # USER LOGS + #========================================================================== + tbl = db_1_6_0.RepositoryField.__table__ + tbl.create() + + # issue fixups + fixups(db_1_6_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Upgrading repositories Caches') + repositories = models.Repository.getAll() + for repo in repositories: + print repo + repo.update_commit_cache() + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py b/rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py @@ -0,0 +1,150 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_7_0 + + #========================================================================== + # UserUserGroupToPerm + #========================================================================== + tbl = db_1_7_0.UserUserGroupToPerm.__table__ + tbl.create() + + #========================================================================== + # UserGroupUserGroupToPerm + #========================================================================== + tbl = db_1_7_0.UserGroupUserGroupToPerm.__table__ + tbl.create() + + #========================================================================== + # Gist + #========================================================================== + tbl = db_1_7_0.Gist.__table__ + tbl.create() + + #========================================================================== + # UserGroup + #========================================================================== + tbl = db_1_7_0.UserGroup.__table__ + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), + nullable=True, unique=False, default=None) + # create username column + user_id.create(table=tbl) + + #========================================================================== + # RepoGroup + #========================================================================== + tbl = db_1_7_0.RepoGroup.__table__ + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), + nullable=True, unique=False, default=None) + # create username column + user_id.create(table=tbl) + + # issue fixups + fixups(db_1_7_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + # ** create default permissions ** # + #===================================== + for p in models.Permission.PERMS: + if not models.Permission.get_by_key(p[0]): + new_perm = models.Permission() + new_perm.permission_name = p[0] + new_perm.permission_longname = p[0] #translation err with p[1] + _SESSION().add(new_perm) + + _SESSION().commit() + + # ** populate default permissions ** # + #===================================== + + user = models.User.query().filter(models.User.username == 'default').scalar() + + def _make_perm(perm): + new_perm = models.UserToPerm() + new_perm.user = user + new_perm.permission = models.Permission.get_by_key(perm) + return new_perm + + def _get_group(perm_name): + return '.'.join(perm_name.split('.')[:1]) + + perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all() + defined_perms_groups = map(_get_group, + (x.permission.permission_name for x in perms)) + log.debug('GOT ALREADY DEFINED:%s' % perms) + DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS + + # for every default permission that needs to be created, we check if + # it's group is already defined, if it's not we create default perm + for perm_name in DEFAULT_PERMS: + gr = _get_group(perm_name) + if gr not in defined_perms_groups: + log.debug('GR:%s not found, creating permission %s' + % (gr, perm_name)) + new_perm = _make_perm(perm_name) + _SESSION().add(new_perm) + _SESSION().commit() + + #fix all usergroups + + def _create_default_perms(user_group): + # create default permission + default_perm = 'usergroup.read' + def_user = models.User.get_default_user() + for p in def_user.user_perms: + if p.permission.permission_name.startswith('usergroup.'): + default_perm = p.permission.permission_name + break + + user_group_to_perm = models.UserUserGroupToPerm() + user_group_to_perm.permission = models.Permission.get_by_key(default_perm) + + user_group_to_perm.user_group = user_group + user_group_to_perm.user_id = def_user.user_id + return user_group_to_perm + + for ug in models.UserGroup.get_all(): + perm_obj = _create_default_perms(ug) + _SESSION().add(perm_obj) + _SESSION().commit() + + adm = models.User.get_first_admin() + # fix owners of UserGroup + for ug in _SESSION().query(models.UserGroup).all(): + ug.user_id = adm.user_id + _SESSION().add(ug) + _SESSION().commit() + + # fix owners of RepoGroup + for ug in _SESSION().query(models.RepoGroup).all(): + ug.user_id = adm.user_id + _SESSION().add(ug) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/013_version_1_7_0.py b/rhodecode/lib/dbmigrate/versions/013_version_1_7_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/013_version_1_7_0.py @@ -0,0 +1,47 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + + + #========================================================================== + # UserGroup + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserGroup + tbl = UserGroup.__table__ + user_id = tbl.columns.user_id + user_id.alter(nullable=False) + + #========================================================================== + # RepoGroup + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import RepoGroup + tbl = RepoGroup.__table__ + user_id = tbl.columns.user_id + user_id.alter(nullable=False) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/014_version_1_7_1.py b/rhodecode/lib/dbmigrate/versions/014_version_1_7_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/014_version_1_7_1.py @@ -0,0 +1,50 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_7_0 + + #========================================================================== + # Gist + #========================================================================== + tbl = db_1_7_0.Gist.__table__ + user_id = tbl.columns.gist_expires + user_id.alter(type=Float(53)) + + # issue fixups + fixups(db_1_7_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + # fix nullable columns on last_update + for r in models.Repository().get_all(): + if r.updated_on is None: + r.updated_on = datetime.datetime.fromtimestamp(0) + _SESSION().add(r) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/015_version_1_8_0.py b/rhodecode/lib/dbmigrate/versions/015_version_1_8_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/015_version_1_8_0.py @@ -0,0 +1,86 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_1_8_0 + tbl = db_1_8_0.RhodeCodeSetting.__table__ + app_settings_type = Column("app_settings_type", + String(255, convert_unicode=False), + nullable=True, unique=None, default=None) + app_settings_type.create(table=tbl) + + # issue fixups + fixups(db_1_8_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing default options now...') + + settings = [ + #general + ('realm', '', 'unicode'), + ('title', '', 'unicode'), + ('ga_code', '', 'unicode'), + ('show_public_icon', False, 'bool'), + ('show_private_icon', True, 'bool'), + ('stylify_metatags', True, 'bool'), + + # defaults + ('default_repo_enable_locking', False, 'bool'), + ('default_repo_enable_downloads', False, 'bool'), + ('default_repo_enable_statistics', False, 'bool'), + ('default_repo_private', False, 'bool'), + ('default_repo_type', 'hg', 'unicode'), + + #other + ('dashboard_items', 100, 'int'), + ('show_version', True, 'bool') + ] + + for name, default, type_ in settings: + setting = get_by_name(models.RhodeCodeSetting, name) + if not setting: + # if we don't have this option create it + setting = models.RhodeCodeSetting(name, default, type_) + + # fix certain key to new defaults + if name in ['title', 'show_public_icon']: + # change title if it's only the default + if name == 'title' and setting.app_settings_value == 'RhodeCode': + setting.app_settings_value = default + else: + setting.app_settings_value = default + + setting._app_settings_type = type_ + _SESSION().add(setting) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/016_version_2_0_0.py b/rhodecode/lib/dbmigrate/versions/016_version_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/016_version_2_0_0.py @@ -0,0 +1,69 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_0 + tbl = db_2_0_0.User.__table__ + + extern_type = Column("extern_type", + String(255, convert_unicode=False, ), + nullable=True, unique=None, default=None) + extern_type.create(table=tbl) + + extern_name = Column("extern_name", String(255, convert_unicode=False), + nullable=True, unique=None, default=None) + extern_name.create(table=tbl) + + created_on = Column('created_on', DateTime(timezone=False), + nullable=True, default=datetime.datetime.now) + created_on.create(table=tbl) + + # issue fixups + fixups(db_2_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing default created on') + + for usr in models.User.get_all(): + usr.created_on = datetime.datetime.now() + _SESSION().add(usr) + _SESSION().commit() + + notify('Migrating LDAP attribute to extern') + for usr in models.User.get_all(): + ldap_dn = usr.ldap_dn + if ldap_dn: + usr.extern_name = ldap_dn + usr.extern_type = 'ldap' + else: + usr.extern_name = 'rhodecode' + usr.extern_type = 'rhodecode' + _SESSION().add(usr) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/017_version_2_0_0.py b/rhodecode/lib/dbmigrate/versions/017_version_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/017_version_2_0_0.py @@ -0,0 +1,52 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_0 + tbl = db_2_0_0.UserGroup.__table__ + + user_group_description = Column("user_group_description", + String(10000, convert_unicode=False), + nullable=True, unique=None, default=None) + user_group_description.create(table=tbl) + + created_on = Column('created_on', DateTime(timezone=False), + nullable=True, default=datetime.datetime.now) + created_on.create(table=tbl) + + # issue fixups + fixups(db_2_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing default created on') + + for gr in models.UserGroup.get_all(): + gr.created_on = datetime.datetime.now() + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/018_version_2_0_0.py b/rhodecode/lib/dbmigrate/versions/018_version_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/018_version_2_0_0.py @@ -0,0 +1,82 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_0 + + # issue fixups + fixups(db_2_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing default auth modules') + plugins = 'rhodecode.lib.auth_modules.auth_rhodecode' + opts = [] + ldap_enabled = str2bool(getattr( + get_by_name(models.RhodeCodeSetting, 'ldap_active'), + 'app_settings_value', False)) + if ldap_enabled: + plugins += ',rhodecode.lib.auth_modules.auth_ldap' + opts.append(('auth_ldap_enabled', 'True', 'bool')) + + opts.append(('auth_plugins', plugins, 'list'),) + opts.append(('auth_rhodecode_enabled', 'True', 'bool')) + + for name, default, type_ in opts: + setting = get_by_name(models.RhodeCodeSetting, name) + if not setting: + # if we don't have this option create it + setting = models.RhodeCodeSetting(name, default, type_) + + _SESSION().add(setting) + _SESSION().commit() + + #copy over the LDAP settings + old_ldap = [('ldap_active', 'false', 'bool'), ('ldap_host', '', 'unicode'), + ('ldap_port', '389', 'int'), ('ldap_tls_kind', 'PLAIN', 'unicode'), + ('ldap_tls_reqcert', '', 'unicode'), ('ldap_dn_user', '', 'unicode'), + ('ldap_dn_pass', '', 'unicode'), ('ldap_base_dn', '', 'unicode'), + ('ldap_filter', '', 'unicode'), ('ldap_search_scope', '', 'unicode'), + ('ldap_attr_login', '', 'unicode'), ('ldap_attr_firstname', '', 'unicode'), + ('ldap_attr_lastname', '', 'unicode'), ('ldap_attr_email', '', 'unicode')] + for k, v, t in old_ldap: + old_setting = get_by_name(models.RhodeCodeSetting, k) + name = 'auth_%s' % k + setting = get_by_name(models.RhodeCodeSetting, name) + if not setting: + # if we don't have this option create it + setting = models.RhodeCodeSetting(name, old_setting.app_settings_value, t) + + _SESSION().add(setting) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/019_version_2_0_0.py b/rhodecode/lib/dbmigrate/versions/019_version_2_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/019_version_2_0_0.py @@ -0,0 +1,42 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_0 + tbl = db_2_0_0.RhodeCodeSetting.__table__ + settings_value = tbl.columns.app_settings_value + settings_value.alter(type=String(4096)) + + # issue fixups + fixups(db_2_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + return diff --git a/rhodecode/lib/dbmigrate/versions/020_version_2_0_1.py b/rhodecode/lib/dbmigrate/versions/020_version_2_0_1.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/020_version_2_0_1.py @@ -0,0 +1,45 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_1 + + # issue fixups + fixups(db_2_0_1, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + # fix all empty extern type users to default 'rhodecode' + for usr in models.User.query().all(): + if not usr.extern_name: + usr.extern_name = 'rhodecode' + usr.extern_type = 'rhodecode' + _SESSION().add(usr) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/021_version_2_0_2.py b/rhodecode/lib/dbmigrate/versions/021_version_2_0_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/021_version_2_0_2.py @@ -0,0 +1,85 @@ +import os +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_key(cls, key): + return cls.query().filter(cls.ui_key == key).scalar() + + +def get_repos_location(cls): + return get_by_key(cls, '/').ui_value + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_1 + tbl = db_2_0_1.RepoGroup.__table__ + + created_on = Column('created_on', DateTime(timezone=False), nullable=True, + default=datetime.datetime.now) + created_on.create(table=tbl) + + #fix null values on certain columns when upgrading from older releases + tbl = db_2_0_1.UserLog.__table__ + col = tbl.columns.user_id + col.alter(nullable=True) + + tbl = db_2_0_1.UserFollowing.__table__ + col = tbl.columns.follows_repository_id + col.alter(nullable=True) + + tbl = db_2_0_1.UserFollowing.__table__ + col = tbl.columns.follows_user_id + col.alter(nullable=True) + + # issue fixups + fixups(db_2_0_1, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing default created on for repo groups') + + for gr in models.RepoGroup.get_all(): + gr.created_on = datetime.datetime.now() + _SESSION().add(gr) + _SESSION().commit() + + repo_store_path = get_repos_location(models.RhodeCodeUi) + _store = os.path.join(repo_store_path, '.cache', 'largefiles') + notify('Setting largefiles usercache') + print _store + + if not models.RhodeCodeUi.query().filter( + models.RhodeCodeUi.ui_key == 'usercache').scalar(): + largefiles = models.RhodeCodeUi() + largefiles.ui_section = 'largefiles' + largefiles.ui_key = 'usercache' + largefiles.ui_value = _store + _SESSION().add(largefiles) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/022_version_2_0_2.py b/rhodecode/lib/dbmigrate/versions/022_version_2_0_2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/022_version_2_0_2.py @@ -0,0 +1,70 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_0_2 + + # issue fixups + fixups(db_2_0_2, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('fixing new schema for landing_rev') + + for repo in models.Repository.get_all(): + print u'repo %s old landing rev is: %s' % (repo, repo.landing_rev) + _rev = repo.landing_rev[1] + _rev_type = 'rev' # default + + if _rev in ['default', 'master']: + _rev_type = 'branch' + elif _rev in ['tip']: + _rev_type = 'rev' + else: + try: + scm = repo.scm_instance + if scm: + known_branches = scm.branches.keys() + known_bookmarks = scm.bookmarks.keys() + if _rev in known_branches: + _rev_type = 'branch' + elif _rev in known_bookmarks: + _rev_type = 'book' + except Exception as e: + print e + print 'continue...' + #we don't want any error to break the process + pass + + _new_landing_rev = '%s:%s' % (_rev_type, _rev) + print u'setting to %s' % _new_landing_rev + repo.landing_rev = _new_landing_rev + _SESSION().add(repo) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/023_version_2_1_0.py b/rhodecode/lib/dbmigrate/versions/023_version_2_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/023_version_2_1_0.py @@ -0,0 +1,35 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_1_0 + + tbl = db_2_1_0.UserApiKeys.__table__ + tbl.create() + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/024_version_2_1_0.py b/rhodecode/lib/dbmigrate/versions/024_version_2_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/024_version_2_1_0.py @@ -0,0 +1,90 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_1_0 + + # issue fixups + fixups(db_2_1_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + from pylons import config + from rhodecode.lib.utils2 import str2bool + + Optional = models.Optional + + def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + def create_or_update(cls, key, val=Optional(''), type=Optional('unicode')): + res = get_by_name(cls, key) + if not res: + val = Optional.extract(val) + type = Optional.extract(type) + res = cls(key, val, type) + else: + res.app_settings_name = key + if not isinstance(val, Optional): + # update if set + res.app_settings_value = val + if not isinstance(type, Optional): + # update if set + res.app_settings_type = type + return res + + notify('migrating options from .ini file') + use_gravatar = str2bool(config.get('use_gravatar')) + print('Setting gravatar use to: %s' % use_gravatar) + sett = create_or_update(models.RhodeCodeSetting, + 'use_gravatar', use_gravatar, 'bool') + _SESSION().add(sett) + _SESSION.commit() + # set the new format of gravatar URL + gravatar_url = models.User.DEFAULT_GRAVATAR_URL + if config.get('alternative_gravatar_url'): + gravatar_url = config.get('alternative_gravatar_url') + + print('Setting gravatar url to:%s' % gravatar_url) + sett = create_or_update(models.RhodeCodeSetting, + 'gravatar_url', gravatar_url, 'unicode') + _SESSION().add(sett) + _SESSION.commit() + + # now create new changed value of clone_url + clone_uri_tmpl = models.Repository.DEFAULT_CLONE_URI + print('settings new clone url template to %s' % clone_uri_tmpl) + + sett = create_or_update(models.RhodeCodeSetting, + 'clone_uri_tmpl', clone_uri_tmpl, 'unicode') + _SESSION().add(sett) + _SESSION.commit() diff --git a/rhodecode/lib/dbmigrate/versions/025_version_2_1_0.py b/rhodecode/lib/dbmigrate/versions/025_version_2_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/025_version_2_1_0.py @@ -0,0 +1,64 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_1_0 + + # issue fixups + fixups(db_2_1_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + Optional = models.Optional + + def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + def create_or_update(cls, key, val=Optional(''), type=Optional('unicode')): + res = get_by_name(cls, key) + if not res: + val = Optional.extract(val) + type = Optional.extract(type) + res = cls(key, val, type) + else: + res.app_settings_name = key + if not isinstance(val, Optional): + # update if set + res.app_settings_value = val + if not isinstance(type, Optional): + # update if set + res.app_settings_type = type + return res + + notify('Creating upgrade URL') + sett = create_or_update(models.RhodeCodeSetting, + 'update_url', models.RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode') + _SESSION().add(sett) + _SESSION.commit() diff --git a/rhodecode/lib/dbmigrate/versions/026_version_2_2_0.py b/rhodecode/lib/dbmigrate/versions/026_version_2_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/026_version_2_2_0.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_0 + + tbl = db_2_2_0.User.__table__ + + user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + user_data.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/027_version_2_2_0.py b/rhodecode/lib/dbmigrate/versions/027_version_2_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/027_version_2_2_0.py @@ -0,0 +1,65 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_0 + + # issue fixups + fixups(db_2_2_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + # ** create default permissions ** # + #===================================== + for p in models.Permission.PERMS: + if not get_by_key(models.Permission, p[0]): + new_perm = models.Permission() + new_perm.permission_name = p[0] + new_perm.permission_longname = p[0] #translation err with p[1] + print 'Creating new permission %s' % p[0] + _SESSION().add(new_perm) + + _SESSION().commit() + + # ** set default create_on_write to active + user = models.User.query().filter( + models.User.username == 'default').scalar() + + _def = 'hg.create.write_on_repogroup.true' + new = models.UserToPerm() + new.user = user + new.permission = get_by_key(models.Permission, _def) + print 'Setting default to %s' % _def + _SESSION().add(new) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/028_version_2_2_3.py b/rhodecode/lib/dbmigrate/versions/028_version_2_2_3.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/028_version_2_2_3.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_0 + + tbl = db_2_2_0.UserGroup.__table__ + + user_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + user_data.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/029_version_2_2_3.py b/rhodecode/lib/dbmigrate/versions/029_version_2_2_3.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/029_version_2_2_3.py @@ -0,0 +1,56 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_0 + + # issue fixups + fixups(db_2_2_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Adding grid items options now...') + + settings = [ + ('admin_grid_items', 25, 'int'), # old hardcoded value was 25 + ] + + for name, default, type_ in settings: + setting = get_by_name(models.RhodeCodeSetting, name) + if not setting: + # if we don't have this option create it + setting = models.RhodeCodeSetting(name, default, type_) + setting._app_settings_type = type_ + _SESSION().add(setting) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/030_version_2_2_3.py b/rhodecode/lib/dbmigrate/versions/030_version_2_2_3.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/030_version_2_2_3.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_0 + + tbl = db_2_2_0.Repository.__table__ + + repo_state = Column("repo_state", String(255), nullable=True) + repo_state.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/031_version_2_2_3.py b/rhodecode/lib/dbmigrate/versions/031_version_2_2_3.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/031_version_2_2_3.py @@ -0,0 +1,45 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_3 + + # issue fixups + fixups(db_2_2_3, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Creating repository states') + _state = models.Repository.STATE_CREATED + for repo in models.Repository.get_all(): + print 'setting repo %s state to "%s"' % (repo, _state) + repo.repo_state = _state + _SESSION().add(repo) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/032_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/032_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/032_version_2_3_0.py @@ -0,0 +1,38 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_2_3 + + tbl = db_2_2_3.UserApiKeys.__table__ + + role = Column('role', String(255), nullable=True) + role.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + diff --git a/rhodecode/lib/dbmigrate/versions/033_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/033_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/033_version_2_3_0.py @@ -0,0 +1,45 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_0 + + # issue fixups + fixups(db_2_3_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing auth tokens roles') + _role = models.UserApiKeys.ROLE_ALL + for token in models.UserApiKeys.get_all(): + print 'setting key %s role to "%s"' % (token, _role) + token.role = _role + _SESSION().add(token) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/034_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/034_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/034_version_2_3_0.py @@ -0,0 +1,82 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def get_by_name_or_create(cls, key, val='', type='unicode'): + res = get_by_name(cls, key) + if not res: + res = cls(key, val, type) + return res + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_0 + + # issue fixups + fixups(db_2_3_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Fixing existing GA code into new format') + cur_code = get_by_name(models.RhodeCodeSetting, 'ga_code') + val = ''' +<script> + // google analytics + var _gaq_code = '_GACODE_'; + var _gaq = _gaq || []; + _gaq.push(['_setAccount', _gaq_code]); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + + rhodecode_statechange_callback = function(url, data){ + // ANALYTICS callback on html5 history state changed + // triggered by file browser, url is the new url, + // data is extra info passed from the State object + if ( typeof window._gaq !== 'undefined' ) { + _gaq.push(['_trackPageview', url]); + } + } +</script>''' + if cur_code and getattr(cur_code, 'app_settings_value', ''): + cur_val = getattr(cur_code, 'app_settings_value', '') + val = val.replace('_GACODE_', cur_val) + notify('Found GA code %s, migrating' % cur_val) + new = get_by_name_or_create(models.RhodeCodeSetting, 'pre_code', val) + new.app_settings_value = val + _SESSION().add(new) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/035_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/035_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/035_version_2_3_0.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_0 + + tbl = db_2_3_0_0.ChangesetComment.__table__ + + renderer = Column('renderer', Unicode(64), nullable=True) + renderer.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/036_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/036_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/036_version_2_3_0.py @@ -0,0 +1,44 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_1 + + # issue fixups + fixups(db_2_3_0_1, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Setting default renderer to rst') + for cs_comment in models.ChangesetComment.get_all(): + print 'comment_id %s renderer rst' % (cs_comment.comment_id) + cs_comment.renderer = 'rst' + _SESSION().add(cs_comment) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/037_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/037_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/037_version_2_3_0.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_1 + + tbl = db_2_3_0_1.UserIpMap.__table__ + + description = Column("description", String(10000), nullable=True, unique=None, default=None) + description.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/038_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/038_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/038_version_2_3_0.py @@ -0,0 +1,57 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_name(cls, key): + return cls.query().filter(cls.app_settings_name == key).scalar() + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_1 + + # issue fixups + fixups(db_2_3_0_1, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + notify('Adding revision look items options now...') + + settings = [ + ('show_revision_number', True, 'bool'), + ('show_sha_length', 12, 'int'), + ] + + for name, default, type_ in settings: + setting = get_by_name(models.RhodeCodeSetting, name) + if not setting: + # if we don't have this option create it + setting = models.RhodeCodeSetting(name, default, type_) + setting._app_settings_type = type_ + _SESSION().add(setting) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/039_version_2_3_0.py b/rhodecode/lib/dbmigrate/versions/039_version_2_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/039_version_2_3_0.py @@ -0,0 +1,43 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_2_3_0_2 + + tbl = db_2_3_0_2.PullRequest.__table__ + + _last_merge_org_rev = Column('last_merge_org_rev', String(40), nullable=True) + _last_merge_other_rev = Column('last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + _last_merge_org_rev.create(table=tbl) + _last_merge_other_rev.create(table=tbl) + _last_merge_status.create(table=tbl) + merge_rev.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/040_version_3_0_0.py b/rhodecode/lib/dbmigrate/versions/040_version_3_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/040_version_3_0_0.py @@ -0,0 +1,47 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_0_0_0 + + # issue fixups + fixups(db_3_0_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + # ** create default permissions ** # + from rhodecode.model.permission import PermissionModel + PermissionModel(_SESSION()).create_permissions() + _SESSION().commit() + + res = PermissionModel(_SESSION()).create_default_user_permissions( + models.User.DEFAULT_USER) + print res + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/041_version_3_0_0.py b/rhodecode/lib/dbmigrate/versions/041_version_3_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/041_version_3_0_0.py @@ -0,0 +1,88 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def get_by_key(cls, key): + return cls.query().filter(cls.ui_key == key).scalar() + + +def create_or_update_hook(cls, key, val, SESSION): + new_ui = get_by_key(cls, key) or cls() + new_ui.ui_section = 'hooks' + new_ui.ui_active = True + new_ui.ui_key = key + new_ui.ui_value = val + + SESSION().add(new_ui) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_0_0_0 + + # issue fixups + fixups(db_3_0_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + + cleanup_if_present = ( + models.RhodeCodeUi.HOOK_REPO_SIZE, + models.RhodeCodeUi.HOOK_PRE_PULL, + models.RhodeCodeUi.HOOK_PRE_PUSH, + models.RhodeCodeUi.HOOK_PUSH, + models.RhodeCodeUi.HOOK_PULL, + models.RhodeCodeUi.HOOK_PRE_PULL_GIT, + models.RhodeCodeUi.HOOK_PULL_GIT, + models.RhodeCodeUi.HOOK_PRE_PUSH_GIT, + models.RhodeCodeUi.HOOK_PUSH_GIT) + + for hook in cleanup_if_present: + ui_cfg = models.RhodeCodeUi.query().filter( + models.RhodeCodeUi.ui_key == hook).scalar() + if ui_cfg is not None: + log.info('Removing RhodeCodeUI for hook "%s".', hook) + _SESSION().delete(ui_cfg) + + to_add = [ + (models.RhodeCodeUi.HOOK_REPO_SIZE, + 'python:vcsserver.hooks.repo_size'), + (models.RhodeCodeUi.HOOK_PRE_PULL, + 'python:vcsserver.hooks.pre_pull'), + (models.RhodeCodeUi.HOOK_PRE_PUSH, + 'python:vcsserver.hooks.pre_push'), + (models.RhodeCodeUi.HOOK_PULL, + 'python:vcsserver.hooks.log_pull_action'), + (models.RhodeCodeUi.HOOK_PUSH, + 'python:vcsserver.hooks.log_push_action')] + + for hook, value in to_add: + log.info('Adding RhodeCodeUI for hook "%s".', hook) + create_or_update_hook(models.RhodeCodeUi, hook, value, _SESSION) + + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/042_version_3_0_0.py b/rhodecode/lib/dbmigrate/versions/042_version_3_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/042_version_3_0_0.py @@ -0,0 +1,33 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + # this was an bad migration step and was cleaned, but it needs to + # exist for numeric order + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/043_version_3_1_0.py b/rhodecode/lib/dbmigrate/versions/043_version_3_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/043_version_3_1_0.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_0_0_0 + + tbl = db_3_0_0_0.Gist.__table__ + + acl_level = Column('acl_level', Unicode(128), nullable=True) + acl_level.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/044_version_3_1_0.py b/rhodecode/lib/dbmigrate/versions/044_version_3_1_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/044_version_3_1_0.py @@ -0,0 +1,44 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_1_0_1 + + # Add table for PullRequestVersion + tbl = db_3_1_0_1.PullRequestVersion.__table__ + tbl.create() + + # Add pull_request_version to ChangesetComment + tbl = db_3_1_0_1.ChangesetComment.__table__ + pull_request_version_id = Column( + "pull_request_version_id", Integer(), + ForeignKey('pull_request_versions.pull_request_version_id'), + nullable=True) + pull_request_version_id.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/045_version_3_2_0.py b/rhodecode/lib/dbmigrate/versions/045_version_3_2_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/045_version_3_2_0.py @@ -0,0 +1,37 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_2_0_0 + + # Add display_state to ChangesetComment + tbl = db_3_2_0_0.ChangesetComment.__table__ + display_state = Column("display_state", Unicode(128), nullable=True) + display_state.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/dbmigrate/versions/046_version_3_3_0.py b/rhodecode/lib/dbmigrate/versions/046_version_3_3_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/046_version_3_3_0.py @@ -0,0 +1,44 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * +from rhodecode.lib.utils2 import str2bool + +from rhodecode.model.meta import Base +from rhodecode.model import meta, init_model_encryption +from rhodecode.lib.dbmigrate.versions import _reset_base, notify + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_3_0_0 + init_model_encryption(db_3_3_0_0) + fixups(db_3_3_0_0, meta.Session) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + +def fixups(models, _SESSION): + for repo in models.Repository.get_all(): + _lock_info = repo._locked.split(':') if repo._locked else [] + if len(_lock_info) == 2: + _lock_info.append(repo.LOCK_AUTOMATIC) + repo.locked = _lock_info + _SESSION().add(repo) + _SESSION().commit() diff --git a/rhodecode/lib/dbmigrate/versions/047_version_3_5_0.py b/rhodecode/lib/dbmigrate/versions/047_version_3_5_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/047_version_3_5_0.py @@ -0,0 +1,30 @@ +import logging + +from sqlalchemy import MetaData + +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_5_0_0 + + ui_table = db_3_5_0_0.RepoRhodeCodeUi.__table__ + settings_table = db_3_5_0_0.RepoRhodeCodeSetting.__table__ + ui_table.create() + settings_table.create() + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + diff --git a/rhodecode/lib/dbmigrate/versions/048_version_3_8_0.py b/rhodecode/lib/dbmigrate/versions/048_version_3_8_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/048_version_3_8_0.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +import hashlib +import logging + +from alembic.migration import MigrationContext +from alembic.operations import Operations +from sqlalchemy import Text, String, Column +from sqlalchemy.engine import reflection +from sqlalchemy.sql import text + +from rhodecode.lib.dbmigrate.versions import _reset_base +from rhodecode.lib.utils2 import safe_str +from rhodecode.model import meta, init_model_encryption + + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_7_0_0 + + init_model_encryption(db_3_7_0_0) + + context = MigrationContext.configure(migrate_engine.connect()) + op = Operations(context) + + repository = db_3_7_0_0.Repository.__table__ + repo_name_column = repository.columns.repo_name + clone_uri_column = repository.columns.clone_uri + + indexes = _get_indexes_list(migrate_engine, repository.name) + repo_name_indexes = [ + i['name'] for i in indexes if 'repo_name' in i['column_names']] + constraints = _get_unique_constraint_list(migrate_engine, repository.name) + repo_name_constraints = [ + c['name'] for c in constraints if 'repo_name' in c['column_names']] + + with op.batch_alter_table(repository.name) as batch_op: + repo_name_idx = 'r_repo_name_idx' + if repo_name_idx in repo_name_indexes: + batch_op.drop_index(repo_name_idx) + for name in repo_name_constraints: + batch_op.drop_constraint(name, type_='unique') + + batch_op.alter_column(repo_name_column.name, type_=Text) + batch_op.alter_column(clone_uri_column.name, type_=Text) + batch_op.create_index( + 'r_repo_name_idx', ['repo_name'], mysql_length=255) + batch_op.add_column(Column('repo_name_hash', String(40), unique=False)) + + _generate_repo_name_hashes(db_3_7_0_0, op, meta.Session) + + with op.batch_alter_table(repository.name) as batch_op: + batch_op.create_unique_constraint( + 'uq_repo_name_hash', ['repo_name_hash']) + + +def downgrade(migrate_engine): + pass + + +def _generate_repo_name_hashes(models, op, session): + repositories = models.Repository.get_all() + for repository in repositories: + hash_ = hashlib.sha1(safe_str(repository.repo_name)).hexdigest() + params = {'hash': hash_, 'id': repository.repo_id} + query = text( + 'UPDATE repositories SET repo_name_hash = :hash' + ' WHERE repo_id = :id').bindparams(**params) + op.execute(query) + session().commit() + + +def _get_unique_constraint_list(migrate_engine, table_name): + inspector = reflection.Inspector.from_engine(migrate_engine) + return inspector.get_unique_constraints(table_name) + + +def _get_indexes_list(migrate_engine, table_name): + inspector = reflection.Inspector.from_engine(migrate_engine) + return inspector.get_indexes(table_name) diff --git a/rhodecode/lib/dbmigrate/versions/049_version_4_0_0.py b/rhodecode/lib/dbmigrate/versions/049_version_4_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/049_version_4_0_0.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +import logging +import sqlalchemy as sa + +from alembic.migration import MigrationContext +from alembic.operations import Operations + +from rhodecode.lib.dbmigrate.versions import _reset_base + +from rhodecode.model import init_model_encryption + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_7_0_0 + + init_model_encryption(db_3_7_0_0) + + context = MigrationContext.configure(migrate_engine.connect()) + op = Operations(context) + + op.create_table( + 'external_identities', + sa.Column('provider_name', sa.Unicode(255), primary_key=True), + sa.Column('local_user_id', sa.Integer(), + sa.ForeignKey('users.user_id'), primary_key=True), + + sa.Column('external_id', sa.Unicode(255), primary_key=True), + sa.Column('external_username', sa.Unicode(1024), default=u''), + + sa.Column('access_token', sa.String(1024), default=u''), + sa.Column('alt_token', sa.String(1024), default=u''), + sa.Column('token_secret', sa.String(1024), default=u'') + ) + op.create_index('local_user_id_idx', 'external_identities', + ['local_user_id']) + op.create_index('external_id_idx', 'external_identities', + ['external_id']) + + +def downgrade(migrate_engine): + pass diff --git a/rhodecode/lib/dbmigrate/versions/050_version_4_0_0.py b/rhodecode/lib/dbmigrate/versions/050_version_4_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/050_version_4_0_0.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import logging + +from sqlalchemy.orm.attributes import flag_modified + +from rhodecode.lib.dbmigrate.versions import _reset_base +from rhodecode.model import init_model_encryption, meta + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_7_0_0 + init_model_encryption(db_3_7_0_0) + fixups(db_3_7_0_0, meta.Session) + + +def downgrade(migrate_engine): + pass + + +def fixups(models, Session): + for repo in models.Repository.get_all(): + if repo.clone_uri: + print 'Encrypting clone uri in repo %s' % repo + flag_modified(repo, 'clone_uri') + Session().add(repo) + + Session().commit() + + diff --git a/rhodecode/lib/dbmigrate/versions/051_version_4_0_0.py b/rhodecode/lib/dbmigrate/versions/051_version_4_0_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/051_version_4_0_0.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +import logging + +from sqlalchemy.orm.attributes import flag_modified + +from rhodecode.lib.dbmigrate.versions import _reset_base +from rhodecode.model import init_model_encryption, meta + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_3_7_0_0 + init_model_encryption(db_3_7_0_0) + fixups(db_3_7_0_0, meta.Session) + + +def downgrade(migrate_engine): + pass + + +AUTH_PLUGINS_SETTING = "auth_plugins" + +PLUGIN_ID_MAP = { + 'rhodecode.lib.auth_modules.auth_crowd': 'egg:rhodecode-enterprise-ce#crowd', + 'rhodecode.lib.auth_modules.auth_container': 'egg:rhodecode-enterprise-ce#container', + 'rhodecode.lib.auth_modules.auth_jasig_cas': 'egg:rhodecode-enterprise-ce#jasig_cas', + 'rhodecode.lib.auth_modules.auth_ldap': 'egg:rhodecode-enterprise-ce#ldap', + 'rhodecode.lib.auth_modules.auth_pam': 'egg:rhodecode-enterprise-ce#pam', + 'rhodecode.lib.auth_modules.auth_rhodecode': 'egg:rhodecode-enterprise-ce#rhodecode', + + 'rhodecode.lib.auth_modules.auth_bitbucket': 'egg:rhodecode-enterprise-ee#bitbucket', + 'rhodecode.lib.auth_modules.auth_github': 'egg:rhodecode-enterprise-ee#github', + 'rhodecode.lib.auth_modules.auth_google': 'egg:rhodecode-enterprise-ee#google', + 'rhodecode.lib.auth_modules.auth_ldap_group': 'egg:rhodecode-enterprise-ee#ldap_group', + 'rhodecode.lib.auth_modules.auth_token': 'egg:rhodecode-enterprise-ee#token', + 'rhodecode.lib.auth_modules.auth_twitter': 'egg:rhodecode-enterprise-ee#twitter', +} + + +def fixups(models, Session): + + query = models.RhodeCodeSetting.query().filter( + models.RhodeCodeSetting.app_settings_name == AUTH_PLUGINS_SETTING) + plugin_setting = query.scalar() + plugins = plugin_setting.app_settings_value + + new_plugins = [] + missed_plugins = [] + + for plugin_id in plugins: + new_plugin_id = PLUGIN_ID_MAP.get(plugin_id, None) + if new_plugin_id: + new_plugins.append(new_plugin_id) + else: + new_plugins.append(plugin_id) + missed_plugins.append(plugin_id) + + plugin_setting.app_settings_value = ','.join(new_plugins) + + log.info("Migration of the auth plugin IDs") + log.info("Original setting value: %s", plugins) + log.info("New setting value: %s", new_plugins) + if missed_plugins: + log.warning("Unknown plugin ids: %s", missed_plugins) + log.warning( + "Please check the auth settings and re-enable needed plugins.") + + Session().commit() diff --git a/rhodecode/lib/dbmigrate/versions/__init__.py b/rhodecode/lib/dbmigrate/versions/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/__init__.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Package containing new versions of database models +""" + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import scoped_session, sessionmaker +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model import meta + + +def notify(msg, caps=True): + """ + Notification for migrations messages + """ + ml = len(msg) + (4 * 2) + formatted_msg = ('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)) + if caps: + formatted_msg = formatted_msg.upper() + print(formatted_msg) + + +def _reset_base(migrate_engine): + ## RESET COMPLETLY THE metadata for sqlalchemy to use previous declared Base + Base = declarative_base() + Base.metadata.clear() + Base.metadata = MetaData() + Base.metadata.bind = migrate_engine + + # new session and base + #meta.Session = scoped_session(sessionmaker(expire_on_commit=True,)) + #meta.Session.configure(bind=migrate_engine) + meta.Base = Base + + notify('SQLA BASE RESET !') diff --git a/rhodecode/lib/diffs.py b/rhodecode/lib/diffs.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/diffs.py @@ -0,0 +1,872 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Set of diffing helpers, previously part of vcs +""" + +import collections +import re +import difflib +import logging + +from itertools import tee, imap + +from pylons.i18n.translation import _ + +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib.helpers import escape +from rhodecode.lib.utils2 import safe_unicode + +log = logging.getLogger(__name__) + + +class OPS(object): + ADD = 'A' + MOD = 'M' + DEL = 'D' + +def wrap_to_table(str_): + return '''<table class="code-difftable"> + <tr class="line no-comment"> + <td class="add-comment-line"><span class="add-comment-content"></span></td> + <td class="lineno new"></td> + <td class="code no-comment"><pre>%s</pre></td> + </tr> + </table>''' % str_ + + +def wrapped_diff(filenode_old, filenode_new, diff_limit=None, file_limit=None, + show_full_diff=False, ignore_whitespace=True, line_context=3, + enable_comments=False): + """ + returns a wrapped diff into a table, checks for cut_off_limit for file and + whole diff and presents proper message + """ + + if filenode_old is None: + filenode_old = FileNode(filenode_new.path, '', EmptyCommit()) + + if filenode_old.is_binary or filenode_new.is_binary: + diff = wrap_to_table(_('Binary file')) + stats = None + size = 0 + data = None + + elif diff_limit != -1 and (diff_limit is None or + (filenode_old.size < diff_limit and filenode_new.size < diff_limit)): + + f_gitdiff = get_gitdiff(filenode_old, filenode_new, + ignore_whitespace=ignore_whitespace, + context=line_context) + diff_processor = DiffProcessor(f_gitdiff, format='gitdiff', diff_limit=diff_limit, + file_limit=file_limit, show_full_diff=show_full_diff) + _parsed = diff_processor.prepare() + + diff = diff_processor.as_html(enable_comments=enable_comments) + stats = _parsed[0]['stats'] if _parsed else None + size = len(diff or '') + data = _parsed[0] if _parsed else None + else: + diff = wrap_to_table(_('Changeset was too big and was cut off, use ' + 'diff menu to display this diff')) + stats = None + size = 0 + data = None + if not diff: + submodules = filter(lambda o: isinstance(o, SubModuleNode), + [filenode_new, filenode_old]) + if submodules: + diff = wrap_to_table(escape('Submodule %r' % submodules[0])) + else: + diff = wrap_to_table(_('No changes detected')) + + cs1 = filenode_old.commit.raw_id + cs2 = filenode_new.commit.raw_id + + return size, cs1, cs2, diff, stats, data + + +def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3): + """ + Returns git style diff between given ``filenode_old`` and ``filenode_new``. + + :param ignore_whitespace: ignore whitespaces in diff + """ + # make sure we pass in default context + context = context or 3 + submodules = filter(lambda o: isinstance(o, SubModuleNode), + [filenode_new, filenode_old]) + if submodules: + return '' + + for filenode in (filenode_old, filenode_new): + if not isinstance(filenode, FileNode): + raise VCSError( + "Given object should be FileNode object, not %s" + % filenode.__class__) + + repo = filenode_new.commit.repository + old_commit = filenode_old.commit or repo.EMPTY_COMMIT + new_commit = filenode_new.commit + + vcs_gitdiff = repo.get_diff( + old_commit, new_commit, filenode_new.path, + ignore_whitespace, context, path1=filenode_old.path) + return vcs_gitdiff + +NEW_FILENODE = 1 +DEL_FILENODE = 2 +MOD_FILENODE = 3 +RENAMED_FILENODE = 4 +COPIED_FILENODE = 5 +CHMOD_FILENODE = 6 +BIN_FILENODE = 7 + + +class LimitedDiffContainer(object): + + def __init__(self, diff_limit, cur_diff_size, diff): + self.diff = diff + self.diff_limit = diff_limit + self.cur_diff_size = cur_diff_size + + def __getitem__(self, key): + return self.diff.__getitem__(key) + + def __iter__(self): + for l in self.diff: + yield l + + +class Action(object): + """ + Contains constants for the action value of the lines in a parsed diff. + """ + + ADD = 'add' + DELETE = 'del' + UNMODIFIED = 'unmod' + + CONTEXT = 'context' + + +class DiffProcessor(object): + """ + Give it a unified or git diff and it returns a list of the files that were + mentioned in the diff together with a dict of meta information that + can be used to render it in a HTML template. + + .. note:: Unicode handling + + The original diffs are a byte sequence and can contain filenames + in mixed encodings. This class generally returns `unicode` objects + since the result is intended for presentation to the user. + + """ + _chunk_re = re.compile(r'^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)') + _newline_marker = re.compile(r'^\\ No newline at end of file') + + # used for inline highlighter word split + _token_re = re.compile(r'()(>|<|&|\W+?)') + + def __init__(self, diff, format='gitdiff', diff_limit=None, file_limit=None, show_full_diff=True): + """ + :param diff: A `Diff` object representing a diff from a vcs backend + :param format: format of diff passed, `udiff` or `gitdiff` + :param diff_limit: define the size of diff that is considered "big" + based on that parameter cut off will be triggered, set to None + to show full diff + """ + self._diff = diff + self._format = format + self.adds = 0 + self.removes = 0 + # calculate diff size + self.diff_limit = diff_limit + self.file_limit = file_limit + self.show_full_diff = show_full_diff + self.cur_diff_size = 0 + self.parsed = False + self.parsed_diff = [] + + if format == 'gitdiff': + self.differ = self._highlight_line_difflib + self._parser = self._parse_gitdiff + else: + self.differ = self._highlight_line_udiff + self._parser = self._parse_udiff + + def _copy_iterator(self): + """ + make a fresh copy of generator, we should not iterate thru + an original as it's needed for repeating operations on + this instance of DiffProcessor + """ + self.__udiff, iterator_copy = tee(self.__udiff) + return iterator_copy + + def _escaper(self, string): + """ + Escaper for diff escapes special chars and checks the diff limit + + :param string: + """ + + self.cur_diff_size += len(string) + + if not self.show_full_diff and (self.cur_diff_size > self.diff_limit): + raise DiffLimitExceeded('Diff Limit Exceeded') + + return safe_unicode(string)\ + .replace('&', '&')\ + .replace('<', '<')\ + .replace('>', '>') + + def _line_counter(self, l): + """ + Checks each line and bumps total adds/removes for this diff + + :param l: + """ + if l.startswith('+') and not l.startswith('+++'): + self.adds += 1 + elif l.startswith('-') and not l.startswith('---'): + self.removes += 1 + return safe_unicode(l) + + def _highlight_line_difflib(self, line, next_): + """ + Highlight inline changes in both lines. + """ + + if line['action'] == Action.DELETE: + old, new = line, next_ + else: + old, new = next_, line + + oldwords = self._token_re.split(old['line']) + newwords = self._token_re.split(new['line']) + sequence = difflib.SequenceMatcher(None, oldwords, newwords) + + oldfragments, newfragments = [], [] + for tag, i1, i2, j1, j2 in sequence.get_opcodes(): + oldfrag = ''.join(oldwords[i1:i2]) + newfrag = ''.join(newwords[j1:j2]) + if tag != 'equal': + if oldfrag: + oldfrag = '<del>%s</del>' % oldfrag + if newfrag: + newfrag = '<ins>%s</ins>' % newfrag + oldfragments.append(oldfrag) + newfragments.append(newfrag) + + old['line'] = "".join(oldfragments) + new['line'] = "".join(newfragments) + + def _highlight_line_udiff(self, line, next_): + """ + Highlight inline changes in both lines. + """ + start = 0 + limit = min(len(line['line']), len(next_['line'])) + while start < limit and line['line'][start] == next_['line'][start]: + start += 1 + end = -1 + limit -= start + while -end <= limit and line['line'][end] == next_['line'][end]: + end -= 1 + end += 1 + if start or end: + def do(l): + last = end + len(l['line']) + if l['action'] == Action.ADD: + tag = 'ins' + else: + tag = 'del' + l['line'] = '%s<%s>%s</%s>%s' % ( + l['line'][:start], + tag, + l['line'][start:last], + tag, + l['line'][last:] + ) + do(line) + do(next_) + + def _clean_line(self, line, command): + if command in ['+', '-', ' ']: + # only modify the line if it's actually a diff thing + line = line[1:] + return line + + def _parse_gitdiff(self, inline_diff=True): + _files = [] + diff_container = lambda arg: arg + + for chunk in self._diff.chunks(): + head = chunk.header + + diff = imap(self._escaper, chunk.diff.splitlines(1)) + raw_diff = chunk.raw + limited_diff = False + exceeds_limit = False + + op = None + stats = { + 'added': 0, + 'deleted': 0, + 'binary': False, + 'ops': {}, + } + + if head['deleted_file_mode']: + op = OPS.DEL + stats['binary'] = True + stats['ops'][DEL_FILENODE] = 'deleted file' + + elif head['new_file_mode']: + op = OPS.ADD + stats['binary'] = True + stats['ops'][NEW_FILENODE] = 'new file %s' % head['new_file_mode'] + else: # modify operation, can be copy, rename or chmod + + # CHMOD + if head['new_mode'] and head['old_mode']: + op = OPS.MOD + stats['binary'] = True + stats['ops'][CHMOD_FILENODE] = ( + 'modified file chmod %s => %s' % ( + head['old_mode'], head['new_mode'])) + # RENAME + if head['rename_from'] != head['rename_to']: + op = OPS.MOD + stats['binary'] = True + stats['ops'][RENAMED_FILENODE] = ( + 'file renamed from %s to %s' % ( + head['rename_from'], head['rename_to'])) + # COPY + if head.get('copy_from') and head.get('copy_to'): + op = OPS.MOD + stats['binary'] = True + stats['ops'][COPIED_FILENODE] = ( + 'file copied from %s to %s' % ( + head['copy_from'], head['copy_to'])) + + # If our new parsed headers didn't match anything fallback to + # old style detection + if op is None: + if not head['a_file'] and head['b_file']: + op = OPS.ADD + stats['binary'] = True + stats['ops'][NEW_FILENODE] = 'new file' + + elif head['a_file'] and not head['b_file']: + op = OPS.DEL + stats['binary'] = True + stats['ops'][DEL_FILENODE] = 'deleted file' + + # it's not ADD not DELETE + if op is None: + op = OPS.MOD + stats['binary'] = True + stats['ops'][MOD_FILENODE] = 'modified file' + + # a real non-binary diff + if head['a_file'] or head['b_file']: + try: + raw_diff, chunks, _stats = self._parse_lines(diff) + stats['binary'] = False + stats['added'] = _stats[0] + stats['deleted'] = _stats[1] + # explicit mark that it's a modified file + if op == OPS.MOD: + stats['ops'][MOD_FILENODE] = 'modified file' + exceeds_limit = len(raw_diff) > self.file_limit + + # changed from _escaper function so we validate size of + # each file instead of the whole diff + # diff will hide big files but still show small ones + # from my tests, big files are fairly safe to be parsed + # but the browser is the bottleneck + if not self.show_full_diff and exceeds_limit: + raise DiffLimitExceeded('File Limit Exceeded') + + except DiffLimitExceeded: + diff_container = lambda _diff: \ + LimitedDiffContainer( + self.diff_limit, self.cur_diff_size, _diff) + + exceeds_limit = len(raw_diff) > self.file_limit + limited_diff = True + chunks = [] + + else: # GIT format binary patch, or possibly empty diff + if head['bin_patch']: + # we have operation already extracted, but we mark simply + # it's a diff we wont show for binary files + stats['ops'][BIN_FILENODE] = 'binary diff hidden' + chunks = [] + + if chunks and not self.show_full_diff and op == OPS.DEL: + # if not full diff mode show deleted file contents + # TODO: anderson: if the view is not too big, there is no way + # to see the content of the file + chunks = [] + + chunks.insert(0, [{ + 'old_lineno': '', + 'new_lineno': '', + 'action': Action.CONTEXT, + 'line': msg, + } for _op, msg in stats['ops'].iteritems() + if _op not in [MOD_FILENODE]]) + + _files.append({ + 'filename': safe_unicode(head['b_path']), + 'old_revision': head['a_blob_id'], + 'new_revision': head['b_blob_id'], + 'chunks': chunks, + 'raw_diff': safe_unicode(raw_diff), + 'operation': op, + 'stats': stats, + 'exceeds_limit': exceeds_limit, + 'is_limited_diff': limited_diff, + }) + + sorter = lambda info: {OPS.ADD: 0, OPS.MOD: 1, + OPS.DEL: 2}.get(info['operation']) + + if not inline_diff: + return diff_container(sorted(_files, key=sorter)) + + # highlight inline changes + for diff_data in _files: + for chunk in diff_data['chunks']: + lineiter = iter(chunk) + try: + while 1: + line = lineiter.next() + if line['action'] not in ( + Action.UNMODIFIED, Action.CONTEXT): + nextline = lineiter.next() + if nextline['action'] in ['unmod', 'context'] or \ + nextline['action'] == line['action']: + continue + self.differ(line, nextline) + except StopIteration: + pass + + return diff_container(sorted(_files, key=sorter)) + + def _parse_udiff(self, inline_diff=True): + raise NotImplementedError() + + def _parse_lines(self, diff): + """ + Parse the diff an return data for the template. + """ + + lineiter = iter(diff) + stats = [0, 0] + chunks = [] + raw_diff = [] + + try: + line = lineiter.next() + + while line: + raw_diff.append(line) + lines = [] + chunks.append(lines) + + match = self._chunk_re.match(line) + + if not match: + break + + gr = match.groups() + (old_line, old_end, + new_line, new_end) = [int(x or 1) for x in gr[:-1]] + old_line -= 1 + new_line -= 1 + + context = len(gr) == 5 + old_end += old_line + new_end += new_line + + if context: + # skip context only if it's first line + if int(gr[0]) > 1: + lines.append({ + 'old_lineno': '...', + 'new_lineno': '...', + 'action': Action.CONTEXT, + 'line': line, + }) + + line = lineiter.next() + + while old_line < old_end or new_line < new_end: + command = ' ' + if line: + command = line[0] + + affects_old = affects_new = False + + # ignore those if we don't expect them + if command in '#@': + continue + elif command == '+': + affects_new = True + action = Action.ADD + stats[0] += 1 + elif command == '-': + affects_old = True + action = Action.DELETE + stats[1] += 1 + else: + affects_old = affects_new = True + action = Action.UNMODIFIED + + if not self._newline_marker.match(line): + old_line += affects_old + new_line += affects_new + lines.append({ + 'old_lineno': affects_old and old_line or '', + 'new_lineno': affects_new and new_line or '', + 'action': action, + 'line': self._clean_line(line, command) + }) + raw_diff.append(line) + + line = lineiter.next() + + if self._newline_marker.match(line): + # we need to append to lines, since this is not + # counted in the line specs of diff + lines.append({ + 'old_lineno': '...', + 'new_lineno': '...', + 'action': Action.CONTEXT, + 'line': self._clean_line(line, command) + }) + + except StopIteration: + pass + return ''.join(raw_diff), chunks, stats + + def _safe_id(self, idstring): + """Make a string safe for including in an id attribute. + + The HTML spec says that id attributes 'must begin with + a letter ([A-Za-z]) and may be followed by any number + of letters, digits ([0-9]), hyphens ("-"), underscores + ("_"), colons (":"), and periods (".")'. These regexps + are slightly over-zealous, in that they remove colons + and periods unnecessarily. + + Whitespace is transformed into underscores, and then + anything which is not a hyphen or a character that + matches \w (alphanumerics and underscore) is removed. + + """ + # Transform all whitespace to underscore + idstring = re.sub(r'\s', "_", '%s' % idstring) + # Remove everything that is not a hyphen or a member of \w + idstring = re.sub(r'(?!-)\W', "", idstring).lower() + return idstring + + def prepare(self, inline_diff=True): + """ + Prepare the passed udiff for HTML rendering. + + :return: A list of dicts with diff information. + """ + parsed = self._parser(inline_diff=inline_diff) + self.parsed = True + self.parsed_diff = parsed + return parsed + + def as_raw(self, diff_lines=None): + """ + Returns raw diff as a byte string + """ + return self._diff.raw + + def as_html(self, table_class='code-difftable', line_class='line', + old_lineno_class='lineno old', new_lineno_class='lineno new', + code_class='code', enable_comments=False, parsed_lines=None): + """ + Return given diff as html table with customized css classes + """ + def _link_to_if(condition, label, url): + """ + Generates a link if condition is meet or just the label if not. + """ + + if condition: + return '''<a href="%(url)s">%(label)s</a>''' % { + 'url': url, + 'label': label + } + else: + return label + if not self.parsed: + self.prepare() + + diff_lines = self.parsed_diff + if parsed_lines: + diff_lines = parsed_lines + + _html_empty = True + _html = [] + _html.append('''<table class="%(table_class)s">\n''' % { + 'table_class': table_class + }) + + for diff in diff_lines: + for line in diff['chunks']: + _html_empty = False + for change in line: + _html.append('''<tr class="%(lc)s %(action)s">\n''' % { + 'lc': line_class, + 'action': change['action'] + }) + anchor_old_id = '' + anchor_new_id = '' + anchor_old = "%(filename)s_o%(oldline_no)s" % { + 'filename': self._safe_id(diff['filename']), + 'oldline_no': change['old_lineno'] + } + anchor_new = "%(filename)s_n%(oldline_no)s" % { + 'filename': self._safe_id(diff['filename']), + 'oldline_no': change['new_lineno'] + } + cond_old = (change['old_lineno'] != '...' and + change['old_lineno']) + cond_new = (change['new_lineno'] != '...' and + change['new_lineno']) + if cond_old: + anchor_old_id = 'id="%s"' % anchor_old + if cond_new: + anchor_new_id = 'id="%s"' % anchor_new + + if change['action'] != Action.CONTEXT: + anchor_link = True + else: + anchor_link = False + + ########################################################### + # COMMENT ICON + ########################################################### + _html.append('''\t<td class="add-comment-line"><span class="add-comment-content">''') + + if enable_comments and change['action'] != Action.CONTEXT: + _html.append('''<a href="#"><span class="icon-comment-add"></span></a>''') + + _html.append('''</span></td>\n''') + + ########################################################### + # OLD LINE NUMBER + ########################################################### + _html.append('''\t<td %(a_id)s class="%(olc)s">''' % { + 'a_id': anchor_old_id, + 'olc': old_lineno_class + }) + + _html.append('''%(link)s''' % { + 'link': _link_to_if(anchor_link, change['old_lineno'], + '#%s' % anchor_old) + }) + _html.append('''</td>\n''') + ########################################################### + # NEW LINE NUMBER + ########################################################### + + _html.append('''\t<td %(a_id)s class="%(nlc)s">''' % { + 'a_id': anchor_new_id, + 'nlc': new_lineno_class + }) + + _html.append('''%(link)s''' % { + 'link': _link_to_if(anchor_link, change['new_lineno'], + '#%s' % anchor_new) + }) + _html.append('''</td>\n''') + ########################################################### + # CODE + ########################################################### + code_classes = [code_class] + if (not enable_comments or + change['action'] == Action.CONTEXT): + code_classes.append('no-comment') + _html.append('\t<td class="%s">' % ' '.join(code_classes)) + _html.append('''\n\t\t<pre>%(code)s</pre>\n''' % { + 'code': change['line'] + }) + + _html.append('''\t</td>''') + _html.append('''\n</tr>\n''') + _html.append('''</table>''') + if _html_empty: + return None + return ''.join(_html) + + def stat(self): + """ + Returns tuple of added, and removed lines for this instance + """ + return self.adds, self.removes + + def get_context_of_line( + self, path, diff_line=None, context_before=3, context_after=3): + """ + Returns the context lines for the specified diff line. + + :type diff_line: :class:`DiffLineNumber` + """ + assert self.parsed, "DiffProcessor is not initialized." + + if None not in diff_line: + raise ValueError( + "Cannot specify both line numbers: {}".format(diff_line)) + + file_diff = self._get_file_diff(path) + chunk, idx = self._find_chunk_line_index(file_diff, diff_line) + + first_line_to_include = max(idx - context_before, 0) + first_line_after_context = idx + context_after + 1 + context_lines = chunk[first_line_to_include:first_line_after_context] + + line_contents = [ + _context_line(line) for line in context_lines + if _is_diff_content(line)] + # TODO: johbo: Interim fixup, the diff chunks drop the final newline. + # Once they are fixed, we can drop this line here. + if line_contents: + line_contents[-1] = ( + line_contents[-1][0], line_contents[-1][1].rstrip('\n') + '\n') + return line_contents + + def find_context(self, path, context, offset=0): + """ + Finds the given `context` inside of the diff. + + Use the parameter `offset` to specify which offset the target line has + inside of the given `context`. This way the correct diff line will be + returned. + + :param offset: Shall be used to specify the offset of the main line + within the given `context`. + """ + if offset < 0 or offset >= len(context): + raise ValueError( + "Only positive values up to the length of the context " + "minus one are allowed.") + + matches = [] + file_diff = self._get_file_diff(path) + + for chunk in file_diff['chunks']: + context_iter = iter(context) + for line_idx, line in enumerate(chunk): + try: + if _context_line(line) == context_iter.next(): + continue + except StopIteration: + matches.append((line_idx, chunk)) + context_iter = iter(context) + + # Increment position and triger StopIteration + # if we had a match at the end + line_idx += 1 + try: + context_iter.next() + except StopIteration: + matches.append((line_idx, chunk)) + + effective_offset = len(context) - offset + found_at_diff_lines = [ + _line_to_diff_line_number(chunk[idx - effective_offset]) + for idx, chunk in matches] + + return found_at_diff_lines + + def _get_file_diff(self, path): + for file_diff in self.parsed_diff: + if file_diff['filename'] == path: + break + else: + raise FileNotInDiffException("File {} not in diff".format(path)) + return file_diff + + def _find_chunk_line_index(self, file_diff, diff_line): + for chunk in file_diff['chunks']: + for idx, line in enumerate(chunk): + if line['old_lineno'] == diff_line.old: + return chunk, idx + if line['new_lineno'] == diff_line.new: + return chunk, idx + raise LineNotInDiffException( + "The line {} is not part of the diff.".format(diff_line)) + + +def _is_diff_content(line): + return line['action'] in ( + Action.UNMODIFIED, Action.ADD, Action.DELETE) + + +def _context_line(line): + return (line['action'], line['line']) + + +DiffLineNumber = collections.namedtuple('DiffLineNumber', ['old', 'new']) + + +def _line_to_diff_line_number(line): + new_line_no = line['new_lineno'] or None + old_line_no = line['old_lineno'] or None + return DiffLineNumber(old=old_line_no, new=new_line_no) + + +class FileNotInDiffException(Exception): + """ + Raised when the context for a missing file is requested. + + If you request the context for a line in a file which is not part of the + given diff, then this exception is raised. + """ + + +class LineNotInDiffException(Exception): + """ + Raised when the context for a missing line is requested. + + If you request the context for a line in a file and this line is not + part of the given diff, then this exception is raised. + """ + + +class DiffLimitExceeded(Exception): + pass diff --git a/rhodecode/lib/encrypt.py b/rhodecode/lib/encrypt.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/encrypt.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Generic encryption library for RhodeCode +""" + +import hashlib +import base64 + +from Crypto.Cipher import AES +from Crypto import Random + +from rhodecode.lib.utils2 import safe_str + + +class AESCipher(object): + def __init__(self, key): + # create padding, trim to long enc key + if not key: + raise ValueError('passed key variable is empty') + self.block_size = 32 + self.key = hashlib.sha256(safe_str(key)).digest() + + def encrypt(self, raw): + raw = self._pad(raw) + iv = Random.new().read(AES.block_size) + cipher = AES.new(self.key, AES.MODE_CBC, iv) + return base64.b64encode(iv + cipher.encrypt(raw)) + + def decrypt(self, enc): + enc = base64.b64decode(enc) + iv = enc[:AES.block_size] + cipher = AES.new(self.key, AES.MODE_CBC, iv) + return self._unpad(cipher.decrypt(enc[AES.block_size:])) + + def _pad(self, s): + return (s + (self.block_size - len(s) % self.block_size) + * chr(self.block_size - len(s) % self.block_size)) + + @staticmethod + def _unpad(s): + return s[:-ord(s[len(s)-1:])] \ No newline at end of file diff --git a/rhodecode/lib/exceptions.py b/rhodecode/lib/exceptions.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/exceptions.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Set of custom exceptions used in RhodeCode +""" + +from webob.exc import HTTPClientError + + +class LdapUsernameError(Exception): + pass + + +class LdapPasswordError(Exception): + pass + + +class LdapConnectionError(Exception): + pass + + +class LdapImportError(Exception): + pass + + +class DefaultUserException(Exception): + pass + + +class UserOwnsReposException(Exception): + pass + + +class UserOwnsRepoGroupsException(Exception): + pass + + +class UserOwnsUserGroupsException(Exception): + pass + + +class UserGroupAssignedException(Exception): + pass + + +class StatusChangeOnClosedPullRequestError(Exception): + pass + + +class AttachedForksError(Exception): + pass + + +class RepoGroupAssignmentError(Exception): + pass + + +class NonRelativePathError(Exception): + pass + + +class HTTPRequirementError(HTTPClientError): + title = explanation = 'Repository Requirement Missing' + reason = None + + def __init__(self, message, *args, **kwargs): + self.title = self.explanation = message + super(HTTPRequirementError, self).__init__(*args, **kwargs) + self.args = (message, ) + + +class HTTPLockedRC(HTTPClientError): + """ + Special Exception For locked Repos in RhodeCode, the return code can + be overwritten by _code keyword argument passed into constructors + """ + code = 423 + title = explanation = 'Repository Locked' + reason = None + + def __init__(self, message, *args, **kwargs): + from rhodecode import CONFIG + from rhodecode.lib.utils2 import safe_int + _code = CONFIG.get('lock_ret_code') + self.code = safe_int(_code, self.code) + self.title = self.explanation = message + super(HTTPLockedRC, self).__init__(*args, **kwargs) + self.args = (message, ) + + +class IMCCommitError(Exception): + pass + + +class UserCreationError(Exception): + pass + + +class NotAllowedToCreateUserError(Exception): + pass + + +class RepositoryCreationError(Exception): + pass diff --git a/rhodecode/lib/ext_json.py b/rhodecode/lib/ext_json.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/ext_json.py @@ -0,0 +1,64 @@ +import datetime +import decimal +import functools + +import simplejson as json + +from rhodecode.lib.datelib import is_aware + +try: + import pylons +except ImportError: + pylons = None + +__all__ = ['json'] + + +def _obj_dump(obj): + """ + Custom function for dumping objects to JSON, if obj has __json__ attribute + or method defined it will be used for serialization + + :param obj: + """ + + # See "Date Time String Format" in the ECMA-262 specification. + # some code borrowed from django 1.4 + if isinstance(obj, set): + return list(obj) + elif isinstance(obj, datetime.datetime): + r = obj.isoformat() + if isinstance(obj.microsecond, (int, long)): + r = r[:23] + r[26:] + if r.endswith('+00:00'): + r = r[:-6] + 'Z' + return r + elif isinstance(obj, datetime.date): + return obj.isoformat() + elif isinstance(obj, datetime.time): + if is_aware(obj): + raise TypeError("Time-zone aware times are not JSON serializable") + r = obj.isoformat() + if isinstance(obj.microsecond, (int, long)): + r = r[:12] + return r + elif hasattr(obj, '__json__'): + if callable(obj.__json__): + return obj.__json__() + else: + return obj.__json__ + elif isinstance(obj, decimal.Decimal): + return str(obj) + elif isinstance(obj, complex): + return [obj.real, obj.imag] + elif pylons and isinstance(obj, pylons.i18n.translation.LazyString): + return obj.eval() + else: + raise TypeError(repr(obj) + " is not JSON serializable") + + +json.dumps = functools.partial(json.dumps, default=_obj_dump, use_decimal=False) +json.dump = functools.partial(json.dump, default=_obj_dump, use_decimal=False) + +# alias for formatted json +formatted_json = functools.partial(json.dumps, indent=4, sort_keys=True) diff --git a/rhodecode/lib/fakemod.py b/rhodecode/lib/fakemod.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/fakemod.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import imp + + +def create_module(name, path): + """ + Returns module created *on the fly*. Returned module would have name same + as given ``name`` and would contain code read from file at the given + ``path`` (it may also be a zip or package containing *__main__* module). + """ + module = imp.new_module(name) + module.__file__ = path + execfile(path, module.__dict__) + return module diff --git a/rhodecode/lib/graphmod.py b/rhodecode/lib/graphmod.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/graphmod.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Modified mercurial DAG graph functions that re-uses VCS structure + +It allows to have a shared codebase for DAG generation for hg and git repos +""" + +nullrev = -1 + + +def grandparent(parent_idx_func, lowest_idx, roots, head): + """ + Return all ancestors of head in roots which commit is + greater or equal to lowest_idx. + """ + pending = set([head]) + seen = set() + kept = set() + llowestrev = max(nullrev, lowest_idx) + while pending: + r = pending.pop() + if r >= llowestrev and r not in seen: + if r in roots: + kept.add(r) + else: + pending.update(parent_idx_func(r)) + seen.add(r) + return sorted(kept) + + +def _dagwalker(repo, commits): + if not commits: + return + + # TODO: johbo: Use some sort of vcs api here + if repo.alias == 'hg': + def get_parent_indexes(idx): + return repo._remote.ctx_parents(idx) + + elif repo.alias in ['git', 'svn']: + def get_parent_indexes(idx): + return [commit.idx for commit in repo[idx].parents] + + indexes = [commit.idx for commit in commits] + lowest_idx = min(indexes) + known_indexes = set(indexes) + + gpcache = {} + for commit in commits: + parents = sorted(set([p.idx for p in commit.parents + if p.idx in known_indexes])) + mpars = [p.idx for p in commit.parents if + p.idx != nullrev and p.idx not in parents] + for mpar in mpars: + gp = gpcache.get(mpar) + if gp is None: + gp = gpcache[mpar] = grandparent( + get_parent_indexes, lowest_idx, indexes, mpar) + if not gp: + parents.append(mpar) + else: + parents.extend(g for g in gp if g not in parents) + + yield (commit.idx, parents) + + +def _colored(dag): + """annotates a DAG with colored edge information + + For each DAG node this function emits tuples:: + + ((col, color), [(col, nextcol, color)]) + + with the following new elements: + + - Tuple (col, color) with column and color index for the current node + - A list of tuples indicating the edges between the current node and its + parents. + """ + seen = [] + colors = {} + newcolor = 1 + + for commit_idx, parents in dag: + + # Compute seen and next_ + if commit_idx not in seen: + seen.append(commit_idx) # new head + colors[commit_idx] = newcolor + newcolor += 1 + + col = seen.index(commit_idx) + color = colors.pop(commit_idx) + next_ = seen[:] + + # Add parents to next_ + addparents = [p for p in parents if p not in next_] + next_[col:col + 1] = addparents + + # Set colors for the parents + for i, p in enumerate(addparents): + if i == 0: + colors[p] = color + else: + colors[p] = newcolor + newcolor += 1 + + # Add edges to the graph + edges = [] + for ecol, eid in enumerate(seen): + if eid in next_: + edges.append((ecol, next_.index(eid), colors[eid])) + elif eid == commit_idx: + total_parents = len(parents) + edges.extend([ + (ecol, next_.index(p), + _get_edge_color(p, total_parents, color, colors)) + for p in parents]) + + # Yield and move on + yield ((col, color), edges) + seen = next_ + + +def _get_edge_color(parent, total_parents, color, colors): + if total_parents <= 1: + return color + + return colors.get(parent, color) diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/helpers.py @@ -0,0 +1,1712 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Helper functions + +Consists of functions to typically be used within templates, but also +available to Controllers. This module is available to both as 'h'. +""" + +import random +import hashlib +import StringIO +import urllib +import math +import logging +import re +import urlparse +import time +import string +import hashlib + +from datetime import datetime +from functools import partial +from pygments.formatters.html import HtmlFormatter +from pygments import highlight as code_highlight +from pylons import url +from pylons.i18n.translation import _, ungettext +from pyramid.threadlocal import get_current_request + +from webhelpers.html import literal, HTML, escape +from webhelpers.html.tools import * +from webhelpers.html.builder import make_tag +from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \ + end_form, file, form as wh_form, hidden, image, javascript_link, link_to, \ + link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \ + submit, text, password, textarea, title, ul, xml_declaration, radio +from webhelpers.html.tools import auto_link, button_to, highlight, \ + js_obfuscate, mail_to, strip_links, strip_tags, tag_re +from webhelpers.pylonslib import Flash as _Flash +from webhelpers.text import chop_at, collapse, convert_accented_entities, \ + convert_misc_entities, lchop, plural, rchop, remove_formatting, \ + replace_whitespace, urlify, truncate, wrap_paragraphs +from webhelpers.date import time_ago_in_words +from webhelpers.paginate import Page as _Page +from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \ + convert_boolean_attrs, NotGiven, _make_safe_id_component +from webhelpers2.number import format_byte_size + +from rhodecode.lib.annotate import annotate_highlight +from rhodecode.lib.action_parser import action_parser +from rhodecode.lib.utils import repo_name_slug, get_custom_lexer +from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \ + get_commit_safe, datetime_to_time, time_to_datetime, AttributeDict, \ + safe_int, md5, md5_safe +from rhodecode.lib.markup_renderer import MarkupRenderer +from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError +from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyCommit +from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.db import Permission, User, Repository +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.settings import IssueTrackerSettingsModel + +log = logging.getLogger(__name__) + +DEFAULT_USER = User.DEFAULT_USER +DEFAULT_USER_EMAIL = User.DEFAULT_USER_EMAIL + + +def html_escape(text, html_escape_table=None): + """Produce entities within text.""" + if not html_escape_table: + html_escape_table = { + "&": "&", + '"': """, + "'": "'", + ">": ">", + "<": "<", + } + return "".join(html_escape_table.get(c, c) for c in text) + + +def chop_at_smart(s, sub, inclusive=False, suffix_if_chopped=None): + """ + Truncate string ``s`` at the first occurrence of ``sub``. + + If ``inclusive`` is true, truncate just after ``sub`` rather than at it. + """ + suffix_if_chopped = suffix_if_chopped or '' + pos = s.find(sub) + if pos == -1: + return s + + if inclusive: + pos += len(sub) + + chopped = s[:pos] + left = s[pos:].strip() + + if left and suffix_if_chopped: + chopped += suffix_if_chopped + + return chopped + + +def shorter(text, size=20): + postfix = '...' + if len(text) > size: + return text[:size - len(postfix)] + postfix + return text + + +def _reset(name, value=None, id=NotGiven, type="reset", **attrs): + """ + Reset button + """ + _set_input_attrs(attrs, type, name, value) + _set_id_attr(attrs, id, name) + convert_boolean_attrs(attrs, ["disabled"]) + return HTML.input(**attrs) + +reset = _reset +safeid = _make_safe_id_component + + +def branding(name, length=40): + return truncate(name, length, indicator="") + + +def FID(raw_id, path): + """ + Creates a unique ID for filenode based on it's hash of path and commit + it's safe to use in urls + + :param raw_id: + :param path: + """ + + return 'c-%s-%s' % (short_id(raw_id), md5_safe(path)[:12]) + + +class _GetError(object): + """Get error from form_errors, and represent it as span wrapped error + message + + :param field_name: field to fetch errors for + :param form_errors: form errors dict + """ + + def __call__(self, field_name, form_errors): + tmpl = """<span class="error_msg">%s</span>""" + if form_errors and field_name in form_errors: + return literal(tmpl % form_errors.get(field_name)) + +get_error = _GetError() + + +class _ToolTip(object): + + def __call__(self, tooltip_title, trim_at=50): + """ + Special function just to wrap our text into nice formatted + autowrapped text + + :param tooltip_title: + """ + tooltip_title = escape(tooltip_title) + tooltip_title = tooltip_title.replace('<', '<').replace('>', '>') + return tooltip_title +tooltip = _ToolTip() + + +def files_breadcrumbs(repo_name, commit_id, file_path): + if isinstance(file_path, str): + file_path = safe_unicode(file_path) + + # TODO: johbo: Is this always a url like path, or is this operating + # system dependent? + path_segments = file_path.split('/') + + repo_name_html = escape(repo_name) + if len(path_segments) == 1 and path_segments[0] == '': + url_segments = [repo_name_html] + else: + url_segments = [ + link_to( + repo_name_html, + url('files_home', + repo_name=repo_name, + revision=commit_id, + f_path=''), + class_='pjax-link')] + + last_cnt = len(path_segments) - 1 + for cnt, segment in enumerate(path_segments): + if not segment: + continue + segment_html = escape(segment) + + if cnt != last_cnt: + url_segments.append( + link_to( + segment_html, + url('files_home', + repo_name=repo_name, + revision=commit_id, + f_path='/'.join(path_segments[:cnt + 1])), + class_='pjax-link')) + else: + url_segments.append(segment_html) + + return literal('/'.join(url_segments)) + + +class CodeHtmlFormatter(HtmlFormatter): + """ + My code Html Formatter for source codes + """ + + def wrap(self, source, outfile): + return self._wrap_div(self._wrap_pre(self._wrap_code(source))) + + def _wrap_code(self, source): + for cnt, it in enumerate(source): + i, t = it + t = '<div id="L%s">%s</div>' % (cnt + 1, t) + yield i, t + + def _wrap_tablelinenos(self, inner): + dummyoutfile = StringIO.StringIO() + lncount = 0 + for t, line in inner: + if t: + lncount += 1 + dummyoutfile.write(line) + + fl = self.linenostart + mw = len(str(lncount + fl - 1)) + sp = self.linenospecial + st = self.linenostep + la = self.lineanchors + aln = self.anchorlinenos + nocls = self.noclasses + if sp: + lines = [] + + for i in range(fl, fl + lncount): + if i % st == 0: + if i % sp == 0: + if aln: + lines.append('<a href="#%s%d" class="special">%*d</a>' % + (la, i, mw, i)) + else: + lines.append('<span class="special">%*d</span>' % (mw, i)) + else: + if aln: + lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) + else: + lines.append('%*d' % (mw, i)) + else: + lines.append('') + ls = '\n'.join(lines) + else: + lines = [] + for i in range(fl, fl + lncount): + if i % st == 0: + if aln: + lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) + else: + lines.append('%*d' % (mw, i)) + else: + lines.append('') + ls = '\n'.join(lines) + + # in case you wonder about the seemingly redundant <div> here: since the + # content in the other cell also is wrapped in a div, some browsers in + # some configurations seem to mess up the formatting... + if nocls: + yield 0, ('<table class="%stable">' % self.cssclass + + '<tr><td><div class="linenodiv" ' + 'style="background-color: #f0f0f0; padding-right: 10px">' + '<pre style="line-height: 125%">' + + ls + '</pre></div></td><td id="hlcode" class="code">') + else: + yield 0, ('<table class="%stable">' % self.cssclass + + '<tr><td class="linenos"><div class="linenodiv"><pre>' + + ls + '</pre></div></td><td id="hlcode" class="code">') + yield 0, dummyoutfile.getvalue() + yield 0, '</td></tr></table>' + + +def pygmentize(filenode, **kwargs): + """ + pygmentize function using pygments + + :param filenode: + """ + lexer = get_custom_lexer(filenode.extension) or filenode.lexer + return literal(code_highlight(filenode.content, lexer, + CodeHtmlFormatter(**kwargs))) + + +def pygmentize_annotation(repo_name, filenode, **kwargs): + """ + pygmentize function for annotation + + :param filenode: + """ + + color_dict = {} + + def gen_color(n=10000): + """generator for getting n of evenly distributed colors using + hsv color and golden ratio. It always return same order of colors + + :returns: RGB tuple + """ + + def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) # XXX assume int() truncates! + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + golden_ratio = 0.618033988749895 + h = 0.22717784590367374 + + for _ in xrange(n): + h += golden_ratio + h %= 1 + HSV_tuple = [h, 0.95, 0.95] + RGB_tuple = hsv_to_rgb(*HSV_tuple) + yield map(lambda x: str(int(x * 256)), RGB_tuple) + + cgenerator = gen_color() + + def get_color_string(commit_id): + if commit_id in color_dict: + col = color_dict[commit_id] + else: + col = color_dict[commit_id] = cgenerator.next() + return "color: rgb(%s)! important;" % (', '.join(col)) + + def url_func(repo_name): + + def _url_func(commit): + author = commit.author + date = commit.date + message = tooltip(commit.message) + + tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>" + " %s<br/><b>Date:</b> %s</b><br/><b>Message:" + "</b> %s<br/></div>") + + tooltip_html = tooltip_html % (author, date, message) + lnk_format = '%5s:%s' % ('r%s' % commit.idx, commit.short_id) + uri = link_to( + lnk_format, + url('changeset_home', repo_name=repo_name, + revision=commit.raw_id), + style=get_color_string(commit.raw_id), + class_='tooltip', + title=tooltip_html + ) + + uri += '\n' + return uri + return _url_func + + return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs)) + + +def is_following_repo(repo_name, user_id): + from rhodecode.model.scm import ScmModel + return ScmModel().is_following_repo(repo_name, user_id) + + +class _Message(object): + """A message returned by ``Flash.pop_messages()``. + + Converting the message to a string returns the message text. Instances + also have the following attributes: + + * ``message``: the message text. + * ``category``: the category specified when the message was created. + """ + + def __init__(self, category, message): + self.category = category + self.message = message + + def __str__(self): + return self.message + + __unicode__ = __str__ + + def __html__(self): + return escape(safe_unicode(self.message)) + + +class Flash(_Flash): + + def pop_messages(self): + """Return all accumulated messages and delete them from the session. + + The return value is a list of ``Message`` objects. + """ + from pylons import session + + messages = [] + + # Pop the 'old' pylons flash messages. They are tuples of the form + # (category, message) + for cat, msg in session.pop(self.session_key, []): + messages.append(_Message(cat, msg)) + + # Pop the 'new' pyramid flash messages for each category as list + # of strings. + for cat in self.categories: + for msg in session.pop_flash(queue=cat): + messages.append(_Message(cat, msg)) + # Map messages from the default queue to the 'notice' category. + for msg in session.pop_flash(): + messages.append(_Message('notice', msg)) + + session.save() + return messages + +flash = Flash() + +#============================================================================== +# SCM FILTERS available via h. +#============================================================================== +from rhodecode.lib.vcs.utils import author_name, author_email +from rhodecode.lib.utils2 import credentials_filter, age as _age +from rhodecode.model.db import User, ChangesetStatus + +age = _age +capitalize = lambda x: x.capitalize() +email = author_email +short_id = lambda x: x[:12] +hide_credentials = lambda x: ''.join(credentials_filter(x)) + + +def age_component(datetime_iso, value=None): + title = value or format_date(datetime_iso) + + # detect if we have a timezone info, if not assume UTC + if isinstance(datetime_iso, datetime) and not datetime_iso.tzinfo: + tzinfo = '+00:00' + + return literal( + '<time class="timeago tooltip" ' + 'title="{1}" datetime="{0}{2}">{1}</time>'.format( + datetime_iso, title, tzinfo)) + + +def _shorten_commit_id(commit_id): + from rhodecode import CONFIG + def_len = safe_int(CONFIG.get('rhodecode_show_sha_length', 12)) + return commit_id[:def_len] + + +def get_repo_id_from_name(repo_name): + repo = get_by_repo_name(repo_name) + return repo.repo_id + + +def show_id(commit): + """ + Configurable function that shows ID + by default it's r123:fffeeefffeee + + :param commit: commit instance + """ + from rhodecode import CONFIG + show_idx = str2bool(CONFIG.get('rhodecode_show_revision_number', True)) + + raw_id = _shorten_commit_id(commit.raw_id) + if show_idx: + return 'r%s:%s' % (commit.idx, raw_id) + else: + return '%s' % (raw_id, ) + + +def format_date(date): + """ + use a standardized formatting for dates used in RhodeCode + + :param date: date/datetime object + :return: formatted date + """ + + if date: + _fmt = "%a, %d %b %Y %H:%M:%S" + return safe_unicode(date.strftime(_fmt)) + + return u"" + + +class _RepoChecker(object): + + def __init__(self, backend_alias): + self._backend_alias = backend_alias + + def __call__(self, repository): + if hasattr(repository, 'alias'): + _type = repository.alias + elif hasattr(repository, 'repo_type'): + _type = repository.repo_type + else: + _type = repository + return _type == self._backend_alias + +is_git = _RepoChecker('git') +is_hg = _RepoChecker('hg') +is_svn = _RepoChecker('svn') + + +def get_repo_type_by_name(repo_name): + repo = Repository.get_by_repo_name(repo_name) + return repo.repo_type + + +def is_svn_without_proxy(repository): + from rhodecode import CONFIG + if is_svn(repository): + if not CONFIG.get('rhodecode_proxy_subversion_http_requests', False): + return True + return False + + +def email_or_none(author): + # extract email from the commit string + _email = author_email(author) + if _email != '': + # check it against RhodeCode database, and use the MAIN email for this + # user + user = User.get_by_email(_email, case_insensitive=True, cache=True) + if user is not None: + return user.email + return _email + + # See if it contains a username we can get an email from + user = User.get_by_username(author_name(author), case_insensitive=True, + cache=True) + if user is not None: + return user.email + + # No valid email, not a valid user in the system, none! + return None + + +def discover_user(author): + # if author is already an instance use it for extraction + if isinstance(author, User): + return author + + # Valid email in the attribute passed, see if they're in the system + _email = email(author) + if _email != '': + user = User.get_by_email(_email, case_insensitive=True, cache=True) + if user is not None: + return user + + # Maybe it's a username? + _author = author_name(author) + user = User.get_by_username(_author, case_insensitive=True, + cache=True) + if user is not None: + return user + + return None + + +def link_to_user(author, length=0, **kwargs): + user = discover_user(author) + display_person = person(author, 'username_or_name_or_email') + if length: + display_person = shorter(display_person, length) + + if user: + return link_to( + escape(display_person), + url('user_profile', username=user.username), + **kwargs) + else: + return escape(display_person) + + +def person(author, show_attr="username_and_name"): + # attr to return from fetched user + person_getter = lambda usr: getattr(usr, show_attr) + user = discover_user(author) + if user: + return person_getter(user) + else: + _author = author_name(author) + _email = email(author) + return _author or _email + + +def person_by_id(id_, show_attr="username_and_name"): + # attr to return from fetched user + person_getter = lambda usr: getattr(usr, show_attr) + + #maybe it's an ID ? + if str(id_).isdigit() or isinstance(id_, int): + id_ = int(id_) + user = User.get(id_) + if user is not None: + return person_getter(user) + return id_ + + +def gravatar_with_user(author): + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('base/base.html') + return _render('gravatar_with_user', author) + + +def desc_stylize(value): + """ + converts tags from value into html equivalent + + :param value: + """ + if not value: + return '' + + value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', + '<div class="metatag" tag="see">see => \\1 </div>', value) + value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', + '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value) + value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]', + '<div class="metatag" tag="\\1">\\1 => <a href="/\\2">\\2</a></div>', value) + value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', + '<div class="metatag" tag="lang">\\2</div>', value) + value = re.sub(r'\[([a-z]+)\]', + '<div class="metatag" tag="\\1">\\1</div>', value) + + return value + + +def escaped_stylize(value): + """ + converts tags from value into html equivalent, but escaping its value first + """ + if not value: + return '' + + # Using default webhelper escape method, but has to force it as a + # plain unicode instead of a markup tag to be used in regex expressions + value = unicode(escape(safe_unicode(value))) + + value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', + '<div class="metatag" tag="see">see => \\1 </div>', value) + value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', + '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value) + value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]', + '<div class="metatag" tag="\\1">\\1 => <a href="/\\2">\\2</a></div>', value) + value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', + '<div class="metatag" tag="lang">\\2</div>', value) + value = re.sub(r'\[([a-z]+)\]', + '<div class="metatag" tag="\\1">\\1</div>', value) + + return value + + +def bool2icon(value): + """ + Returns boolean value of a given value, represented as html element with + classes that will represent icons + + :param value: given value to convert to html node + """ + + if value: # does bool conversion + return HTML.tag('i', class_="icon-true") + else: # not true as bool + return HTML.tag('i', class_="icon-false") + + +#============================================================================== +# PERMS +#============================================================================== +from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ +HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll, \ +HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token + + +#============================================================================== +# GRAVATAR URL +#============================================================================== +class InitialsGravatar(object): + def __init__(self, email_address, first_name, last_name, size=30, + background=None, text_color='#fff'): + self.size = size + self.first_name = first_name + self.last_name = last_name + self.email_address = email_address + self.background = background or self.str2color(email_address) + self.text_color = text_color + + def get_color_bank(self): + """ + returns a predefined list of colors that gravatars can use. + Those are randomized distinct colors that guarantee readability and + uniqueness. + + generated with: http://phrogz.net/css/distinct-colors.html + """ + return [ + '#bf3030', '#a67f53', '#00ff00', '#5989b3', '#392040', '#d90000', + '#402910', '#204020', '#79baf2', '#a700b3', '#bf6060', '#7f5320', + '#008000', '#003059', '#ee00ff', '#ff0000', '#8c4b00', '#007300', + '#005fb3', '#de73e6', '#ff4040', '#ffaa00', '#3df255', '#203140', + '#47004d', '#591616', '#664400', '#59b365', '#0d2133', '#83008c', + '#592d2d', '#bf9f60', '#73e682', '#1d3f73', '#73006b', '#402020', + '#b2862d', '#397341', '#597db3', '#e600d6', '#a60000', '#736039', + '#00b318', '#79aaf2', '#330d30', '#ff8080', '#403010', '#16591f', + '#002459', '#8c4688', '#e50000', '#ffbf40', '#00732e', '#102340', + '#bf60ac', '#8c4646', '#cc8800', '#00a642', '#1d3473', '#b32d98', + '#660e00', '#ffd580', '#80ffb2', '#7391e6', '#733967', '#d97b6c', + '#8c5e00', '#59b389', '#3967e6', '#590047', '#73281d', '#665200', + '#00e67a', '#2d50b3', '#8c2377', '#734139', '#b2982d', '#16593a', + '#001859', '#ff00aa', '#a65e53', '#ffcc00', '#0d3321', '#2d3959', + '#731d56', '#401610', '#4c3d00', '#468c6c', '#002ca6', '#d936a3', + '#d94c36', '#403920', '#36d9a3', '#0d1733', '#592d4a', '#993626', + '#cca300', '#00734d', '#46598c', '#8c005e', '#7f1100', '#8c7000', + '#00a66f', '#7382e6', '#b32d74', '#d9896c', '#ffe680', '#1d7362', + '#364cd9', '#73003d', '#d93a00', '#998a4d', '#59b3a1', '#5965b3', + '#e5007a', '#73341d', '#665f00', '#00b38f', '#0018b3', '#59163a', + '#b2502d', '#bfb960', '#00ffcc', '#23318c', '#a6537f', '#734939', + '#b2a700', '#104036', '#3d3df2', '#402031', '#e56739', '#736f39', + '#79f2ea', '#000059', '#401029', '#4c1400', '#ffee00', '#005953', + '#101040', '#990052', '#402820', '#403d10', '#00ffee', '#0000d9', + '#ff80c4', '#a66953', '#eeff00', '#00ccbe', '#8080ff', '#e673a1', + '#a62c00', '#474d00', '#1a3331', '#46468c', '#733950', '#662900', + '#858c23', '#238c85', '#0f0073', '#b20047', '#d9986c', '#becc00', + '#396f73', '#281d73', '#ff0066', '#ff6600', '#dee673', '#59adb3', + '#6559b3', '#590024', '#b2622d', '#98b32d', '#36ced9', '#332d59', + '#40001a', '#733f1d', '#526600', '#005359', '#242040', '#bf6079', + '#735039', '#cef23d', '#007780', '#5630bf', '#66001b', '#b24700', + '#acbf60', '#1d6273', '#25008c', '#731d34', '#a67453', '#50592d', + '#00ccff', '#6600ff', '#ff0044', '#4c1f00', '#8a994d', '#79daf2', + '#a173e6', '#d93662', '#402310', '#aaff00', '#2d98b3', '#8c40ff', + '#592d39', '#ff8c40', '#354020', '#103640', '#1a0040', '#331a20', + '#331400', '#334d00', '#1d5673', '#583973', '#7f0022', '#4c3626', + '#88cc00', '#36a3d9', '#3d0073', '#d9364c', '#33241a', '#698c23', + '#5995b3', '#300059', '#e57382', '#7f3300', '#366600', '#00aaff', + '#3a1659', '#733941', '#663600', '#74b32d', '#003c59', '#7f53a6', + '#73000f', '#ff8800', '#baf279', '#79caf2', '#291040', '#a6293a', + '#b2742d', '#587339', '#0077b3', '#632699', '#400009', '#d9a66c', + '#294010', '#2d4a59', '#aa00ff', '#4c131b', '#b25f00', '#5ce600', + '#267399', '#a336d9', '#990014', '#664e33', '#86bf60', '#0088ff', + '#7700b3', '#593a16', '#073300', '#1d4b73', '#ac60bf', '#e59539', + '#4f8c46', '#368dd9', '#5c0073' + ] + + def rgb_to_hex_color(self, rgb_tuple): + """ + Converts an rgb_tuple passed to an hex color. + + :param rgb_tuple: tuple with 3 ints represents rgb color space + """ + return '#' + ("".join(map(chr, rgb_tuple)).encode('hex')) + + def email_to_int_list(self, email_str): + """ + Get every byte of the hex digest value of email and turn it to integer. + It's going to be always between 0-255 + """ + digest = md5_safe(email_str.lower()) + return [int(digest[i * 2:i * 2 + 2], 16) for i in range(16)] + + def pick_color_bank_index(self, email_str, color_bank): + return self.email_to_int_list(email_str)[0] % len(color_bank) + + def str2color(self, email_str): + """ + Tries to map in a stable algorithm an email to color + + :param email_str: + """ + color_bank = self.get_color_bank() + # pick position (module it's length so we always find it in the + # bank even if it's smaller than 256 values + pos = self.pick_color_bank_index(email_str, color_bank) + return color_bank[pos] + + def normalize_email(self, email_address): + import unicodedata + # default host used to fill in the fake/missing email + default_host = u'localhost' + + if not email_address: + email_address = u'%s@%s' % (User.DEFAULT_USER, default_host) + + email_address = safe_unicode(email_address) + + if u'@' not in email_address: + email_address = u'%s@%s' % (email_address, default_host) + + if email_address.endswith(u'@'): + email_address = u'%s%s' % (email_address, default_host) + + email_address = unicodedata.normalize('NFKD', email_address)\ + .encode('ascii', 'ignore') + return email_address + + def get_initials(self): + """ + Returns 2 letter initials calculated based on the input. + The algorithm picks first given email address, and takes first letter + of part before @, and then the first letter of server name. In case + the part before @ is in a format of `somestring.somestring2` it replaces + the server letter with first letter of somestring2 + + In case function was initialized with both first and lastname, this + overrides the extraction from email by first letter of the first and + last name. We add special logic to that functionality, In case Full name + is compound, like Guido Von Rossum, we use last part of the last name + (Von Rossum) picking `R`. + + Function also normalizes the non-ascii characters to they ascii + representation, eg Ą => A + """ + import unicodedata + # replace non-ascii to ascii + first_name = unicodedata.normalize( + 'NFKD', safe_unicode(self.first_name)).encode('ascii', 'ignore') + last_name = unicodedata.normalize( + 'NFKD', safe_unicode(self.last_name)).encode('ascii', 'ignore') + + # do NFKD encoding, and also make sure email has proper format + email_address = self.normalize_email(self.email_address) + + # first push the email initials + prefix, server = email_address.split('@', 1) + + # check if prefix is maybe a 'firstname.lastname' syntax + _dot_split = prefix.rsplit('.', 1) + if len(_dot_split) == 2: + initials = [_dot_split[0][0], _dot_split[1][0]] + else: + initials = [prefix[0], server[0]] + + # then try to replace either firtname or lastname + fn_letter = (first_name or " ")[0].strip() + ln_letter = (last_name.split(' ', 1)[-1] or " ")[0].strip() + + if fn_letter: + initials[0] = fn_letter + + if ln_letter: + initials[1] = ln_letter + + return ''.join(initials).upper() + + def get_img_data_by_type(self, font_family, img_type): + default_user = """ + <svg xmlns="http://www.w3.org/2000/svg" + version="1.1" x="0px" y="0px" width="{size}" height="{size}" + viewBox="-15 -10 439.165 429.164" + + xml:space="preserve" + style="background:{background};" > + + <path d="M204.583,216.671c50.664,0,91.74-48.075, + 91.74-107.378c0-82.237-41.074-107.377-91.74-107.377 + c-50.668,0-91.74,25.14-91.74,107.377C112.844, + 168.596,153.916,216.671, + 204.583,216.671z" fill="{text_color}"/> + <path d="M407.164,374.717L360.88, + 270.454c-2.117-4.771-5.836-8.728-10.465-11.138l-71.83-37.392 + c-1.584-0.823-3.502-0.663-4.926,0.415c-20.316, + 15.366-44.203,23.488-69.076,23.488c-24.877, + 0-48.762-8.122-69.078-23.488 + c-1.428-1.078-3.346-1.238-4.93-0.415L58.75, + 259.316c-4.631,2.41-8.346,6.365-10.465,11.138L2.001,374.717 + c-3.191,7.188-2.537,15.412,1.75,22.005c4.285, + 6.592,11.537,10.526,19.4,10.526h362.861c7.863,0,15.117-3.936, + 19.402-10.527 C409.699,390.129, + 410.355,381.902,407.164,374.717z" fill="{text_color}"/> + </svg>""".format( + size=self.size, + background='#979797', # @grey4 + text_color=self.text_color, + font_family=font_family) + + return { + "default_user": default_user + }[img_type] + + def get_img_data(self, svg_type=None): + """ + generates the svg metadata for image + """ + + font_family = ','.join([ + 'proximanovaregular', + 'Proxima Nova Regular', + 'Proxima Nova', + 'Arial', + 'Lucida Grande', + 'sans-serif' + ]) + if svg_type: + return self.get_img_data_by_type(font_family, svg_type) + + initials = self.get_initials() + img_data = """ + <svg xmlns="http://www.w3.org/2000/svg" pointer-events="none" + width="{size}" height="{size}" + style="width: 100%; height: 100%; background-color: {background}" + viewBox="0 0 {size} {size}"> + <text text-anchor="middle" y="50%" x="50%" dy="0.35em" + pointer-events="auto" fill="{text_color}" + font-family="{font_family}" + style="font-weight: 400; font-size: {f_size}px;">{text} + </text> + </svg>""".format( + size=self.size, + f_size=self.size/1.85, # scale the text inside the box nicely + background=self.background, + text_color=self.text_color, + text=initials.upper(), + font_family=font_family) + + return img_data + + def generate_svg(self, svg_type=None): + img_data = self.get_img_data(svg_type) + return "data:image/svg+xml;base64,%s" % img_data.encode('base64') + + +def initials_gravatar(email_address, first_name, last_name, size=30): + svg_type = None + if email_address == User.DEFAULT_USER_EMAIL: + svg_type = 'default_user' + klass = InitialsGravatar(email_address, first_name, last_name, size) + return klass.generate_svg(svg_type=svg_type) + + +def gravatar_url(email_address, size=30): + # doh, we need to re-import those to mock it later + from pylons import tmpl_context as c + + _use_gravatar = c.visual.use_gravatar + _gravatar_url = c.visual.gravatar_url or User.DEFAULT_GRAVATAR_URL + + email_address = email_address or User.DEFAULT_USER_EMAIL + if isinstance(email_address, unicode): + # hashlib crashes on unicode items + email_address = safe_str(email_address) + + # empty email or default user + if not email_address or email_address == User.DEFAULT_USER_EMAIL: + return initials_gravatar(User.DEFAULT_USER_EMAIL, '', '', size=size) + + if _use_gravatar: + # TODO: Disuse pyramid thread locals. Think about another solution to + # get the host and schema here. + request = get_current_request() + tmpl = safe_str(_gravatar_url) + tmpl = tmpl.replace('{email}', email_address)\ + .replace('{md5email}', md5_safe(email_address.lower())) \ + .replace('{netloc}', request.host)\ + .replace('{scheme}', request.scheme)\ + .replace('{size}', safe_str(size)) + return tmpl + else: + return initials_gravatar(email_address, '', '', size=size) + + +class Page(_Page): + """ + Custom pager to match rendering style with paginator + """ + + def _get_pos(self, cur_page, max_page, items): + edge = (items / 2) + 1 + if (cur_page <= edge): + radius = max(items / 2, items - cur_page) + elif (max_page - cur_page) < edge: + radius = (items - 1) - (max_page - cur_page) + else: + radius = items / 2 + + left = max(1, (cur_page - (radius))) + right = min(max_page, cur_page + (radius)) + return left, cur_page, right + + def _range(self, regexp_match): + """ + Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8'). + + Arguments: + + regexp_match + A "re" (regular expressions) match object containing the + radius of linked pages around the current page in + regexp_match.group(1) as a string + + This function is supposed to be called as a callable in + re.sub. + + """ + radius = int(regexp_match.group(1)) + + # Compute the first and last page number within the radius + # e.g. '1 .. 5 6 [7] 8 9 .. 12' + # -> leftmost_page = 5 + # -> rightmost_page = 9 + leftmost_page, _cur, rightmost_page = self._get_pos(self.page, + self.last_page, + (radius * 2) + 1) + nav_items = [] + + # Create a link to the first page (unless we are on the first page + # or there would be no need to insert '..' spacers) + if self.page != self.first_page and self.first_page < leftmost_page: + nav_items.append(self._pagerlink(self.first_page, self.first_page)) + + # Insert dots if there are pages between the first page + # and the currently displayed page range + if leftmost_page - self.first_page > 1: + # Wrap in a SPAN tag if nolink_attr is set + text = '..' + if self.dotdot_attr: + text = HTML.span(c=text, **self.dotdot_attr) + nav_items.append(text) + + for thispage in xrange(leftmost_page, rightmost_page + 1): + # Hilight the current page number and do not use a link + if thispage == self.page: + text = '%s' % (thispage,) + # Wrap in a SPAN tag if nolink_attr is set + if self.curpage_attr: + text = HTML.span(c=text, **self.curpage_attr) + nav_items.append(text) + # Otherwise create just a link to that page + else: + text = '%s' % (thispage,) + nav_items.append(self._pagerlink(thispage, text)) + + # Insert dots if there are pages between the displayed + # page numbers and the end of the page range + if self.last_page - rightmost_page > 1: + text = '..' + # Wrap in a SPAN tag if nolink_attr is set + if self.dotdot_attr: + text = HTML.span(c=text, **self.dotdot_attr) + nav_items.append(text) + + # Create a link to the very last page (unless we are on the last + # page or there would be no need to insert '..' spacers) + if self.page != self.last_page and rightmost_page < self.last_page: + nav_items.append(self._pagerlink(self.last_page, self.last_page)) + + ## prerender links + #_page_link = url.current() + #nav_items.append(literal('<link rel="prerender" href="%s?page=%s">' % (_page_link, str(int(self.page)+1)))) + #nav_items.append(literal('<link rel="prefetch" href="%s?page=%s">' % (_page_link, str(int(self.page)+1)))) + return self.separator.join(nav_items) + + def pager(self, format='~2~', page_param='page', partial_param='partial', + show_if_single_page=False, separator=' ', onclick=None, + symbol_first='<<', symbol_last='>>', + symbol_previous='<', symbol_next='>', + link_attr={'class': 'pager_link', 'rel': 'prerender'}, + curpage_attr={'class': 'pager_curpage'}, + dotdot_attr={'class': 'pager_dotdot'}, **kwargs): + + self.curpage_attr = curpage_attr + self.separator = separator + self.pager_kwargs = kwargs + self.page_param = page_param + self.partial_param = partial_param + self.onclick = onclick + self.link_attr = link_attr + self.dotdot_attr = dotdot_attr + + # Don't show navigator if there is no more than one page + if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page): + return '' + + from string import Template + # Replace ~...~ in token format by range of pages + result = re.sub(r'~(\d+)~', self._range, format) + + # Interpolate '%' variables + result = Template(result).safe_substitute({ + 'first_page': self.first_page, + 'last_page': self.last_page, + 'page': self.page, + 'page_count': self.page_count, + 'items_per_page': self.items_per_page, + 'first_item': self.first_item, + 'last_item': self.last_item, + 'item_count': self.item_count, + 'link_first': self.page > self.first_page and \ + self._pagerlink(self.first_page, symbol_first) or '', + 'link_last': self.page < self.last_page and \ + self._pagerlink(self.last_page, symbol_last) or '', + 'link_previous': self.previous_page and \ + self._pagerlink(self.previous_page, symbol_previous) \ + or HTML.span(symbol_previous, class_="pg-previous disabled"), + 'link_next': self.next_page and \ + self._pagerlink(self.next_page, symbol_next) \ + or HTML.span(symbol_next, class_="pg-next disabled") + }) + + return literal(result) + + +#============================================================================== +# REPO PAGER, PAGER FOR REPOSITORY +#============================================================================== +class RepoPage(Page): + + def __init__(self, collection, page=1, items_per_page=20, + item_count=None, url=None, **kwargs): + + """Create a "RepoPage" instance. special pager for paging + repository + """ + self._url_generator = url + + # Safe the kwargs class-wide so they can be used in the pager() method + self.kwargs = kwargs + + # Save a reference to the collection + self.original_collection = collection + + self.collection = collection + + # The self.page is the number of the current page. + # The first page has the number 1! + try: + self.page = int(page) # make it int() if we get it as a string + except (ValueError, TypeError): + self.page = 1 + + self.items_per_page = items_per_page + + # Unless the user tells us how many items the collections has + # we calculate that ourselves. + if item_count is not None: + self.item_count = item_count + else: + self.item_count = len(self.collection) + + # Compute the number of the first and last available page + if self.item_count > 0: + self.first_page = 1 + self.page_count = int(math.ceil(float(self.item_count) / + self.items_per_page)) + self.last_page = self.first_page + self.page_count - 1 + + # Make sure that the requested page number is the range of + # valid pages + if self.page > self.last_page: + self.page = self.last_page + elif self.page < self.first_page: + self.page = self.first_page + + # Note: the number of items on this page can be less than + # items_per_page if the last page is not full + self.first_item = max(0, (self.item_count) - (self.page * + items_per_page)) + self.last_item = ((self.item_count - 1) - items_per_page * + (self.page - 1)) + + self.items = list(self.collection[self.first_item:self.last_item + 1]) + + # Links to previous and next page + if self.page > self.first_page: + self.previous_page = self.page - 1 + else: + self.previous_page = None + + if self.page < self.last_page: + self.next_page = self.page + 1 + else: + self.next_page = None + + # No items available + else: + self.first_page = None + self.page_count = 0 + self.last_page = None + self.first_item = None + self.last_item = None + self.previous_page = None + self.next_page = None + self.items = [] + + # This is a subclass of the 'list' type. Initialise the list now. + list.__init__(self, reversed(self.items)) + + +def changed_tooltip(nodes): + """ + Generates a html string for changed nodes in commit page. + It limits the output to 30 entries + + :param nodes: LazyNodesGenerator + """ + if nodes: + pref = ': <br/> ' + suf = '' + if len(nodes) > 30: + suf = '<br/>' + _(' and %s more') % (len(nodes) - 30) + return literal(pref + '<br/> '.join([safe_unicode(x.path) + for x in nodes[:30]]) + suf) + else: + return ': ' + _('No Files') + + +def breadcrumb_repo_link(repo): + """ + Makes a breadcrumbs path link to repo + + ex:: + group >> subgroup >> repo + + :param repo: a Repository instance + """ + + path = [ + link_to(group.name, url('repo_group_home', group_name=group.group_name)) + for group in repo.groups_with_parents + ] + [ + link_to(repo.just_name, url('summary_home', repo_name=repo.repo_name)) + ] + + return literal(' » '.join(path)) + + +def format_byte_size_binary(file_size): + """ + Formats file/folder sizes to standard. + """ + formatted_size = format_byte_size(file_size, binary=True) + return formatted_size + + +def fancy_file_stats(stats): + """ + Displays a fancy two colored bar for number of added/deleted + lines of code on file + + :param stats: two element list of added/deleted lines of code + """ + from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ + MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE + + def cgen(l_type, a_v, d_v): + mapping = {'tr': 'top-right-rounded-corner-mid', + 'tl': 'top-left-rounded-corner-mid', + 'br': 'bottom-right-rounded-corner-mid', + 'bl': 'bottom-left-rounded-corner-mid'} + map_getter = lambda x: mapping[x] + + if l_type == 'a' and d_v: + #case when added and deleted are present + return ' '.join(map(map_getter, ['tl', 'bl'])) + + if l_type == 'a' and not d_v: + return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) + + if l_type == 'd' and a_v: + return ' '.join(map(map_getter, ['tr', 'br'])) + + if l_type == 'd' and not a_v: + return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) + + a, d = stats['added'], stats['deleted'] + width = 100 + + if stats['binary']: # binary operations like chmod/rename etc + lbl = [] + bin_op = 0 # undefined + + # prefix with bin for binary files + if BIN_FILENODE in stats['ops']: + lbl += ['bin'] + + if NEW_FILENODE in stats['ops']: + lbl += [_('new file')] + bin_op = NEW_FILENODE + elif MOD_FILENODE in stats['ops']: + lbl += [_('mod')] + bin_op = MOD_FILENODE + elif DEL_FILENODE in stats['ops']: + lbl += [_('del')] + bin_op = DEL_FILENODE + elif RENAMED_FILENODE in stats['ops']: + lbl += [_('rename')] + bin_op = RENAMED_FILENODE + + # chmod can go with other operations, so we add a + to lbl if needed + if CHMOD_FILENODE in stats['ops']: + lbl += [_('chmod')] + if bin_op == 0: + bin_op = CHMOD_FILENODE + + lbl = '+'.join(lbl) + b_a = '<div class="bin bin%s %s" style="width:100%%">%s</div>' \ + % (bin_op, cgen('a', a_v='', d_v=0), lbl) + b_d = '<div class="bin bin1" style="width:0%%"></div>' + return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d)) + + t = stats['added'] + stats['deleted'] + unit = float(width) / (t or 1) + + # needs > 9% of width to be visible or 0 to be hidden + a_p = max(9, unit * a) if a > 0 else 0 + d_p = max(9, unit * d) if d > 0 else 0 + p_sum = a_p + d_p + + if p_sum > width: + #adjust the percentage to be == 100% since we adjusted to 9 + if a_p > d_p: + a_p = a_p - (p_sum - width) + else: + d_p = d_p - (p_sum - width) + + a_v = a if a > 0 else '' + d_v = d if d > 0 else '' + + d_a = '<div class="added %s" style="width:%s%%">%s</div>' % ( + cgen('a', a_v, d_v), a_p, a_v + ) + d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % ( + cgen('d', a_v, d_v), d_p, d_v + ) + return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d)) + + +def urlify_text(text_, safe=True): + """ + Extrac urls from text and make html links out of them + + :param text_: + """ + + url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@#.&+]''' + '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''') + + def url_func(match_obj): + url_full = match_obj.groups()[0] + return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full}) + _newtext = url_pat.sub(url_func, text_) + if safe: + return literal(_newtext) + return _newtext + + +def urlify_commits(text_, repository): + """ + Extract commit ids from text and make link from them + + :param text_: + :param repository: repo name to build the URL with + """ + from pylons import url # doh, we need to re-import url to mock it later + URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)') + + def url_func(match_obj): + commit_id = match_obj.groups()[1] + pref = match_obj.groups()[0] + suf = match_obj.groups()[2] + + tmpl = ( + '%(pref)s<a class="%(cls)s" href="%(url)s">' + '%(commit_id)s</a>%(suf)s' + ) + return tmpl % { + 'pref': pref, + 'cls': 'revision-link', + 'url': url('changeset_home', repo_name=repository, + revision=commit_id), + 'commit_id': commit_id, + 'suf': suf + } + + newtext = URL_PAT.sub(url_func, text_) + + return newtext + + +def _process_url_func(match_obj, repo_name, uid, entry): + pref = '' + if match_obj.group().startswith(' '): + pref = ' ' + + issue_id = ''.join(match_obj.groups()) + tmpl = ( + '%(pref)s<a class="%(cls)s" href="%(url)s">' + '%(issue-prefix)s%(id-repr)s' + '</a>') + + (repo_name_cleaned, + parent_group_name) = RepoGroupModel().\ + _get_group_name_and_parent(repo_name) + + # variables replacement + named_vars = { + 'id': issue_id, + 'repo': repo_name, + 'repo_name': repo_name_cleaned, + 'group_name': parent_group_name + } + # named regex variables + named_vars.update(match_obj.groupdict()) + _url = string.Template(entry['url']).safe_substitute(**named_vars) + + return tmpl % { + 'pref': pref, + 'cls': 'issue-tracker-link', + 'url': _url, + 'id-repr': issue_id, + 'issue-prefix': entry['pref'], + 'serv': entry['url'], + } + + +def process_patterns(text_string, repo_name, config): + repo = None + if repo_name: + # Retrieving repo_name to avoid invalid repo_name to explode on + # IssueTrackerSettingsModel but still passing invalid name further down + repo = Repository.get_by_repo_name(repo_name) + + settings_model = IssueTrackerSettingsModel(repo=repo) + active_entries = settings_model.get_settings() + + newtext = text_string + for uid, entry in active_entries.items(): + url_func = partial( + _process_url_func, repo_name=repo_name, entry=entry, uid=uid) + + log.debug('found issue tracker entry with uid %s' % (uid,)) + + if not (entry['pat'] and entry['url']): + log.debug('skipping due to missing data') + continue + + log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s' + % (uid, entry['pat'], entry['url'], entry['pref'])) + + try: + pattern = re.compile(r'%s' % entry['pat']) + except re.error: + log.exception( + 'issue tracker pattern: `%s` failed to compile', + entry['pat']) + continue + + newtext = pattern.sub(url_func, newtext) + log.debug('processed prefix:uid `%s`' % (uid,)) + + return newtext + + +def urlify_commit_message(commit_text, repository=None): + """ + Parses given text message and makes proper links. + issues are linked to given issue-server, and rest is a commit link + + :param commit_text: + :param repository: + """ + from pylons import url # doh, we need to re-import url to mock it later + from rhodecode import CONFIG + + def escaper(string): + return string.replace('<', '<').replace('>', '>') + + newtext = escaper(commit_text) + # urlify commits - extract commit ids and make link out of them, if we have + # the scope of repository present. + if repository: + newtext = urlify_commits(newtext, repository) + + # extract http/https links and make them real urls + newtext = urlify_text(newtext, safe=False) + + # process issue tracker patterns + newtext = process_patterns(newtext, repository or '', CONFIG) + + return literal(newtext) + + +def rst(source, mentions=False): + return literal('<div class="rst-block">%s</div>' % + MarkupRenderer.rst(source, mentions=mentions)) + + +def markdown(source, mentions=False): + return literal('<div class="markdown-block">%s</div>' % + MarkupRenderer.markdown(source, flavored=False, + mentions=mentions)) + +def renderer_from_filename(filename, exclude=None): + from rhodecode.config.conf import MARKDOWN_EXTS, RST_EXTS + + def _filter(elements): + if isinstance(exclude, (list, tuple)): + return [x for x in elements if x not in exclude] + return elements + + if filename.endswith(tuple(_filter([x[0] for x in MARKDOWN_EXTS if x[0]]))): + return 'markdown' + if filename.endswith(tuple(_filter([x[0] for x in RST_EXTS if x[0]]))): + return 'rst' + + +def render(source, renderer='rst', mentions=False): + if renderer == 'rst': + return rst(source, mentions=mentions) + if renderer == 'markdown': + return markdown(source, mentions=mentions) + + +def commit_status(repo, commit_id): + return ChangesetStatusModel().get_status(repo, commit_id) + + +def commit_status_lbl(commit_status): + return dict(ChangesetStatus.STATUSES).get(commit_status) + + +def commit_time(repo_name, commit_id): + repo = Repository.get_by_repo_name(repo_name) + commit = repo.get_commit(commit_id=commit_id) + return commit.date + + +def get_permission_name(key): + return dict(Permission.PERMS).get(key) + + +def journal_filter_help(): + return _( + 'Example filter terms:\n' + + ' repository:vcs\n' + + ' username:marcin\n' + + ' action:*push*\n' + + ' ip:127.0.0.1\n' + + ' date:20120101\n' + + ' date:[20120101100000 TO 20120102]\n' + + '\n' + + 'Generate wildcards using \'*\' character:\n' + + ' "repository:vcs*" - search everything starting with \'vcs\'\n' + + ' "repository:*vcs*" - search for repository containing \'vcs\'\n' + + '\n' + + 'Optional AND / OR operators in queries\n' + + ' "repository:vcs OR repository:test"\n' + + ' "username:test AND repository:test*"\n' + ) + + +def not_mapped_error(repo_name): + flash(_('%s repository is not mapped to db perhaps' + ' it was created or renamed from the filesystem' + ' please run the application again' + ' in order to rescan repositories') % repo_name, category='error') + + +def ip_range(ip_addr): + from rhodecode.model.db import UserIpMap + s, e = UserIpMap._get_ip_range(ip_addr) + return '%s - %s' % (s, e) + + +def form(url, method='post', needs_csrf_token=True, **attrs): + """Wrapper around webhelpers.tags.form to prevent CSRF attacks.""" + if method.lower() != 'get' and needs_csrf_token: + raise Exception( + 'Forms to POST/PUT/DELETE endpoints should have (in general) a ' + + 'CSRF token. If the endpoint does not require such token you can ' + + 'explicitly set the parameter needs_csrf_token to false.') + + return wh_form(url, method=method, **attrs) + + +def secure_form(url, method="POST", multipart=False, **attrs): + """Start a form tag that points the action to an url. This + form tag will also include the hidden field containing + the auth token. + + The url options should be given either as a string, or as a + ``url()`` function. The method for the form defaults to POST. + + Options: + + ``multipart`` + If set to True, the enctype is set to "multipart/form-data". + ``method`` + The method to use when submitting the form, usually either + "GET" or "POST". If "PUT", "DELETE", or another verb is used, a + hidden input with name _method is added to simulate the verb + over POST. + + """ + from webhelpers.pylonslib.secure_form import insecure_form + from rhodecode.lib.auth import get_csrf_token, csrf_token_key + form = insecure_form(url, method, multipart, **attrs) + token = HTML.div(hidden(csrf_token_key, get_csrf_token()), style="display: none;") + return literal("%s\n%s" % (form, token)) + +def dropdownmenu(name, selected, options, enable_filter=False, **attrs): + select_html = select(name, selected, options, **attrs) + select2 = """ + <script> + $(document).ready(function() { + $('#%s').select2({ + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true%s + }); + }); + </script> + """ + filter_option = """, + minimumResultsForSearch: -1 + """ + input_id = attrs.get('id') or name + filter_enabled = "" if enable_filter else filter_option + select_script = literal(select2 % (input_id, filter_enabled)) + + return literal(select_html+select_script) + + +def get_visual_attr(tmpl_context_var, attr_name): + """ + A safe way to get a variable from visual variable of template context + + :param tmpl_context_var: instance of tmpl_context, usually present as `c` + :param attr_name: name of the attribute we fetch from the c.visual + """ + visual = getattr(tmpl_context_var, 'visual', None) + if not visual: + return + else: + return getattr(visual, attr_name, None) + + +def get_last_path_part(file_node): + if not file_node.path: + return u'' + + path = safe_unicode(file_node.path.split('/')[-1]) + return u'../' + path + + +def route_path(*args, **kwds): + """ + Wrapper around pyramids `route_path` function. It is used to generate + URLs from within pylons views or templates. This will be removed when + pyramid migration if finished. + """ + req = get_current_request() + return req.route_path(*args, **kwds) + + +def resource_path(*args, **kwds): + """ + Wrapper around pyramids `route_path` function. It is used to generate + URLs from within pylons views or templates. This will be removed when + pyramid migration if finished. + """ + req = get_current_request() + return req.resource_path(*args, **kwds) diff --git a/rhodecode/lib/hooks_base.py b/rhodecode/lib/hooks_base.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/hooks_base.py @@ -0,0 +1,366 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Set of hooks run by RhodeCode Enterprise +""" + +import os +import collections + +import rhodecode +from rhodecode.lib import helpers as h +from rhodecode.lib.utils import action_logger +from rhodecode.lib.utils2 import safe_str +from rhodecode.lib.exceptions import HTTPLockedRC, UserCreationError +from rhodecode.model.db import Repository, User + + +HookResponse = collections.namedtuple('HookResponse', ('status', 'output')) + + +def _get_scm_size(alias, root_path): + + if not alias.startswith('.'): + alias += '.' + + size_scm, size_root = 0, 0 + for path, unused_dirs, files in os.walk(safe_str(root_path)): + if path.find(alias) != -1: + for f in files: + try: + size_scm += os.path.getsize(os.path.join(path, f)) + except OSError: + pass + else: + for f in files: + try: + size_root += os.path.getsize(os.path.join(path, f)) + except OSError: + pass + + size_scm_f = h.format_byte_size_binary(size_scm) + size_root_f = h.format_byte_size_binary(size_root) + size_total_f = h.format_byte_size_binary(size_root + size_scm) + + return size_scm_f, size_root_f, size_total_f + + +# actual hooks called by Mercurial internally, and GIT by our Python Hooks +def repo_size(extras): + """Present size of repository after push.""" + repo = Repository.get_by_repo_name(extras.repository) + vcs_part = safe_str(u'.%s' % repo.repo_type) + size_vcs, size_root, size_total = _get_scm_size(vcs_part, + repo.repo_full_path) + msg = ('Repository `%s` size summary %s:%s repo:%s total:%s\n' + % (repo.repo_name, vcs_part, size_vcs, size_root, size_total)) + return HookResponse(0, msg) + + +def pre_push(extras): + """ + Hook executed before pushing code. + + It bans pushing when the repository is locked. + """ + usr = User.get_by_username(extras.username) + + + output = '' + if extras.locked_by[0] and usr.user_id != int(extras.locked_by[0]): + locked_by = User.get(extras.locked_by[0]).username + reason = extras.locked_by[2] + # this exception is interpreted in git/hg middlewares and based + # on that proper return code is server to client + _http_ret = HTTPLockedRC( + _locked_by_explanation(extras.repository, locked_by, reason)) + if str(_http_ret.code).startswith('2'): + # 2xx Codes don't raise exceptions + output = _http_ret.title + else: + raise _http_ret + + # Calling hooks after checking the lock, for consistent behavior + pre_push_extension(repo_store_path=Repository.base_path(), **extras) + + return HookResponse(0, output) + + +def pre_pull(extras): + """ + Hook executed before pulling the code. + + It bans pulling when the repository is locked. + """ + + output = '' + if extras.locked_by[0]: + locked_by = User.get(extras.locked_by[0]).username + reason = extras.locked_by[2] + # this exception is interpreted in git/hg middlewares and based + # on that proper return code is server to client + _http_ret = HTTPLockedRC( + _locked_by_explanation(extras.repository, locked_by, reason)) + if str(_http_ret.code).startswith('2'): + # 2xx Codes don't raise exceptions + output = _http_ret.title + else: + raise _http_ret + + # Calling hooks after checking the lock, for consistent behavior + pre_pull_extension(**extras) + + return HookResponse(0, output) + + +def post_pull(extras): + """Hook executed after client pulls the code.""" + user = User.get_by_username(extras.username) + action = 'pull' + action_logger(user, action, extras.repository, extras.ip, commit=True) + + # extension hook call + post_pull_extension(**extras) + + output = '' + # make lock is a tri state False, True, None. We only make lock on True + if extras.make_lock is True: + Repository.lock(Repository.get_by_repo_name(extras.repository), + user.user_id, + lock_reason=Repository.LOCK_PULL) + msg = 'Made lock on repo `%s`' % (extras.repository,) + output += msg + + if extras.locked_by[0]: + locked_by = User.get(extras.locked_by[0]).username + reason = extras.locked_by[2] + _http_ret = HTTPLockedRC( + _locked_by_explanation(extras.repository, locked_by, reason)) + if str(_http_ret.code).startswith('2'): + # 2xx Codes don't raise exceptions + output += _http_ret.title + + return HookResponse(0, output) + + +def post_push(extras): + """Hook executed after user pushes to the repository.""" + action_tmpl = extras.action + ':%s' + commit_ids = extras.commit_ids[:29000] + + action = action_tmpl % ','.join(commit_ids) + action_logger( + extras.username, action, extras.repository, extras.ip, commit=True) + + # extension hook call + post_push_extension( + repo_store_path=Repository.base_path(), + pushed_revs=commit_ids, + **extras) + + output = '' + # make lock is a tri state False, True, None. We only release lock on False + if extras.make_lock is False: + Repository.unlock(Repository.get_by_repo_name(extras.repository)) + msg = 'Released lock on repo `%s`\n' % extras.repository + output += msg + + if extras.locked_by[0]: + locked_by = User.get(extras.locked_by[0]).username + reason = extras.locked_by[2] + _http_ret = HTTPLockedRC( + _locked_by_explanation(extras.repository, locked_by, reason)) + # TODO: johbo: if not? + if str(_http_ret.code).startswith('2'): + # 2xx Codes don't raise exceptions + output += _http_ret.title + + output += 'RhodeCode: push completed\n' + + return HookResponse(0, output) + + +def _locked_by_explanation(repo_name, user_name, reason): + message = ( + 'Repository `%s` locked by user `%s`. Reason:`%s`' + % (repo_name, user_name, reason)) + return message + + +def check_allowed_create_user(user_dict, created_by, **kwargs): + # pre create hooks + if pre_create_user.is_active(): + allowed, reason = pre_create_user(created_by=created_by, **user_dict) + if not allowed: + raise UserCreationError(reason) + + +class ExtensionCallback(object): + """ + Forwards a given call to rcextensions, sanitizes keyword arguments. + + Does check if there is an extension active for that hook. If it is + there, it will forward all `kwargs_keys` keyword arguments to the + extension callback. + """ + + def __init__(self, hook_name, kwargs_keys): + self._hook_name = hook_name + self._kwargs_keys = set(kwargs_keys) + + def __call__(self, *args, **kwargs): + kwargs_to_pass = dict((key, kwargs[key]) for key in self._kwargs_keys) + callback = self._get_callback() + if callback: + return callback(**kwargs_to_pass) + + def is_active(self): + return hasattr(rhodecode.EXTENSIONS, self._hook_name) + + def _get_callback(self): + return getattr(rhodecode.EXTENSIONS, self._hook_name, None) + + +pre_pull_extension = ExtensionCallback( + hook_name='PRE_PULL_HOOK', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository')) + + +post_pull_extension = ExtensionCallback( + hook_name='PULL_HOOK', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository')) + + +pre_push_extension = ExtensionCallback( + hook_name='PRE_PUSH_HOOK', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'repo_store_path')) + + +post_push_extension = ExtensionCallback( + hook_name='PUSH_HOOK', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'repo_store_path', 'pushed_revs')) + + +pre_create_user = ExtensionCallback( + hook_name='PRE_CREATE_USER_HOOK', + kwargs_keys=( + 'username', 'password', 'email', 'firstname', 'lastname', 'active', + 'admin', 'created_by')) + + +log_create_pull_request = ExtensionCallback( + hook_name='CREATE_PULL_REQUEST', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers')) + + +log_merge_pull_request = ExtensionCallback( + hook_name='MERGE_PULL_REQUEST', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers')) + + +log_close_pull_request = ExtensionCallback( + hook_name='CLOSE_PULL_REQUEST', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers')) + + +log_review_pull_request = ExtensionCallback( + hook_name='REVIEW_PULL_REQUEST', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers')) + + +log_update_pull_request = ExtensionCallback( + hook_name='UPDATE_PULL_REQUEST', + kwargs_keys=( + 'server_url', 'config', 'scm', 'username', 'ip', 'action', + 'repository', 'pull_request_id', 'url', 'title', 'description', + 'status', 'created_on', 'updated_on', 'commit_ids', 'review_status', + 'mergeable', 'source', 'target', 'author', 'reviewers')) + + +log_create_user = ExtensionCallback( + hook_name='CREATE_USER_HOOK', + kwargs_keys=( + 'username', 'full_name_or_username', 'full_contact', 'user_id', + 'name', 'firstname', 'short_contact', 'admin', 'lastname', + 'ip_addresses', 'extern_type', 'extern_name', + 'email', 'api_key', 'api_keys', 'last_login', + 'full_name', 'active', 'password', 'emails', + 'inherit_default_permissions', 'created_by', 'created_on')) + + +log_delete_user = ExtensionCallback( + hook_name='DELETE_USER_HOOK', + kwargs_keys=( + 'username', 'full_name_or_username', 'full_contact', 'user_id', + 'name', 'firstname', 'short_contact', 'admin', 'lastname', + 'ip_addresses', + 'email', 'api_key', 'last_login', + 'full_name', 'active', 'password', 'emails', + 'inherit_default_permissions', 'deleted_by')) + + +log_create_repository = ExtensionCallback( + hook_name='CREATE_REPO_HOOK', + kwargs_keys=( + 'repo_name', 'repo_type', 'description', 'private', 'created_on', + 'enable_downloads', 'repo_id', 'user_id', 'enable_statistics', + 'clone_uri', 'fork_id', 'group_id', 'created_by')) + + +log_delete_repository = ExtensionCallback( + hook_name='DELETE_REPO_HOOK', + kwargs_keys=( + 'repo_name', 'repo_type', 'description', 'private', 'created_on', + 'enable_downloads', 'repo_id', 'user_id', 'enable_statistics', + 'clone_uri', 'fork_id', 'group_id', 'deleted_by', 'deleted_on')) + + +log_create_repository_group = ExtensionCallback( + hook_name='CREATE_REPO_GROUP_HOOK', + kwargs_keys=( + 'group_name', 'group_parent_id', 'group_description', + 'group_id', 'user_id', 'created_by', 'created_on', + 'enable_locking')) diff --git a/rhodecode/lib/hooks_daemon.py b/rhodecode/lib/hooks_daemon.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/hooks_daemon.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import json +import logging +import threading +from BaseHTTPServer import BaseHTTPRequestHandler +from SocketServer import TCPServer + +import Pyro4 + +from rhodecode.lib import hooks_base +from rhodecode.lib.utils2 import AttributeDict + + +log = logging.getLogger(__name__) + + +class HooksHttpHandler(BaseHTTPRequestHandler): + def do_POST(self): + method, extras = self._read_request() + try: + result = self._call_hook(method, extras) + except Exception as e: + result = { + 'exception': e.__class__.__name__, + 'exception_args': e.args + } + self._write_response(result) + + def _read_request(self): + length = int(self.headers['Content-Length']) + body = self.rfile.read(length).decode('utf-8') + data = json.loads(body) + return data['method'], data['extras'] + + def _write_response(self, result): + self.send_response(200) + self.send_header("Content-type", "text/json") + self.end_headers() + self.wfile.write(json.dumps(result)) + + def _call_hook(self, method, extras): + hooks = Hooks() + result = getattr(hooks, method)(extras) + return result + + def log_message(self, format, *args): + """ + This is an overriden method of BaseHTTPRequestHandler which logs using + logging library instead of writing directly to stderr. + """ + + message = format % args + + # TODO: mikhail: add different log levels support + log.debug( + "%s - - [%s] %s", self.client_address[0], + self.log_date_time_string(), message) + + +class DummyHooksCallbackDaemon(object): + def __init__(self): + self.hooks_module = Hooks.__module__ + + def __enter__(self): + log.debug('Running dummy hooks callback daemon') + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + log.debug('Exiting dummy hooks callback daemon') + + +class ThreadedHookCallbackDaemon(object): + + _callback_thread = None + _daemon = None + _done = False + + def __init__(self): + self._prepare() + + def __enter__(self): + self._run() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self._stop() + + def _prepare(self): + raise NotImplementedError() + + def _run(self): + raise NotImplementedError() + + def _stop(self): + raise NotImplementedError() + + +class Pyro4HooksCallbackDaemon(ThreadedHookCallbackDaemon): + """ + Context manager which will run a callback daemon in a background thread. + """ + + hooks_uri = None + + def _prepare(self): + log.debug("Preparing callback daemon and registering hook object") + self._daemon = Pyro4.Daemon() + hooks_interface = Hooks() + self.hooks_uri = str(self._daemon.register(hooks_interface)) + log.debug("Hooks uri is: %s", self.hooks_uri) + + def _run(self): + log.debug("Running event loop of callback daemon in background thread") + callback_thread = threading.Thread( + target=self._daemon.requestLoop, + kwargs={'loopCondition': lambda: not self._done}) + callback_thread.daemon = True + callback_thread.start() + self._callback_thread = callback_thread + + def _stop(self): + log.debug("Waiting for background thread to finish.") + self._done = True + self._callback_thread.join() + self._daemon.close() + self._daemon = None + self._callback_thread = None + + +class HttpHooksCallbackDaemon(ThreadedHookCallbackDaemon): + """ + Context manager which will run a callback daemon in a background thread. + """ + + hooks_uri = None + + IP_ADDRESS = '127.0.0.1' + + # From Python docs: Polling reduces our responsiveness to a shutdown + # request and wastes cpu at all other times. + POLL_INTERVAL = 0.1 + + def _prepare(self): + log.debug("Preparing callback daemon and registering hook object") + + self._done = False + self._daemon = TCPServer((self.IP_ADDRESS, 0), HooksHttpHandler) + _, port = self._daemon.server_address + self.hooks_uri = '{}:{}'.format(self.IP_ADDRESS, port) + + log.debug("Hooks uri is: %s", self.hooks_uri) + + def _run(self): + log.debug("Running event loop of callback daemon in background thread") + callback_thread = threading.Thread( + target=self._daemon.serve_forever, + kwargs={'poll_interval': self.POLL_INTERVAL}) + callback_thread.daemon = True + callback_thread.start() + self._callback_thread = callback_thread + + def _stop(self): + log.debug("Waiting for background thread to finish.") + self._daemon.shutdown() + self._callback_thread.join() + self._daemon = None + self._callback_thread = None + + +def prepare_callback_daemon(extras, protocol=None, use_direct_calls=False): + callback_daemon = None + protocol = protocol.lower() if protocol else None + + if use_direct_calls: + callback_daemon = DummyHooksCallbackDaemon() + extras['hooks_module'] = callback_daemon.hooks_module + else: + callback_daemon = ( + Pyro4HooksCallbackDaemon() + if protocol == 'pyro4' + else HttpHooksCallbackDaemon()) + extras['hooks_uri'] = callback_daemon.hooks_uri + extras['hooks_protocol'] = protocol + + return callback_daemon, extras + + +class Hooks(object): + """ + Exposes the hooks for remote call backs + """ + + @Pyro4.callback + def repo_size(self, extras): + log.debug("Called repo_size of Hooks object") + return self._call_hook(hooks_base.repo_size, extras) + + @Pyro4.callback + def pre_pull(self, extras): + log.debug("Called pre_pull of Hooks object") + return self._call_hook(hooks_base.pre_pull, extras) + + @Pyro4.callback + def post_pull(self, extras): + log.debug("Called post_pull of Hooks object") + return self._call_hook(hooks_base.post_pull, extras) + + @Pyro4.callback + def pre_push(self, extras): + log.debug("Called pre_push of Hooks object") + return self._call_hook(hooks_base.pre_push, extras) + + @Pyro4.callback + def post_push(self, extras): + log.debug("Called post_push of Hooks object") + return self._call_hook(hooks_base.post_push, extras) + + def _call_hook(self, hook, extras): + extras = AttributeDict(extras) + + try: + result = hook(extras) + except Exception as error: + log.exception('Exception when handling hook %s', hook) + error_args = error.args + return { + 'status': 128, + 'output': '', + 'exception': type(error).__name__, + 'exception_args': error_args, + } + return { + 'status': result.status, + 'output': result.output, + } + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + pass diff --git a/rhodecode/lib/hooks_utils.py b/rhodecode/lib/hooks_utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/hooks_utils.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pylons +import webob + +from rhodecode.lib import hooks_base +from rhodecode.lib import utils2 + + +def _get_rc_scm_extras(username, repo_name, repo_alias, action): + # TODO: johbo: Replace by vcs_operation_context and remove fully + from rhodecode.lib.base import vcs_operation_context + check_locking = action in ('pull', 'push') + + try: + environ = pylons.request.environ + except TypeError: + # we might use this outside of request context, let's fake the + # environ data + environ = webob.Request.blank('').environ + + extras = vcs_operation_context( + environ, repo_name, username, action, repo_alias, check_locking) + return utils2.AttributeDict(extras) + + +def trigger_post_push_hook( + username, action, repo_name, repo_alias, commit_ids): + """ + Triggers push action hooks + + :param username: username who pushes + :param action: push/push_local/push_remote + :param repo_name: name of repo + :param repo_alias: the type of SCM repo + :param commit_ids: list of commit ids that we pushed + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, action) + extras.commit_ids = commit_ids + hooks_base.post_push(extras) + + +def trigger_log_create_pull_request_hook(username, repo_name, repo_alias, + pull_request): + """ + Triggers create pull request action hooks + + :param username: username who creates the pull request + :param repo_name: name of target repo + :param repo_alias: the type of SCM target repo + :param pull_request: the pull request that was created + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, + 'create_pull_request') + extras.update(pull_request.get_api_data()) + hooks_base.log_create_pull_request(**extras) + + +def trigger_log_merge_pull_request_hook(username, repo_name, repo_alias, + pull_request): + """ + Triggers merge pull request action hooks + + :param username: username who creates the pull request + :param repo_name: name of target repo + :param repo_alias: the type of SCM target repo + :param pull_request: the pull request that was merged + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, + 'merge_pull_request') + extras.update(pull_request.get_api_data()) + hooks_base.log_merge_pull_request(**extras) + + +def trigger_log_close_pull_request_hook(username, repo_name, repo_alias, + pull_request): + """ + Triggers close pull request action hooks + + :param username: username who creates the pull request + :param repo_name: name of target repo + :param repo_alias: the type of SCM target repo + :param pull_request: the pull request that was closed + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, + 'close_pull_request') + extras.update(pull_request.get_api_data()) + hooks_base.log_close_pull_request(**extras) + + +def trigger_log_review_pull_request_hook(username, repo_name, repo_alias, + pull_request): + """ + Triggers review status change pull request action hooks + + :param username: username who creates the pull request + :param repo_name: name of target repo + :param repo_alias: the type of SCM target repo + :param pull_request: the pull request that review status changed + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, + 'review_pull_request') + extras.update(pull_request.get_api_data()) + hooks_base.log_review_pull_request(**extras) + + +def trigger_log_update_pull_request_hook(username, repo_name, repo_alias, + pull_request): + """ + Triggers update pull request action hooks + + :param username: username who creates the pull request + :param repo_name: name of target repo + :param repo_alias: the type of SCM target repo + :param pull_request: the pull request that was updated + """ + if repo_alias not in ('hg', 'git'): + return + + extras = _get_rc_scm_extras(username, repo_name, repo_alias, + 'update_pull_request') + extras.update(pull_request.get_api_data()) + hooks_base.log_update_pull_request(**extras) diff --git a/rhodecode/lib/index/__init__.py b/rhodecode/lib/index/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/index/__init__.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Index schema for RhodeCode +""" + +import importlib +import logging + +log = logging.getLogger(__name__) + +# leave defaults for backward compat +default_searcher = 'rhodecode.lib.index.whoosh' +default_location = '%(here)s/data/index' + + +class BaseSearch(object): + def __init__(self): + pass + + def cleanup(self): + pass + + def search(self, query, document_type, search_user, repo_name=None): + raise Exception('NotImplemented') + + +def searcher_from_config(config, prefix='search.'): + _config = {} + for key in config.keys(): + if key.startswith(prefix): + _config[key[len(prefix):]] = config[key] + + if 'location' not in _config: + _config['location'] = default_location + imported = importlib.import_module(_config.get('module', default_searcher)) + searcher = imported.Search(config=_config) + return searcher diff --git a/rhodecode/lib/index/whoosh.py b/rhodecode/lib/index/whoosh.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/index/whoosh.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Index schema for RhodeCode +""" + +from __future__ import absolute_import +import logging +import os + +from pylons.i18n.translation import _ + +from whoosh import query as query_lib, sorting +from whoosh.highlight import HtmlFormatter, ContextFragmenter +from whoosh.index import create_in, open_dir, exists_in, EmptyIndexError +from whoosh.qparser import QueryParser, QueryParserError + +import rhodecode.lib.helpers as h +from rhodecode.lib.index import BaseSearch + +log = logging.getLogger(__name__) + + +try: + # we first try to import from rhodecode tools, fallback to copies if + # we're unable to + from rhodecode_tools.lib.fts_index.whoosh_schema import ( + ANALYZER, FILE_INDEX_NAME, FILE_SCHEMA, COMMIT_INDEX_NAME, + COMMIT_SCHEMA) +except ImportError: + log.warning('rhodecode_tools schema not available, doing a fallback ' + 'import from `rhodecode.lib.index.whoosh_fallback_schema`') + from rhodecode.lib.index.whoosh_fallback_schema import ( + ANALYZER, FILE_INDEX_NAME, FILE_SCHEMA, COMMIT_INDEX_NAME, + COMMIT_SCHEMA) + + +FORMATTER = HtmlFormatter('span', between='\n<span class="break">...</span>\n') +FRAGMENTER = ContextFragmenter(200) + +log = logging.getLogger(__name__) + + +class Search(BaseSearch): + + name = 'whoosh' + + def __init__(self, config): + self.config = config + if not os.path.isdir(self.config['location']): + os.makedirs(self.config['location']) + + opener = create_in + if exists_in(self.config['location'], indexname=FILE_INDEX_NAME): + opener = open_dir + file_index = opener(self.config['location'], schema=FILE_SCHEMA, + indexname=FILE_INDEX_NAME) + + opener = create_in + if exists_in(self.config['location'], indexname=COMMIT_INDEX_NAME): + opener = open_dir + changeset_index = opener(self.config['location'], schema=COMMIT_SCHEMA, + indexname=COMMIT_INDEX_NAME) + + self.commit_schema = COMMIT_SCHEMA + self.commit_index = changeset_index + self.file_schema = FILE_SCHEMA + self.file_index = file_index + self.searcher = None + + def cleanup(self): + if self.searcher: + self.searcher.close() + + def search(self, query, document_type, search_user, repo_name=None): + log.debug(u'QUERY: %s on %s', query, document_type) + result = { + 'results': [], + 'count': 0, + 'error': None, + 'runtime': 0 + } + search_type, index_name, schema_defn = self._prepare_for_search( + document_type) + self._init_searcher(index_name) + try: + qp = QueryParser(search_type, schema=schema_defn) + allowed_repos_filter = self._get_repo_filter( + search_user, repo_name) + try: + query = qp.parse(unicode(query)) + log.debug('query: %s (%s)' % (query, repr(query))) + + sortedby = None + if search_type == 'message': + sortedby = sorting.FieldFacet('commit_idx', reverse=True) + + whoosh_results = self.searcher.search( + query, filter=allowed_repos_filter, limit=None, + sortedby=sortedby,) + + # fixes for 32k limit that whoosh uses for highlight + whoosh_results.fragmenter.charlimit = None + res_ln = whoosh_results.scored_length() + result['runtime'] = whoosh_results.runtime + result['count'] = res_ln + result['results'] = WhooshResultWrapper( + search_type, res_ln, whoosh_results) + + except QueryParserError: + result['error'] = _('Invalid search query. Try quoting it.') + except (EmptyIndexError, IOError, OSError): + msg = _('There is no index to search in. ' + 'Please run whoosh indexer') + log.exception(msg) + result['error'] = msg + except Exception: + msg = _('An error occurred during this search operation') + log.exception(msg) + result['error'] = msg + + return result + + def statistics(self): + stats = [ + {'key': _('Index Type'), 'value': 'Whoosh'}, + {'key': _('File Index'), 'value': str(self.file_index)}, + {'key': _('Indexed documents'), + 'value': self.file_index.doc_count()}, + {'key': _('Last update'), + 'value': h.time_to_datetime(self.file_index.last_modified())}, + {'key': _('Commit index'), 'value': str(self.commit_index)}, + {'key': _('Indexed documents'), + 'value': str(self.commit_index.doc_count())}, + {'key': _('Last update'), + 'value': h.time_to_datetime(self.commit_index.last_modified())} + ] + return stats + + def _get_repo_filter(self, auth_user, repo_name): + + allowed_to_search = [ + repo for repo, perm in + auth_user.permissions['repositories'].items() + if perm != 'repository.none'] + + if repo_name: + repo_filter = [query_lib.Term('repository', repo_name)] + + elif 'hg.admin' in auth_user.permissions.get('global', []): + return None + + else: + repo_filter = [query_lib.Term('repository', _rn) + for _rn in allowed_to_search] + # in case we're not allowed to search anywhere, it's a trick + # to tell whoosh we're filtering, on ALL results + repo_filter = repo_filter or [query_lib.Term('repository', '')] + + return query_lib.Or(repo_filter) + + def _prepare_for_search(self, cur_type): + search_type = { + 'content': 'content', + 'commit': 'message', + 'path': 'path', + 'repository': 'repository' + }.get(cur_type, 'content') + + index_name = { + 'content': FILE_INDEX_NAME, + 'commit': COMMIT_INDEX_NAME, + 'path': FILE_INDEX_NAME + }.get(cur_type, FILE_INDEX_NAME) + + schema_defn = { + 'content': self.file_schema, + 'commit': self.commit_schema, + 'path': self.file_schema + }.get(cur_type, self.file_schema) + + log.debug('IDX: %s' % index_name) + log.debug('SCHEMA: %s' % schema_defn) + return search_type, index_name, schema_defn + + def _init_searcher(self, index_name): + idx = open_dir(self.config['location'], indexname=index_name) + self.searcher = idx.searcher() + return self.searcher + + +class WhooshResultWrapper(object): + def __init__(self, search_type, total_hits, results): + self.search_type = search_type + self.results = results + self.total_hits = total_hits + + def __str__(self): + return '<%s at %s>' % (self.__class__.__name__, len(self)) + + def __repr__(self): + return self.__str__() + + def __len__(self): + return self.total_hits + + def __iter__(self): + """ + Allows Iteration over results,and lazy generate content + + *Requires* implementation of ``__getitem__`` method. + """ + for hit in self.results: + yield self.get_full_content(hit) + + def __getitem__(self, key): + """ + Slicing of resultWrapper + """ + i, j = key.start, key.stop + for hit in self.results[i:j]: + yield self.get_full_content(hit) + + def get_full_content(self, hit): + # TODO: marcink: this feels like an overkill, there's a lot of data + # inside hit object, and we don't need all + res = dict(hit) + + f_path = '' # noqa + if self.search_type in ['content', 'path']: + f_path = res['path'].split(res['repository'])[-1] + f_path = f_path.lstrip(os.sep) + + if self.search_type == 'content': + res.update({'content_short_hl': hit.highlights('content'), + 'f_path': f_path}) + elif self.search_type == 'path': + res.update({'f_path': f_path}) + elif self.search_type == 'message': + res.update({'message_hl': hit.highlights('message')}) + + return res diff --git a/rhodecode/lib/index/whoosh_fallback_schema.py b/rhodecode/lib/index/whoosh_fallback_schema.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/index/whoosh_fallback_schema.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Whoosh fallback schema for RhodeCode in case rhodecode_tools defined one is +not available +""" + +from __future__ import absolute_import + +from whoosh.analysis import RegexTokenizer, LowercaseFilter +from whoosh.formats import Characters +from whoosh.fields import ( + TEXT, ID, STORED, NUMERIC, BOOLEAN, Schema, FieldType, DATETIME) + +# CUSTOM ANALYZER wordsplit + lowercase filter for case insensitive search +ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter() + +# FILE INDEX SCHEMA DEFINITION +FILE_INDEX_NAME = 'FILE_INDEX' +FILE_SCHEMA = Schema( + fileid=ID(unique=True), # Path + repository=ID(stored=True), + repository_id=NUMERIC(unique=True, stored=True), # Numeric id of repo + repo_name=TEXT(stored=True), + owner=TEXT(), + path=TEXT(stored=True), + content=FieldType(format=Characters(), analyzer=ANALYZER, + scorable=True, stored=True), + modtime=STORED(), + md5=STORED(), + extension=ID(stored=True), + commit_id=TEXT(stored=True), + + size=NUMERIC(stored=True), + mimetype=TEXT(stored=True), + lines=NUMERIC(stored=True), +) + + +# COMMIT INDEX SCHEMA +COMMIT_INDEX_NAME = 'COMMIT_INDEX' +COMMIT_SCHEMA = Schema( + commit_id=ID(unique=True, stored=True), + repository=ID(unique=True, stored=True), + repository_id=NUMERIC(unique=True, stored=True), + commit_idx=NUMERIC(stored=True, sortable=True), + commit_idx_sort=ID(), + date=NUMERIC(stored=True), + owner=TEXT(stored=True), + author=TEXT(stored=True), + message=FieldType(format=Characters(), analyzer=ANALYZER, + scorable=True, stored=True), + parents=TEXT(stored=True), + added=TEXT(stored=True), # space separated names of added files + removed=TEXT(stored=True), # space separated names of removed files + changed=TEXT(stored=True), # space separated names of changed files +) diff --git a/rhodecode/lib/logging_formatter.py b/rhodecode/lib/logging_formatter.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/logging_formatter.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + + +BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) + +# Sequences +RESET_SEQ = "\033[0m" +COLOR_SEQ = "\033[0;%dm" +BOLD_SEQ = "\033[1m" + +COLORS = { + 'CRITICAL': MAGENTA, + 'ERROR': RED, + 'WARNING': CYAN, + 'INFO': GREEN, + 'DEBUG': BLUE, + 'SQL': YELLOW +} + + +def one_space_trim(s): + if s.find(" ") == -1: + return s + else: + s = s.replace(' ', ' ') + return one_space_trim(s) + + +def format_sql(sql): + sql = sql.replace('\n', '') + sql = one_space_trim(sql) + sql = sql\ + .replace(',', ',\n\t')\ + .replace('SELECT', '\n\tSELECT \n\t')\ + .replace('UPDATE', '\n\tUPDATE \n\t')\ + .replace('DELETE', '\n\tDELETE \n\t')\ + .replace('FROM', '\n\tFROM')\ + .replace('ORDER BY', '\n\tORDER BY')\ + .replace('LIMIT', '\n\tLIMIT')\ + .replace('WHERE', '\n\tWHERE')\ + .replace('AND', '\n\tAND')\ + .replace('LEFT', '\n\tLEFT')\ + .replace('INNER', '\n\tINNER')\ + .replace('INSERT', '\n\tINSERT')\ + .replace('DELETE', '\n\tDELETE') + return sql + + +class Pyro4AwareFormatter(logging.Formatter): + """ + Extended logging formatter which prints out Pyro4 remote tracebacks. + """ + + def formatException(self, ei): + ex_type, ex_value, ex_tb = ei + if hasattr(ex_value, '_pyroTraceback'): + # johbo: Avoiding to import pyro4 until we get an exception + # which actually has a remote traceback. This avoids issues + # when gunicorn is used with gevent, since the logging would + # trigger an import of Pyro4 before the patches of gevent + # are applied. + import Pyro4.util + return ''.join( + Pyro4.util.getPyroTraceback(ex_type, ex_value, ex_tb)) + return logging.Formatter.formatException(self, ei) + + +class ColorFormatter(Pyro4AwareFormatter): + + def format(self, record): + """ + Changes record's levelname to use with COLORS enum + """ + + levelname = record.levelname + start = COLOR_SEQ % (COLORS[levelname]) + def_record = logging.Formatter.format(self, record) + end = RESET_SEQ + + colored_record = ''.join([start, def_record, end]) + return colored_record + + +class ColorFormatterSql(logging.Formatter): + + def format(self, record): + """ + Changes record's levelname to use with COLORS enum + """ + + start = COLOR_SEQ % (COLORS['SQL']) + def_record = format_sql(logging.Formatter.format(self, record)) + end = RESET_SEQ + + colored_record = ''.join([start, def_record, end]) + return colored_record diff --git a/rhodecode/lib/markdown_ext.py b/rhodecode/lib/markdown_ext.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/markdown_ext.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import re + +import markdown + + +class FlavoredCheckboxExtension(markdown.Extension): + + def extendMarkdown(self, md, md_globals): + md.preprocessors.add('checklist', + FlavoredCheckboxPreprocessor(md), '<reference') + md.postprocessors.add('checklist', + FlavoredCheckboxPostprocessor(md), '>unescape') + + +class FlavoredCheckboxPreprocessor(markdown.preprocessors.Preprocessor): + """ + Replaces occurrences of [ ] or [x] to checkbox input + """ + + pattern = re.compile(r'^([*-]) \[([ x])\]') + + def run(self, lines): + return [self._transform_line(line) for line in lines] + + def _transform_line(self, line): + return self.pattern.sub(self._replacer, line) + + def _replacer(self, match): + list_prefix, state = match.groups() + checked = '' if state == ' ' else ' checked="checked"' + return '%s <input type="checkbox" disabled="disabled"%s>' % (list_prefix, + checked) + + +class FlavoredCheckboxPostprocessor(markdown.postprocessors.Postprocessor): + """ + Adds `flavored_checkbox_list` class to list of checkboxes + """ + + pattern = re.compile(r'^([*-]) \[([ x])\]') + + def run(self, html): + before = '<ul>\n<li><input type="checkbox"' + after = '<ul class="flavored_checkbox_list">\n<li><input type="checkbox"' + return html.replace(before, after) + + + + +# Global Vars +URLIZE_RE = '(%s)' % '|'.join([ + r'<(?:f|ht)tps?://[^>]*>', + r'\b(?:f|ht)tps?://[^)<>\s]+[^.,)<>\s]', + r'\bwww\.[^)<>\s]+[^.,)<>\s]', + r'[^(<\s]+\.(?:com|net|org)\b', +]) + +class UrlizePattern(markdown.inlinepatterns.Pattern): + """ Return a link Element given an autolink (`http://example/com`). """ + def handleMatch(self, m): + url = m.group(2) + + if url.startswith('<'): + url = url[1:-1] + + text = url + + if not url.split('://')[0] in ('http','https','ftp'): + if '@' in url and not '/' in url: + url = 'mailto:' + url + else: + url = 'http://' + url + + el = markdown.util.etree.Element("a") + el.set('href', url) + el.text = markdown.util.AtomicString(text) + return el + + +class UrlizeExtension(markdown.Extension): + """ Urlize Extension for Python-Markdown. """ + + def extendMarkdown(self, md, md_globals): + """ Replace autolink with UrlizePattern """ + md.inlinePatterns['autolink'] = UrlizePattern(URLIZE_RE, md) diff --git a/rhodecode/lib/markup_renderer.py b/rhodecode/lib/markup_renderer.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/markup_renderer.py @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Renderer for markup languages with ability to parse using rst or markdown +""" + + +import re +import os +import logging +from mako.lookup import TemplateLookup + +from docutils.core import publish_parts +from docutils.parsers.rst import directives +import markdown + +from rhodecode.lib.markdown_ext import FlavoredCheckboxExtension, UrlizeExtension +from rhodecode.lib.utils2 import safe_unicode, md5_safe, MENTIONS_REGEX + +log = logging.getLogger(__name__) + +# default renderer used to generate automated comments +DEFAULT_COMMENTS_RENDERER = 'rst' + + +class MarkupRenderer(object): + RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw'] + + MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE) + RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE) + PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE) + + def _detect_renderer(self, source, filename=None): + """ + runs detection of what renderer should be used for generating html + from a markup language + + filename can be also explicitly a renderer name + + :param source: + :param filename: + """ + + if MarkupRenderer.MARKDOWN_PAT.findall(filename): + detected_renderer = 'markdown' + elif MarkupRenderer.RST_PAT.findall(filename): + detected_renderer = 'rst' + elif MarkupRenderer.PLAIN_PAT.findall(filename): + detected_renderer = 'rst' + else: + detected_renderer = 'plain' + + return getattr(MarkupRenderer, detected_renderer) + + def render(self, source, filename=None): + """ + Renders a given filename using detected renderer + it detects renderers based on file extension or mimetype. + At last it will just do a simple html replacing new lines with <br/> + + :param file_name: + :param source: + """ + + renderer = self._detect_renderer(source, filename) + readme_data = renderer(source) + return readme_data + + @classmethod + def _flavored_markdown(cls, text): + """ + Github style flavored markdown + + :param text: + """ + + # Extract pre blocks. + extractions = {} + + def pre_extraction_callback(matchobj): + digest = md5_safe(matchobj.group(0)) + extractions[digest] = matchobj.group(0) + return "{gfm-extraction-%s}" % digest + pattern = re.compile(r'<pre>.*?</pre>', re.MULTILINE | re.DOTALL) + text = re.sub(pattern, pre_extraction_callback, text) + + # Prevent foo_bar_baz from ending up with an italic word in the middle. + def italic_callback(matchobj): + s = matchobj.group(0) + if list(s).count('_') >= 2: + return s.replace('_', r'\_') + return s + text = re.sub(r'^(?! {4}|\t)\w+_\w+_\w[\w_]*', italic_callback, text) + + # Insert pre block extractions. + def pre_insert_callback(matchobj): + return '\n\n' + extractions[matchobj.group(1)] + text = re.sub(r'\{gfm-extraction-([0-9a-f]{32})\}', + pre_insert_callback, text) + + return text + + @classmethod + def urlify_text(cls, text): + url_pat = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]' + r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)') + + def url_func(match_obj): + url_full = match_obj.groups()[0] + return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full}) + + return url_pat.sub(url_func, text) + + @classmethod + def plain(cls, source, universal_newline=True): + source = safe_unicode(source) + if universal_newline: + newline = '\n' + source = newline.join(source.splitlines()) + + source = cls.urlify_text(source) + return '<br />' + source.replace("\n", '<br />') + + @classmethod + def markdown(cls, source, safe=True, flavored=False, mentions=False): + # It does not allow to insert inline HTML. In presence of HTML tags, it + # will replace them instead with [HTML_REMOVED]. This is controlled by + # the safe_mode=True parameter of the markdown method. + extensions = ['codehilite', 'extra', 'def_list', 'sane_lists'] + if flavored: + extensions.append('nl2br') + extensions.append(FlavoredCheckboxExtension()) + extensions.append(UrlizeExtension()) + + if mentions: + mention_pat = re.compile(MENTIONS_REGEX) + + def wrapp(match_obj): + uname = match_obj.groups()[0] + return ' **@%(uname)s** ' % {'uname': uname} + mention_hl = mention_pat.sub(wrapp, source).strip() + # we extracted mentions render with this using Mentions false + return cls.markdown(mention_hl, safe=safe, flavored=flavored, + mentions=False) + + source = safe_unicode(source) + try: + if flavored: + source = cls._flavored_markdown(source) + return markdown.markdown( + source, extensions, safe_mode=True, enable_attributes=False) + except Exception: + log.exception('Error when rendering Markdown') + if safe: + log.debug('Fallbacking to render in plain mode') + return cls.plain(source) + else: + raise + + @classmethod + def rst(cls, source, safe=True, mentions=False): + if mentions: + mention_pat = re.compile(MENTIONS_REGEX) + + def wrapp(match_obj): + uname = match_obj.groups()[0] + return ' **@%(uname)s** ' % {'uname': uname} + mention_hl = mention_pat.sub(wrapp, source).strip() + # we extracted mentions render with this using Mentions false + return cls.rst(mention_hl, safe=safe, mentions=False) + + source = safe_unicode(source) + try: + docutils_settings = dict([(alias, None) for alias in + cls.RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES]) + + docutils_settings.update({'input_encoding': 'unicode', + 'report_level': 4}) + + for k, v in docutils_settings.iteritems(): + directives.register_directive(k, v) + + parts = publish_parts(source=source, + writer_name="html4css1", + settings_overrides=docutils_settings) + + return parts['html_title'] + parts["fragment"] + except Exception: + log.exception('Error when rendering RST') + if safe: + log.debug('Fallbacking to render in plain mode') + return cls.plain(source) + else: + raise + + +class RstTemplateRenderer(object): + + def __init__(self): + base = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + rst_template_dirs = [os.path.join(base, 'templates', 'rst_templates')] + self.template_store = TemplateLookup( + directories=rst_template_dirs, + input_encoding='utf-8', + imports=['from rhodecode.lib import helpers as h']) + + def _get_template(self, templatename): + return self.template_store.get_template(templatename) + + def render(self, template_name, **kwargs): + template = self._get_template(template_name) + return template.render(**kwargs) diff --git a/rhodecode/lib/memory_lru_debug.py b/rhodecode/lib/memory_lru_debug.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/memory_lru_debug.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Custom LRU memory manager for debugging purposes. It allows to track the keys +and the state of LRU dict. + +inrae.cache is licensed under LRUDict is licensed under ZPL license +This software is Copyright (c) Zope Corporation (tm) and +Contributors. All rights reserved. + +TODO: marcink, we might think of replacing the LRUDict with lru-dict library +written in C. + +eg difference in speed: + + LRUDictC Time : 0.00025 s, Memory : 110592 Kb + LRUDict Time : 0.00369 s, Memory : 147456 Kb +""" +import logging + +from infrae.cache.beakerext.lru import LRUDict +from beaker.container import MemoryNamespaceManager, AbstractDictionaryNSManager +from rhodecode.lib.utils2 import safe_str + +log = logging.getLogger(__name__) + + +class LRUDictDebug(LRUDict): + """ + Wrapper to provide some debug options + """ + def _report_keys(self): + elems_cnt = '%s/%s' % (len(self.keys()), self.size) + # trick for pformat print it more nicely + fmt = '\n' + for cnt, elem in enumerate(self.keys()): + fmt += '%s - %s\n' % (cnt+1, safe_str(elem)) + log.debug('current LRU keys (%s):%s' % (elems_cnt, fmt)) + + def __getitem__(self, key): + self._report_keys() + return self.get(key) + + +class MemoryLRUNamespaceManagerBase(MemoryNamespaceManager): + default_max_items = 10000 + + def _get_factory(self, max_items): + + def Factory(): + return LRUDict(int(max_items)) + return Factory + + def __init__(self, namespace, **kwargs): + AbstractDictionaryNSManager.__init__(self, namespace) + if kwargs.has_key('max_items'): + max_items = kwargs['max_items'] + else: + max_items = self.default_max_items + + Factory = self._get_factory(max_items) + + self.dictionary = MemoryNamespaceManager.namespaces.get( + self.namespace, Factory) + + +class MemoryLRUNamespaceManagerDebug(MemoryLRUNamespaceManagerBase): + """ + A memory namespace manager that return with LRU dicts backend, + special debug for testing + """ + default_max_items = 10000 + + def _get_factory(self, max_items): + + def Factory(): + return LRUDictDebug(int(max_items)) + return Factory diff --git a/rhodecode/lib/middleware/__init__.py b/rhodecode/lib/middleware/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/middleware/appenlight.py b/rhodecode/lib/middleware/appenlight.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/appenlight.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +middleware to handle appenlight publishing of errors +""" + +from appenlight_client import make_appenlight_middleware +from appenlight_client.exceptions import get_current_traceback +from appenlight_client.wsgi import AppenlightWSGIWrapper +from paste.deploy.converters import asbool + + +def track_exception(environ): + if 'appenlight.client' not in environ: + return + + # pass the traceback object to middleware + environ['appenlight.__traceback'] = get_current_traceback( + skip=1, + show_hidden_frames=True, + ignore_system_exceptions=True) + + +def track_extra_information(environ, section, value): + """ + Utility function to attach extra information in case of an error condition. + + It will take care of attaching this information to the right place inside + of `environ`, so that the appenight client can pick it up. + """ + environ.setdefault('appenlight.extra', {}) + environ['appenlight.extra'][section] = value + + +def wrap_in_appenlight_if_enabled(app, config, appenlight_client=None): + """ + Wraps the given `app` for appenlight support. + + .. important:: + + Appenlight expects that the wrapper is executed only once, that's why + the parameter `appenlight_client` can be used to pass in an already + existing client instance to avoid that decorators are applied more than + once. + + This is in use to support our setup of the vcs related middlewares. + + """ + if asbool(config['app_conf'].get('appenlight')): + app = RemoteTracebackTracker(app) + if not appenlight_client: + app = make_appenlight_middleware(app, config) + appenlight_client = app.appenlight_client + else: + app = AppenlightWSGIWrapper(app, appenlight_client) + return app, appenlight_client + + +class RemoteTracebackTracker(object): + """ + Utility middleware which forwards Pyro4 remote traceback information. + """ + + def __init__(self, app): + self.application = app + + def __call__(self, environ, start_response): + try: + return self.application(environ, start_response) + except Exception as e: + if hasattr(e, '_pyroTraceback'): + track_extra_information( + environ, 'remote_traceback', ''.join(e._pyroTraceback)) + raise diff --git a/rhodecode/lib/middleware/csrf.py b/rhodecode/lib/middleware/csrf.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/csrf.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging +import textwrap + +import routes.middleware +import urlobject +import webob +import webob.exc + +import rhodecode.lib.auth + + +log = logging.getLogger(__name__) + + +class CSRFDetector(object): + """ + Middleware for preventing CSRF. + + + It checks that all requests are either GET or POST. + For POST requests, it logs the requests that do not have a CSRF token. + Eventually it will raise an error. + + It special cases some endpoints as they do not really require a token. + + Note: this middleware is only intended for testing. + """ + + _PUT_DELETE_MESSAGE = textwrap.dedent(''' + Do not call in tests app.delete or app.put, use instead + app.post(..., params={'_method': 'delete'}. + + The reason is twofold. The first is because that's how the browser is + calling rhodecode and the second is because it allow us to detect + potential CSRF.''').strip() + + _PATHS_WITHOUT_TOKEN = frozenset(( + # The password is the token. + '/_admin/login', + # Captcha may be enabled. + '/_admin/password_reset', + # Captcha may be enabled. + '/_admin/password_reset_confirmation', + # Captcha may be enabled. + '/_admin/register', + # No change in state with this controller. + '/error/document', + )) + + def __init__(self, app): + self._app = app + + def __call__(self, environ, start_response): + if environ['REQUEST_METHOD'].upper() not in ('GET', 'POST'): + raise Exception(self._PUT_DELETE_MESSAGE) + + if (environ['REQUEST_METHOD'] == 'POST' and + environ['PATH_INFO'] not in self._PATHS_WITHOUT_TOKEN and + routes.middleware.is_form_post(environ)): + body = environ['wsgi.input'] + if body.seekable(): + pos = body.tell() + content = body.read() + body.seek(pos) + elif hasattr(body, 'peek'): + content = body.peek() + else: + raise Exception("Cannot check if the request has a CSRF token") + if rhodecode.lib.auth.csrf_token_key not in content: + raise Exception( + '%s to %s does not have a csrf_token %r' % + (environ['REQUEST_METHOD'], environ['PATH_INFO'], content)) + + return self._app(environ, start_response) + + +def _get_scheme_host_port(url): + url = urlobject.URLObject(url) + if '://' not in url: + return None, url, None + + scheme = url.scheme or 'http' + port = url.port + if not port: + if scheme == 'http': + port = 80 + elif scheme == 'https': + port = 443 + host = url.netloc.without_port() + + return scheme, host, port + + +def _equivalent_urls(url1, url2): + """Check if both urls are equivalent.""" + return _get_scheme_host_port(url1) == _get_scheme_host_port(url2) + + +class OriginChecker(object): + """ + Check whether the request has a valid Origin header. + + See https://wiki.mozilla.org/Security/Origin for details. + """ + + def __init__(self, app, expected_origin, skip_urls=None): + """ + :param expected_origin: the value we expect to see for the Origin + header. + :param skip_urls: list of urls for which we do not need to check the + Origin header. + """ + self._app = app + self._expected_origin = expected_origin + self._skip_urls = frozenset(skip_urls or []) + + def __call__(self, environ, start_response): + origin_header = environ.get('HTTP_ORIGIN', '') + origin = origin_header.split(' ', 1)[0] + if origin == 'null': + origin = None + + if (environ['PATH_INFO'] not in self._skip_urls and origin and + not _equivalent_urls(origin, self._expected_origin)): + log.warn( + 'Invalid Origin header detected: got %s, expected %s', + origin_header, self._expected_origin) + return webob.exc.HTTPForbidden('Origin header mismatch')( + environ, start_response) + else: + return self._app(environ, start_response) diff --git a/rhodecode/lib/middleware/disable_vcs.py b/rhodecode/lib/middleware/disable_vcs.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/disable_vcs.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2015-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Disable VCS pages when VCS Server is not available +""" + +import logging +import re + + +log = logging.getLogger(__name__) + + +class DisableVCSPagesWrapper(object): + """ + Wrapper to disable all pages that require VCS Server to be running, + avoiding that errors explode to the user. + + This Wrapper should be enabled only in case VCS Server is not available + for the instance. + """ + + VCS_NOT_REQUIRED = [ + '^/$', + ('/_admin(?!/settings/mapping)(?!/my_account/repos)' + '(?!/create_repository)(?!/gists)(?!/notifications/)' + ), + ] + _REGEX_VCS_NOT_REQUIRED = [re.compile(path) for path in VCS_NOT_REQUIRED] + + def _check_vcs_requirement(self, path_info): + """ + Tries to match the current path to one of the safe URLs to be rendered. + Displays an error message in case + """ + for regex in self._REGEX_VCS_NOT_REQUIRED: + safe_url = regex.match(path_info) + if safe_url: + return True + + # Url is not safe to be rendered without VCS Server + log.debug('accessing: `%s` with VCS Server disabled', path_info) + return False + + def __init__(self, app): + self.application = app + + def __call__(self, environ, start_response): + if not self._check_vcs_requirement(environ['PATH_INFO']): + environ['PATH_INFO'] = '/error/vcs_unavailable' + + return self.application(environ, start_response) diff --git a/rhodecode/lib/middleware/https_fixup.py b/rhodecode/lib/middleware/https_fixup.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/https_fixup.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +middleware to handle https correctly +""" + + +from rhodecode.lib.utils2 import str2bool + + +class HttpsFixup(object): + + def __init__(self, app, config): + self.application = app + self.config = config + + def __call__(self, environ, start_response): + self.__fixup(environ) + debug = str2bool(self.config.get('debug')) + is_ssl = environ['wsgi.url_scheme'] == 'https' + + def custom_start_response(status, headers, exc_info=None): + if is_ssl and str2bool(self.config.get('use_htsts')) and not debug: + headers.append(('Strict-Transport-Security', + 'max-age=8640000; includeSubDomains')) + return start_response(status, headers, exc_info) + + return self.application(environ, custom_start_response) + + def __fixup(self, environ): + """ + Function to fixup the environ as needed. In order to use this + middleware you should set this header inside your + proxy ie. nginx, apache etc. + """ + # DETECT PROTOCOL ! + if 'HTTP_X_URL_SCHEME' in environ: + proto = environ.get('HTTP_X_URL_SCHEME') + elif 'HTTP_X_FORWARDED_SCHEME' in environ: + proto = environ.get('HTTP_X_FORWARDED_SCHEME') + elif 'HTTP_X_FORWARDED_PROTO' in environ: + proto = environ.get('HTTP_X_FORWARDED_PROTO') + else: + proto = 'http' + org_proto = proto + + # if we have force, just override + if str2bool(self.config.get('force_https')): + proto = 'https' + + environ['wsgi.url_scheme'] = proto + environ['wsgi._org_proto'] = org_proto diff --git a/rhodecode/lib/middleware/request_wrapper.py b/rhodecode/lib/middleware/request_wrapper.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/request_wrapper.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import time +import logging + + +from rhodecode.lib.base import get_ip_addr, get_access_path +from rhodecode.lib.utils2 import safe_str + + +log = logging.getLogger(__name__) + + +class RequestWrapperTween(object): + def __init__(self, handler, registry): + self.handler = handler + self.registry = registry + + # one-time configuration code goes here + + def __call__(self, request): + start = time.time() + try: + response = self.handler(request) + finally: + end = time.time() + + log.info('IP: %s Request to %s time: %.3fs' % ( + get_ip_addr(request.environ), + safe_str(get_access_path(request.environ)), end - start) + ) + + return response + + +def includeme(config): + config.add_tween( + 'rhodecode.lib.middleware.request_wrapper.RequestWrapperTween', + ) \ No newline at end of file diff --git a/rhodecode/lib/middleware/simplegit.py b/rhodecode/lib/middleware/simplegit.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/simplegit.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SimpleGit middleware for handling git protocol request (push/clone etc.) +It's implemented with basic auth function +""" +import re +import urlparse + +import rhodecode +from rhodecode.lib import utils2 +from rhodecode.lib.middleware import simplevcs + + +GIT_PROTO_PAT = re.compile( + r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)') + + +class SimpleGit(simplevcs.SimpleVCS): + + SCM = 'git' + + def _get_repository_name(self, environ): + """ + Gets repository name out of PATH_INFO header + + :param environ: environ where PATH_INFO is stored + """ + repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1) + return repo_name + + _ACTION_MAPPING = { + 'git-receive-pack': 'push', + 'git-upload-pack': 'pull', + } + + def _get_action(self, environ): + """ + Maps git request commands into a pull or push command. + In case of unknown/unexpected data, it returns 'pull' to be safe. + + :param environ: + """ + path = environ['PATH_INFO'] + + if path.endswith('/info/refs'): + query = urlparse.parse_qs(environ['QUERY_STRING']) + service_cmd = query.get('service', [''])[0] + return self._ACTION_MAPPING.get(service_cmd, 'pull') + elif path.endswith('/git-receive-pack'): + return 'push' + elif path.endswith('/git-upload-pack'): + return 'pull' + + return 'pull' + + def _create_wsgi_app(self, repo_path, repo_name, config): + return self.scm_app.create_git_wsgi_app(repo_path, repo_name, config) + + def _create_config(self, extras, repo_name): + extras['git_update_server_info'] = utils2.str2bool( + rhodecode.CONFIG.get('git_update_server_info')) + return extras diff --git a/rhodecode/lib/middleware/simplehg.py b/rhodecode/lib/middleware/simplehg.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/simplehg.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SimpleHG middleware for handling mercurial protocol request +(push/clone etc.). It's implemented with basic auth function +""" + +import urlparse + +from rhodecode.lib import utils +from rhodecode.lib.ext_json import json +from rhodecode.lib.middleware import simplevcs + + +class SimpleHg(simplevcs.SimpleVCS): + + SCM = 'hg' + + def _get_repository_name(self, environ): + """ + Gets repository name out of PATH_INFO header + + :param environ: environ where PATH_INFO is stored + """ + return environ['PATH_INFO'].strip('/') + + _ACTION_MAPPING = { + 'changegroup': 'pull', + 'changegroupsubset': 'pull', + 'getbundle': 'pull', + 'stream_out': 'pull', + 'listkeys': 'pull', + 'unbundle': 'push', + 'pushkey': 'push', + } + + def _get_action(self, environ): + """ + Maps mercurial request commands into a pull or push command. + In case of unknown/unexpected data, it returns 'pull' to be safe. + + :param environ: + """ + query = urlparse.parse_qs(environ['QUERY_STRING'], + keep_blank_values=True) + if 'cmd' in query: + cmd = query['cmd'][0] + return self._ACTION_MAPPING.get(cmd, 'pull') + + return 'pull' + + def _create_wsgi_app(self, repo_path, repo_name, config): + return self.scm_app.create_hg_wsgi_app(repo_path, repo_name, config) + + def _create_config(self, extras, repo_name): + config = utils.make_db_config(repo=repo_name) + config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras)) + + return config.serialize() diff --git a/rhodecode/lib/middleware/simplesvn.py b/rhodecode/lib/middleware/simplesvn.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/simplesvn.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from urlparse import urljoin + +import requests + +import rhodecode +from rhodecode.lib.middleware import simplevcs +from rhodecode.lib.utils import is_valid_repo + + +class SimpleSvnApp(object): + IGNORED_HEADERS = [ + 'connection', 'keep-alive', 'content-encoding', + 'transfer-encoding'] + + def __init__(self, config): + self.config = config + + def __call__(self, environ, start_response): + request_headers = self._get_request_headers(environ) + + data = environ['wsgi.input'] + # johbo: On Gunicorn, we end up with a 415 response if we pass data + # to requests. I think the request is usually without payload, still + # reading the data to be on the safe side. + if environ['REQUEST_METHOD'] == 'MKCOL': + data = data.read() + + response = requests.request( + environ['REQUEST_METHOD'], self._get_url(environ['PATH_INFO']), + data=data, headers=request_headers) + + response_headers = self._get_response_headers(response.headers) + start_response( + '{} {}'.format(response.status_code, response.reason), + response_headers) + return response.iter_content(chunk_size=1024) + + def _get_url(self, path): + return urljoin( + self.config.get('subversion_http_server_url', ''), path) + + def _get_request_headers(self, environ): + headers = {} + + for key in environ: + if not key.startswith('HTTP_'): + continue + new_key = key.split('_') + new_key = [k.capitalize() for k in new_key[1:]] + new_key = '-'.join(new_key) + headers[new_key] = environ[key] + + if 'CONTENT_TYPE' in environ: + headers['Content-Type'] = environ['CONTENT_TYPE'] + + if 'CONTENT_LENGTH' in environ: + headers['Content-Length'] = environ['CONTENT_LENGTH'] + + return headers + + def _get_response_headers(self, headers): + return [ + (h, headers[h]) + for h in headers + if h.lower() not in self.IGNORED_HEADERS + ] + + +class SimpleSvn(simplevcs.SimpleVCS): + + SCM = 'svn' + READ_ONLY_COMMANDS = ('OPTIONS', 'PROPFIND', 'GET', 'REPORT') + + def _get_repository_name(self, environ): + """ + Gets repository name out of PATH_INFO header + + :param environ: environ where PATH_INFO is stored + """ + path = environ['PATH_INFO'].split('!') + repo_name = path[0].strip('/') + + # SVN includes the whole path in it's requests, including + # subdirectories inside the repo. Therefore we have to search for + # the repo root directory. + if not is_valid_repo(repo_name, self.basepath, self.SCM): + current_path = '' + for component in repo_name.split('/'): + current_path += component + if is_valid_repo(current_path, self.basepath, self.SCM): + return current_path + current_path += '/' + + return repo_name + + def _get_action(self, environ): + return ( + 'pull' + if environ['REQUEST_METHOD'] in self.READ_ONLY_COMMANDS + else 'push') + + def _create_wsgi_app(self, repo_path, repo_name, config): + return SimpleSvnApp(config) + + def _create_config(self, extras, repo_name): + server_url = rhodecode.CONFIG.get( + 'rhodecode_subversion_http_server_url', '') + extras['subversion_http_server_url'] = ( + server_url or 'http://localhost/') + return extras diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/simplevcs.py @@ -0,0 +1,440 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SimpleVCS middleware for handling protocol request (push/clone etc.) +It's implemented with basic auth function +""" + +import os +import logging +import importlib +from functools import wraps + +from paste.httpheaders import REMOTE_USER, AUTH_TYPE +from webob.exc import ( + HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError) + +import rhodecode +from rhodecode.authentication.base import authenticate, VCS_TYPE +from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware +from rhodecode.lib.base import BasicAuth, get_ip_addr, vcs_operation_context +from rhodecode.lib.exceptions import ( + HTTPLockedRC, HTTPRequirementError, UserCreationError, + NotAllowedToCreateUserError) +from rhodecode.lib.hooks_daemon import prepare_callback_daemon +from rhodecode.lib.middleware import appenlight +from rhodecode.lib.middleware.utils import scm_app +from rhodecode.lib.utils import is_valid_repo +from rhodecode.lib.utils2 import safe_str, fix_PATH, str2bool +from rhodecode.model import meta +from rhodecode.model.db import User, Repository +from rhodecode.model.scm import ScmModel +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +def initialize_generator(factory): + """ + Initializes the returned generator by draining its first element. + + This can be used to give a generator an initializer, which is the code + up to the first yield statement. This decorator enforces that the first + produced element has the value ``"__init__"`` to make its special + purpose very explicit in the using code. + """ + + @wraps(factory) + def wrapper(*args, **kwargs): + gen = factory(*args, **kwargs) + try: + init = gen.next() + except StopIteration: + raise ValueError('Generator must yield at least one element.') + if init != "__init__": + raise ValueError('First yielded element must be "__init__".') + return gen + return wrapper + + +class SimpleVCS(object): + """Common functionality for SCM HTTP handlers.""" + + SCM = 'unknown' + + def __init__(self, application, config): + self.application = application + self.config = config + # base path of repo locations + self.basepath = self.config['base_path'] + # authenticate this VCS request using authfunc + auth_ret_code_detection = \ + str2bool(self.config.get('auth_ret_code_detection', False)) + self.authenticate = BasicAuth('', authenticate, + config.get('auth_ret_code'), + auth_ret_code_detection) + self.ip_addr = '0.0.0.0' + + @property + def scm_app(self): + custom_implementation = self.config.get('vcs.scm_app_implementation') + if custom_implementation: + log.info( + "Using custom implementation of scm_app: %s", + custom_implementation) + scm_app_impl = importlib.import_module(custom_implementation) + else: + scm_app_impl = scm_app + return scm_app_impl + + def _get_by_id(self, repo_name): + """ + Gets a special pattern _<ID> from clone url and tries to replace it + with a repository_name for support of _<ID> non changable urls + + :param repo_name: + """ + + data = repo_name.split('/') + if len(data) >= 2: + from rhodecode.model.repo import RepoModel + by_id_match = RepoModel().get_repo_by_id(repo_name) + if by_id_match: + data[1] = by_id_match.repo_name + + return safe_str('/'.join(data)) + + def _invalidate_cache(self, repo_name): + """ + Set's cache for this repository for invalidation on next access + + :param repo_name: full repo name, also a cache key + """ + ScmModel().mark_for_invalidation(repo_name) + + def is_valid_and_existing_repo(self, repo_name, base_path, scm_type): + db_repo = Repository.get_by_repo_name(repo_name) + if not db_repo: + log.debug('Repository `%s` not found inside the database.') + return False + + if db_repo.repo_type != scm_type: + log.warning( + 'Repository `%s` have incorrect scm_type, expected %s got %s', + repo_name, db_repo.repo_type, scm_type) + return False + + return is_valid_repo(repo_name, base_path, expect_scm=scm_type) + + def valid_and_active_user(self, user): + """ + Checks if that user is not empty, and if it's actually object it checks + if he's active. + + :param user: user object or None + :return: boolean + """ + if user is None: + return False + + elif user.active: + return True + + return False + + def _check_permission(self, action, user, repo_name, ip_addr=None): + """ + Checks permissions using action (push/pull) user and repository + name + + :param action: push or pull action + :param user: user instance + :param repo_name: repository name + """ + # check IP + inherit = user.inherit_default_permissions + ip_allowed = AuthUser.check_ip_allowed(user.user_id, ip_addr, + inherit_from_default=inherit) + if ip_allowed: + log.info('Access for IP:%s allowed', ip_addr) + else: + return False + + if action == 'push': + if not HasPermissionAnyMiddleware('repository.write', + 'repository.admin')(user, + repo_name): + return False + + else: + # any other action need at least read permission + if not HasPermissionAnyMiddleware('repository.read', + 'repository.write', + 'repository.admin')(user, + repo_name): + return False + + return True + + def _check_ssl(self, environ, start_response): + """ + Checks the SSL check flag and returns False if SSL is not present + and required True otherwise + """ + org_proto = environ['wsgi._org_proto'] + # check if we have SSL required ! if not it's a bad request ! + require_ssl = str2bool( + SettingsModel().get_ui_by_key('push_ssl').ui_value) + if require_ssl and org_proto == 'http': + log.debug('proto is %s and SSL is required BAD REQUEST !', + org_proto) + return False + return True + + def __call__(self, environ, start_response): + try: + return self._handle_request(environ, start_response) + except Exception: + log.exception("Exception while handling request") + appenlight.track_exception(environ) + return HTTPInternalServerError()(environ, start_response) + finally: + meta.Session.remove() + + def _handle_request(self, environ, start_response): + + if not self._check_ssl(environ, start_response): + reason = ('SSL required, while RhodeCode was unable ' + 'to detect this as SSL request') + log.debug('User not allowed to proceed, %s', reason) + return HTTPNotAcceptable(reason)(environ, start_response) + + ip_addr = get_ip_addr(environ) + username = None + + # skip passing error to error controller + environ['pylons.status_code_redirect'] = True + + # ====================================================================== + # EXTRACT REPOSITORY NAME FROM ENV + # ====================================================================== + environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO']) + repo_name = self._get_repository_name(environ) + environ['REPO_NAME'] = repo_name + log.debug('Extracted repo name is %s', repo_name) + + # check for type, presence in database and on filesystem + if not self.is_valid_and_existing_repo( + repo_name, self.basepath, self.SCM): + return HTTPNotFound()(environ, start_response) + + # ====================================================================== + # GET ACTION PULL or PUSH + # ====================================================================== + action = self._get_action(environ) + + # ====================================================================== + # CHECK ANONYMOUS PERMISSION + # ====================================================================== + if action in ['pull', 'push']: + anonymous_user = User.get_default_user() + username = anonymous_user.username + if anonymous_user.active: + # ONLY check permissions if the user is activated + anonymous_perm = self._check_permission( + action, anonymous_user, repo_name, ip_addr) + else: + anonymous_perm = False + + if not anonymous_user.active or not anonymous_perm: + if not anonymous_user.active: + log.debug('Anonymous access is disabled, running ' + 'authentication') + + if not anonymous_perm: + log.debug('Not enough credentials to access this ' + 'repository as anonymous user') + + username = None + # ============================================================== + # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE + # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS + # ============================================================== + + # try to auth based on environ, container auth methods + log.debug('Running PRE-AUTH for container based authentication') + pre_auth = authenticate('', '', environ,VCS_TYPE) + if pre_auth and pre_auth.get('username'): + username = pre_auth['username'] + log.debug('PRE-AUTH got %s as username', username) + + # If not authenticated by the container, running basic auth + if not username: + self.authenticate.realm = \ + safe_str(self.config['rhodecode_realm']) + + try: + result = self.authenticate(environ) + except (UserCreationError, NotAllowedToCreateUserError) as e: + log.error(e) + reason = safe_str(e) + return HTTPNotAcceptable(reason)(environ, start_response) + + if isinstance(result, str): + AUTH_TYPE.update(environ, 'basic') + REMOTE_USER.update(environ, result) + username = result + else: + return result.wsgi_application(environ, start_response) + + # ============================================================== + # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME + # ============================================================== + user = User.get_by_username(username) + if not self.valid_and_active_user(user): + return HTTPForbidden()(environ, start_response) + username = user.username + user.update_lastactivity() + meta.Session().commit() + + # check user attributes for password change flag + user_obj = user + if user_obj and user_obj.username != User.DEFAULT_USER and \ + user_obj.user_data.get('force_password_change'): + reason = 'password change required' + log.debug('User not allowed to authenticate, %s', reason) + return HTTPNotAcceptable(reason)(environ, start_response) + + # check permissions for this repository + perm = self._check_permission(action, user, repo_name, ip_addr) + if not perm: + return HTTPForbidden()(environ, start_response) + + # extras are injected into UI object and later available + # in hooks executed by rhodecode + check_locking = _should_check_locking(environ.get('QUERY_STRING')) + extras = vcs_operation_context( + environ, repo_name=repo_name, username=username, + action=action, scm=self.SCM, + check_locking=check_locking) + + # ====================================================================== + # REQUEST HANDLING + # ====================================================================== + str_repo_name = safe_str(repo_name) + repo_path = os.path.join(safe_str(self.basepath), str_repo_name) + log.debug('Repository path is %s', repo_path) + + fix_PATH() + + log.info( + '%s action on %s repo "%s" by "%s" from %s', + action, self.SCM, str_repo_name, safe_str(username), ip_addr) + return self._generate_vcs_response( + environ, start_response, repo_path, repo_name, extras, action) + + @initialize_generator + def _generate_vcs_response( + self, environ, start_response, repo_path, repo_name, extras, + action): + """ + Returns a generator for the response content. + + This method is implemented as a generator, so that it can trigger + the cache validation after all content sent back to the client. It + also handles the locking exceptions which will be triggered when + the first chunk is produced by the underlying WSGI application. + """ + callback_daemon, extras = self._prepare_callback_daemon(extras) + config = self._create_config(extras, repo_name) + log.debug('HOOKS extras is %s', extras) + app = self._create_wsgi_app(repo_path, repo_name, config) + + try: + with callback_daemon: + try: + response = app(environ, start_response) + finally: + # This statement works together with the decorator + # "initialize_generator" above. The decorator ensures that + # we hit the first yield statement before the generator is + # returned back to the WSGI server. This is needed to + # ensure that the call to "app" above triggers the + # needed callback to "start_response" before the + # generator is actually used. + yield "__init__" + + for chunk in response: + yield chunk + except Exception as exc: + # TODO: johbo: Improve "translating" back the exception. + if getattr(exc, '_vcs_kind', None) == 'repo_locked': + exc = HTTPLockedRC(*exc.args) + _code = rhodecode.CONFIG.get('lock_ret_code') + log.debug('Repository LOCKED ret code %s!', (_code,)) + elif getattr(exc, '_vcs_kind', None) == 'requirement': + log.debug( + 'Repository requires features unknown to this Mercurial') + exc = HTTPRequirementError(*exc.args) + else: + raise + + for chunk in exc(environ, start_response): + yield chunk + finally: + # invalidate cache on push + if action == 'push': + self._invalidate_cache(repo_name) + + def _get_repository_name(self, environ): + """Get repository name out of the environmnent + + :param environ: WSGI environment + """ + raise NotImplementedError() + + def _get_action(self, environ): + """Map request commands into a pull or push command. + + :param environ: WSGI environment + """ + raise NotImplementedError() + + def _create_wsgi_app(self, repo_path, repo_name, config): + """Return the WSGI app that will finally handle the request.""" + raise NotImplementedError() + + def _create_config(self, extras, repo_name): + """Create a Pyro safe config representation.""" + raise NotImplementedError() + + def _prepare_callback_daemon(self, extras): + return prepare_callback_daemon( + extras, protocol=self.config.get('vcs.hooks.protocol'), + use_direct_calls=self.config.get('vcs.hooks.direct_calls')) + + +def _should_check_locking(query_string): + # this is kind of hacky, but due to how mercurial handles client-server + # server see all operation on commit; bookmarks, phases and + # obsolescence marker in different transaction, we don't want to check + # locking on those + return query_string not in ['cmd=listkeys'] diff --git a/rhodecode/lib/middleware/utils/__init__.py b/rhodecode/lib/middleware/utils/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/utils/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/middleware/utils/scm_app.py b/rhodecode/lib/middleware/utils/scm_app.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/utils/scm_app.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Equivalent of rhodecode.lib.middleware.scm_app but using remote apps. +""" + +import logging + +from rhodecode.lib.middleware.utils import wsgi_app_caller_client + + +log = logging.getLogger(__name__) + + +HG_REMOTE_WSGI = None +GIT_REMOTE_WSGI = None + + +def create_git_wsgi_app(repo_path, repo_name, config): + """ + Return a WSGI app backed by a remote app to handle Git. + + config is a dictionary holding the extras. + """ + factory = GIT_REMOTE_WSGI + if not factory: + log.error('Pyro server has not been initialized yet') + + return wsgi_app_caller_client.RemoteAppCaller( + factory, repo_path, repo_name, config) + + +def create_hg_wsgi_app(repo_path, repo_name, config): + """ + Return a WSGI app backed by a remote app to handle Mercurial. + + config is a list of 3-item tuples representing a ConfigObject (it is the + serialized version of the config object). + """ + factory = HG_REMOTE_WSGI + if not factory: + log.error('Pyro server has not been initialized yet') + + return wsgi_app_caller_client.RemoteAppCaller( + factory, repo_path, repo_name, config) diff --git a/rhodecode/lib/middleware/utils/scm_app_http.py b/rhodecode/lib/middleware/utils/scm_app_http.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/utils/scm_app_http.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Implementation of the scm_app interface using raw HTTP communication. +""" + +import base64 +import logging +import urlparse +import wsgiref.util + +import msgpack +import requests +import webob.request + +import rhodecode + + +log = logging.getLogger(__name__) + + +def create_git_wsgi_app(repo_path, repo_name, config): + url = _vcs_streaming_url() + 'git/' + return VcsHttpProxy(url, repo_path, repo_name, config) + + +def create_hg_wsgi_app(repo_path, repo_name, config): + url = _vcs_streaming_url() + 'hg/' + return VcsHttpProxy(url, repo_path, repo_name, config) + + +def _vcs_streaming_url(): + template = 'http://{}/stream/' + return template.format(rhodecode.CONFIG['vcs.server']) + + +# TODO: johbo: Avoid the global. +session = requests.Session() +# Requests speedup, avoid reading .netrc and similar +session.trust_env = False + + +class VcsHttpProxy(object): + """ + A WSGI application which proxies vcs requests. + + The goal is to shuffle the data around without touching it. The only + exception is the extra data from the config object which we send to the + server as well. + """ + + def __init__(self, url, repo_path, repo_name, config): + """ + :param str url: The URL of the VCSServer to call. + """ + self._url = url + self._repo_name = repo_name + self._repo_path = repo_path + self._config = config + log.debug( + "Creating VcsHttpProxy for repo %s, url %s", + repo_name, url) + + def __call__(self, environ, start_response): + status = '200 OK' + + config = msgpack.packb(self._config) + request = webob.request.Request(environ) + request_headers = request.headers + request_headers.update({ + # TODO: johbo: Remove this, rely on URL path only + 'X-RC-Repo-Name': self._repo_name, + 'X-RC-Repo-Path': self._repo_path, + 'X-RC-Path-Info': environ['PATH_INFO'], + # TODO: johbo: Avoid encoding and put this into payload? + 'X-RC-Repo-Config': base64.b64encode(config), + }) + + data = environ['wsgi.input'].read() + method = environ['REQUEST_METHOD'] + + # Preserve the query string + url = self._url + url = urlparse.urljoin(url, self._repo_name) + if environ.get('QUERY_STRING'): + url += '?' + environ['QUERY_STRING'] + + response = session.request( + method, url, + data=data, + headers=request_headers, + stream=True) + + # Preserve the headers of the response, except hop_by_hop ones + response_headers = [ + (h, v) for h, v in response.headers.items() + if not wsgiref.util.is_hop_by_hop(h) + ] + + # TODO: johbo: Better way to get the status including text? + status = str(response.status_code) + start_response(status, response_headers) + return _maybe_stream(response) + + +def _maybe_stream(response): + """ + Try to generate chunks from the response if it is chunked. + """ + if _is_chunked(response): + return response.raw.read_chunked() + else: + return [response.content] + + +def _is_chunked(response): + return response.headers.get('Transfer-Encoding', '') == 'chunked' diff --git a/rhodecode/lib/middleware/utils/wsgi_app_caller_client.py b/rhodecode/lib/middleware/utils/wsgi_app_caller_client.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/utils/wsgi_app_caller_client.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Utility to call a WSGI app wrapped in a WSGIAppCaller object. +""" + +import logging + +from Pyro4.errors import ConnectionClosedError + + +log = logging.getLogger(__name__) + + +def _get_clean_environ(environ): + """Return a copy of the WSGI environment without wsgi.* keys. + + It also omits any non-string values. + + :param environ: WSGI environment to clean + :type environ: dict + + :returns: WSGI environment to pass to WSGIAppCaller.handle. + :rtype: dict + """ + clean_environ = dict( + (k, v) for k, v in environ.iteritems() + if type(v) == str and type(k) == str and not k.startswith('wsgi.') + ) + + return clean_environ + + +# pylint: disable=too-few-public-methods +class RemoteAppCaller(object): + """Create and calls a remote WSGI app using the given factory. + + It first cleans the environment, so as to reduce the data transferred. + """ + + def __init__(self, remote_wsgi, *args, **kwargs): + """ + :param remote_wsgi: The remote wsgi object that creates a + WSGIAppCaller. This object + has to have a handle method, with the signature: + handle(environ, start_response, *args, **kwargs) + :param args: args to be passed to the app creation + :param kwargs: kwargs to be passed to the app creation + """ + self._remote_wsgi = remote_wsgi + self._args = args + self._kwargs = kwargs + + def __call__(self, environ, start_response): + """ + :param environ: WSGI environment with which the app will be run + :type environ: dict + :param start_response: callable of WSGI protocol + :type start_response: callable + + :returns: an iterable with the data returned by the app + :rtype: iterable<str> + """ + log.debug("Forwarding WSGI request via proxy %s", self._remote_wsgi) + input_data = environ['wsgi.input'].read() + clean_environ = _get_clean_environ(environ) + + try: + data, status, headers = self._remote_wsgi.handle( + clean_environ, input_data, *self._args, **self._kwargs) + except ConnectionClosedError: + log.debug('Remote Pyro Server ConnectionClosedError') + self._remote_wsgi._pyroReconnect(tries=15) + data, status, headers = self._remote_wsgi.handle( + clean_environ, input_data, *self._args, **self._kwargs) + + log.debug("Got result from proxy, returning to WSGI container") + start_response(status, headers) + + return data diff --git a/rhodecode/lib/middleware/vcs.py b/rhodecode/lib/middleware/vcs.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/middleware/vcs.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import gzip +import shutil +import logging +import tempfile +import urlparse + +import rhodecode +from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled +from rhodecode.lib.middleware.simplegit import SimpleGit, GIT_PROTO_PAT +from rhodecode.lib.middleware.simplehg import SimpleHg +from rhodecode.lib.middleware.simplesvn import SimpleSvn + + +log = logging.getLogger(__name__) + + +def is_git(environ): + """ + Returns True if requests should be handled by GIT wsgi middleware + """ + is_git_path = GIT_PROTO_PAT.match(environ['PATH_INFO']) + log.debug( + 'request path: `%s` detected as GIT PROTOCOL %s', environ['PATH_INFO'], + is_git_path is not None) + + return is_git_path + + +def is_hg(environ): + """ + Returns True if requests target is mercurial server - header + ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``. + """ + is_hg_path = False + + http_accept = environ.get('HTTP_ACCEPT') + + if http_accept and http_accept.startswith('application/mercurial'): + query = urlparse.parse_qs(environ['QUERY_STRING']) + if 'cmd' in query: + is_hg_path = True + + log.debug( + 'request path: `%s` detected as HG PROTOCOL %s', environ['PATH_INFO'], + is_hg_path) + + return is_hg_path + + +def is_svn(environ): + """ + Returns True if requests target is Subversion server + """ + http_dav = environ.get('HTTP_DAV', '') + is_svn_path = 'subversion' in http_dav + log.debug( + 'request path: `%s` detected as SVN PROTOCOL %s', environ['PATH_INFO'], + is_svn_path) + + return is_svn_path + + +class GunzipMiddleware(object): + """ + WSGI middleware that unzips gzip-encoded requests before + passing on to the underlying application. + """ + + def __init__(self, application): + self.app = application + + def __call__(self, environ, start_response): + accepts_encoding_header = environ.get('HTTP_CONTENT_ENCODING', b'') + + if b'gzip' in accepts_encoding_header: + log.debug('gzip detected, now running gunzip wrapper') + wsgi_input = environ['wsgi.input'] + + if not hasattr(environ['wsgi.input'], 'seek'): + # The gzip implementation in the standard library of Python 2.x + # requires the '.seek()' and '.tell()' methods to be available + # on the input stream. Read the data into a temporary file to + # work around this limitation. + + wsgi_input = tempfile.SpooledTemporaryFile(64 * 1024 * 1024) + shutil.copyfileobj(environ['wsgi.input'], wsgi_input) + wsgi_input.seek(0) + + environ['wsgi.input'] = gzip.GzipFile(fileobj=wsgi_input, mode='r') + # since we "Ungzipped" the content we say now it's no longer gzip + # content encoding + del environ['HTTP_CONTENT_ENCODING'] + + # content length has changes ? or i'm not sure + if 'CONTENT_LENGTH' in environ: + del environ['CONTENT_LENGTH'] + else: + log.debug('content not gzipped, gzipMiddleware passing ' + 'request further') + return self.app(environ, start_response) + + +class VCSMiddleware(object): + + def __init__(self, app, config, appenlight_client): + self.application = app + self.config = config + self.appenlight_client = appenlight_client + + def _get_handler_app(self, environ): + app = None + if is_hg(environ): + app = SimpleHg(self.application, self.config) + + if is_git(environ): + app = SimpleGit(self.application, self.config) + + proxy_svn = rhodecode.CONFIG.get( + 'rhodecode_proxy_subversion_http_requests', False) + if proxy_svn and is_svn(environ): + app = SimpleSvn(self.application, self.config) + + if app: + app = GunzipMiddleware(app) + app, _ = wrap_in_appenlight_if_enabled( + app, self.config, self.appenlight_client) + + return app + + def __call__(self, environ, start_response): + # check if we handle one of interesting protocols ? + vcs_handler = self._get_handler_app(environ) + if vcs_handler: + return vcs_handler(environ, start_response) + + return self.application(environ, start_response) diff --git a/rhodecode/lib/paster_commands/__init__.py b/rhodecode/lib/paster_commands/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/paster_commands/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/paster_commands/ishell.py b/rhodecode/lib/paster_commands/ishell.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/paster_commands/ishell.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +interactive shell paster command for RhodeCode +""" + +import os +import sys +import logging + +from rhodecode.lib.utils import BasePasterCommand + +# fix rhodecode import +from os.path import dirname as dn +rc_path = dn(dn(dn(os.path.realpath(__file__)))) +sys.path.append(rc_path) + +log = logging.getLogger(__name__) + + +class Command(BasePasterCommand): + + max_args = 1 + min_args = 1 + + usage = "CONFIG_FILE" + group_name = "RhodeCode" + takes_config_file = -1 + parser = BasePasterCommand.standard_parser(verbose=True) + summary = "Interactive shell" + + def command(self): + #get SqlAlchemy session + self._init_session() + + # imports, used in ipython shell + import os + import sys + import time + import shutil + import datetime + from rhodecode.model.db import * + + try: + from IPython import embed + from IPython.config.loader import Config + cfg = Config() + cfg.InteractiveShellEmbed.confirm_exit = False + embed(config=cfg, banner1="RhodeCode IShell.") + except ImportError: + print 'ipython installation required for ishell' + sys.exit(-1) + + def update_parser(self): + pass diff --git a/rhodecode/lib/paster_commands/make_config.py b/rhodecode/lib/paster_commands/make_config.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/paster_commands/make_config.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +depracated make-config paster command for RhodeCode +""" + +import os +import sys +from paste.script.appinstall import AbstractInstallCommand +from paste.script.command import BadCommand +from paste.deploy import appconfig + +# fix rhodecode import +from os.path import dirname as dn +rc_path = dn(dn(dn(os.path.realpath(__file__)))) +sys.path.append(rc_path) + +class Command(AbstractInstallCommand): + + default_verbosity = 1 + max_args = None + min_args = 1 + summary = "*DEPRECATED* Install a package and create a fresh config file/directory" + usage = "PACKAGE_NAME [CONFIG_FILE] [VAR=VALUE]" + + description = """\ + Note: this is an experimental command, and it will probably change + in several ways by the next release. + + make-config is part of a two-phase installation process (the + second phase is setup-app). make-config installs the package + (using easy_install) and asks it to create a bare configuration + file or directory (possibly filling in defaults from the extra + variables you give). + """ + + parser = AbstractInstallCommand.standard_parser( + simulate=True, quiet=True, no_interactive=True) + + def command(self): + sys.stderr.write( + '** Warning **\n' + 'This command is now removed and depracated, please ' + 'use new rhodecode-config command instead.') + sys.exit(-1) + def update_parser(self): + pass diff --git a/rhodecode/lib/paster_commands/setup_rhodecode.py b/rhodecode/lib/paster_commands/setup_rhodecode.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/paster_commands/setup_rhodecode.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import sys +from paste.script.appinstall import AbstractInstallCommand +from paste.script.command import BadCommand +from paste.deploy import appconfig + +# fix rhodecode import +from os.path import dirname as dn +rc_path = dn(dn(dn(os.path.realpath(__file__)))) +sys.path.append(rc_path) + + +class Command(AbstractInstallCommand): + + default_verbosity = 1 + max_args = 1 + min_args = 1 + summary = "Setup an application, given a config file" + usage = "CONFIG_FILE" + group_name = "RhodeCode" + + description = """\ + + Setup RhodeCode according to its configuration file. This is + the second part of a two-phase web application installation + process (the first phase is prepare-app). The setup process + consist of things like setting up databases, creating super user + """ + + parser = AbstractInstallCommand.standard_parser( + simulate=True, quiet=True, interactive=True) + parser.add_option( + '--user', + action='store', + dest='username', + default=None, + help='Admin Username') + parser.add_option( + '--email', + action='store', + dest='email', + default=None, + help='Admin Email') + parser.add_option( + '--password', + action='store', + dest='password', + default=None, + help='Admin password min 6 chars') + parser.add_option( + '--api-key', + action='store', + dest='api_key', + help='Initial API key for the admin user') + parser.add_option( + '--repos', + action='store', + dest='repos_location', + default=None, + help='Absolute path to repositories location') + parser.add_option( + '--name', + action='store', + dest='section_name', + default=None, + help='The name of the section to set up (default: app:main)') + parser.add_option( + '--force-yes', + action='store_true', + dest='force_ask', + default=None, + help='Force yes to every question') + parser.add_option( + '--force-no', + action='store_false', + dest='force_ask', + default=None, + help='Force no to every question') + parser.add_option( + '--public-access', + action='store_true', + dest='public_access', + default=None, + help='Enable public access on this installation (default)') + parser.add_option( + '--no-public-access', + action='store_false', + dest='public_access', + default=None, + help='Disable public access on this installation ') + + def command(self): + config_spec = self.args[0] + section = self.options.section_name + if section is None: + if '#' in config_spec: + config_spec, section = config_spec.split('#', 1) + else: + section = 'main' + if ':' not in section: + plain_section = section + section = 'app:' + section + else: + plain_section = section.split(':', 1)[0] + if not config_spec.startswith('config:'): + config_spec = 'config:' + config_spec + if plain_section != 'main': + config_spec += '#' + plain_section + config_file = config_spec[len('config:'):].split('#', 1)[0] + config_file = os.path.join(os.getcwd(), config_file) + self.logging_file_config(config_file) + conf = appconfig(config_spec, relative_to=os.getcwd()) + ep_name = conf.context.entry_point_name + ep_group = conf.context.protocol + dist = conf.context.distribution + if dist is None: + raise BadCommand( + "The section %r is not the application (probably a filter). " + "You should add #section_name, where section_name is the " + "section that configures your application" % plain_section) + installer = self.get_installer(dist, ep_group, ep_name) + installer.setup_config( + self, config_file, section, self.sysconfig_install_vars(installer)) + self.call_sysconfig_functions( + 'post_setup_hook', installer, config_file) diff --git a/rhodecode/lib/pidlock.py b/rhodecode/lib/pidlock.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/pidlock.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import errno + +from multiprocessing.util import Finalize + +from rhodecode.lib.compat import kill + + +class LockHeld(Exception): + pass + + +class DaemonLock(object): + """daemon locking + USAGE: + try: + l = DaemonLock(file_='/path/tolockfile',desc='test lock') + main() + l.release() + except LockHeld: + sys.exit(1) + """ + + def __init__(self, file_=None, callbackfn=None, + desc='daemon lock', debug=False): + + lock_name = os.path.join(os.path.dirname(__file__), 'running.lock') + self.pidfile = file_ if file_ else lock_name + self.callbackfn = callbackfn + self.desc = desc + self.debug = debug + self.held = False + #run the lock automatically ! + self.lock() + self._finalize = Finalize(self, DaemonLock._on_finalize, + args=(self, debug), exitpriority=10) + + @staticmethod + def _on_finalize(lock, debug): + if lock.held: + if debug: + print 'leck held finilazing and running lock.release()' + lock.release() + + def lock(self): + """ + locking function, if lock is present it + will raise LockHeld exception + """ + lockname = '%s' % (os.getpid()) + if self.debug: + print 'running lock' + self.trylock() + self.makelock(lockname, self.pidfile) + return True + + def trylock(self): + running_pid = False + if self.debug: + print 'checking for already running process' + try: + with open(self.pidfile, 'r') as f: + try: + running_pid = int(f.readline()) + except ValueError: + running_pid = -1 + + if self.debug: + print ('lock file present running_pid: %s, ' + 'checking for execution' % (running_pid,)) + # Now we check the PID from lock file matches to the current + # process PID + if running_pid: + try: + kill(running_pid, 0) + except OSError as exc: + if exc.errno in (errno.ESRCH, errno.EPERM): + print ("Lock File is there but" + " the program is not running") + print "Removing lock file for the: %s" % running_pid + self.release() + else: + raise + else: + print "You already have an instance of the program running" + print "It is running as process %s" % running_pid + raise LockHeld() + + except IOError as e: + if e.errno != 2: + raise + + def release(self): + """releases the pid by removing the pidfile + """ + if self.debug: + print 'trying to release the pidlock' + + if self.callbackfn: + #execute callback function on release + if self.debug: + print 'executing callback function %s' % self.callbackfn + self.callbackfn() + try: + if self.debug: + print 'removing pidfile %s' % self.pidfile + os.remove(self.pidfile) + self.held = False + except OSError as e: + if self.debug: + print 'removing pidfile failed %s' % e + pass + + def makelock(self, lockname, pidfile): + """ + this function will make an actual lock + + :param lockname: acctual pid of file + :param pidfile: the file to write the pid in + """ + if self.debug: + print 'creating a file %s and pid: %s' % (pidfile, lockname) + + dir_, file_ = os.path.split(pidfile) + if not os.path.isdir(dir_): + os.makedirs(dir_) + with open(self.pidfile, 'wb') as f: + f.write(lockname) + self.held = True diff --git a/rhodecode/lib/plugins/__init__.py b/rhodecode/lib/plugins/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/plugins/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/plugins/utils.py b/rhodecode/lib/plugins/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/plugins/utils.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +def get_plugin_settings(prefix, settings): + """ + Returns plugin settings. Use:: + + + + :param prefix: + :param settings: + :return: + """ + prefix = prefix + '.' if not prefix.endswith('.') else prefix + plugin_settings = {} + for k, v in settings.items(): + if k.startswith(prefix): + plugin_settings[k[len(prefix):]] = v + + return plugin_settings + + +def register_rhodecode_plugin(config, plugin_name, plugin_config): + def register(): + if plugin_name not in config.registry.rhodecode_plugins: + config.registry.rhodecode_plugins[plugin_name] = { + 'javascript': None, + 'static': None, + 'css': None, + 'top_nav': None, + 'fulltext_indexer': None, + 'sqlalchemy_migrations': None, + 'default_values_setter': None, + 'resource_types': [], + 'url_gen': None + } + config.registry.rhodecode_plugins[plugin_name].update( + plugin_config) + # inform RC what kind of resource types we have available + # so we can avoid failing when a plugin is removed but data + # is still present in the db + if plugin_config.get('resource_types'): + config.registry.resource_types.extend( + plugin_config['resource_types']) + + config.action( + 'register_rhodecode_plugin={}'.format(plugin_name), register) diff --git a/rhodecode/lib/profiler.py b/rhodecode/lib/profiler.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/profiler.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import gc +import objgraph +import cProfile +import pstats +import cgi +import pprint +import threading + +from StringIO import StringIO + + +class ProfilingMiddleware(object): + def __init__(self, app): + self.lock = threading.Lock() + self.app = app + + def __call__(self, environ, start_response): + with self.lock: + profiler = cProfile.Profile() + + def run_app(*a, **kw): + self.response = self.app(environ, start_response) + + profiler.runcall(run_app, environ, start_response) + + profiler.snapshot_stats() + + stats = pstats.Stats(profiler) + stats.sort_stats('calls') #cummulative + + # Redirect output + out = StringIO() + stats.stream = out + + stats.print_stats() + + resp = ''.join(self.response) + + # Lets at least only put this on html-like responses. + if resp.strip().startswith('<'): + ## The profiling info is just appended to the response. + ## Browsers don't mind this. + resp += ('<pre style="text-align:left; ' + 'border-top: 4px dashed red; padding: 1em;">') + resp += cgi.escape(out.getvalue(), True) + + ct = objgraph.show_most_common_types() + print ct + + resp += ct if ct else '---' + + output = StringIO() + pprint.pprint(environ, output, depth=3) + + resp += cgi.escape(output.getvalue(), True) + resp += '</pre>' + + return resp diff --git a/rhodecode/lib/rcmail/__init__.py b/rhodecode/lib/rcmail/__init__.py new file mode 100644 diff --git a/rhodecode/lib/rcmail/exceptions.py b/rhodecode/lib/rcmail/exceptions.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rcmail/exceptions.py @@ -0,0 +1,13 @@ + + +class InvalidMessage(RuntimeError): + """ + Raised if message is missing vital headers, such + as recipients or sender address. + """ + + +class BadHeaders(RuntimeError): + """ + Raised if message contains newlines in headers. + """ diff --git a/rhodecode/lib/rcmail/message.py b/rhodecode/lib/rcmail/message.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rcmail/message.py @@ -0,0 +1,183 @@ +from rhodecode.lib.rcmail.response import MailResponse + +from rhodecode.lib.rcmail.exceptions import BadHeaders +from rhodecode.lib.rcmail.exceptions import InvalidMessage + + +class Attachment(object): + """ + Encapsulates file attachment information. + + :param filename: filename of attachment + :param content_type: file mimetype + :param data: the raw file data, either as string or file obj + :param disposition: content-disposition (if any) + """ + + def __init__(self, + filename=None, + content_type=None, + data=None, + disposition=None): + + self.filename = filename + self.content_type = content_type + self.disposition = disposition or 'attachment' + self._data = data + + @property + def data(self): + if isinstance(self._data, basestring): + return self._data + self._data = self._data.read() + return self._data + + +class Message(object): + """ + Encapsulates an email message. + + :param subject: email subject header + :param recipients: list of email addresses + :param body: plain text message + :param html: HTML message + :param sender: email sender address + :param cc: CC list + :param bcc: BCC list + :param extra_headers: dict of extra email headers + :param attachments: list of Attachment instances + :param recipients_separator: alternative separator for any of + 'From', 'To', 'Delivered-To', 'Cc', 'Bcc' fields + """ + + def __init__(self, + subject=None, + recipients=None, + body=None, + html=None, + sender=None, + cc=None, + bcc=None, + extra_headers=None, + attachments=None, + recipients_separator="; "): + + self.subject = subject or '' + self.sender = sender + self.body = body + self.html = html + + self.recipients = recipients or [] + self.attachments = attachments or [] + self.cc = cc or [] + self.bcc = bcc or [] + self.extra_headers = extra_headers or {} + + self.recipients_separator = recipients_separator + + @property + def send_to(self): + return set(self.recipients) | set(self.bcc or ()) | set(self.cc or ()) + + def to_message(self): + """ + Returns raw email.Message instance.Validates message first. + """ + + self.validate() + + return self.get_response().to_message() + + def get_response(self): + """ + Creates a Lamson MailResponse instance + """ + + response = MailResponse(Subject=self.subject, + To=self.recipients, + From=self.sender, + Body=self.body, + Html=self.html, + separator=self.recipients_separator) + + if self.cc: + response.base['Cc'] = self.cc + + for attachment in self.attachments: + + response.attach(attachment.filename, + attachment.content_type, + attachment.data, + attachment.disposition) + + response.update(self.extra_headers) + + return response + + def is_bad_headers(self): + """ + Checks for bad headers i.e. newlines in subject, sender or recipients. + """ + + headers = [self.subject, self.sender] + headers += list(self.send_to) + headers += self.extra_headers.values() + + for val in headers: + for c in '\r\n': + if c in val: + return True + return False + + def validate(self): + """ + Checks if message is valid and raises appropriate exception. + """ + + if not self.recipients: + raise InvalidMessage("No recipients have been added") + + if not self.body and not self.html: + raise InvalidMessage("No body has been set") + + if not self.sender: + raise InvalidMessage("No sender address has been set") + + if self.is_bad_headers(): + raise BadHeaders + + def add_recipient(self, recipient): + """ + Adds another recipient to the message. + + :param recipient: email address of recipient. + """ + + self.recipients.append(recipient) + + def add_cc(self, recipient): + """ + Adds an email address to the CC list. + + :param recipient: email address of recipient. + """ + + self.cc.append(recipient) + + def add_bcc(self, recipient): + """ + Adds an email address to the BCC list. + + :param recipient: email address of recipient. + """ + + self.bcc.append(recipient) + + def attach(self, attachment): + """ + Adds an attachment to the message. + + :param attachment: an **Attachment** instance. + """ + + self.attachments.append(attachment) diff --git a/rhodecode/lib/rcmail/response.py b/rhodecode/lib/rcmail/response.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rcmail/response.py @@ -0,0 +1,454 @@ +# The code in this module is entirely lifted from the Lamson project +# (http://lamsonproject.org/). Its copyright is: + +# Copyright (c) 2008, Zed A. Shaw +# All rights reserved. + +# It is provided under this license: + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# * Neither the name of the Zed A. Shaw nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import mimetypes +import string +from email import encoders +from email.charset import Charset +from email.utils import parseaddr +from email.mime.base import MIMEBase + +ADDRESS_HEADERS_WHITELIST = ['From', 'To', 'Delivered-To', 'Cc'] +DEFAULT_ENCODING = "utf-8" +VALUE_IS_EMAIL_ADDRESS = lambda v: '@' in v + + +def normalize_header(header): + return string.capwords(header.lower(), '-') + + +class EncodingError(Exception): + """Thrown when there is an encoding error.""" + pass + + +class MailBase(object): + """MailBase is used as the basis of lamson.mail and contains the basics of + encoding an email. You actually can do all your email processing with this + class, but it's more raw. + """ + def __init__(self, items=()): + self.headers = dict(items) + self.parts = [] + self.body = None + self.content_encoding = {'Content-Type': (None, {}), + 'Content-Disposition': (None, {}), + 'Content-Transfer-Encoding': (None, {})} + + def __getitem__(self, key): + return self.headers.get(normalize_header(key), None) + + def __len__(self): + return len(self.headers) + + def __iter__(self): + return iter(self.headers) + + def __contains__(self, key): + return normalize_header(key) in self.headers + + def __setitem__(self, key, value): + self.headers[normalize_header(key)] = value + + def __delitem__(self, key): + del self.headers[normalize_header(key)] + + def __nonzero__(self): + return self.body is not None or len(self.headers) > 0 or len(self.parts) > 0 + + def keys(self): + """Returns the sorted keys.""" + return sorted(self.headers.keys()) + + def attach_file(self, filename, data, ctype, disposition): + """ + A file attachment is a raw attachment with a disposition that + indicates the file name. + """ + assert filename, "You can't attach a file without a filename." + ctype = ctype.lower() + + part = MailBase() + part.body = data + part.content_encoding['Content-Type'] = (ctype, {'name': filename}) + part.content_encoding['Content-Disposition'] = (disposition, + {'filename': filename}) + self.parts.append(part) + + def attach_text(self, data, ctype): + """ + This attaches a simpler text encoded part, which doesn't have a + filename. + """ + ctype = ctype.lower() + + part = MailBase() + part.body = data + part.content_encoding['Content-Type'] = (ctype, {}) + self.parts.append(part) + + def walk(self): + for p in self.parts: + yield p + for x in p.walk(): + yield x + + +class MailResponse(object): + """ + You are given MailResponse objects from the lamson.view methods, and + whenever you want to generate an email to send to someone. It has the + same basic functionality as MailRequest, but it is designed to be written + to, rather than read from (although you can do both). + + You can easily set a Body or Html during creation or after by passing it + as __init__ parameters, or by setting those attributes. + + You can initially set the From, To, and Subject, but they are headers so + use the dict notation to change them: msg['From'] = 'joe@test.com'. + + The message is not fully crafted until right when you convert it with + MailResponse.to_message. This lets you change it and work with it, then + send it out when it's ready. + """ + def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None, + separator="; "): + self.Body = Body + self.Html = Html + self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)]) + self.multipart = self.Body and self.Html + self.attachments = [] + self.separator = separator + + def __contains__(self, key): + return self.base.__contains__(key) + + def __getitem__(self, key): + return self.base.__getitem__(key) + + def __setitem__(self, key, val): + return self.base.__setitem__(key, val) + + def __delitem__(self, name): + del self.base[name] + + def attach(self, filename=None, content_type=None, data=None, + disposition=None): + """ + + Simplifies attaching files from disk or data as files. To attach + simple text simple give data and a content_type. To attach a file, + give the data/content_type/filename/disposition combination. + + For convenience, if you don't give data and only a filename, then it + will read that file's contents when you call to_message() later. If + you give data and filename then it will assume you've filled data + with what the file's contents are and filename is just the name to + use. + """ + + assert filename or data, ("You must give a filename or some data to " + "attach.") + assert data or os.path.exists(filename), ("File doesn't exist, and no " + "data given.") + + self.multipart = True + + if filename and not content_type: + content_type, encoding = mimetypes.guess_type(filename) + + assert content_type, ("No content type given, and couldn't guess " + "from the filename: %r" % filename) + + self.attachments.append({'filename': filename, + 'content_type': content_type, + 'data': data, + 'disposition': disposition,}) + + def attach_part(self, part): + """ + Attaches a raw MailBase part from a MailRequest (or anywhere) + so that you can copy it over. + """ + self.multipart = True + + self.attachments.append({'filename': None, + 'content_type': None, + 'data': None, + 'disposition': None, + 'part': part, + }) + + def attach_all_parts(self, mail_request): + """ + Used for copying the attachment parts of a mail.MailRequest + object for mailing lists that need to maintain attachments. + """ + for part in mail_request.all_parts(): + self.attach_part(part) + + self.base.content_encoding = mail_request.base.content_encoding.copy() + + def clear(self): + """ + Clears out the attachments so you can redo them. Use this to keep the + headers for a series of different messages with different attachments. + """ + del self.attachments[:] + del self.base.parts[:] + self.multipart = False + + def update(self, message): + """ + Used to easily set a bunch of heading from another dict + like object. + """ + for k in message.keys(): + self.base[k] = message[k] + + def __str__(self): + """ + Converts to a string. + """ + return self.to_message().as_string() + + def _encode_attachment(self, filename=None, content_type=None, data=None, + disposition=None, part=None): + """ + Used internally to take the attachments mentioned in self.attachments + and do the actual encoding in a lazy way when you call to_message. + """ + if part: + self.base.parts.append(part) + elif filename: + if not data: + with open(filename) as f: + data = f.read() + + self.base.attach_file(filename, data, content_type, + disposition or 'attachment') + else: + self.base.attach_text(data, content_type) + + ctype = self.base.content_encoding['Content-Type'][0] + + if ctype and not ctype.startswith('multipart'): + self.base.content_encoding['Content-Type'] = ('multipart/mixed', {}) + + def to_message(self): + """ + Figures out all the required steps to finally craft the + message you need and return it. The resulting message + is also available as a self.base attribute. + + What is returned is a Python email API message you can + use with those APIs. The self.base attribute is the raw + lamson.encoding.MailBase. + """ + del self.base.parts[:] + + if self.Body and self.Html: + self.multipart = True + self.base.content_encoding['Content-Type'] = ( + 'multipart/alternative', {}) + + if self.multipart: + self.base.body = None + if self.Body: + self.base.attach_text(self.Body, 'text/plain') + + if self.Html: + self.base.attach_text(self.Html, 'text/html') + + for args in self.attachments: + self._encode_attachment(**args) + + elif self.Body: + self.base.body = self.Body + self.base.content_encoding['Content-Type'] = ('text/plain', {}) + + elif self.Html: + self.base.body = self.Html + self.base.content_encoding['Content-Type'] = ('text/html', {}) + + return to_message(self.base, separator=self.separator) + + def all_parts(self): + """ + Returns all the encoded parts. Only useful for debugging + or inspecting after calling to_message(). + """ + return self.base.parts + + def keys(self): + return self.base.keys() + + +def to_message(mail, separator="; "): + """ + Given a MailBase message, this will construct a MIMEPart + that is canonicalized for use with the Python email API. + """ + ctype, params = mail.content_encoding['Content-Type'] + + if not ctype: + if mail.parts: + ctype = 'multipart/mixed' + else: + ctype = 'text/plain' + else: + if mail.parts: + assert ctype.startswith(("multipart", "message")), \ + "Content type should be multipart or message, not %r" % ctype + + # adjust the content type according to what it should be now + mail.content_encoding['Content-Type'] = (ctype, params) + + try: + out = MIMEPart(ctype, **params) + except TypeError as exc: # pragma: no cover + raise EncodingError("Content-Type malformed, not allowed: %r; " + "%r (Python ERROR: %s" % + (ctype, params, exc.message)) + + for k in mail.keys(): + if k in ADDRESS_HEADERS_WHITELIST: + out[k.encode('ascii')] = header_to_mime_encoding( + mail[k], + not_email=False, + separator=separator + ) + else: + out[k.encode('ascii')] = header_to_mime_encoding( + mail[k], + not_email=True + ) + + out.extract_payload(mail) + + # go through the children + for part in mail.parts: + out.attach(to_message(part)) + + return out + + +class MIMEPart(MIMEBase): + """ + A reimplementation of nearly everything in email.mime to be more useful + for actually attaching things. Rather than one class for every type of + thing you'd encode, there's just this one, and it figures out how to + encode what you ask it. + """ + def __init__(self, type, **params): + self.maintype, self.subtype = type.split('/') + MIMEBase.__init__(self, self.maintype, self.subtype, **params) + + def add_text(self, content): + # this is text, so encode it in canonical form + try: + encoded = content.encode('ascii') + charset = 'ascii' + except UnicodeError: + encoded = content.encode('utf-8') + charset = 'utf-8' + + self.set_payload(encoded, charset=charset) + + def extract_payload(self, mail): + if mail.body is None: + return # only None, '' is still ok + + ctype, ctype_params = mail.content_encoding['Content-Type'] + cdisp, cdisp_params = mail.content_encoding['Content-Disposition'] + + assert ctype, ("Extract payload requires that mail.content_encoding " + "have a valid Content-Type.") + + if ctype.startswith("text/"): + self.add_text(mail.body) + else: + if cdisp: + # replicate the content-disposition settings + self.add_header('Content-Disposition', cdisp, **cdisp_params) + + self.set_payload(mail.body) + encoders.encode_base64(self) + + def __repr__(self): + return "<MIMEPart '%s/%s': %r, %r, multipart=%r>" % ( + self.subtype, + self.maintype, + self['Content-Type'], + self['Content-Disposition'], + self.is_multipart()) + + +def header_to_mime_encoding(value, not_email=False, separator=", "): + if not value: + return "" + + encoder = Charset(DEFAULT_ENCODING) + if type(value) == list: + return separator.join(properly_encode_header( + v, encoder, not_email) for v in value) + else: + return properly_encode_header(value, encoder, not_email) + + +def properly_encode_header(value, encoder, not_email): + """ + The only thing special (weird) about this function is that it tries + to do a fast check to see if the header value has an email address in + it. Since random headers could have an email address, and email addresses + have weird special formatting rules, we have to check for it. + + Normally this works fine, but in Librelist, we need to "obfuscate" email + addresses by changing the '@' to '-AT-'. This is where + VALUE_IS_EMAIL_ADDRESS exists. It's a simple lambda returning True/False + to check if a header value has an email address. If you need to make this + check different, then change this. + """ + try: + return value.encode("ascii") + except UnicodeEncodeError: + if not not_email and VALUE_IS_EMAIL_ADDRESS(value): + # this could have an email address, make sure we don't screw it up + name, address = parseaddr(value) + return '"%s" <%s>' % ( + encoder.header_encode(name.encode("utf-8")), address) + + return encoder.header_encode(value.encode("utf-8")) diff --git a/rhodecode/lib/rcmail/smtp_mailer.py b/rhodecode/lib/rcmail/smtp_mailer.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rcmail/smtp_mailer.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Simple smtp mailer used in RhodeCode +""" + +import time +import logging +from socket import sslerror +from email.utils import formatdate +from rhodecode.lib.rcmail.message import Message +from rhodecode.lib.rcmail.utils import DNS_NAME + +log = logging.getLogger(__name__) + + +class SmtpMailer(object): + """SMTP mailer class + + mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth + mail_port, ssl, tls) + mailer.send(recipients, subject, body, attachment_files) + + :param recipients might be a list of string or single string + :param attachment_files is a dict of {filename:location} + it tries to guess the mimetype and attach the file + + """ + + def __init__(self, mail_from, user, passwd, mail_server, smtp_auth=None, + mail_port=None, ssl=False, tls=False, debug=False): + + self.mail_from = mail_from + self.mail_server = mail_server + self.mail_port = mail_port + self.user = user + self.passwd = passwd + self.ssl = ssl + self.tls = tls + self.debug = debug + self.auth = smtp_auth + + def _get_smptlib(self): + #patch the output + import smtplib + + class StderrLogger(object): + + def write(self, message): + log.debug(message) + + org_stderr = smtplib.stderr + smtplib.stderr = StderrLogger() + return smtplib + + def send(self, recipients=[], subject='', body='', html='', + attachment_files=None): + + if isinstance(recipients, basestring): + recipients = [recipients] + headers = { + 'Date': formatdate(time.time()) + } + msg = Message(subject, recipients, body, html, self.mail_from, + recipients_separator=", ", extra_headers=headers) + raw_msg = msg.to_message() + + #patched smtplib without stderr + smtplib = self._get_smptlib() + if self.ssl: + smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port, + local_hostname=DNS_NAME.get_fqdn()) + else: + smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port, + local_hostname=DNS_NAME.get_fqdn()) + + if self.tls: + smtp_serv.ehlo() + smtp_serv.starttls() + + if self.debug: + smtp_serv.set_debuglevel(1) + + smtp_serv.ehlo() + if self.auth: + smtp_serv.esmtp_features["auth"] = self.auth + + # if server requires authorization you must provide login and password + # but only if we have them + if self.user and self.passwd: + smtp_serv.login(self.user, self.passwd) + + smtp_serv.sendmail(msg.sender, msg.send_to, raw_msg.as_string()) + logging.info('MAIL SEND TO: %s' % recipients) + + try: + smtp_serv.quit() + except sslerror: + # sslerror is raised in tls connections on closing sometimes + smtp_serv.close() diff --git a/rhodecode/lib/rcmail/utils.py b/rhodecode/lib/rcmail/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rcmail/utils.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Email message and email sending related helper functions. +""" + +import socket + + +# Cache the hostname, but do it lazily: socket.getfqdn() can take a couple of +# seconds, which slows down the restart of the server. +class CachedDnsName(object): + def __str__(self): + return self.get_fqdn() + + def get_fqdn(self): + if not hasattr(self, '_fqdn'): + self._fqdn = socket.getfqdn() + return self._fqdn + +DNS_NAME = CachedDnsName() diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/utils.py @@ -0,0 +1,983 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Utilities library for RhodeCode +""" + +import datetime +import decorator +import json +import logging +import os +import re +import shutil +import tempfile +import traceback +import tarfile +import warnings +from os.path import abspath +from os.path import dirname as dn, join as jn + +import paste +import pkg_resources +from paste.script.command import Command, BadCommand +from webhelpers.text import collapse, remove_formatting, strip_tags +from mako import exceptions + +from rhodecode.lib.fakemod import create_module +from rhodecode.lib.vcs.backends.base import Config +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend +from rhodecode.lib.utils2 import ( + safe_str, safe_unicode, get_current_rhodecode_user, md5) +from rhodecode.model import meta +from rhodecode.model.db import ( + Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup) +from rhodecode.model.meta import Session +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.settings import VcsSettingsModel, SettingsModel + +log = logging.getLogger(__name__) + +REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*') + +_license_cache = None + + +def recursive_replace(str_, replace=' '): + """ + Recursive replace of given sign to just one instance + + :param str_: given string + :param replace: char to find and replace multiple instances + + Examples:: + >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-') + 'Mighty-Mighty-Bo-sstones' + """ + + if str_.find(replace * 2) == -1: + return str_ + else: + str_ = str_.replace(replace * 2, replace) + return recursive_replace(str_, replace) + + +def repo_name_slug(value): + """ + Return slug of name of repository + This function is called on each creation/modification + of repository to prevent bad names in repo + """ + + slug = remove_formatting(value) + slug = strip_tags(slug) + + for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """: + slug = slug.replace(c, '-') + slug = recursive_replace(slug, '-') + slug = collapse(slug, '-') + return slug + + +#============================================================================== +# PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS +#============================================================================== +def get_repo_slug(request): + _repo = request.environ['pylons.routes_dict'].get('repo_name') + if _repo: + _repo = _repo.rstrip('/') + return _repo + + +def get_repo_group_slug(request): + _group = request.environ['pylons.routes_dict'].get('group_name') + if _group: + _group = _group.rstrip('/') + return _group + + +def get_user_group_slug(request): + _group = request.environ['pylons.routes_dict'].get('user_group_id') + try: + _group = UserGroup.get(_group) + if _group: + _group = _group.users_group_name + except Exception: + log.debug(traceback.format_exc()) + #catch all failures here + pass + + return _group + + +def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): + """ + Action logger for various actions made by users + + :param user: user that made this action, can be a unique username string or + object containing user_id attribute + :param action: action to log, should be on of predefined unique actions for + easy translations + :param repo: string name of repository or object containing repo_id, + that action was made on + :param ipaddr: optional ip address from what the action was made + :param sa: optional sqlalchemy session + + """ + + if not sa: + sa = meta.Session() + # if we don't get explicit IP address try to get one from registered user + # in tmpl context var + if not ipaddr: + ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '') + + try: + if getattr(user, 'user_id', None): + user_obj = User.get(user.user_id) + elif isinstance(user, basestring): + user_obj = User.get_by_username(user) + else: + raise Exception('You have to provide a user object or a username') + + if getattr(repo, 'repo_id', None): + repo_obj = Repository.get(repo.repo_id) + repo_name = repo_obj.repo_name + elif isinstance(repo, basestring): + repo_name = repo.lstrip('/') + repo_obj = Repository.get_by_repo_name(repo_name) + else: + repo_obj = None + repo_name = '' + + user_log = UserLog() + user_log.user_id = user_obj.user_id + user_log.username = user_obj.username + action = safe_unicode(action) + user_log.action = action[:1200000] + + user_log.repository = repo_obj + user_log.repository_name = repo_name + + user_log.action_date = datetime.datetime.now() + user_log.user_ip = ipaddr + sa.add(user_log) + + log.info('Logging action:`%s` on repo:`%s` by user:%s ip:%s', + action, safe_unicode(repo), user_obj, ipaddr) + if commit: + sa.commit() + except Exception: + log.error(traceback.format_exc()) + raise + + +def get_filesystem_repos(path, recursive=False, skip_removed_repos=True): + """ + Scans given path for repos and return (name,(type,path)) tuple + + :param path: path to scan for repositories + :param recursive: recursive search and return names with subdirs in front + """ + + # remove ending slash for better results + path = path.rstrip(os.sep) + log.debug('now scanning in %s location recursive:%s...', path, recursive) + + def _get_repos(p): + dirpaths = _get_dirpaths(p) + if not _is_dir_writable(p): + log.warning('repo path without write access: %s', p) + + for dirpath in dirpaths: + if os.path.isfile(os.path.join(p, dirpath)): + continue + cur_path = os.path.join(p, dirpath) + + # skip removed repos + if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath): + continue + + #skip .<somethin> dirs + if dirpath.startswith('.'): + continue + + try: + scm_info = get_scm(cur_path) + yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info + except VCSError: + if not recursive: + continue + #check if this dir containts other repos for recursive scan + rec_path = os.path.join(p, dirpath) + if os.path.isdir(rec_path): + for inner_scm in _get_repos(rec_path): + yield inner_scm + + return _get_repos(path) + + +def _get_dirpaths(p): + try: + # OS-independable way of checking if we have at least read-only + # access or not. + dirpaths = os.listdir(p) + except OSError: + log.warning('ignoring repo path without read access: %s', p) + return [] + + # os.listpath has a tweak: If a unicode is passed into it, then it tries to + # decode paths and suddenly returns unicode objects itself. The items it + # cannot decode are returned as strings and cause issues. + # + # Those paths are ignored here until a solid solution for path handling has + # been built. + expected_type = type(p) + + def _has_correct_type(item): + if type(item) is not expected_type: + log.error( + u"Ignoring path %s since it cannot be decoded into unicode.", + # Using "repr" to make sure that we see the byte value in case + # of support. + repr(item)) + return False + return True + + dirpaths = [item for item in dirpaths if _has_correct_type(item)] + + return dirpaths + + +def _is_dir_writable(path): + """ + Probe if `path` is writable. + + Due to trouble on Cygwin / Windows, this is actually probing if it is + possible to create a file inside of `path`, stat does not produce reliable + results in this case. + """ + try: + with tempfile.TemporaryFile(dir=path): + pass + except OSError: + return False + return True + + +def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None): + """ + Returns True if given path is a valid repository False otherwise. + If expect_scm param is given also, compare if given scm is the same + as expected from scm parameter. If explicit_scm is given don't try to + detect the scm, just use the given one to check if repo is valid + + :param repo_name: + :param base_path: + :param expect_scm: + :param explicit_scm: + + :return True: if given path is a valid repository + """ + full_path = os.path.join(safe_str(base_path), safe_str(repo_name)) + log.debug('Checking if `%s` is a valid path for repository', repo_name) + + try: + if explicit_scm: + detected_scms = [get_scm_backend(explicit_scm)] + else: + detected_scms = get_scm(full_path) + + if expect_scm: + return detected_scms[0] == expect_scm + log.debug('path: %s is an vcs object:%s', full_path, detected_scms) + return True + except VCSError: + log.debug('path: %s is not a valid repo !', full_path) + return False + + +def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False): + """ + Returns True if given path is a repository group, False otherwise + + :param repo_name: + :param base_path: + """ + full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name)) + log.debug('Checking if `%s` is a valid path for repository group', + repo_group_name) + + # check if it's not a repo + if is_valid_repo(repo_group_name, base_path): + log.debug('Repo called %s exist, it is not a valid ' + 'repo group' % repo_group_name) + return False + + try: + # we need to check bare git repos at higher level + # since we might match branches/hooks/info/objects or possible + # other things inside bare git repo + scm_ = get_scm(os.path.dirname(full_path)) + log.debug('path: %s is a vcs object:%s, not valid ' + 'repo group' % (full_path, scm_)) + return False + except VCSError: + pass + + # check if it's a valid path + if skip_path_check or os.path.isdir(full_path): + log.debug('path: %s is a valid repo group !', full_path) + return True + + log.debug('path: %s is not a valid repo group !', full_path) + return False + + +def ask_ok(prompt, retries=4, complaint='Yes or no please!'): + while True: + ok = raw_input(prompt) + if ok in ('y', 'ye', 'yes'): + return True + if ok in ('n', 'no', 'nop', 'nope'): + return False + retries = retries - 1 + if retries < 0: + raise IOError + print complaint + +# propagated from mercurial documentation +ui_sections = [ + 'alias', 'auth', + 'decode/encode', 'defaults', + 'diff', 'email', + 'extensions', 'format', + 'merge-patterns', 'merge-tools', + 'hooks', 'http_proxy', + 'smtp', 'patch', + 'paths', 'profiling', + 'server', 'trusted', + 'ui', 'web', ] + + +def config_data_from_db(clear_session=True, repo=None): + """ + Read the configuration data from the database and return configuration + tuples. + """ + config = [] + + sa = meta.Session() + settings_model = VcsSettingsModel(repo=repo, sa=sa) + + ui_settings = settings_model.get_ui_settings() + + for setting in ui_settings: + if setting.active: + log.debug( + 'settings ui from db: [%s] %s=%s', + setting.section, setting.key, setting.value) + config.append(( + safe_str(setting.section), safe_str(setting.key), + safe_str(setting.value))) + if setting.key == 'push_ssl': + # force set push_ssl requirement to False, rhodecode + # handles that + config.append(( + safe_str(setting.section), safe_str(setting.key), False)) + if clear_session: + meta.Session.remove() + + # TODO: mikhail: probably it makes no sense to re-read hooks information. + # It's already there and activated/deactivated + skip_entries = [] + enabled_hook_classes = get_enabled_hook_classes(ui_settings) + if 'pull' not in enabled_hook_classes: + skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL)) + if 'push' not in enabled_hook_classes: + skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH)) + + config = [entry for entry in config if entry[:2] not in skip_entries] + + return config + + +def make_db_config(clear_session=True, repo=None): + """ + Create a :class:`Config` instance based on the values in the database. + """ + config = Config() + config_data = config_data_from_db(clear_session=clear_session, repo=repo) + for section, option, value in config_data: + config.set(section, option, value) + return config + + +def get_enabled_hook_classes(ui_settings): + """ + Return the enabled hook classes. + + :param ui_settings: List of ui_settings as returned + by :meth:`VcsSettingsModel.get_ui_settings` + + :return: a list with the enabled hook classes. The order is not guaranteed. + :rtype: list + """ + enabled_hooks = [] + active_hook_keys = [ + key for section, key, value, active in ui_settings + if section == 'hooks' and active] + + hook_names = { + RhodeCodeUi.HOOK_PUSH: 'push', + RhodeCodeUi.HOOK_PULL: 'pull', + RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size' + } + + for key in active_hook_keys: + hook = hook_names.get(key) + if hook: + enabled_hooks.append(hook) + + return enabled_hooks + + +def set_rhodecode_config(config): + """ + Updates pylons config with new settings from database + + :param config: + """ + app_settings = SettingsModel().get_all_settings() + + for k, v in app_settings.items(): + config[k] = v + + +def map_groups(path): + """ + Given a full path to a repository, create all nested groups that this + repo is inside. This function creates parent-child relationships between + groups and creates default perms for all new groups. + + :param paths: full path to repository + """ + sa = meta.Session() + groups = path.split(Repository.NAME_SEP) + parent = None + group = None + + # last element is repo in nested groups structure + groups = groups[:-1] + rgm = RepoGroupModel(sa) + owner = User.get_first_admin() + for lvl, group_name in enumerate(groups): + group_name = '/'.join(groups[:lvl] + [group_name]) + group = RepoGroup.get_by_group_name(group_name) + desc = '%s group' % group_name + + # skip folders that are now removed repos + if REMOVED_REPO_PAT.match(group_name): + break + + if group is None: + log.debug('creating group level: %s group_name: %s', + lvl, group_name) + group = RepoGroup(group_name, parent) + group.group_description = desc + group.user = owner + sa.add(group) + perm_obj = rgm._create_default_perms(group) + sa.add(perm_obj) + sa.flush() + + parent = group + return group + + +def repo2db_mapper(initial_repo_list, remove_obsolete=False): + """ + maps all repos given in initial_repo_list, non existing repositories + are created, if remove_obsolete is True it also checks for db entries + that are not in initial_repo_list and removes them. + + :param initial_repo_list: list of repositories found by scanning methods + :param remove_obsolete: check for obsolete entries in database + """ + from rhodecode.model.repo import RepoModel + from rhodecode.model.scm import ScmModel + sa = meta.Session() + repo_model = RepoModel() + user = User.get_first_admin() + added = [] + + # creation defaults + defs = SettingsModel().get_default_repo_settings(strip_prefix=True) + enable_statistics = defs.get('repo_enable_statistics') + enable_locking = defs.get('repo_enable_locking') + enable_downloads = defs.get('repo_enable_downloads') + private = defs.get('repo_private') + + for name, repo in initial_repo_list.items(): + group = map_groups(name) + unicode_name = safe_unicode(name) + db_repo = repo_model.get_by_repo_name(unicode_name) + # found repo that is on filesystem not in RhodeCode database + if not db_repo: + log.info('repository %s not found, creating now', name) + added.append(name) + desc = (repo.description + if repo.description != 'unknown' + else '%s repository' % name) + + db_repo = repo_model._create_repo( + repo_name=name, + repo_type=repo.alias, + description=desc, + repo_group=getattr(group, 'group_id', None), + owner=user, + enable_locking=enable_locking, + enable_downloads=enable_downloads, + enable_statistics=enable_statistics, + private=private, + state=Repository.STATE_CREATED + ) + sa.commit() + # we added that repo just now, and make sure we updated server info + if db_repo.repo_type == 'git': + git_repo = db_repo.scm_instance() + # update repository server-info + log.debug('Running update server info') + git_repo._update_server_info() + + db_repo.update_commit_cache() + + config = db_repo._config + config.set('extensions', 'largefiles', '') + ScmModel().install_hooks( + db_repo.scm_instance(config=config), + repo_type=db_repo.repo_type) + + removed = [] + if remove_obsolete: + # remove from database those repositories that are not in the filesystem + for repo in sa.query(Repository).all(): + if repo.repo_name not in initial_repo_list.keys(): + log.debug("Removing non-existing repository found in db `%s`", + repo.repo_name) + try: + RepoModel(sa).delete(repo, forks='detach', fs_remove=False) + sa.commit() + removed.append(repo.repo_name) + except Exception: + # don't hold further removals on error + log.error(traceback.format_exc()) + sa.rollback() + + def splitter(full_repo_name): + _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1) + gr_name = None + if len(_parts) == 2: + gr_name = _parts[0] + return gr_name + + initial_repo_group_list = [splitter(x) for x in + initial_repo_list.keys() if splitter(x)] + + # remove from database those repository groups that are not in the + # filesystem due to parent child relationships we need to delete them + # in a specific order of most nested first + all_groups = [x.group_name for x in sa.query(RepoGroup).all()] + nested_sort = lambda gr: len(gr.split('/')) + for group_name in sorted(all_groups, key=nested_sort, reverse=True): + if group_name not in initial_repo_group_list: + repo_group = RepoGroup.get_by_group_name(group_name) + if (repo_group.children.all() or + not RepoGroupModel().check_exist_filesystem( + group_name=group_name, exc_on_failure=False)): + continue + + log.info( + 'Removing non-existing repository group found in db `%s`', + group_name) + try: + RepoGroupModel(sa).delete(group_name, fs_remove=False) + sa.commit() + removed.append(group_name) + except Exception: + # don't hold further removals on error + log.exception( + 'Unable to remove repository group `%s`', + group_name) + sa.rollback() + raise + + return added, removed + + +def get_default_cache_settings(settings): + cache_settings = {} + for key in settings.keys(): + for prefix in ['beaker.cache.', 'cache.']: + if key.startswith(prefix): + name = key.split(prefix)[1].strip() + cache_settings[name] = settings[key].strip() + return cache_settings + + +# set cache regions for beaker so celery can utilise it +def add_cache(settings): + from rhodecode.lib import caches + cache_settings = {'regions': None} + # main cache settings used as default ... + cache_settings.update(get_default_cache_settings(settings)) + + if cache_settings['regions']: + for region in cache_settings['regions'].split(','): + region = region.strip() + region_settings = {} + for key, value in cache_settings.items(): + if key.startswith(region): + region_settings[key.split('.')[1]] = value + + caches.configure_cache_region( + region, region_settings, cache_settings) + + +def load_rcextensions(root_path): + import rhodecode + from rhodecode.config import conf + + path = os.path.join(root_path, 'rcextensions', '__init__.py') + if os.path.isfile(path): + rcext = create_module('rc', path) + EXT = rhodecode.EXTENSIONS = rcext + log.debug('Found rcextensions now loading %s...', rcext) + + # Additional mappings that are not present in the pygments lexers + conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {})) + + # auto check if the module is not missing any data, set to default if is + # this will help autoupdate new feature of rcext module + #from rhodecode.config import rcextensions + #for k in dir(rcextensions): + # if not k.startswith('_') and not hasattr(EXT, k): + # setattr(EXT, k, getattr(rcextensions, k)) + + +def get_custom_lexer(extension): + """ + returns a custom lexer if it is defined in rcextensions module, or None + if there's no custom lexer defined + """ + import rhodecode + from pygments import lexers + # check if we didn't define this extension as other lexer + extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None) + if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS: + _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension] + return lexers.get_lexer_by_name(_lexer_name) + + +#============================================================================== +# TEST FUNCTIONS AND CREATORS +#============================================================================== +def create_test_index(repo_location, config, full_index): + """ + Makes default test index + + :param config: test config + :param full_index: + # start test server: + rcserver --with-vcsserver test.ini + + # build index and store it in /tmp/rc/index: + rhodecode-index --force --api-host=http://vps1.dev:5000 --api-key=xxx --engine-location=/tmp/rc/index + + # package and move new packages + tar -zcvf vcs_search_index.tar.gz -C /tmp/rc index + mv vcs_search_index.tar.gz rhodecode/tests/fixtures/ + + """ + cur_dir = dn(dn(abspath(__file__))) + with tarfile.open(jn(cur_dir, 'tests', 'fixtures', + 'vcs_search_index.tar.gz')) as tar: + tar.extractall(os.path.dirname(config['search.location'])) + + +def create_test_env(repos_test_path, config): + """ + Makes a fresh database and + installs test repository into tmp dir + """ + from rhodecode.lib.db_manage import DbManage + from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO, TESTS_TMP_PATH + + # PART ONE create db + dbconf = config['sqlalchemy.db1.url'] + log.debug('making test db %s', dbconf) + + # create test dir if it doesn't exist + if not os.path.isdir(repos_test_path): + log.debug('Creating testdir %s', repos_test_path) + os.makedirs(repos_test_path) + + dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'], + tests=True, cli_args={'force_ask': True}) + dbmanage.create_tables(override=True) + dbmanage.set_db_version() + # for tests dynamically set new root paths based on generated content + dbmanage.create_settings(dbmanage.config_prompt(repos_test_path)) + dbmanage.create_default_user() + dbmanage.create_test_admin_and_users() + dbmanage.create_permissions() + dbmanage.populate_default_permissions() + Session().commit() + # PART TWO make test repo + log.debug('making test vcs repositories') + + idx_path = config['app_conf']['search.location'] + data_path = config['app_conf']['cache_dir'] + + #clean index and data + if idx_path and os.path.exists(idx_path): + log.debug('remove %s', idx_path) + shutil.rmtree(idx_path) + + if data_path and os.path.exists(data_path): + log.debug('remove %s', data_path) + shutil.rmtree(data_path) + + #CREATE DEFAULT TEST REPOS + cur_dir = dn(dn(abspath(__file__))) + with tarfile.open(jn(cur_dir, 'tests', 'fixtures', + 'vcs_test_hg.tar.gz')) as tar: + tar.extractall(jn(TESTS_TMP_PATH, HG_REPO)) + + cur_dir = dn(dn(abspath(__file__))) + with tarfile.open(jn(cur_dir, 'tests', 'fixtures', + 'vcs_test_git.tar.gz')) as tar: + tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO)) + + # Note: Subversion is in the process of being integrated with the system, + # until we have a properly packed version of the test svn repository, this + # tries to copy over the repo from a package "rc_testdata" + import rc_testdata + svn_repo_path = rc_testdata.get_svn_repo_archive() + with tarfile.open(svn_repo_path) as tar: + tar.extractall(jn(TESTS_TMP_PATH, SVN_REPO)) + + + +#============================================================================== +# PASTER COMMANDS +#============================================================================== +class BasePasterCommand(Command): + """ + Abstract Base Class for paster commands. + + The celery commands are somewhat aggressive about loading + celery.conf, and since our module sets the `CELERY_LOADER` + environment variable to our loader, we have to bootstrap a bit and + make sure we've had a chance to load the pylons config off of the + command line, otherwise everything fails. + """ + min_args = 1 + min_args_error = "Please provide a paster config file as an argument." + takes_config_file = 1 + requires_config_file = True + + def notify_msg(self, msg, log=False): + """Make a notification to user, additionally if logger is passed + it logs this action using given logger + + :param msg: message that will be printed to user + :param log: logging instance, to use to additionally log this message + + """ + if log and isinstance(log, logging): + log(msg) + + def run(self, args): + """ + Overrides Command.run + + Checks for a config file argument and loads it. + """ + if len(args) < self.min_args: + raise BadCommand( + self.min_args_error % {'min_args': self.min_args, + 'actual_args': len(args)}) + + # Decrement because we're going to lob off the first argument. + # @@ This is hacky + self.min_args -= 1 + self.bootstrap_config(args[0]) + self.update_parser() + return super(BasePasterCommand, self).run(args[1:]) + + def update_parser(self): + """ + Abstract method. Allows for the class' parser to be updated + before the superclass' `run` method is called. Necessary to + allow options/arguments to be passed through to the underlying + celery command. + """ + raise NotImplementedError("Abstract Method.") + + def bootstrap_config(self, conf): + """ + Loads the pylons configuration. + """ + from pylons import config as pylonsconfig + + self.path_to_ini_file = os.path.realpath(conf) + conf = paste.deploy.appconfig('config:' + self.path_to_ini_file) + pylonsconfig.init_app(conf.global_conf, conf.local_conf) + + def _init_session(self): + """ + Inits SqlAlchemy Session + """ + logging.config.fileConfig(self.path_to_ini_file) + from pylons import config + from rhodecode.config.utils import initialize_database + + # get to remove repos !! + add_cache(config) + initialize_database(config) + + +@decorator.decorator +def jsonify(func, *args, **kwargs): + """Action decorator that formats output for JSON + + Given a function that will return content, this decorator will turn + the result into JSON, with a content-type of 'application/json' and + output it. + + """ + from pylons.decorators.util import get_pylons + from rhodecode.lib.ext_json import json + pylons = get_pylons(args) + pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8' + data = func(*args, **kwargs) + if isinstance(data, (list, tuple)): + msg = "JSON responses with Array envelopes are susceptible to " \ + "cross-site data leak attacks, see " \ + "http://wiki.pylonshq.com/display/pylonsfaq/Warnings" + warnings.warn(msg, Warning, 2) + log.warning(msg) + log.debug("Returning JSON wrapped action output") + return json.dumps(data, encoding='utf-8') + + +class PartialRenderer(object): + """ + Partial renderer used to render chunks of html used in datagrids + use like:: + + _render = PartialRenderer('data_table/_dt_elements.html') + _render('quick_menu', args, kwargs) + PartialRenderer.h, + c, + _, + ungettext + are the template stuff initialized inside and can be re-used later + + :param tmpl_name: template path relate to /templates/ dir + """ + + def __init__(self, tmpl_name): + import rhodecode + from pylons import request, tmpl_context as c + from pylons.i18n.translation import _, ungettext + from rhodecode.lib import helpers as h + + self.tmpl_name = tmpl_name + self.rhodecode = rhodecode + self.c = c + self._ = _ + self.ungettext = ungettext + self.h = h + self.request = request + + def _mako_lookup(self): + _tmpl_lookup = self.rhodecode.CONFIG['pylons.app_globals'].mako_lookup + return _tmpl_lookup.get_template(self.tmpl_name) + + def _update_kwargs_for_render(self, kwargs): + """ + Inject params required for Mako rendering + """ + _kwargs = { + '_': self._, + 'h': self.h, + 'c': self.c, + 'request': self.request, + 'ungettext': self.ungettext, + } + _kwargs.update(kwargs) + return _kwargs + + def _render_with_exc(self, render_func, args, kwargs): + try: + return render_func.render(*args, **kwargs) + except: + log.error(exceptions.text_error_template().render()) + raise + + def _get_template(self, template_obj, def_name): + if def_name: + tmpl = template_obj.get_def(def_name) + else: + tmpl = template_obj + return tmpl + + def render(self, def_name, *args, **kwargs): + lookup_obj = self._mako_lookup() + tmpl = self._get_template(lookup_obj, def_name=def_name) + kwargs = self._update_kwargs_for_render(kwargs) + return self._render_with_exc(tmpl, args, kwargs) + + def __call__(self, tmpl, *args, **kwargs): + return self.render(tmpl, *args, **kwargs) + + +def password_changed(auth_user, session): + if auth_user.username == User.DEFAULT_USER: + return False + password_hash = md5(auth_user.password) if auth_user.password else None + rhodecode_user = session.get('rhodecode_user', {}) + session_password_hash = rhodecode_user.get('password', '') + return password_hash != session_password_hash + + +def read_opensource_licenses(): + global _license_cache + + if not _license_cache: + licenses = pkg_resources.resource_string( + 'rhodecode.config', 'licenses.json') + _license_cache = json.loads(licenses) + + return _license_cache diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/utils2.py @@ -0,0 +1,843 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Some simple helper functions +""" + + +import collections +import datetime +import dateutil.relativedelta +import hashlib +import logging +import re +import sys +import time +import threading +import urllib +import urlobject +import uuid + +import pygments.lexers +import sqlalchemy +import sqlalchemy.engine.url +import webob + +import rhodecode + + +def md5(s): + return hashlib.md5(s).hexdigest() + + +def md5_safe(s): + return md5(safe_str(s)) + + +def __get_lem(): + """ + Get language extension map based on what's inside pygments lexers + """ + d = collections.defaultdict(lambda: []) + + def __clean(s): + s = s.lstrip('*') + s = s.lstrip('.') + + if s.find('[') != -1: + exts = [] + start, stop = s.find('['), s.find(']') + + for suffix in s[start + 1:stop]: + exts.append(s[:s.find('[')] + suffix) + return [e.lower() for e in exts] + else: + return [s.lower()] + + for lx, t in sorted(pygments.lexers.LEXERS.items()): + m = map(__clean, t[-2]) + if m: + m = reduce(lambda x, y: x + y, m) + for ext in m: + desc = lx.replace('Lexer', '') + d[ext].append(desc) + + return dict(d) + + +def str2bool(_str): + """ + returs True/False value from given string, it tries to translate the + string into boolean + + :param _str: string value to translate into boolean + :rtype: boolean + :returns: boolean from given string + """ + if _str is None: + return False + if _str in (True, False): + return _str + _str = str(_str).strip().lower() + return _str in ('t', 'true', 'y', 'yes', 'on', '1') + + +def aslist(obj, sep=None, strip=True): + """ + Returns given string separated by sep as list + + :param obj: + :param sep: + :param strip: + """ + if isinstance(obj, (basestring)): + lst = obj.split(sep) + if strip: + lst = [v.strip() for v in lst] + return lst + elif isinstance(obj, (list, tuple)): + return obj + elif obj is None: + return [] + else: + return [obj] + + +def convert_line_endings(line, mode): + """ + Converts a given line "line end" accordingly to given mode + + Available modes are:: + 0 - Unix + 1 - Mac + 2 - DOS + + :param line: given line to convert + :param mode: mode to convert to + :rtype: str + :return: converted line according to mode + """ + if mode == 0: + line = line.replace('\r\n', '\n') + line = line.replace('\r', '\n') + elif mode == 1: + line = line.replace('\r\n', '\r') + line = line.replace('\n', '\r') + elif mode == 2: + line = re.sub('\r(?!\n)|(?<!\r)\n', '\r\n', line) + return line + + +def detect_mode(line, default): + """ + Detects line break for given line, if line break couldn't be found + given default value is returned + + :param line: str line + :param default: default + :rtype: int + :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS + """ + if line.endswith('\r\n'): + return 2 + elif line.endswith('\n'): + return 0 + elif line.endswith('\r'): + return 1 + else: + return default + + +def safe_int(val, default=None): + """ + Returns int() of val if val is not convertable to int use default + instead + + :param val: + :param default: + """ + + try: + val = int(val) + except (ValueError, TypeError): + val = default + + return val + + +def safe_unicode(str_, from_encoding=None): + """ + safe unicode function. Does few trick to turn str_ into unicode + + In case of UnicodeDecode error, we try to return it with encoding detected + by chardet library if it fails fallback to unicode with errors replaced + + :param str_: string to decode + :rtype: unicode + :returns: unicode object + """ + if isinstance(str_, unicode): + return str_ + + if not from_encoding: + DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding', + 'utf8'), sep=',') + from_encoding = DEFAULT_ENCODINGS + + if not isinstance(from_encoding, (list, tuple)): + from_encoding = [from_encoding] + + try: + return unicode(str_) + except UnicodeDecodeError: + pass + + for enc in from_encoding: + try: + return unicode(str_, enc) + except UnicodeDecodeError: + pass + + try: + import chardet + encoding = chardet.detect(str_)['encoding'] + if encoding is None: + raise Exception() + return str_.decode(encoding) + except (ImportError, UnicodeDecodeError, Exception): + return unicode(str_, from_encoding[0], 'replace') + + +def safe_str(unicode_, to_encoding=None): + """ + safe str function. Does few trick to turn unicode_ into string + + In case of UnicodeEncodeError, we try to return it with encoding detected + by chardet library if it fails fallback to string with errors replaced + + :param unicode_: unicode to encode + :rtype: str + :returns: str object + """ + + # if it's not basestr cast to str + if not isinstance(unicode_, basestring): + return str(unicode_) + + if isinstance(unicode_, str): + return unicode_ + + if not to_encoding: + DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding', + 'utf8'), sep=',') + to_encoding = DEFAULT_ENCODINGS + + if not isinstance(to_encoding, (list, tuple)): + to_encoding = [to_encoding] + + for enc in to_encoding: + try: + return unicode_.encode(enc) + except UnicodeEncodeError: + pass + + try: + import chardet + encoding = chardet.detect(unicode_)['encoding'] + if encoding is None: + raise UnicodeEncodeError() + + return unicode_.encode(encoding) + except (ImportError, UnicodeEncodeError): + return unicode_.encode(to_encoding[0], 'replace') + + +def remove_suffix(s, suffix): + if s.endswith(suffix): + s = s[:-1 * len(suffix)] + return s + + +def remove_prefix(s, prefix): + if s.startswith(prefix): + s = s[len(prefix):] + return s + + +def find_calling_context(ignore_modules=None): + """ + Look through the calling stack and return the frame which called + this function and is part of core module ( ie. rhodecode.* ) + + :param ignore_modules: list of modules to ignore eg. ['rhodecode.lib'] + """ + + ignore_modules = ignore_modules or [] + + f = sys._getframe(2) + while f.f_back is not None: + name = f.f_globals.get('__name__') + if name and name.startswith(__name__.split('.')[0]): + if name not in ignore_modules: + return f + f = f.f_back + return None + + +def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): + """Custom engine_from_config functions.""" + log = logging.getLogger('sqlalchemy.engine') + engine = sqlalchemy.engine_from_config(configuration, prefix, **kwargs) + + def color_sql(sql): + color_seq = '\033[1;33m' # This is yellow: code 33 + normal = '\x1b[0m' + return ''.join([color_seq, sql, normal]) + + if configuration['debug']: + # attach events only for debug configuration + + def before_cursor_execute(conn, cursor, statement, + parameters, context, executemany): + setattr(conn, 'query_start_time', time.time()) + log.info(color_sql(">>>>> STARTING QUERY >>>>>")) + calling_context = find_calling_context(ignore_modules=[ + 'rhodecode.lib.caching_query' + ]) + if calling_context: + log.info(color_sql('call context %s:%s' % ( + calling_context.f_code.co_filename, + calling_context.f_lineno, + ))) + + def after_cursor_execute(conn, cursor, statement, + parameters, context, executemany): + delattr(conn, 'query_start_time') + + sqlalchemy.event.listen(engine, "before_cursor_execute", + before_cursor_execute) + sqlalchemy.event.listen(engine, "after_cursor_execute", + after_cursor_execute) + + return engine + + +def age(prevdate, now=None, show_short_version=False, show_suffix=True, + short_format=False): + """ + Turns a datetime into an age string. + If show_short_version is True, this generates a shorter string with + an approximate age; ex. '1 day ago', rather than '1 day and 23 hours ago'. + + * IMPORTANT* + Code of this function is written in special way so it's easier to + backport it to javascript. If you mean to update it, please also update + `jquery.timeago-extension.js` file + + :param prevdate: datetime object + :param now: get current time, if not define we use + `datetime.datetime.now()` + :param show_short_version: if it should approximate the date and + return a shorter string + :param show_suffix: + :param short_format: show short format, eg 2D instead of 2 days + :rtype: unicode + :returns: unicode words describing age + """ + from pylons.i18n.translation import _, ungettext + + def _get_relative_delta(now, prevdate): + base = dateutil.relativedelta.relativedelta(now, prevdate) + return { + 'year': base.years, + 'month': base.months, + 'day': base.days, + 'hour': base.hours, + 'minute': base.minutes, + 'second': base.seconds, + } + + def _is_leap_year(year): + return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) + + def get_month(prevdate): + return prevdate.month + + def get_year(prevdate): + return prevdate.year + + now = now or datetime.datetime.now() + order = ['year', 'month', 'day', 'hour', 'minute', 'second'] + deltas = {} + future = False + + if prevdate > now: + now_old = now + now = prevdate + prevdate = now_old + future = True + if future: + prevdate = prevdate.replace(microsecond=0) + # Get date parts deltas + for part in order: + rel_delta = _get_relative_delta(now, prevdate) + deltas[part] = rel_delta[part] + + # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00, + # not 1 hour, -59 minutes and -59 seconds) + offsets = [[5, 60], [4, 60], [3, 24]] + for element in offsets: # seconds, minutes, hours + num = element[0] + length = element[1] + + part = order[num] + carry_part = order[num - 1] + + if deltas[part] < 0: + deltas[part] += length + deltas[carry_part] -= 1 + + # Same thing for days except that the increment depends on the (variable) + # number of days in the month + month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + if deltas['day'] < 0: + if get_month(prevdate) == 2 and _is_leap_year(get_year(prevdate)): + deltas['day'] += 29 + else: + deltas['day'] += month_lengths[get_month(prevdate) - 1] + + deltas['month'] -= 1 + + if deltas['month'] < 0: + deltas['month'] += 12 + deltas['year'] -= 1 + + # Format the result + if short_format: + fmt_funcs = { + 'year': lambda d: u'%dy' % d, + 'month': lambda d: u'%dm' % d, + 'day': lambda d: u'%dd' % d, + 'hour': lambda d: u'%dh' % d, + 'minute': lambda d: u'%dmin' % d, + 'second': lambda d: u'%dsec' % d, + } + else: + fmt_funcs = { + 'year': lambda d: ungettext(u'%d year', '%d years', d) % d, + 'month': lambda d: ungettext(u'%d month', '%d months', d) % d, + 'day': lambda d: ungettext(u'%d day', '%d days', d) % d, + 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d, + 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d, + 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d, + } + + i = 0 + for part in order: + value = deltas[part] + if value != 0: + + if i < 5: + sub_part = order[i + 1] + sub_value = deltas[sub_part] + else: + sub_value = 0 + + if sub_value == 0 or show_short_version: + _val = fmt_funcs[part](value) + if future: + if show_suffix: + return _(u'in %s') % _val + else: + return _val + + else: + if show_suffix: + return _(u'%s ago') % _val + else: + return _val + + val = fmt_funcs[part](value) + val_detail = fmt_funcs[sub_part](sub_value) + + if short_format: + datetime_tmpl = u'%s, %s' + if show_suffix: + datetime_tmpl = _(u'%s, %s ago') + if future: + datetime_tmpl = _(u'in %s, %s') + else: + datetime_tmpl = _(u'%s and %s') + if show_suffix: + datetime_tmpl = _(u'%s and %s ago') + if future: + datetime_tmpl = _(u'in %s and %s') + + return datetime_tmpl % (val, val_detail) + i += 1 + return _(u'just now') + + +def uri_filter(uri): + """ + Removes user:password from given url string + + :param uri: + :rtype: unicode + :returns: filtered list of strings + """ + if not uri: + return '' + + proto = '' + + for pat in ('https://', 'http://'): + if uri.startswith(pat): + uri = uri[len(pat):] + proto = pat + break + + # remove passwords and username + uri = uri[uri.find('@') + 1:] + + # get the port + cred_pos = uri.find(':') + if cred_pos == -1: + host, port = uri, None + else: + host, port = uri[:cred_pos], uri[cred_pos + 1:] + + return filter(None, [proto, host, port]) + + +def credentials_filter(uri): + """ + Returns a url with removed credentials + + :param uri: + """ + + uri = uri_filter(uri) + # check if we have port + if len(uri) > 2 and uri[2]: + uri[2] = ':' + uri[2] + + return ''.join(uri) + + +def get_clone_url(uri_tmpl, qualifed_home_url, repo_name, repo_id, **override): + parsed_url = urlobject.URLObject(qualifed_home_url) + decoded_path = safe_unicode(urllib.unquote(parsed_url.path.rstrip('/'))) + args = { + 'scheme': parsed_url.scheme, + 'user': '', + # path if we use proxy-prefix + 'netloc': parsed_url.netloc+decoded_path, + 'prefix': decoded_path, + 'repo': repo_name, + 'repoid': str(repo_id) + } + args.update(override) + args['user'] = urllib.quote(safe_str(args['user'])) + + for k, v in args.items(): + uri_tmpl = uri_tmpl.replace('{%s}' % k, v) + + # remove leading @ sign if it's present. Case of empty user + url_obj = urlobject.URLObject(uri_tmpl) + url = url_obj.with_netloc(url_obj.netloc.lstrip('@')) + + return safe_unicode(url) + + +def get_commit_safe(repo, commit_id=None, commit_idx=None, pre_load=None): + """ + Safe version of get_commit if this commit doesn't exists for a + repository it returns a Dummy one instead + + :param repo: repository instance + :param commit_id: commit id as str + :param pre_load: optional list of commit attributes to load + """ + # TODO(skreft): remove these circular imports + from rhodecode.lib.vcs.backends.base import BaseRepository, EmptyCommit + from rhodecode.lib.vcs.exceptions import RepositoryError + if not isinstance(repo, BaseRepository): + raise Exception('You must pass an Repository ' + 'object as first argument got %s', type(repo)) + + try: + commit = repo.get_commit( + commit_id=commit_id, commit_idx=commit_idx, pre_load=pre_load) + except (RepositoryError, LookupError): + commit = EmptyCommit() + return commit + + +def datetime_to_time(dt): + if dt: + return time.mktime(dt.timetuple()) + + +def time_to_datetime(tm): + if tm: + if isinstance(tm, basestring): + try: + tm = float(tm) + except ValueError: + return + return datetime.datetime.fromtimestamp(tm) + + +MENTIONS_REGEX = re.compile( + # ^@ or @ without any special chars in front + r'(?:^@|[^a-zA-Z0-9\-\_\.]@)' + # main body starts with letter, then can be . - _ + r'([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)', + re.VERBOSE | re.MULTILINE) + + +def extract_mentioned_users(s): + """ + Returns unique usernames from given string s that have @mention + + :param s: string to get mentions + """ + usrs = set() + for username in MENTIONS_REGEX.findall(s): + usrs.add(username) + + return sorted(list(usrs), key=lambda k: k.lower()) + + +class AttributeDict(dict): + def __getattr__(self, attr): + return self.get(attr, None) + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + + +def fix_PATH(os_=None): + """ + Get current active python path, and append it to PATH variable to fix + issues of subprocess calls and different python versions + """ + if os_ is None: + import os + else: + os = os_ + + cur_path = os.path.split(sys.executable)[0] + if not os.environ['PATH'].startswith(cur_path): + os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH']) + + +def obfuscate_url_pw(engine): + _url = engine or '' + try: + _url = sqlalchemy.engine.url.make_url(engine) + if _url.password: + _url.password = 'XXXXX' + except Exception: + pass + return unicode(_url) + + +def get_server_url(environ): + req = webob.Request(environ) + return req.host_url + req.script_name + + +def unique_id(hexlen=32): + alphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz" + return suuid(truncate_to=hexlen, alphabet=alphabet) + + +def suuid(url=None, truncate_to=22, alphabet=None): + """ + Generate and return a short URL safe UUID. + + If the url parameter is provided, set the namespace to the provided + URL and generate a UUID. + + :param url to get the uuid for + :truncate_to: truncate the basic 22 UUID to shorter version + + The IDs won't be universally unique any longer, but the probability of + a collision will still be very low. + """ + # Define our alphabet. + _ALPHABET = alphabet or "23456789ABCDEFGHJKLMNPQRSTUVWXYZ" + + # If no URL is given, generate a random UUID. + if url is None: + unique_id = uuid.uuid4().int + else: + unique_id = uuid.uuid3(uuid.NAMESPACE_URL, url).int + + alphabet_length = len(_ALPHABET) + output = [] + while unique_id > 0: + digit = unique_id % alphabet_length + output.append(_ALPHABET[digit]) + unique_id = int(unique_id / alphabet_length) + return "".join(output)[:truncate_to] + + +def get_current_rhodecode_user(): + """ + Gets rhodecode user from threadlocal tmpl_context variable if it's + defined, else returns None. + """ + from pylons import tmpl_context as c + if hasattr(c, 'rhodecode_user'): + return c.rhodecode_user + + return None + + +def action_logger_generic(action, namespace=''): + """ + A generic logger for actions useful to the system overview, tries to find + an acting user for the context of the call otherwise reports unknown user + + :param action: logging message eg 'comment 5 deleted' + :param type: string + + :param namespace: namespace of the logging message eg. 'repo.comments' + :param type: string + + """ + + logger_name = 'rhodecode.actions' + + if namespace: + logger_name += '.' + namespace + + log = logging.getLogger(logger_name) + + # get a user if we can + user = get_current_rhodecode_user() + + logfunc = log.info + + if not user: + user = '<unknown user>' + logfunc = log.warning + + logfunc('Logging action by {}: {}'.format(user, action)) + + +def escape_split(text, sep=',', maxsplit=-1): + r""" + Allows for escaping of the separator: e.g. arg='foo\, bar' + + It should be noted that the way bash et. al. do command line parsing, those + single quotes are required. + """ + escaped_sep = r'\%s' % sep + + if escaped_sep not in text: + return text.split(sep, maxsplit) + + before, _mid, after = text.partition(escaped_sep) + startlist = before.split(sep, maxsplit) # a regular split is fine here + unfinished = startlist[-1] + startlist = startlist[:-1] + + # recurse because there may be more escaped separators + endlist = escape_split(after, sep, maxsplit) + + # finish building the escaped value. we use endlist[0] becaue the first + # part of the string sent in recursion is the rest of the escaped value. + unfinished += sep + endlist[0] + + return startlist + [unfinished] + endlist[1:] # put together all the parts + + +class OptionalAttr(object): + """ + Special Optional Option that defines other attribute. Example:: + + def test(apiuser, userid=Optional(OAttr('apiuser')): + user = Optional.extract(userid) + # calls + + """ + + def __init__(self, attr_name): + self.attr_name = attr_name + + def __repr__(self): + return '<OptionalAttr:%s>' % self.attr_name + + def __call__(self): + return self + + +# alias +OAttr = OptionalAttr + + +class Optional(object): + """ + Defines an optional parameter:: + + param = param.getval() if isinstance(param, Optional) else param + param = param() if isinstance(param, Optional) else param + + is equivalent of:: + + param = Optional.extract(param) + + """ + + def __init__(self, type_): + self.type_ = type_ + + def __repr__(self): + return '<Optional:%s>' % self.type_.__repr__() + + def __call__(self): + return self.getval() + + def getval(self): + """ + returns value from this Optional instance + """ + if isinstance(self.type_, OAttr): + # use params name + return self.type_.attr_name + return self.type_ + + @classmethod + def extract(cls, val): + """ + Extracts value from Optional() instance + + :param val: + :return: original value if it's not Optional instance else + value of instance + """ + if isinstance(val, cls): + return val.getval() + return val diff --git a/rhodecode/lib/vcs/__init__.py b/rhodecode/lib/vcs/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/__init__.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Various version Control System version lib (vcs) management abstraction layer +for Python. Build with server client architecture. +""" + + +VERSION = (0, 5, 0, 'dev') + +__version__ = '.'.join((str(each) for each in VERSION[:4])) + +__all__ = [ + 'get_version', 'get_repo', 'get_backend', + 'VCSError', 'RepositoryError', 'CommitError' + ] + +import atexit +import logging +import subprocess +import time +import urlparse +from cStringIO import StringIO + +import pycurl +import Pyro4 +from Pyro4.errors import CommunicationError + +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.backends import get_repo, get_backend +from rhodecode.lib.vcs.exceptions import ( + VCSError, RepositoryError, CommitError) + + +log = logging.getLogger(__name__) + + +def get_version(): + """ + Returns shorter version (digit parts only) as string. + """ + return '.'.join((str(each) for each in VERSION[:3])) + + +def connect_pyro4(server_and_port): + from rhodecode.lib.vcs import connection, client + from rhodecode.lib.middleware.utils import scm_app + + git_remote = client.ThreadlocalProxyFactory( + settings.pyro_remote(settings.PYRO_GIT, server_and_port)) + hg_remote = client.ThreadlocalProxyFactory( + settings.pyro_remote(settings.PYRO_HG, server_and_port)) + svn_remote = client.ThreadlocalProxyFactory( + settings.pyro_remote(settings.PYRO_SVN, server_and_port)) + + connection.Git = client.RepoMaker(proxy_factory=git_remote) + connection.Hg = client.RepoMaker(proxy_factory=hg_remote) + connection.Svn = client.RepoMaker(proxy_factory=svn_remote) + + scm_app.GIT_REMOTE_WSGI = Pyro4.Proxy( + settings.pyro_remote( + settings.PYRO_GIT_REMOTE_WSGI, server_and_port)) + scm_app.HG_REMOTE_WSGI = Pyro4.Proxy( + settings.pyro_remote( + settings.PYRO_HG_REMOTE_WSGI, server_and_port)) + + @atexit.register + def free_connection_resources(): + connection.Git = None + connection.Hg = None + connection.Svn = None + + +def connect_http(server_and_port): + from rhodecode.lib.vcs import connection, client_http + from rhodecode.lib.middleware.utils import scm_app + + session = _create_http_rpc_session() + + connection.Git = client_http.RepoMaker(server_and_port, '/git', session) + connection.Hg = client_http.RepoMaker(server_and_port, '/hg', session) + connection.Svn = client_http.RepoMaker(server_and_port, '/svn', session) + + scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy( + server_and_port, '/proxy/hg') + scm_app.GIT_REMOTE_WSGI = client_http.VcsHttpProxy( + server_and_port, '/proxy/git') + + @atexit.register + def free_connection_resources(): + connection.Git = None + connection.Hg = None + connection.Svn = None + + +def connect_vcs(server_and_port, protocol='pyro4'): + """ + Initializes the connection to the vcs server. + + :param server_and_port: str, e.g. "localhost:9900" + :param protocol: str, "pyro4" or "http" + """ + if protocol == 'pyro4': + connect_pyro4(server_and_port) + elif protocol == 'http': + connect_http(server_and_port) + + +# TODO: johbo: This function should be moved into our test suite, there is +# no reason to support starting the vcsserver in Enterprise itself. +def start_vcs_server(server_and_port, protocol='pyro4', log_level=None): + """ + Starts the vcs server in a subprocess. + """ + log.info('Starting VCSServer as a sub process with %s protocol', protocol) + if protocol == 'http': + return _start_http_vcs_server(server_and_port, log_level) + elif protocol == 'pyro4': + return _start_pyro4_vcs_server(server_and_port, log_level) + + +def _start_pyro4_vcs_server(server_and_port, log_level=None): + _try_to_shutdown_running_server(server_and_port) + host, port = server_and_port.rsplit(":", 1) + host = host.strip('[]') + args = [ + 'vcsserver', '--port', port, '--host', host, '--locale', 'en_US.UTF-8', + '--threadpool', '32'] + if log_level: + args += ['--log-level', log_level] + proc = subprocess.Popen(args) + + def cleanup_server_process(): + proc.kill() + atexit.register(cleanup_server_process) + + server = create_vcsserver_proxy(server_and_port, protocol='pyro4') + _wait_until_vcs_server_is_reachable(server) + + +def _start_http_vcs_server(server_and_port, log_level=None): + # TODO: mikhail: shutdown if an http server already runs + + host, port = server_and_port.rsplit(":", 1) + args = [ + 'pserve', 'vcsserver/development_pyramid.ini', + 'http_port=%s' % (port, ), 'http_host=%s' % (host, )] + proc = subprocess.Popen(args) + + def cleanup_server_process(): + proc.kill() + atexit.register(cleanup_server_process) + + server = create_vcsserver_proxy(server_and_port, protocol='http') + _wait_until_vcs_server_is_reachable(server) + + +def _wait_until_vcs_server_is_reachable(server): + while xrange(80): # max 40s of sleep + try: + server.ping() + break + except (CommunicationError, pycurl.error): + pass + time.sleep(0.5) + + +def _try_to_shutdown_running_server(server_and_port): + server = create_vcsserver_proxy(server_and_port) + try: + server.shutdown() + except (CommunicationError, pycurl.error): + return + + # TODO: Not sure why this is important, but without it the following start + # of the server fails. + server = create_vcsserver_proxy(server_and_port) + server.ping() + + +def create_vcsserver_proxy(server_and_port, protocol='pyro4'): + if protocol == 'pyro4': + return _create_vcsserver_proxy_pyro4(server_and_port) + elif protocol == 'http': + return _create_vcsserver_proxy_http(server_and_port) + + +def _create_vcsserver_proxy_pyro4(server_and_port): + server = Pyro4.Proxy( + settings.pyro_remote(settings.PYRO_VCSSERVER, server_and_port)) + return server + + +def _create_vcsserver_proxy_http(server_and_port): + from rhodecode.lib.vcs import client_http + + session = _create_http_rpc_session() + url = urlparse.urljoin('http://%s' % server_and_port, '/server') + return client_http.RemoteObject(url, session) + + +class CurlSession(object): + """ + Modeled so that it provides a subset of the requests interface. + + This has been created so that it does only provide a minimal API for our + needs. The parts which it provides are based on the API of the library + `requests` which allows us to easily benchmark against it. + + Please have a look at the class :class:`requests.Session` when you extend + it. + """ + + def __init__(self): + curl = pycurl.Curl() + # TODO: johbo: I did test with 7.19 of libcurl. This version has + # trouble with 100 - continue being set in the expect header. This + # can lead to massive performance drops, switching it off here. + curl.setopt(curl.HTTPHEADER, ["Expect:"]) + curl.setopt(curl.TCP_NODELAY, True) + curl.setopt(curl.PROTOCOLS, curl.PROTO_HTTP) + self._curl = curl + + def post(self, url, data, allow_redirects=False): + response_buffer = StringIO() + + curl = self._curl + curl.setopt(curl.URL, url) + curl.setopt(curl.POST, True) + curl.setopt(curl.POSTFIELDS, data) + curl.setopt(curl.FOLLOWLOCATION, allow_redirects) + curl.setopt(curl.WRITEDATA, response_buffer) + curl.perform() + + return CurlResponse(response_buffer) + + +class CurlResponse(object): + """ + The response of a request, modeled after the requests API. + + This class provides a subset of the response interface known from the + library `requests`. It is intentionally kept similar, so that we can use + `requests` as a drop in replacement for benchmarking purposes. + """ + + def __init__(self, response_buffer): + self._response_buffer = response_buffer + + @property + def content(self): + return self._response_buffer.getvalue() + + +def _create_http_rpc_session(): + session = CurlSession() + return session diff --git a/rhodecode/lib/vcs/backends/__init__.py b/rhodecode/lib/vcs/backends/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/__init__.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +VCS Backends module +""" + +import os +from pprint import pformat + +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.utils.imports import import_class + + +def get_repo(path=None, alias=None, create=False): + """ + Returns ``Repository`` object of type linked with given ``alias`` at + the specified ``path``. If ``alias`` is not given it will try to guess it + using get_scm method + """ + if create: + if not (path or alias): + raise TypeError( + "If create is specified, we need path and scm type") + return get_backend(alias)(path, create=True) + if path is None: + path = os.path.abspath(os.path.curdir) + try: + scm, path = get_scm(path, search_path_up=True) + path = os.path.abspath(path) + alias = scm + except VCSError: + raise VCSError("No scm found at %s" % path) + if alias is None: + alias = get_scm(path)[0] + + backend = get_backend(alias) + repo = backend(path, create=create) + return repo + + +def get_backend(alias): + """ + Returns ``Repository`` class identified by the given alias or raises + VCSError if alias is not recognized or backend class cannot be imported. + """ + if alias not in settings.BACKENDS: + raise VCSError( + "Given alias '%s' is not recognized! Allowed aliases:\n%s" % + (alias, pformat(settings.BACKENDS.keys()))) + backend_path = settings.BACKENDS[alias] + klass = import_class(backend_path) + return klass + + +def get_supported_backends(): + """ + Returns list of aliases of supported backends. + """ + return settings.BACKENDS.keys() diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/base.py @@ -0,0 +1,1496 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Base module for all VCS systems +""" + +import collections +import datetime +import itertools +import logging +import os +import time +import warnings + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils2 import safe_str, safe_unicode +from rhodecode.lib.vcs import connection +from rhodecode.lib.vcs.utils import author_name, author_email +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import ( + CommitError, EmptyRepositoryError, NodeAlreadyAddedError, + NodeAlreadyChangedError, NodeAlreadyExistsError, NodeAlreadyRemovedError, + NodeDoesNotExistError, NodeNotChangedError, VCSError, + ImproperArchiveTypeError, BranchDoesNotExistError, CommitDoesNotExistError, + RepositoryError) + + +log = logging.getLogger(__name__) + + +FILEMODE_DEFAULT = 0100644 +FILEMODE_EXECUTABLE = 0100755 + +Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id')) +MergeResponse = collections.namedtuple( + 'MergeResponse', + ('possible', 'executed', 'merge_commit_id', 'failure_reason')) + + +class MergeFailureReason(object): + """ + Enumeration with all the reasons why the server side merge could fail. + + DO NOT change the number of the reasons, as they may be stored in the + database. + + Changing the name of a reason is acceptable and encouraged to deprecate old + reasons. + """ + + # Everything went well. + NONE = 0 + + # An unexpected exception was raised. Check the logs for more details. + UNKNOWN = 1 + + # The merge was not successful, there are conflicts. + MERGE_FAILED = 2 + + # The merge succeeded but we could not push it to the target repository. + PUSH_FAILED = 3 + + # The specified target is not a head in the target repository. + TARGET_IS_NOT_HEAD = 4 + + # The source repository contains more branches than the target. Pushing + # the merge will create additional branches in the target. + HG_SOURCE_HAS_MORE_BRANCHES = 5 + + # The target reference has multiple heads. That does not allow to correctly + # identify the target location. This could only happen for mercurial + # branches. + HG_TARGET_HAS_MULTIPLE_HEADS = 6 + + # The target repository is locked + TARGET_IS_LOCKED = 7 + + # A involved commit could not be found. + MISSING_COMMIT = 8 + + +class BaseRepository(object): + """ + Base Repository for final backends + + .. attribute:: DEFAULT_BRANCH_NAME + + name of default branch (i.e. "trunk" for svn, "master" for git etc. + + .. attribute:: commit_ids + + list of all available commit ids, in ascending order + + .. attribute:: path + + absolute path to the repository + + .. attribute:: bookmarks + + Mapping from name to :term:`Commit ID` of the bookmark. Empty in case + there are no bookmarks or the backend implementation does not support + bookmarks. + + .. attribute:: tags + + Mapping from name to :term:`Commit ID` of the tag. + + """ + + DEFAULT_BRANCH_NAME = None + DEFAULT_CONTACT = u"Unknown" + DEFAULT_DESCRIPTION = u"unknown" + EMPTY_COMMIT_ID = '0' * 40 + + path = None + + def __init__(self, repo_path, config=None, create=False, **kwargs): + """ + Initializes repository. Raises RepositoryError if repository could + not be find at the given ``repo_path`` or directory at ``repo_path`` + exists and ``create`` is set to True. + + :param repo_path: local path of the repository + :param config: repository configuration + :param create=False: if set to True, would try to create repository. + :param src_url=None: if set, should be proper url from which repository + would be cloned; requires ``create`` parameter to be set to True - + raises RepositoryError if src_url is set and create evaluates to + False + """ + raise NotImplementedError + + def __repr__(self): + return '<%s at %s>' % (self.__class__.__name__, self.path) + + def __len__(self): + return self.count() + + def __eq__(self, other): + same_instance = isinstance(other, self.__class__) + return same_instance and other.path == self.path + + def __ne__(self, other): + return not self.__eq__(other) + + @LazyProperty + def EMPTY_COMMIT(self): + return EmptyCommit(self.EMPTY_COMMIT_ID) + + @LazyProperty + def alias(self): + for k, v in settings.BACKENDS.items(): + if v.split('.')[-1] == str(self.__class__.__name__): + return k + + @LazyProperty + def name(self): + return safe_unicode(os.path.basename(self.path)) + + @LazyProperty + def description(self): + raise NotImplementedError + + def refs(self): + """ + returns a `dict` with branches, bookmarks, tags, and closed_branches + for this repository + """ + raise NotImplementedError + + @LazyProperty + def branches(self): + """ + A `dict` which maps branch names to commit ids. + """ + raise NotImplementedError + + @LazyProperty + def size(self): + """ + Returns combined size in bytes for all repository files + """ + tip = self.get_commit() + return tip.size + + def size_at_commit(self, commit_id): + commit = self.get_commit(commit_id) + return commit.size + + def is_empty(self): + return not bool(self.commit_ids) + + @staticmethod + def check_url(url, config): + """ + Function will check given url and try to verify if it's a valid + link. + """ + raise NotImplementedError + + @staticmethod + def is_valid_repository(path): + """ + Check if given `path` contains a valid repository of this backend + """ + raise NotImplementedError + + # ========================================================================== + # COMMITS + # ========================================================================== + + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): + """ + Returns instance of `BaseCommit` class. If `commit_id` and `commit_idx` + are both None, most recent commit is returned. + + :param pre_load: Optional. List of commit attributes to load. + + :raises ``EmptyRepositoryError``: if there are no commits + """ + raise NotImplementedError + + def __iter__(self): + for commit_id in self.commit_ids: + yield self.get_commit(commit_id=commit_id) + + def get_commits( + self, start_id=None, end_id=None, start_date=None, end_date=None, + branch_name=None, pre_load=None): + """ + Returns iterator of `BaseCommit` objects from start to end + not inclusive. This should behave just like a list, ie. end is not + inclusive. + + :param start_id: None or str, must be a valid commit id + :param end_id: None or str, must be a valid commit id + :param start_date: + :param end_date: + :param branch_name: + :param pre_load: + """ + raise NotImplementedError + + def __getitem__(self, key): + """ + Allows index based access to the commit objects of this repository. + """ + pre_load = ["author", "branch", "date", "message", "parents"] + if isinstance(key, slice): + return self._get_range(key, pre_load) + return self.get_commit(commit_idx=key, pre_load=pre_load) + + def _get_range(self, slice_obj, pre_load): + for commit_id in self.commit_ids.__getitem__(slice_obj): + yield self.get_commit(commit_id=commit_id, pre_load=pre_load) + + def count(self): + return len(self.commit_ids) + + def tag(self, name, user, commit_id=None, message=None, date=None, **opts): + """ + Creates and returns a tag for the given ``commit_id``. + + :param name: name for new tag + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param commit_id: commit id for which new tag would be created + :param message: message of the tag's commit + :param date: date of tag's commit + + :raises TagAlreadyExistError: if tag with same name already exists + """ + raise NotImplementedError + + def remove_tag(self, name, user, message=None, date=None): + """ + Removes tag with the given ``name``. + + :param name: name of the tag to be removed + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param message: message of the tag's removal commit + :param date: date of tag's removal commit + + :raises TagDoesNotExistError: if tag with given name does not exists + """ + raise NotImplementedError + + def get_diff( + self, commit1, commit2, path=None, ignore_whitespace=False, + context=3, path1=None): + """ + Returns (git like) *diff*, as plain text. Shows changes introduced by + `commit2` since `commit1`. + + :param commit1: Entry point from which diff is shown. Can be + ``self.EMPTY_COMMIT`` - in this case, patch showing all + the changes since empty state of the repository until `commit2` + :param commit2: Until which commit changes should be shown. + :param path: Can be set to a path of a file to create a diff of that + file. If `path1` is also set, this value is only associated to + `commit2`. + :param ignore_whitespace: If set to ``True``, would not show whitespace + changes. Defaults to ``False``. + :param context: How many lines before/after changed lines should be + shown. Defaults to ``3``. + :param path1: Can be set to a path to associate with `commit1`. This + parameter works only for backends which support diff generation for + different paths. Other backends will raise a `ValueError` if `path1` + is set and has a different value than `path`. + """ + raise NotImplementedError + + def strip(self, commit_id, branch=None): + """ + Strip given commit_id from the repository + """ + raise NotImplementedError + + def get_common_ancestor(self, commit_id1, commit_id2, repo2): + """ + Return a latest common ancestor commit if one exists for this repo + `commit_id1` vs `commit_id2` from `repo2`. + + :param commit_id1: Commit it from this repository to use as a + target for the comparison. + :param commit_id2: Source commit id to use for comparison. + :param repo2: Source repository to use for comparison. + """ + raise NotImplementedError + + def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None): + """ + Compare this repository's revision `commit_id1` with `commit_id2`. + + Returns a tuple(commits, ancestor) that would be merged from + `commit_id2`. Doing a normal compare (``merge=False``), ``None`` + will be returned as ancestor. + + :param commit_id1: Commit it from this repository to use as a + target for the comparison. + :param commit_id2: Source commit id to use for comparison. + :param repo2: Source repository to use for comparison. + :param merge: If set to ``True`` will do a merge compare which also + returns the common ancestor. + :param pre_load: Optional. List of commit attributes to load. + """ + raise NotImplementedError + + def merge(self, target_ref, source_repo, source_ref, workspace_id, + user_name='', user_email='', message='', dry_run=False): + """ + Merge the revisions specified in `source_ref` from `source_repo` + onto the `target_ref` of this repository. + + `source_ref` and `target_ref` are named tupls with the following + fields `type`, `name` and `commit_id`. + + Returns a MergeResponse named tuple with the following fields + 'possible', 'executed', 'source_commit', 'target_commit', + 'merge_commit'. + + :param target_ref: `target_ref` points to the commit on top of which + the `source_ref` should be merged. + :param source_repo: The repository that contains the commits to be + merged. + :param source_ref: `source_ref` points to the topmost commit from + the `source_repo` which should be merged. + :param workspace_id: `workspace_id` unique identifier. + :param user_name: Merge commit `user_name`. + :param user_email: Merge commit `user_email`. + :param message: Merge commit `message`. + :param dry_run: If `True` the merge will not take place. + """ + if dry_run: + message = message or 'sample_message' + user_email = user_email or 'user@email.com' + user_name = user_name or 'user name' + else: + if not user_name: + raise ValueError('user_name cannot be empty') + if not user_email: + raise ValueError('user_email cannot be empty') + if not message: + raise ValueError('message cannot be empty') + + shadow_repository_path = self._maybe_prepare_merge_workspace( + workspace_id, target_ref) + + try: + return self._merge_repo( + shadow_repository_path, target_ref, source_repo, + source_ref, message, user_name, user_email, dry_run=dry_run) + except RepositoryError: + log.exception('Unexpected failure when running merge') + return MergeResponse( + False, False, None, MergeFailureReason.UNKNOWN) + + def _merge_repo(self, shadow_repository_path, target_ref, + source_repo, source_ref, merge_message, + merger_name, merger_email, dry_run=False): + """Internal implementation of merge.""" + raise NotImplementedError + + def _maybe_prepare_merge_workspace(self, workspace_id, target_ref): + """ + Create the merge workspace. + + :param workspace_id: `workspace_id` unique identifier. + """ + raise NotImplementedError + + def cleanup_merge_workspace(self, workspace_id): + """ + Remove merge workspace. + + This function MUST not fail in case there is no workspace associated to + the given `workspace_id`. + + :param workspace_id: `workspace_id` unique identifier. + """ + raise NotImplementedError + + # ========== # + # COMMIT API # + # ========== # + + @LazyProperty + def in_memory_commit(self): + """ + Returns :class:`InMemoryCommit` object for this repository. + """ + raise NotImplementedError + + # ======================== # + # UTILITIES FOR SUBCLASSES # + # ======================== # + + def _validate_diff_commits(self, commit1, commit2): + """ + Validates that the given commits are related to this repository. + + Intended as a utility for sub classes to have a consistent validation + of input parameters in methods like :meth:`get_diff`. + """ + self._validate_commit(commit1) + self._validate_commit(commit2) + if (isinstance(commit1, EmptyCommit) and + isinstance(commit2, EmptyCommit)): + raise ValueError("Cannot compare two empty commits") + + def _validate_commit(self, commit): + if not isinstance(commit, BaseCommit): + raise TypeError( + "%s is not of type BaseCommit" % repr(commit)) + if commit.repository != self and not isinstance(commit, EmptyCommit): + raise ValueError( + "Commit %s must be a valid commit from this repository %s, " + "related to this repository instead %s." % + (commit, self, commit.repository)) + + def _validate_commit_id(self, commit_id): + if not isinstance(commit_id, basestring): + raise TypeError("commit_id must be a string value") + + def _validate_commit_idx(self, commit_idx): + if not isinstance(commit_idx, (int, long)): + raise TypeError("commit_idx must be a numeric value") + + def _validate_branch_name(self, branch_name): + if branch_name and branch_name not in self.branches_all: + msg = ("Branch %s not found in %s" % (branch_name, self)) + raise BranchDoesNotExistError(msg) + + # + # Supporting deprecated API parts + # TODO: johbo: consider to move this into a mixin + # + + @property + def EMPTY_CHANGESET(self): + warnings.warn( + "Use EMPTY_COMMIT or EMPTY_COMMIT_ID instead", DeprecationWarning) + return self.EMPTY_COMMIT_ID + + @property + def revisions(self): + warnings.warn("Use commits attribute instead", DeprecationWarning) + return self.commit_ids + + @revisions.setter + def revisions(self, value): + warnings.warn("Use commits attribute instead", DeprecationWarning) + self.commit_ids = value + + def get_changeset(self, revision=None, pre_load=None): + warnings.warn("Use get_commit instead", DeprecationWarning) + commit_id = None + commit_idx = None + if isinstance(revision, basestring): + commit_id = revision + else: + commit_idx = revision + return self.get_commit( + commit_id=commit_id, commit_idx=commit_idx, pre_load=pre_load) + + def get_changesets( + self, start=None, end=None, start_date=None, end_date=None, + branch_name=None, pre_load=None): + warnings.warn("Use get_commits instead", DeprecationWarning) + start_id = self._revision_to_commit(start) + end_id = self._revision_to_commit(end) + return self.get_commits( + start_id=start_id, end_id=end_id, start_date=start_date, + end_date=end_date, branch_name=branch_name, pre_load=pre_load) + + def _revision_to_commit(self, revision): + """ + Translates a revision to a commit_id + + Helps to support the old changeset based API which allows to use + commit ids and commit indices interchangeable. + """ + if revision is None: + return revision + + if isinstance(revision, basestring): + commit_id = revision + else: + commit_id = self.commit_ids[revision] + return commit_id + + @property + def in_memory_changeset(self): + warnings.warn("Use in_memory_commit instead", DeprecationWarning) + return self.in_memory_commit + + +class BaseCommit(object): + """ + Each backend should implement it's commit representation. + + **Attributes** + + ``repository`` + repository object within which commit exists + + ``id`` + The commit id, may be ``raw_id`` or i.e. for mercurial's tip + just ``tip``. + + ``raw_id`` + raw commit representation (i.e. full 40 length sha for git + backend) + + ``short_id`` + shortened (if apply) version of ``raw_id``; it would be simple + shortcut for ``raw_id[:12]`` for git/mercurial backends or same + as ``raw_id`` for subversion + + ``idx`` + commit index + + ``files`` + list of ``FileNode`` (``Node`` with NodeKind.FILE) objects + + ``dirs`` + list of ``DirNode`` (``Node`` with NodeKind.DIR) objects + + ``nodes`` + combined list of ``Node`` objects + + ``author`` + author of the commit, as unicode + + ``message`` + message of the commit, as unicode + + ``parents`` + list of parent commits + + """ + + branch = None + """ + Depending on the backend this should be set to the branch name of the + commit. Backends not supporting branches on commits should leave this + value as ``None``. + """ + + _ARCHIVE_PREFIX_TEMPLATE = b'{repo_name}-{short_id}' + """ + This template is used to generate a default prefix for repository archives + if no prefix has been specified. + """ + + def __str__(self): + return '<%s at %s:%s>' % ( + self.__class__.__name__, self.idx, self.short_id) + + def __repr__(self): + return self.__str__() + + def __unicode__(self): + return u'%s:%s' % (self.idx, self.short_id) + + def __eq__(self, other): + return self.raw_id == other.raw_id + + def __json__(self): + parents = [] + try: + for parent in self.parents: + parents.append({'raw_id': parent.raw_id}) + except NotImplementedError: + # empty commit doesn't have parents implemented + pass + + return { + 'short_id': self.short_id, + 'raw_id': self.raw_id, + 'revision': self.idx, + 'message': self.message, + 'date': self.date, + 'author': self.author, + 'parents': parents, + 'branch': self.branch + } + + @LazyProperty + def last(self): + """ + ``True`` if this is last commit in repository, ``False`` + otherwise; trying to access this attribute while there is no + commits would raise `EmptyRepositoryError` + """ + if self.repository is None: + raise CommitError("Cannot check if it's most recent commit") + return self.raw_id == self.repository.commit_ids[-1] + + @LazyProperty + def parents(self): + """ + Returns list of parent commits. + """ + raise NotImplementedError + + @property + def merge(self): + """ + Returns boolean if commit is a merge. + """ + return len(self.parents) > 1 + + @LazyProperty + def children(self): + """ + Returns list of child commits. + """ + raise NotImplementedError + + @LazyProperty + def id(self): + """ + Returns string identifying this commit. + """ + raise NotImplementedError + + @LazyProperty + def raw_id(self): + """ + Returns raw string identifying this commit. + """ + raise NotImplementedError + + @LazyProperty + def short_id(self): + """ + Returns shortened version of ``raw_id`` attribute, as string, + identifying this commit, useful for presentation to users. + """ + raise NotImplementedError + + @LazyProperty + def idx(self): + """ + Returns integer identifying this commit. + """ + raise NotImplementedError + + @LazyProperty + def committer(self): + """ + Returns committer for this commit + """ + raise NotImplementedError + + @LazyProperty + def committer_name(self): + """ + Returns committer name for this commit + """ + + return author_name(self.committer) + + @LazyProperty + def committer_email(self): + """ + Returns committer email address for this commit + """ + + return author_email(self.committer) + + @LazyProperty + def author(self): + """ + Returns author for this commit + """ + + raise NotImplementedError + + @LazyProperty + def author_name(self): + """ + Returns author name for this commit + """ + + return author_name(self.author) + + @LazyProperty + def author_email(self): + """ + Returns author email address for this commit + """ + + return author_email(self.author) + + def get_file_mode(self, path): + """ + Returns stat mode of the file at `path`. + """ + raise NotImplementedError + + def is_link(self, path): + """ + Returns ``True`` if given `path` is a symlink + """ + raise NotImplementedError + + def get_file_content(self, path): + """ + Returns content of the file at the given `path`. + """ + raise NotImplementedError + + def get_file_size(self, path): + """ + Returns size of the file at the given `path`. + """ + raise NotImplementedError + + def get_file_commit(self, path, pre_load=None): + """ + Returns last commit of the file at the given `path`. + + :param pre_load: Optional. List of commit attributes to load. + """ + return self.get_file_history(path, limit=1, pre_load=pre_load)[0] + + def get_file_history(self, path, limit=None, pre_load=None): + """ + Returns history of file as reversed list of :class:`BaseCommit` + objects for which file at given `path` has been modified. + + :param limit: Optional. Allows to limit the size of the returned + history. This is intended as a hint to the underlying backend, so + that it can apply optimizations depending on the limit. + :param pre_load: Optional. List of commit attributes to load. + """ + raise NotImplementedError + + def get_file_annotate(self, path, pre_load=None): + """ + Returns a generator of four element tuples with + lineno, sha, commit lazy loader and line + + :param pre_load: Optional. List of commit attributes to load. + """ + raise NotImplementedError + + def get_nodes(self, path): + """ + Returns combined ``DirNode`` and ``FileNode`` objects list representing + state of commit at the given ``path``. + + :raises ``CommitError``: if node at the given ``path`` is not + instance of ``DirNode`` + """ + raise NotImplementedError + + def get_node(self, path): + """ + Returns ``Node`` object from the given ``path``. + + :raises ``NodeDoesNotExistError``: if there is no node at the given + ``path`` + """ + raise NotImplementedError + + def get_largefile_node(self, path): + """ + Returns the path to largefile from Mercurial storage. + """ + raise NotImplementedError + + def archive_repo(self, file_path, kind='tgz', subrepos=None, + prefix=None, write_metadata=False, mtime=None): + """ + Creates an archive containing the contents of the repository. + + :param file_path: path to the file which to create the archive. + :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``. + :param prefix: name of root directory in archive. + Default is repository name and commit's short_id joined with dash: + ``"{repo_name}-{short_id}"``. + :param write_metadata: write a metadata file into archive. + :param mtime: custom modification time for archive creation, defaults + to time.time() if not given. + + :raise VCSError: If prefix has a problem. + """ + allowed_kinds = settings.ARCHIVE_SPECS.keys() + if kind not in allowed_kinds: + raise ImproperArchiveTypeError( + 'Archive kind (%s) not supported use one of %s' % + (kind, allowed_kinds)) + + prefix = self._validate_archive_prefix(prefix) + + mtime = mtime or time.time() + + file_info = [] + cur_rev = self.repository.get_commit(commit_id=self.raw_id) + for _r, _d, files in cur_rev.walk('/'): + for f in files: + f_path = os.path.join(prefix, f.path) + file_info.append( + (f_path, f.mode, f.is_link(), f._get_content())) + + if write_metadata: + metadata = [ + ('repo_name', self.repository.name), + ('rev', self.raw_id), + ('create_time', mtime), + ('branch', self.branch), + ('tags', ','.join(self.tags)), + ] + meta = ["%s:%s" % (f_name, value) for f_name, value in metadata] + file_info.append(('.archival.txt', 0644, False, '\n'.join(meta))) + + connection.Hg.archive_repo(file_path, mtime, file_info, kind) + + def _validate_archive_prefix(self, prefix): + if prefix is None: + prefix = self._ARCHIVE_PREFIX_TEMPLATE.format( + repo_name=safe_str(self.repository.name), + short_id=self.short_id) + elif not isinstance(prefix, str): + raise ValueError("prefix not a bytes object: %s" % repr(prefix)) + elif prefix.startswith('/'): + raise VCSError("Prefix cannot start with leading slash") + elif prefix.strip() == '': + raise VCSError("Prefix cannot be empty") + return prefix + + @LazyProperty + def root(self): + """ + Returns ``RootNode`` object for this commit. + """ + return self.get_node('') + + def next(self, branch=None): + """ + Returns next commit from current, if branch is gives it will return + next commit belonging to this branch + + :param branch: show commits within the given named branch + """ + indexes = xrange(self.idx + 1, self.repository.count()) + return self._find_next(indexes, branch) + + def prev(self, branch=None): + """ + Returns previous commit from current, if branch is gives it will + return previous commit belonging to this branch + + :param branch: show commit within the given named branch + """ + indexes = xrange(self.idx - 1, -1, -1) + return self._find_next(indexes, branch) + + def _find_next(self, indexes, branch=None): + if branch and self.branch != branch: + raise VCSError('Branch option used on commit not belonging ' + 'to that branch') + + for next_idx in indexes: + commit = self.repository.get_commit(commit_idx=next_idx) + if branch and branch != commit.branch: + continue + return commit + raise CommitDoesNotExistError + + def diff(self, ignore_whitespace=True, context=3): + """ + Returns a `Diff` object representing the change made by this commit. + """ + parent = ( + self.parents[0] if self.parents else self.repository.EMPTY_COMMIT) + diff = self.repository.get_diff( + parent, self, + ignore_whitespace=ignore_whitespace, + context=context) + return diff + + @LazyProperty + def added(self): + """ + Returns list of added ``FileNode`` objects. + """ + raise NotImplementedError + + @LazyProperty + def changed(self): + """ + Returns list of modified ``FileNode`` objects. + """ + raise NotImplementedError + + @LazyProperty + def removed(self): + """ + Returns list of removed ``FileNode`` objects. + """ + raise NotImplementedError + + @LazyProperty + def size(self): + """ + Returns total number of bytes from contents of all filenodes. + """ + return sum((node.size for node in self.get_filenodes_generator())) + + def walk(self, topurl=''): + """ + Similar to os.walk method. Insted of filesystem it walks through + commit starting at given ``topurl``. Returns generator of tuples + (topnode, dirnodes, filenodes). + """ + topnode = self.get_node(topurl) + if not topnode.is_dir(): + return + yield (topnode, topnode.dirs, topnode.files) + for dirnode in topnode.dirs: + for tup in self.walk(dirnode.path): + yield tup + + def get_filenodes_generator(self): + """ + Returns generator that yields *all* file nodes. + """ + for topnode, dirs, files in self.walk(): + for node in files: + yield node + + # + # Utilities for sub classes to support consistent behavior + # + + def no_node_at_path(self, path): + return NodeDoesNotExistError( + "There is no file nor directory at the given path: " + "'%s' at commit %s" % (path, self.short_id)) + + def _fix_path(self, path): + """ + Paths are stored without trailing slash so we need to get rid off it if + needed. + """ + return path.rstrip('/') + + # + # Deprecated API based on changesets + # + + @property + def revision(self): + warnings.warn("Use idx instead", DeprecationWarning) + return self.idx + + @revision.setter + def revision(self, value): + warnings.warn("Use idx instead", DeprecationWarning) + self.idx = value + + def get_file_changeset(self, path): + warnings.warn("Use get_file_commit instead", DeprecationWarning) + return self.get_file_commit(path) + + +class BaseChangesetClass(type): + + def __instancecheck__(self, instance): + return isinstance(instance, BaseCommit) + + +class BaseChangeset(BaseCommit): + + __metaclass__ = BaseChangesetClass + + def __new__(cls, *args, **kwargs): + warnings.warn( + "Use BaseCommit instead of BaseChangeset", DeprecationWarning) + return super(BaseChangeset, cls).__new__(cls, *args, **kwargs) + + +class BaseInMemoryCommit(object): + """ + Represents differences between repository's state (most recent head) and + changes made *in place*. + + **Attributes** + + ``repository`` + repository object for this in-memory-commit + + ``added`` + list of ``FileNode`` objects marked as *added* + + ``changed`` + list of ``FileNode`` objects marked as *changed* + + ``removed`` + list of ``FileNode`` or ``RemovedFileNode`` objects marked to be + *removed* + + ``parents`` + list of :class:`BaseCommit` instances representing parents of + in-memory commit. Should always be 2-element sequence. + + """ + + def __init__(self, repository): + self.repository = repository + self.added = [] + self.changed = [] + self.removed = [] + self.parents = [] + + def add(self, *filenodes): + """ + Marks given ``FileNode`` objects as *to be committed*. + + :raises ``NodeAlreadyExistsError``: if node with same path exists at + latest commit + :raises ``NodeAlreadyAddedError``: if node with same path is already + marked as *added* + """ + # Check if not already marked as *added* first + for node in filenodes: + if node.path in (n.path for n in self.added): + raise NodeAlreadyAddedError( + "Such FileNode %s is already marked for addition" + % node.path) + for node in filenodes: + self.added.append(node) + + def change(self, *filenodes): + """ + Marks given ``FileNode`` objects to be *changed* in next commit. + + :raises ``EmptyRepositoryError``: if there are no commits yet + :raises ``NodeAlreadyExistsError``: if node with same path is already + marked to be *changed* + :raises ``NodeAlreadyRemovedError``: if node with same path is already + marked to be *removed* + :raises ``NodeDoesNotExistError``: if node doesn't exist in latest + commit + :raises ``NodeNotChangedError``: if node hasn't really be changed + """ + for node in filenodes: + if node.path in (n.path for n in self.removed): + raise NodeAlreadyRemovedError( + "Node at %s is already marked as removed" % node.path) + try: + self.repository.get_commit() + except EmptyRepositoryError: + raise EmptyRepositoryError( + "Nothing to change - try to *add* new nodes rather than " + "changing them") + for node in filenodes: + if node.path in (n.path for n in self.changed): + raise NodeAlreadyChangedError( + "Node at '%s' is already marked as changed" % node.path) + self.changed.append(node) + + def remove(self, *filenodes): + """ + Marks given ``FileNode`` (or ``RemovedFileNode``) objects to be + *removed* in next commit. + + :raises ``NodeAlreadyRemovedError``: if node has been already marked to + be *removed* + :raises ``NodeAlreadyChangedError``: if node has been already marked to + be *changed* + """ + for node in filenodes: + if node.path in (n.path for n in self.removed): + raise NodeAlreadyRemovedError( + "Node is already marked to for removal at %s" % node.path) + if node.path in (n.path for n in self.changed): + raise NodeAlreadyChangedError( + "Node is already marked to be changed at %s" % node.path) + # We only mark node as *removed* - real removal is done by + # commit method + self.removed.append(node) + + def reset(self): + """ + Resets this instance to initial state (cleans ``added``, ``changed`` + and ``removed`` lists). + """ + self.added = [] + self.changed = [] + self.removed = [] + self.parents = [] + + def get_ipaths(self): + """ + Returns generator of paths from nodes marked as added, changed or + removed. + """ + for node in itertools.chain(self.added, self.changed, self.removed): + yield node.path + + def get_paths(self): + """ + Returns list of paths from nodes marked as added, changed or removed. + """ + return list(self.get_ipaths()) + + def check_integrity(self, parents=None): + """ + Checks in-memory commit's integrity. Also, sets parents if not + already set. + + :raises CommitError: if any error occurs (i.e. + ``NodeDoesNotExistError``). + """ + if not self.parents: + parents = parents or [] + if len(parents) == 0: + try: + parents = [self.repository.get_commit(), None] + except EmptyRepositoryError: + parents = [None, None] + elif len(parents) == 1: + parents += [None] + self.parents = parents + + # Local parents, only if not None + parents = [p for p in self.parents if p] + + # Check nodes marked as added + for p in parents: + for node in self.added: + try: + p.get_node(node.path) + except NodeDoesNotExistError: + pass + else: + raise NodeAlreadyExistsError( + "Node `%s` already exists at %s" % (node.path, p)) + + # Check nodes marked as changed + missing = set(self.changed) + not_changed = set(self.changed) + if self.changed and not parents: + raise NodeDoesNotExistError(str(self.changed[0].path)) + for p in parents: + for node in self.changed: + try: + old = p.get_node(node.path) + missing.remove(node) + # if content actually changed, remove node from not_changed + if old.content != node.content: + not_changed.remove(node) + except NodeDoesNotExistError: + pass + if self.changed and missing: + raise NodeDoesNotExistError( + "Node `%s` marked as modified but missing in parents: %s" + % (node.path, parents)) + + if self.changed and not_changed: + raise NodeNotChangedError( + "Node `%s` wasn't actually changed (parents: %s)" + % (not_changed.pop().path, parents)) + + # Check nodes marked as removed + if self.removed and not parents: + raise NodeDoesNotExistError( + "Cannot remove node at %s as there " + "were no parents specified" % self.removed[0].path) + really_removed = set() + for p in parents: + for node in self.removed: + try: + p.get_node(node.path) + really_removed.add(node) + except CommitError: + pass + not_removed = set(self.removed) - really_removed + if not_removed: + # TODO: johbo: This code branch does not seem to be covered + raise NodeDoesNotExistError( + "Cannot remove node at %s from " + "following parents: %s" % (not_removed, parents)) + + def commit( + self, message, author, parents=None, branch=None, date=None, + **kwargs): + """ + Performs in-memory commit (doesn't check workdir in any way) and + returns newly created :class:`BaseCommit`. Updates repository's + attribute `commits`. + + .. note:: + + While overriding this method each backend's should call + ``self.check_integrity(parents)`` in the first place. + + :param message: message of the commit + :param author: full username, i.e. "Joe Doe <joe.doe@example.com>" + :param parents: single parent or sequence of parents from which commit + would be derived + :param date: ``datetime.datetime`` instance. Defaults to + ``datetime.datetime.now()``. + :param branch: branch name, as string. If none given, default backend's + branch would be used. + + :raises ``CommitError``: if any error occurs while committing + """ + raise NotImplementedError + + +class BaseInMemoryChangesetClass(type): + + def __instancecheck__(self, instance): + return isinstance(instance, BaseInMemoryCommit) + + +class BaseInMemoryChangeset(BaseInMemoryCommit): + + __metaclass__ = BaseInMemoryChangesetClass + + def __new__(cls, *args, **kwargs): + warnings.warn( + "Use BaseCommit instead of BaseInMemoryCommit", DeprecationWarning) + return super(BaseInMemoryChangeset, cls).__new__(cls, *args, **kwargs) + + +class EmptyCommit(BaseCommit): + """ + An dummy empty commit. It's possible to pass hash when creating + an EmptyCommit + """ + + def __init__( + self, commit_id='0' * 40, repo=None, alias=None, idx=-1, + message='', author='', date=None): + self._empty_commit_id = commit_id + # TODO: johbo: Solve idx parameter, default value does not make + # too much sense + self.idx = idx + self.message = message + self.author = author + self.date = date or datetime.datetime.fromtimestamp(0) + self.repository = repo + self.alias = alias + + @LazyProperty + def raw_id(self): + """ + Returns raw string identifying this commit, useful for web + representation. + """ + + return self._empty_commit_id + + @LazyProperty + def branch(self): + if self.alias: + from rhodecode.lib.vcs.backends import get_backend + return get_backend(self.alias).DEFAULT_BRANCH_NAME + + @LazyProperty + def short_id(self): + return self.raw_id[:12] + + def get_file_commit(self, path): + return self + + def get_file_content(self, path): + return u'' + + def get_file_size(self, path): + return 0 + + +class EmptyChangesetClass(type): + + def __instancecheck__(self, instance): + return isinstance(instance, EmptyCommit) + + +class EmptyChangeset(EmptyCommit): + + __metaclass__ = EmptyChangesetClass + + def __new__(cls, *args, **kwargs): + warnings.warn( + "Use EmptyCommit instead of EmptyChangeset", DeprecationWarning) + return super(EmptyCommit, cls).__new__(cls, *args, **kwargs) + + def __init__(self, cs='0' * 40, repo=None, requested_revision=None, + alias=None, revision=-1, message='', author='', date=None): + if requested_revision is not None: + warnings.warn( + "Parameter requested_revision not supported anymore", + DeprecationWarning) + super(EmptyChangeset, self).__init__( + commit_id=cs, repo=repo, alias=alias, idx=revision, + message=message, author=author, date=date) + + @property + def revision(self): + warnings.warn("Use idx instead", DeprecationWarning) + return self.idx + + @revision.setter + def revision(self, value): + warnings.warn("Use idx instead", DeprecationWarning) + self.idx = value + + +class CollectionGenerator(object): + + def __init__(self, repo, commit_ids, collection_size=None, pre_load=None): + self.repo = repo + self.commit_ids = commit_ids + # TODO: (oliver) this isn't currently hooked up + self.collection_size = None + self.pre_load = pre_load + + def __len__(self): + if self.collection_size is not None: + return self.collection_size + return self.commit_ids.__len__() + + def __iter__(self): + for commit_id in self.commit_ids: + # TODO: johbo: Mercurial passes in commit indices or commit ids + yield self._commit_factory(commit_id) + + def _commit_factory(self, commit_id): + """ + Allows backends to override the way commits are generated. + """ + return self.repo.get_commit(commit_id=commit_id, + pre_load=self.pre_load) + + def __getslice__(self, i, j): + """ + Returns an iterator of sliced repository + """ + commit_ids = self.commit_ids[i:j] + return self.__class__( + self.repo, commit_ids, pre_load=self.pre_load) + + def __repr__(self): + return '<CollectionGenerator[len:%s]>' % (self.__len__()) + + +class Config(object): + """ + Represents the configuration for a repository. + + The API is inspired by :class:`ConfigParser.ConfigParser` from the + standard library. It implements only the needed subset. + """ + + def __init__(self): + self._values = {} + + def copy(self): + clone = Config() + for section, values in self._values.items(): + clone._values[section] = values.copy() + return clone + + def __repr__(self): + return '<Config(%s values) at %s>' % (len(self._values), hex(id(self))) + + def items(self, section): + return self._values.get(section, {}).iteritems() + + def get(self, section, option): + return self._values.get(section, {}).get(option) + + def set(self, section, option, value): + section_values = self._values.setdefault(section, {}) + section_values[option] = value + + def clear_section(self, section): + self._values[section] = {} + + def serialize(self): + """ + Creates a list of three tuples (section, key, value) representing + this config object. + """ + items = [] + for section in self._values: + for option, value in self._values[section].items(): + items.append( + (safe_str(section), safe_str(option), safe_str(value))) + return items + + +class Diff(object): + """ + Represents a diff result from a repository backend. + + Subclasses have to provide a backend specific value for :attr:`_header_re`. + """ + + _header_re = None + + def __init__(self, raw_diff): + self.raw = raw_diff + + def chunks(self): + """ + split the diff in chunks of separate --git a/file b/file chunks + to make diffs consistent we must prepend with \n, and make sure + we can detect last chunk as this was also has special rule + """ + chunks = ('\n' + self.raw).split('\ndiff --git')[1:] + total_chunks = len(chunks) + return (DiffChunk(chunk, self, cur_chunk == total_chunks) + for cur_chunk, chunk in enumerate(chunks, start=1)) + + +class DiffChunk(object): + + def __init__(self, chunk, diff, last_chunk): + self._diff = diff + + # since we split by \ndiff --git that part is lost from original diff + # we need to re-apply it at the end, EXCEPT ! if it's last chunk + if not last_chunk: + chunk += '\n' + + match = self._diff._header_re.match(chunk) + self.header = match.groupdict() + self.diff = chunk[match.end():] + self.raw = chunk diff --git a/rhodecode/lib/vcs/backends/git/__init__.py b/rhodecode/lib/vcs/backends/git/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/git/__init__.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT module +""" + +import logging + +from rhodecode.lib.vcs import connection +from rhodecode.lib.vcs.backends.git.repository import GitRepository +from rhodecode.lib.vcs.backends.git.commit import GitCommit +from rhodecode.lib.vcs.backends.git.inmemory import GitInMemoryCommit + + +log = logging.getLogger(__name__) + + +def discover_git_version(): + """ + Returns the string as it was returned by running 'git --version' + + It will return an empty string in case the connection is not initialized + or no vcsserver is available. + """ + try: + return connection.Git.discover_git_version() + except Exception: + log.warning("Failed to discover the Git version", exc_info=True) + return '' diff --git a/rhodecode/lib/vcs/backends/git/commit.py b/rhodecode/lib/vcs/backends/git/commit.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/git/commit.py @@ -0,0 +1,527 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT commit module +""" + +import re +import stat +from ConfigParser import ConfigParser +from itertools import chain +from StringIO import StringIO + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.datelib import date_fromtimestamp +from rhodecode.lib.utils import safe_unicode, safe_str +from rhodecode.lib.utils2 import safe_int +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.backends import base +from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError +from rhodecode.lib.vcs.nodes import ( + FileNode, DirNode, NodeKind, RootNode, SubModuleNode, + ChangedFileNodesGenerator, AddedFileNodesGenerator, + RemovedFileNodesGenerator) + + +class GitCommit(base.BaseCommit): + """ + Represents state of the repository at single commit id. + """ + _author_property = 'author' + _committer_property = 'committer' + _date_property = 'commit_time' + _date_tz_property = 'commit_timezone' + _message_property = 'message' + _parents_property = 'parents' + + _filter_pre_load = [ + # done through a more complex tree walk on parents + "affected_files", + # based on repository cached property + "branch", + # done through subprocess not remote call + "children", + # done through a more complex tree walk on parents + "status", + # mercurial specific property not supported here + "_file_paths", + ] + + def __init__(self, repository, raw_id, idx, pre_load=None): + self.repository = repository + self._remote = repository._remote + # TODO: johbo: Tweak of raw_id should not be necessary + self.raw_id = safe_str(raw_id) + self.idx = idx + + self._set_bulk_properties(pre_load) + + # caches + self._stat_modes = {} # stat info for paths + self._paths = {} # path processed with parse_tree + self.nodes = {} + self._submodules = None + + def _set_bulk_properties(self, pre_load): + if not pre_load: + return + pre_load = [entry for entry in pre_load + if entry not in self._filter_pre_load] + if not pre_load: + return + + result = self._remote.bulk_request(self.raw_id, pre_load) + for attr, value in result.items(): + if attr in ["author", "message"]: + if value: + value = safe_unicode(value) + elif attr == "date": + value = date_fromtimestamp(*value) + elif attr == "parents": + value = self._make_commits(value) + self.__dict__[attr] = value + + @LazyProperty + def _commit(self): + return self._remote[self.raw_id] + + @LazyProperty + def _tree_id(self): + return self._remote[self._commit['tree']]['id'] + + @LazyProperty + def id(self): + return self.raw_id + + @LazyProperty + def short_id(self): + return self.raw_id[:12] + + @LazyProperty + def message(self): + return safe_unicode( + self._remote.commit_attribute(self.id, self._message_property)) + + @LazyProperty + def committer(self): + return safe_unicode( + self._remote.commit_attribute(self.id, self._committer_property)) + + @LazyProperty + def author(self): + return safe_unicode( + self._remote.commit_attribute(self.id, self._author_property)) + + @LazyProperty + def date(self): + unix_ts, tz = self._remote.get_object_attrs( + self.raw_id, self._date_property, self._date_tz_property) + return date_fromtimestamp(unix_ts, tz) + + @LazyProperty + def status(self): + """ + Returns modified, added, removed, deleted files for current commit + """ + return self.changed, self.added, self.removed + + @LazyProperty + def tags(self): + tags = [safe_unicode(name) for name, + commit_id in self.repository.tags.iteritems() + if commit_id == self.raw_id] + return tags + + @LazyProperty + def branch(self): + for name, commit_id in self.repository.branches.iteritems(): + if commit_id == self.raw_id: + return safe_unicode(name) + return None + + def _get_id_for_path(self, path): + path = safe_str(path) + if path in self._paths: + return self._paths[path] + + tree_id = self._tree_id + + path = path.strip('/') + if path == '': + data = [tree_id, "tree"] + self._paths[''] = data + return data + + parts = path.split('/') + dirs, name = parts[:-1], parts[-1] + cur_dir = '' + + # initially extract things from root dir + tree_items = self._remote.tree_items(tree_id) + self._process_tree_items(tree_items, cur_dir) + + for dir in dirs: + if cur_dir: + cur_dir = '/'.join((cur_dir, dir)) + else: + cur_dir = dir + dir_id = None + for item, stat_, id_, type_ in tree_items: + if item == dir: + dir_id = id_ + break + if dir_id: + if type_ != "tree": + raise CommitError('%s is not a directory' % cur_dir) + # update tree + tree_items = self._remote.tree_items(dir_id) + else: + raise CommitError('%s have not been found' % cur_dir) + + # cache all items from the given traversed tree + self._process_tree_items(tree_items, cur_dir) + + if path not in self._paths: + raise self.no_node_at_path(path) + + return self._paths[path] + + def _process_tree_items(self, items, cur_dir): + for item, stat_, id_, type_ in items: + if cur_dir: + name = '/'.join((cur_dir, item)) + else: + name = item + self._paths[name] = [id_, type_] + self._stat_modes[name] = stat_ + + def _get_kind(self, path): + path_id, type_ = self._get_id_for_path(path) + if type_ == 'blob': + return NodeKind.FILE + elif type_ == 'tree': + return NodeKind.DIR + elif type == 'link': + return NodeKind.SUBMODULE + return None + + def _get_filectx(self, path): + path = self._fix_path(path) + if self._get_kind(path) != NodeKind.FILE: + raise CommitError( + "File does not exist for commit %s at '%s'" % + (self.raw_id, path)) + return path + + def _get_file_nodes(self): + return chain(*(t[2] for t in self.walk())) + + @LazyProperty + def parents(self): + """ + Returns list of parent commits. + """ + parent_ids = self._remote.commit_attribute( + self.id, self._parents_property) + return self._make_commits(parent_ids) + + @LazyProperty + def children(self): + """ + Returns list of child commits. + """ + rev_filter = settings.GIT_REV_FILTER + output, __ = self.repository.run_git_command( + ['rev-list', '--children'] + rev_filter) + + child_ids = [] + pat = re.compile(r'^%s' % self.raw_id) + for l in output.splitlines(): + if pat.match(l): + found_ids = l.split(' ')[1:] + child_ids.extend(found_ids) + return self._make_commits(child_ids) + + def _make_commits(self, commit_ids): + return [self.repository.get_commit(commit_id=commit_id) + for commit_id in commit_ids] + + def get_file_mode(self, path): + """ + Returns stat mode of the file at the given `path`. + """ + path = safe_str(path) + # ensure path is traversed + self._get_id_for_path(path) + return self._stat_modes[path] + + def is_link(self, path): + return stat.S_ISLNK(self.get_file_mode(path)) + + def get_file_content(self, path): + """ + Returns content of the file at given `path`. + """ + id_, _ = self._get_id_for_path(path) + return self._remote.blob_as_pretty_string(id_) + + def get_file_size(self, path): + """ + Returns size of the file at given `path`. + """ + id_, _ = self._get_id_for_path(path) + return self._remote.blob_raw_length(id_) + + def get_file_history(self, path, limit=None, pre_load=None): + """ + Returns history of file as reversed list of `GitCommit` objects for + which file at given `path` has been modified. + + TODO: This function now uses an underlying 'git' command which works + quickly but ideally we should replace with an algorithm. + """ + self._get_filectx(path) + f_path = safe_str(path) + + cmd = ['log'] + if limit: + cmd.extend(['-n', str(safe_int(limit, 0))]) + cmd.extend(['--pretty=format: %H', '-s', self.raw_id, '--', f_path]) + + output, __ = self.repository.run_git_command(cmd) + commit_ids = re.findall(r'[0-9a-fA-F]{40}', output) + + return [ + self.repository.get_commit(commit_id=commit_id, pre_load=pre_load) + for commit_id in commit_ids] + + # TODO: unused for now potential replacement for subprocess + def get_file_history_2(self, path, limit=None, pre_load=None): + """ + Returns history of file as reversed list of `Commit` objects for + which file at given `path` has been modified. + """ + self._get_filectx(path) + f_path = safe_str(path) + + commit_ids = self._remote.get_file_history(f_path, self.id, limit) + + return [ + self.repository.get_commit(commit_id=commit_id, pre_load=pre_load) + for commit_id in commit_ids] + + def get_file_annotate(self, path, pre_load=None): + """ + Returns a generator of four element tuples with + lineno, commit_id, commit lazy loader and line + + TODO: This function now uses os underlying 'git' command which is + generally not good. Should be replaced with algorithm iterating + commits. + """ + cmd = ['blame', '-l', '--root', '-r', self.raw_id, '--', path] + # -l ==> outputs long shas (and we need all 40 characters) + # --root ==> doesn't put '^' character for bounderies + # -r commit_id ==> blames for the given commit + output, __ = self.repository.run_git_command(cmd) + + for i, blame_line in enumerate(output.split('\n')[:-1]): + line_no = i + 1 + commit_id, line = re.split(r' ', blame_line, 1) + yield ( + line_no, commit_id, + lambda: self.repository.get_commit(commit_id=commit_id, + pre_load=pre_load), + line) + + def get_nodes(self, path): + if self._get_kind(path) != NodeKind.DIR: + raise CommitError( + "Directory does not exist for commit %s at " + " '%s'" % (self.raw_id, path)) + path = self._fix_path(path) + id_, _ = self._get_id_for_path(path) + tree_id = self._remote[id_]['id'] + dirnodes = [] + filenodes = [] + alias = self.repository.alias + for name, stat_, id_, type_ in self._remote.tree_items(tree_id): + if type_ == 'link': + url = self._get_submodule_url('/'.join((path, name))) + dirnodes.append(SubModuleNode( + name, url=url, commit=id_, alias=alias)) + continue + + if path != '': + obj_path = '/'.join((path, name)) + else: + obj_path = name + if obj_path not in self._stat_modes: + self._stat_modes[obj_path] = stat_ + + if type_ == 'tree': + dirnodes.append(DirNode(obj_path, commit=self)) + elif type_ == 'blob': + filenodes.append(FileNode(obj_path, commit=self, mode=stat_)) + else: + raise CommitError( + "Requested object should be Tree or Blob, is %s", type_) + + nodes = dirnodes + filenodes + for node in nodes: + if node.path not in self.nodes: + self.nodes[node.path] = node + nodes.sort() + return nodes + + def get_node(self, path): + if isinstance(path, unicode): + path = path.encode('utf-8') + path = self._fix_path(path) + if path not in self.nodes: + try: + id_, type_ = self._get_id_for_path(path) + except CommitError: + raise NodeDoesNotExistError( + "Cannot find one of parents' directories for a given " + "path: %s" % path) + + if type_ == 'link': + url = self._get_submodule_url(path) + node = SubModuleNode(path, url=url, commit=id_, + alias=self.repository.alias) + elif type_ == 'tree': + if path == '': + node = RootNode(commit=self) + else: + node = DirNode(path, commit=self) + elif type_ == 'blob': + node = FileNode(path, commit=self) + else: + raise self.no_node_at_path(path) + + # cache node + self.nodes[path] = node + return self.nodes[path] + + @LazyProperty + def affected_files(self): + """ + Gets a fast accessible file changes for given commit + """ + added, modified, deleted = self._changes_cache + return list(added.union(modified).union(deleted)) + + @LazyProperty + def _changes_cache(self): + added = set() + modified = set() + deleted = set() + _r = self._remote + + parents = self.parents + if not self.parents: + parents = [base.EmptyCommit()] + for parent in parents: + if isinstance(parent, base.EmptyCommit): + oid = None + else: + oid = parent.raw_id + changes = _r.tree_changes(oid, self.raw_id) + for (oldpath, newpath), (_, _), (_, _) in changes: + if newpath and oldpath: + modified.add(newpath) + elif newpath and not oldpath: + added.add(newpath) + elif not newpath and oldpath: + deleted.add(oldpath) + return added, modified, deleted + + def _get_paths_for_status(self, status): + """ + Returns sorted list of paths for given ``status``. + + :param status: one of: *added*, *modified* or *deleted* + """ + added, modified, deleted = self._changes_cache + return sorted({ + 'added': list(added), + 'modified': list(modified), + 'deleted': list(deleted)}[status] + ) + + @LazyProperty + def added(self): + """ + Returns list of added ``FileNode`` objects. + """ + if not self.parents: + return list(self._get_file_nodes()) + return AddedFileNodesGenerator( + [n for n in self._get_paths_for_status('added')], self) + + @LazyProperty + def changed(self): + """ + Returns list of modified ``FileNode`` objects. + """ + if not self.parents: + return [] + return ChangedFileNodesGenerator( + [n for n in self._get_paths_for_status('modified')], self) + + @LazyProperty + def removed(self): + """ + Returns list of removed ``FileNode`` objects. + """ + if not self.parents: + return [] + return RemovedFileNodesGenerator( + [n for n in self._get_paths_for_status('deleted')], self) + + def _get_submodule_url(self, submodule_path): + git_modules_path = '.gitmodules' + + if self._submodules is None: + self._submodules = {} + + try: + submodules_node = self.get_node(git_modules_path) + except NodeDoesNotExistError: + return None + + content = submodules_node.content + + # ConfigParser fails if there are whitespaces + content = '\n'.join(l.strip() for l in content.split('\n')) + + parser = ConfigParser() + parser.readfp(StringIO(content)) + + for section in parser.sections(): + path = parser.get(section, 'path') + url = parser.get(section, 'url') + if path and url: + self._submodules[path.strip('/')] = url + + return self._submodules.get(submodule_path.strip('/')) diff --git a/rhodecode/lib/vcs/backends/git/diff.py b/rhodecode/lib/vcs/backends/git/diff.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/git/diff.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT diff module +""" + +import re + +from rhodecode.lib.vcs.backends import base + + +class GitDiff(base.Diff): + + _header_re = re.compile(r""" + #^diff[ ]--git + [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n + (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n + ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n + ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))? + (?:^old[ ]mode[ ](?P<old_mode>\d+)\n + ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))? + (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))? + (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))? + (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+) + \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? + (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))? + (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))? + (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))? + """, re.VERBOSE | re.MULTILINE) diff --git a/rhodecode/lib/vcs/backends/git/inmemory.py b/rhodecode/lib/vcs/backends/git/inmemory.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/git/inmemory.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT inmemory module +""" + +from rhodecode.lib.datelib import date_to_timestamp_plus_offset +from rhodecode.lib.utils import safe_str +from rhodecode.lib.vcs.backends import base + + +class GitInMemoryCommit(base.BaseInMemoryCommit): + + def commit(self, message, author, parents=None, branch=None, date=None, + **kwargs): + """ + Performs in-memory commit (doesn't check workdir in any way) and + returns newly created `GitCommit`. Updates repository's + `commit_ids`. + + :param message: message of the commit + :param author: full username, i.e. "Joe Doe <joe.doe@example.com>" + :param parents: single parent or sequence of parents from which commit + would be derived + :param date: `datetime.datetime` instance. Defaults to + ``datetime.datetime.now()``. + :param branch: branch name, as string. If none given, default backend's + branch would be used. + + :raises `CommitError`: if any error occurs while committing + """ + self.check_integrity(parents) + if branch is None: + branch = self.repository.DEFAULT_BRANCH_NAME + + ENCODING = "UTF-8" + + commit_tree = None + if self.parents[0]: + commit_tree = self.parents[0]._commit['tree'] + + updated = [] + for node in self.added + self.changed: + if not node.is_binary: + content = node.content.encode(ENCODING) + else: + content = node.content + updated.append({ + 'path': node.path, + 'node_path': node.name.encode(ENCODING), + 'content': content, + 'mode': node.mode, + }) + + removed = [node.path for node in self.removed] + + date, tz = date_to_timestamp_plus_offset(date) + + # TODO: johbo: Make kwargs explicit and check if this is needed. + author_time = kwargs.pop('author_time', date) + author_tz = kwargs.pop('author_timezone', tz) + + commit_data = { + 'parents': [p._commit['id'] for p in self.parents if p], + 'author': safe_str(author), + 'committer': safe_str(author), + 'encoding': ENCODING, + 'message': safe_str(message), + 'commit_time': int(date), + 'author_time': int(author_time), + 'commit_timezone': tz, + 'author_timezone': author_tz, + } + + commit_id = self.repository._remote.commit( + commit_data, branch, commit_tree, updated, removed) + + # Update vcs repository object + self.repository.commit_ids.append(commit_id) + self.repository._rebuild_cache(self.repository.commit_ids) + + # invalidate parsed refs after commit + self.repository._parsed_refs = self.repository._get_parsed_refs() + self.repository.branches = self.repository._get_branches() + tip = self.repository.get_commit() + self.reset() + return tip diff --git a/rhodecode/lib/vcs/backends/git/repository.py b/rhodecode/lib/vcs/backends/git/repository.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/git/repository.py @@ -0,0 +1,906 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT repository module +""" + +import logging +import os +import re +import shutil +import time + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.datelib import makedate, date_fromtimestamp +from rhodecode.lib.utils import safe_unicode, safe_str +from rhodecode.lib.vcs import connection, path as vcspath +from rhodecode.lib.vcs.backends.base import ( + BaseRepository, CollectionGenerator, Config, MergeResponse, + MergeFailureReason) +from rhodecode.lib.vcs.backends.git.commit import GitCommit +from rhodecode.lib.vcs.backends.git.diff import GitDiff +from rhodecode.lib.vcs.backends.git.inmemory import GitInMemoryCommit +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import ( + CommitDoesNotExistError, EmptyRepositoryError, + RepositoryError, TagAlreadyExistError, TagDoesNotExistError, VCSError) + + +SHA_PATTERN = re.compile(r'^[[0-9a-fA-F]{12}|[0-9a-fA-F]{40}]$') + +log = logging.getLogger(__name__) + + +class GitRepository(BaseRepository): + """ + Git repository backend. + """ + DEFAULT_BRANCH_NAME = 'master' + + contact = BaseRepository.DEFAULT_CONTACT + + def __init__(self, repo_path, config=None, create=False, src_url=None, + update_after_clone=False, with_wire=None, bare=False): + + self.path = safe_str(os.path.abspath(repo_path)) + self.config = config if config else Config() + self._remote = connection.Git( + self.path, self.config, with_wire=with_wire) + + self._init_repo(create, src_url, update_after_clone, bare) + + # caches + self._commit_ids = {} + + self.bookmarks = {} + + @LazyProperty + def bare(self): + return self._remote.bare() + + @LazyProperty + def head(self): + return self._remote.head() + + @LazyProperty + def commit_ids(self): + """ + Returns list of commit ids, in ascending order. Being lazy + attribute allows external tools to inject commit ids from cache. + """ + commit_ids = self._get_all_commit_ids() + self._rebuild_cache(commit_ids) + return commit_ids + + def _rebuild_cache(self, commit_ids): + self._commit_ids = dict((commit_id, index) + for index, commit_id in enumerate(commit_ids)) + + def run_git_command(self, cmd, **opts): + """ + Runs given ``cmd`` as git command and returns tuple + (stdout, stderr). + + :param cmd: git command to be executed + :param opts: env options to pass into Subprocess command + """ + if not isinstance(cmd, list): + raise ValueError('cmd must be a list, got %s instead' % type(cmd)) + + out, err = self._remote.run_git_command(cmd, **opts) + log.debug('Stderr output of git command "%s":\n%s', cmd, err) + return out, err + + @staticmethod + def check_url(url, config): + """ + Function will check given url and try to verify if it's a valid + link. Sometimes it may happened that git will issue basic + auth request that can cause whole API to hang when used from python + or other external calls. + + On failures it'll raise urllib2.HTTPError, exception is also thrown + when the return code is non 200 + """ + # check first if it's not an url + if os.path.isdir(url) or url.startswith('file:'): + return True + + if '+' in url.split('://', 1)[0]: + url = url.split('+', 1)[1] + + # Request the _remote to verify the url + return connection.Git.check_url(url, config.serialize()) + + @staticmethod + def is_valid_repository(path): + if os.path.isdir(os.path.join(path, '.git')): + return True + # check case of bare repository + try: + GitRepository(path) + return True + except VCSError: + pass + return False + + def _init_repo(self, create, src_url=None, update_after_clone=False, + bare=False): + if create and os.path.exists(self.path): + raise RepositoryError( + "Cannot create repository at %s, location already exist" + % self.path) + + try: + if create and src_url: + GitRepository.check_url(src_url, self.config) + self.clone(src_url, update_after_clone, bare) + elif create: + os.makedirs(self.path, mode=0755) + + if bare: + self._remote.init_bare() + else: + self._remote.init() + else: + self._remote.assert_correct_path() + # TODO: johbo: check if we have to translate the OSError here + except OSError as err: + raise RepositoryError(err) + + def _get_all_commit_ids(self, filters=None): + # we must check if this repo is not empty, since later command + # fails if it is. And it's cheaper to ask than throw the subprocess + # errors + try: + self._remote.head() + except KeyError: + return [] + + rev_filter = ['--branches', '--tags'] + extra_filter = [] + + if filters: + if filters.get('since'): + extra_filter.append('--since=%s' % (filters['since'])) + if filters.get('until'): + extra_filter.append('--until=%s' % (filters['until'])) + if filters.get('branch_name'): + rev_filter = ['--tags'] + extra_filter.append(filters['branch_name']) + rev_filter.extend(extra_filter) + + # if filters.get('start') or filters.get('end'): + # # skip is offset, max-count is limit + # if filters.get('start'): + # extra_filter += ' --skip=%s' % filters['start'] + # if filters.get('end'): + # extra_filter += ' --max-count=%s' % (filters['end'] - (filters['start'] or 0)) + + cmd = ['rev-list', '--reverse', '--date-order'] + rev_filter + try: + output, __ = self.run_git_command(cmd) + except RepositoryError: + # Can be raised for empty repositories + return [] + return output.splitlines() + + def _get_all_commit_ids2(self): + # alternate implementation + includes = [x[1][0] for x in self._parsed_refs.iteritems() + if x[1][1] != 'T'] + return [c.commit.id for c in self._remote.get_walker(include=includes)] + + def _get_commit_id(self, commit_id_or_idx): + def is_null(value): + return len(value) == commit_id_or_idx.count('0') + + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + + if commit_id_or_idx in (None, '', 'tip', 'HEAD', 'head', -1): + return self.commit_ids[-1] + + is_bstr = isinstance(commit_id_or_idx, (str, unicode)) + if ((is_bstr and commit_id_or_idx.isdigit() and len(commit_id_or_idx) < 12) + or isinstance(commit_id_or_idx, int) or is_null(commit_id_or_idx)): + try: + commit_id_or_idx = self.commit_ids[int(commit_id_or_idx)] + except Exception: + msg = "Commit %s does not exist for %s" % ( + commit_id_or_idx, self) + raise CommitDoesNotExistError(msg) + + elif is_bstr: + # get by branch/tag name + ref_id = self._parsed_refs.get(commit_id_or_idx) + if ref_id: # and ref_id[1] in ['H', 'RH', 'T']: + return ref_id[0] + + tag_ids = self.tags.values() + # maybe it's a tag ? we don't have them in self.commit_ids + if commit_id_or_idx in tag_ids: + return commit_id_or_idx + + elif (not SHA_PATTERN.match(commit_id_or_idx) or + commit_id_or_idx not in self.commit_ids): + msg = "Commit %s does not exist for %s" % ( + commit_id_or_idx, self) + raise CommitDoesNotExistError(msg) + + # Ensure we return full id + if not SHA_PATTERN.match(str(commit_id_or_idx)): + raise CommitDoesNotExistError( + "Given commit id %s not recognized" % commit_id_or_idx) + return commit_id_or_idx + + def get_hook_location(self): + """ + returns absolute path to location where hooks are stored + """ + loc = os.path.join(self.path, 'hooks') + if not self.bare: + loc = os.path.join(self.path, '.git', 'hooks') + return loc + + @LazyProperty + def last_change(self): + """ + Returns last change made on this repository as + `datetime.datetime` object. + """ + return date_fromtimestamp(self._get_mtime(), makedate()[1]) + + def _get_mtime(self): + try: + return time.mktime(self.get_commit().date.timetuple()) + except RepositoryError: + idx_loc = '' if self.bare else '.git' + # fallback to filesystem + in_path = os.path.join(self.path, idx_loc, "index") + he_path = os.path.join(self.path, idx_loc, "HEAD") + if os.path.exists(in_path): + return os.stat(in_path).st_mtime + else: + return os.stat(he_path).st_mtime + + @LazyProperty + def description(self): + description = self._remote.get_description() + return safe_unicode(description or self.DEFAULT_DESCRIPTION) + + def _get_refs_entry(self, value, reverse): + if self.is_empty(): + return {} + + def get_name(ctx): + return ctx[0] + + _branches = [ + (safe_unicode(x[0]), x[1][0]) + for x in self._parsed_refs.iteritems() if x[1][1] == value] + return OrderedDict(sorted(_branches, key=get_name, reverse=reverse)) + + def _get_branches(self): + return self._get_refs_entry('H', False) + + @LazyProperty + def branches(self): + return self._get_branches() + + @LazyProperty + def branches_closed(self): + return {} + + @LazyProperty + def branches_all(self): + all_branches = {} + all_branches.update(self.branches) + all_branches.update(self.branches_closed) + return all_branches + + @LazyProperty + def tags(self): + return self._get_tags() + + def _get_tags(self): + return self._get_refs_entry('T', True) + + def tag(self, name, user, commit_id=None, message=None, date=None, + **kwargs): + """ + Creates and returns a tag for the given ``commit_id``. + + :param name: name for new tag + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param commit_id: commit id for which new tag would be created + :param message: message of the tag's commit + :param date: date of tag's commit + + :raises TagAlreadyExistError: if tag with same name already exists + """ + if name in self.tags: + raise TagAlreadyExistError("Tag %s already exists" % name) + commit = self.get_commit(commit_id=commit_id) + message = message or "Added tag %s for commit %s" % ( + name, commit.raw_id) + self._remote.set_refs('refs/tags/%s' % name, commit._commit['id']) + + self._parsed_refs = self._get_parsed_refs() + self.tags = self._get_tags() + return commit + + def remove_tag(self, name, user, message=None, date=None): + """ + Removes tag with the given ``name``. + + :param name: name of the tag to be removed + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param message: message of the tag's removal commit + :param date: date of tag's removal commit + + :raises TagDoesNotExistError: if tag with given name does not exists + """ + if name not in self.tags: + raise TagDoesNotExistError("Tag %s does not exist" % name) + tagpath = vcspath.join( + self._remote.get_refs_path(), 'refs', 'tags', name) + try: + os.remove(tagpath) + self._parsed_refs = self._get_parsed_refs() + self.tags = self._get_tags() + except OSError as e: + raise RepositoryError(e.strerror) + + @LazyProperty + def _parsed_refs(self): + return self._get_parsed_refs() + + def _get_parsed_refs(self): + # TODO: (oliver) who needs RH; branches? + # Remote Heads were commented out, as they may overwrite local branches + # See the TODO note in rhodecode.lib.vcs.remote.git:get_refs for more + # details. + keys = [('refs/heads/', 'H'), + #('refs/remotes/origin/', 'RH'), + ('refs/tags/', 'T')] + return self._remote.get_refs(keys=keys) + + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): + """ + Returns `GitCommit` object representing commit from git repository + at the given `commit_id` or head (most recent commit) if None given. + """ + if commit_id is not None: + self._validate_commit_id(commit_id) + elif commit_idx is not None: + self._validate_commit_idx(commit_idx) + commit_id = commit_idx + commit_id = self._get_commit_id(commit_id) + try: + # Need to call remote to translate id for tagging scenario + commit_id = self._remote.get_object(commit_id)["commit_id"] + idx = self._commit_ids[commit_id] + except KeyError: + raise RepositoryError("Cannot get object with id %s" % commit_id) + + return GitCommit(self, commit_id, idx, pre_load=pre_load) + + def get_commits( + self, start_id=None, end_id=None, start_date=None, end_date=None, + branch_name=None, pre_load=None): + """ + Returns generator of `GitCommit` objects from start to end (both + are inclusive), in ascending date order. + + :param start_id: None, str(commit_id) + :param end_id: None, str(commit_id) + :param start_date: if specified, commits with commit date less than + ``start_date`` would be filtered out from returned set + :param end_date: if specified, commits with commit date greater than + ``end_date`` would be filtered out from returned set + :param branch_name: if specified, commits not reachable from given + branch would be filtered out from returned set + + :raise BranchDoesNotExistError: If given `branch_name` does not + exist. + :raise CommitDoesNotExistError: If commits for given `start` or + `end` could not be found. + + """ + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + self._validate_branch_name(branch_name) + + if start_id is not None: + self._validate_commit_id(start_id) + if end_id is not None: + self._validate_commit_id(end_id) + + start_raw_id = self._get_commit_id(start_id) + start_pos = self._commit_ids[start_raw_id] if start_id else None + end_raw_id = self._get_commit_id(end_id) + end_pos = max(0, self._commit_ids[end_raw_id]) if end_id else None + + if None not in [start_id, end_id] and start_pos > end_pos: + raise RepositoryError( + "Start commit '%s' cannot be after end commit '%s'" % + (start_id, end_id)) + + if end_pos is not None: + end_pos += 1 + + filter_ = [] + if branch_name: + filter_.append({'branch_name': branch_name}) + if start_date and not end_date: + filter_.append({'since': start_date}) + if end_date and not start_date: + filter_.append({'until': end_date}) + if start_date and end_date: + filter_.append({'since': start_date}) + filter_.append({'until': end_date}) + + # if start_pos or end_pos: + # filter_.append({'start': start_pos}) + # filter_.append({'end': end_pos}) + + if filter_: + revfilters = { + 'branch_name': branch_name, + 'since': start_date.strftime('%m/%d/%y %H:%M:%S') if start_date else None, + 'until': end_date.strftime('%m/%d/%y %H:%M:%S') if end_date else None, + 'start': start_pos, + 'end': end_pos, + } + commit_ids = self._get_all_commit_ids(filters=revfilters) + + # pure python stuff, it's slow due to walker walking whole repo + # def get_revs(walker): + # for walker_entry in walker: + # yield walker_entry.commit.id + # revfilters = {} + # commit_ids = list(reversed(list(get_revs(self._repo.get_walker(**revfilters))))) + else: + commit_ids = self.commit_ids + + if start_pos or end_pos: + commit_ids = commit_ids[start_pos: end_pos] + + return CollectionGenerator(self, commit_ids, pre_load=pre_load) + + def get_diff( + self, commit1, commit2, path='', ignore_whitespace=False, + context=3, path1=None): + """ + Returns (git like) *diff*, as plain text. Shows changes introduced by + ``commit2`` since ``commit1``. + + :param commit1: Entry point from which diff is shown. Can be + ``self.EMPTY_COMMIT`` - in this case, patch showing all + the changes since empty state of the repository until ``commit2`` + :param commit2: Until which commits changes should be shown. + :param ignore_whitespace: If set to ``True``, would not show whitespace + changes. Defaults to ``False``. + :param context: How many lines before/after changed lines should be + shown. Defaults to ``3``. + """ + self._validate_diff_commits(commit1, commit2) + if path1 is not None and path1 != path: + raise ValueError("Diff of two different paths not supported.") + + flags = [ + '-U%s' % context, '--full-index', '--binary', '-p', + '-M', '--abbrev=40'] + if ignore_whitespace: + flags.append('-w') + + if commit1 == self.EMPTY_COMMIT: + cmd = ['show'] + flags + [commit2.raw_id] + else: + cmd = ['diff'] + flags + [commit1.raw_id, commit2.raw_id] + + if path: + cmd.extend(['--', path]) + + stdout, __ = self.run_git_command(cmd) + # If we used 'show' command, strip first few lines (until actual diff + # starts) + if commit1 == self.EMPTY_COMMIT: + lines = stdout.splitlines() + x = 0 + for line in lines: + if line.startswith('diff'): + break + x += 1 + # Append new line just like 'diff' command do + stdout = '\n'.join(lines[x:]) + '\n' + return GitDiff(stdout) + + def strip(self, commit_id, branch_name): + commit = self.get_commit(commit_id=commit_id) + if commit.merge: + raise Exception('Cannot reset to merge commit') + + # parent is going to be the new head now + commit = commit.parents[0] + self._remote.set_refs('refs/heads/%s' % branch_name, commit.raw_id) + + self.commit_ids = self._get_all_commit_ids() + self._rebuild_cache(self.commit_ids) + + def get_common_ancestor(self, commit_id1, commit_id2, repo2): + if commit_id1 == commit_id2: + return commit_id1 + + if self != repo2: + commits = self._remote.get_missing_revs( + commit_id1, commit_id2, repo2.path) + if commits: + commit = repo2.get_commit(commits[-1]) + if commit.parents: + ancestor_id = commit.parents[0].raw_id + else: + ancestor_id = None + else: + # no commits from other repo, ancestor_id is the commit_id2 + ancestor_id = commit_id2 + else: + output, __ = self.run_git_command( + ['merge-base', commit_id1, commit_id2]) + ancestor_id = re.findall(r'[0-9a-fA-F]{40}', output)[0] + + return ancestor_id + + def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None): + repo1 = self + ancestor_id = None + + if commit_id1 == commit_id2: + commits = [] + elif repo1 != repo2: + missing_ids = self._remote.get_missing_revs(commit_id1, commit_id2, + repo2.path) + commits = [ + repo2.get_commit(commit_id=commit_id, pre_load=pre_load) + for commit_id in reversed(missing_ids)] + else: + output, __ = repo1.run_git_command( + ['log', '--reverse', '--pretty=format: %H', '-s', + '%s..%s' % (commit_id1, commit_id2)]) + commits = [ + repo1.get_commit(commit_id=commit_id, pre_load=pre_load) + for commit_id in re.findall(r'[0-9a-fA-F]{40}', output)] + + return commits + + @LazyProperty + def in_memory_commit(self): + """ + Returns ``GitInMemoryCommit`` object for this repository. + """ + return GitInMemoryCommit(self) + + def clone(self, url, update_after_clone=True, bare=False): + """ + Tries to clone commits from external location. + + :param update_after_clone: If set to ``False``, git won't checkout + working directory + :param bare: If set to ``True``, repository would be cloned into + *bare* git repository (no working directory at all). + """ + # init_bare and init expect empty dir created to proceed + if not os.path.exists(self.path): + os.mkdir(self.path) + + if bare: + self._remote.init_bare() + else: + self._remote.init() + + deferred = '^{}' + valid_refs = ('refs/heads', 'refs/tags', 'HEAD') + + return self._remote.clone( + url, deferred, valid_refs, update_after_clone) + + def pull(self, url, commit_ids=None): + """ + Tries to pull changes from external location. We use fetch here since + pull in get does merges and we want to be compatible with hg backend so + pull == fetch in this case + """ + self.fetch(url, commit_ids=commit_ids) + + def fetch(self, url, commit_ids=None): + """ + Tries to fetch changes from external location. + """ + refs = None + + if commit_ids is not None: + remote_refs = self._remote.get_remote_refs(url) + refs = [ + ref for ref in remote_refs if remote_refs[ref] in commit_ids] + self._remote.fetch(url, refs=refs) + + def set_refs(self, ref_name, commit_id): + self._remote.set_refs(ref_name, commit_id) + + def remove_ref(self, ref_name): + self._remote.remove_ref(ref_name) + + def _update_server_info(self): + """ + runs gits update-server-info command in this repo instance + """ + self._remote.update_server_info() + + def _current_branch(self): + """ + Return the name of the current branch. + + It only works for non bare repositories (i.e. repositories with a + working copy) + """ + if self.bare: + raise RepositoryError('Bare git repos do not have active branches') + + if self.is_empty(): + return None + + stdout, _ = self.run_git_command(['rev-parse', '--abbrev-ref', 'HEAD']) + return stdout.strip() + + def _checkout(self, branch_name, create=False): + """ + Checkout a branch in the working directory. + + It tries to create the branch if create is True, failing if the branch + already exists. + + It only works for non bare repositories (i.e. repositories with a + working copy) + """ + if self.bare: + raise RepositoryError('Cannot checkout branches in a bare git repo') + + cmd = ['checkout'] + if create: + cmd.append('-b') + cmd.append(branch_name) + self.run_git_command(cmd, fail_on_stderr=False) + + def _local_clone(self, clone_path, branch_name): + """ + Create a local clone of the current repo. + """ + # N.B.(skreft): the --branch option is required as otherwise the shallow + # clone will only fetch the active branch. + cmd = ['clone', '--branch', branch_name, '--single-branch', + self.path, os.path.abspath(clone_path)] + self.run_git_command(cmd, fail_on_stderr=False) + + def _local_fetch(self, repository_path, branch_name): + """ + Fetch a branch from a local repository. + """ + repository_path = os.path.abspath(repository_path) + if repository_path == self.path: + raise ValueError('Cannot fetch from the same repository') + + cmd = ['fetch', '--no-tags', repository_path, branch_name] + self.run_git_command(cmd, fail_on_stderr=False) + + def _last_fetch_heads(self): + """ + Return the last fetched heads that need merging. + + The algorithm is defined at + https://github.com/git/git/blob/v2.1.3/git-pull.sh#L283 + """ + if not self.bare: + fetch_heads_path = os.path.join(self.path, '.git', 'FETCH_HEAD') + else: + fetch_heads_path = os.path.join(self.path, 'FETCH_HEAD') + + heads = [] + with open(fetch_heads_path) as f: + for line in f: + if ' not-for-merge ' in line: + continue + line = re.sub('\t.*', '', line, flags=re.DOTALL) + heads.append(line) + + return heads + + def _local_pull(self, repository_path, branch_name): + """ + Pull a branch from a local repository. + """ + if self.bare: + raise RepositoryError('Cannot pull into a bare git repository') + # N.B.(skreft): The --ff-only option is to make sure this is a + # fast-forward (i.e., we are only pulling new changes and there are no + # conflicts with our current branch) + # Additionally, that option needs to go before --no-tags, otherwise git + # pull complains about it being an unknown flag. + cmd = ['pull', '--ff-only', '--no-tags', repository_path, branch_name] + self.run_git_command(cmd, fail_on_stderr=False) + + def _local_merge(self, merge_message, user_name, user_email, heads): + """ + Merge the given head into the checked out branch. + + It will force a merge commit. + + Currently it raises an error if the repo is empty, as it is not possible + to create a merge commit in an empty repo. + + :param merge_message: The message to use for the merge commit. + :param heads: the heads to merge. + """ + if self.bare: + raise RepositoryError('Cannot merge into a bare git repository') + + if not heads: + return + + if self.is_empty(): + # TODO(skreft): do somehting more robust in this case. + raise RepositoryError( + 'Do not know how to merge into empty repositories yet') + + # N.B.(skreft): the --no-ff option is used to enforce the creation of a + # commit message. We also specify the user who is doing the merge. + cmd = ['-c', 'user.name=%s' % safe_str(user_name), + '-c', 'user.email=%s' % safe_str(user_email), + 'merge', '--no-ff', '-m', safe_str(merge_message)] + cmd.extend(heads) + try: + self.run_git_command(cmd, fail_on_stderr=False) + except RepositoryError: + # Cleanup any merge leftovers + self.run_git_command(['merge', '--abort'], fail_on_stderr=False) + raise + + def _local_push( + self, source_branch, repository_path, target_branch, + enable_hooks=False, rc_scm_data=None): + """ + Push the source_branch to the given repository and target_branch. + + Currently it if the target_branch is not master and the target repo is + empty, the push will work, but then GitRepository won't be able to find + the pushed branch or the commits. As the HEAD will be corrupted (i.e., + pointing to master, which does not exist). + + It does not run the hooks in the target repo. + """ + # TODO(skreft): deal with the case in which the target repo is empty, + # and the target_branch is not master. + target_repo = GitRepository(repository_path) + if (not target_repo.bare and + target_repo._current_branch() == target_branch): + # Git prevents pushing to the checked out branch, so simulate it by + # pulling into the target repository. + target_repo._local_pull(self.path, source_branch) + else: + cmd = ['push', os.path.abspath(repository_path), + '%s:%s' % (source_branch, target_branch)] + gitenv = {} + if rc_scm_data: + gitenv.update({'RC_SCM_DATA': rc_scm_data}) + + if not enable_hooks: + gitenv['RC_SKIP_HOOKS'] = '1' + self.run_git_command(cmd, fail_on_stderr=False, extra_env=gitenv) + + def _get_new_pr_branch(self, source_branch, target_branch): + prefix = 'pr_%s-%s_' % (source_branch, target_branch) + pr_branches = [] + for branch in self.branches: + if branch.startswith(prefix): + pr_branches.append(int(branch[len(prefix):])) + + if not pr_branches: + branch_id = 0 + else: + branch_id = max(pr_branches) + 1 + + return '%s%d' % (prefix, branch_id) + + def _merge_repo(self, shadow_repository_path, target_ref, + source_repo, source_ref, merge_message, + merger_name, merger_email, dry_run=False): + if target_ref.commit_id != self.branches[target_ref.name]: + return MergeResponse( + False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD) + + shadow_repo = GitRepository(shadow_repository_path) + shadow_repo._checkout(target_ref.name) + shadow_repo._local_pull(self.path, target_ref.name) + # Need to reload repo to invalidate the cache, or otherwise we cannot + # retrieve the last target commit. + shadow_repo = GitRepository(shadow_repository_path) + if target_ref.commit_id != shadow_repo.branches[target_ref.name]: + return MergeResponse( + False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD) + + pr_branch = shadow_repo._get_new_pr_branch( + source_ref.name, target_ref.name) + shadow_repo._checkout(pr_branch, create=True) + try: + shadow_repo._local_fetch(source_repo.path, source_ref.name) + except RepositoryError: + return MergeResponse( + False, False, None, MergeFailureReason.MISSING_COMMIT) + + merge_commit_id = None + merge_failure_reason = MergeFailureReason.NONE + try: + shadow_repo._local_merge(merge_message, merger_name, merger_email, + [source_ref.commit_id]) + merge_possible = True + except RepositoryError: + merge_possible = False + merge_failure_reason = MergeFailureReason.MERGE_FAILED + + if merge_possible and not dry_run: + try: + shadow_repo._local_push( + pr_branch, self.path, target_ref.name, enable_hooks=True, + rc_scm_data=self.config.get('rhodecode', 'RC_SCM_DATA')) + merge_succeeded = True + # Need to reload repo to invalidate the cache, or otherwise we + # cannot retrieve the merge commit. + shadow_repo = GitRepository(shadow_repository_path) + merge_commit_id = shadow_repo.branches[pr_branch] + except RepositoryError: + merge_succeeded = False + merge_failure_reason = MergeFailureReason.PUSH_FAILED + else: + merge_succeeded = False + + return MergeResponse( + merge_possible, merge_succeeded, merge_commit_id, + merge_failure_reason) + + def _get_shadow_repository_path(self, workspace_id): + # The name of the shadow repository must start with '.', so it is + # skipped by 'rhodecode.lib.utils.get_filesystem_repos'. + return os.path.join( + os.path.dirname(self.path), + '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id)) + + def _maybe_prepare_merge_workspace(self, workspace_id, target_ref): + shadow_repository_path = self._get_shadow_repository_path(workspace_id) + if not os.path.exists(shadow_repository_path): + self._local_clone(shadow_repository_path, target_ref.name) + + return shadow_repository_path + + def cleanup_merge_workspace(self, workspace_id): + shadow_repository_path = self._get_shadow_repository_path(workspace_id) + shutil.rmtree(shadow_repository_path, ignore_errors=True) diff --git a/rhodecode/lib/vcs/backends/hg/__init__.py b/rhodecode/lib/vcs/backends/hg/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/hg/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +HG module +""" + +from rhodecode.lib.vcs.backends.hg.commit import MercurialCommit +from rhodecode.lib.vcs.backends.hg.inmemory import MercurialInMemoryCommit +from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository diff --git a/rhodecode/lib/vcs/backends/hg/commit.py b/rhodecode/lib/vcs/backends/hg/commit.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/hg/commit.py @@ -0,0 +1,362 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +HG commit module +""" + +import os + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.datelib import date_fromtimestamp +from rhodecode.lib.utils import safe_str, safe_unicode +from rhodecode.lib.vcs import path as vcspath +from rhodecode.lib.vcs.backends import base +from rhodecode.lib.vcs.backends.hg.diff import MercurialDiff +from rhodecode.lib.vcs.exceptions import CommitError +from rhodecode.lib.vcs.nodes import ( + AddedFileNodesGenerator, ChangedFileNodesGenerator, DirNode, FileNode, + NodeKind, RemovedFileNodesGenerator, RootNode, SubModuleNode, + LargeFileNode, LARGEFILE_PREFIX) +from rhodecode.lib.vcs.utils.paths import get_dirs_for_path + + +class MercurialCommit(base.BaseCommit): + """ + Represents state of the repository at the single commit. + """ + + _filter_pre_load = [ + # git specific property not supported here + "_commit", + ] + + def __init__(self, repository, raw_id, idx, pre_load=None): + raw_id = safe_str(raw_id) + + self.repository = repository + self._remote = repository._remote + + self.raw_id = raw_id + self.idx = repository._sanitize_commit_idx(idx) + + self._set_bulk_properties(pre_load) + + # caches + self.nodes = {} + + def _set_bulk_properties(self, pre_load): + if not pre_load: + return + pre_load = [entry for entry in pre_load + if entry not in self._filter_pre_load] + if not pre_load: + return + + result = self._remote.bulk_request(self.idx, pre_load) + for attr, value in result.items(): + if attr in ["author", "branch", "message"]: + value = safe_unicode(value) + elif attr == "affected_files": + value = map(safe_unicode, value) + elif attr == "date": + value = date_fromtimestamp(*value) + elif attr in ["children", "parents"]: + value = self._make_commits(value) + self.__dict__[attr] = value + + @LazyProperty + def tags(self): + tags = [name for name, commit_id in self.repository.tags.iteritems() + if commit_id == self.raw_id] + return tags + + @LazyProperty + def branch(self): + return safe_unicode(self._remote.ctx_branch(self.idx)) + + @LazyProperty + def bookmarks(self): + bookmarks = [ + name for name, commit_id in self.repository.bookmarks.iteritems() + if commit_id == self.raw_id] + return bookmarks + + @LazyProperty + def message(self): + return safe_unicode(self._remote.ctx_description(self.idx)) + + @LazyProperty + def committer(self): + return safe_unicode(self.author) + + @LazyProperty + def author(self): + return safe_unicode(self._remote.ctx_user(self.idx)) + + @LazyProperty + def date(self): + return date_fromtimestamp(*self._remote.ctx_date(self.idx)) + + @LazyProperty + def status(self): + """ + Returns modified, added, removed, deleted files for current commit + """ + return self._remote.ctx_status(self.idx) + + @LazyProperty + def _file_paths(self): + return self._remote.ctx_list(self.idx) + + @LazyProperty + def _dir_paths(self): + p = list(set(get_dirs_for_path(*self._file_paths))) + p.insert(0, '') + return p + + @LazyProperty + def _paths(self): + return self._dir_paths + self._file_paths + + @LazyProperty + def id(self): + if self.last: + return u'tip' + return self.short_id + + @LazyProperty + def short_id(self): + return self.raw_id[:12] + + def _make_commits(self, indexes): + return [self.repository.get_commit(commit_idx=idx) + for idx in indexes if idx >= 0] + + @LazyProperty + def parents(self): + """ + Returns list of parent commits. + """ + parents = self._remote.ctx_parents(self.idx) + return self._make_commits(parents) + + @LazyProperty + def children(self): + """ + Returns list of child commits. + """ + children = self._remote.ctx_children(self.idx) + return self._make_commits(children) + + def diff(self, ignore_whitespace=True, context=3): + result = self._remote.ctx_diff( + self.idx, + git=True, ignore_whitespace=ignore_whitespace, context=context) + diff = ''.join(result) + return MercurialDiff(diff) + + def _fix_path(self, path): + """ + Mercurial keeps filenodes as str so we need to encode from unicode + to str. + """ + return safe_str(super(MercurialCommit, self)._fix_path(path)) + + def _get_kind(self, path): + path = self._fix_path(path) + if path in self._file_paths: + return NodeKind.FILE + elif path in self._dir_paths: + return NodeKind.DIR + else: + raise CommitError( + "Node does not exist at the given path '%s'" % (path, )) + + def _get_filectx(self, path): + path = self._fix_path(path) + if self._get_kind(path) != NodeKind.FILE: + raise CommitError( + "File does not exist for idx %s at '%s'" % (self.raw_id, path)) + return path + + def get_file_mode(self, path): + """ + Returns stat mode of the file at the given ``path``. + """ + path = self._get_filectx(path) + if 'x' in self._remote.fctx_flags(self.idx, path): + return base.FILEMODE_EXECUTABLE + else: + return base.FILEMODE_DEFAULT + + def is_link(self, path): + path = self._get_filectx(path) + return 'l' in self._remote.fctx_flags(self.idx, path) + + def get_file_content(self, path): + """ + Returns content of the file at given ``path``. + """ + path = self._get_filectx(path) + return self._remote.fctx_data(self.idx, path) + + def get_file_size(self, path): + """ + Returns size of the file at given ``path``. + """ + path = self._get_filectx(path) + return self._remote.fctx_size(self.idx, path) + + def get_file_history(self, path, limit=None, pre_load=None): + """ + Returns history of file as reversed list of `MercurialCommit` objects + for which file at given ``path`` has been modified. + """ + path = self._get_filectx(path) + hist = self._remote.file_history(self.idx, path, limit) + return [ + self.repository.get_commit(commit_id=commit_id, pre_load=pre_load) + for commit_id in hist] + + def get_file_annotate(self, path, pre_load=None): + """ + Returns a generator of four element tuples with + lineno, commit_id, commit lazy loader and line + """ + result = self._remote.fctx_annotate(self.idx, path) + + for ln_no, commit_id, content in result: + yield ( + ln_no, commit_id, + lambda: self.repository.get_commit(commit_id=commit_id, + pre_load=pre_load), + content) + + def get_nodes(self, path): + """ + Returns combined ``DirNode`` and ``FileNode`` objects list representing + state of commit at the given ``path``. If node at the given ``path`` + is not instance of ``DirNode``, CommitError would be raised. + """ + + if self._get_kind(path) != NodeKind.DIR: + raise CommitError( + "Directory does not exist for idx %s at '%s'" % + (self.idx, path)) + path = self._fix_path(path) + + filenodes = [ + FileNode(f, commit=self) for f in self._file_paths + if os.path.dirname(f) == path] + # TODO: johbo: Check if this can be done in a more obvious way + dirs = path == '' and '' or [ + d for d in self._dir_paths + if d and vcspath.dirname(d) == path] + dirnodes = [ + DirNode(d, commit=self) for d in dirs + if os.path.dirname(d) == path] + + alias = self.repository.alias + for k, vals in self._submodules.iteritems(): + loc = vals[0] + commit = vals[1] + dirnodes.append( + SubModuleNode(k, url=loc, commit=commit, alias=alias)) + nodes = dirnodes + filenodes + # cache nodes + for node in nodes: + self.nodes[node.path] = node + nodes.sort() + + return nodes + + def get_node(self, path): + """ + Returns `Node` object from the given `path`. If there is no node at + the given `path`, `NodeDoesNotExistError` would be raised. + """ + path = self._fix_path(path) + + if path not in self.nodes: + if path in self._file_paths: + node = FileNode(path, commit=self) + elif path in self._dir_paths: + if path == '': + node = RootNode(commit=self) + else: + node = DirNode(path, commit=self) + else: + raise self.no_node_at_path(path) + + # cache node + self.nodes[path] = node + return self.nodes[path] + + def get_largefile_node(self, path): + path = os.path.join(LARGEFILE_PREFIX, path) + + if self._remote.is_large_file(path): + # content of that file regular FileNode is the hash of largefile + file_id = self.get_file_content(path).strip() + if self._remote.in_store(file_id): + path = self._remote.store_path(file_id) + return LargeFileNode(path, commit=self) + elif self._remote.in_user_cache(file_id): + path = self._remote.store_path(file_id) + self._remote.link(file_id, path) + return LargeFileNode(path, commit=self) + + @LazyProperty + def _submodules(self): + """ + Returns a dictionary with submodule information from substate file + of hg repository. + """ + return self._remote.ctx_substate(self.idx) + + @LazyProperty + def affected_files(self): + """ + Gets a fast accessible file changes for given commit + """ + return self._remote.ctx_files(self.idx) + + @property + def added(self): + """ + Returns list of added ``FileNode`` objects. + """ + return AddedFileNodesGenerator([n for n in self.status[1]], self) + + @property + def changed(self): + """ + Returns list of modified ``FileNode`` objects. + """ + return ChangedFileNodesGenerator([n for n in self.status[0]], self) + + @property + def removed(self): + """ + Returns list of removed ``FileNode`` objects. + """ + return RemovedFileNodesGenerator([n for n in self.status[2]], self) diff --git a/rhodecode/lib/vcs/backends/hg/diff.py b/rhodecode/lib/vcs/backends/hg/diff.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/hg/diff.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +GIT diff module +""" + +import re + +from rhodecode.lib.vcs.backends import base + + +class MercurialDiff(base.Diff): + + _header_re = re.compile(r""" + #^diff[ ]--git + [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n + (?:^old[ ]mode[ ](?P<old_mode>\d+)\n + ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))? + (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))? + (?:^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n + ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))? + (?:^copy[ ]from[ ](?P<copy_from>[^\r\n]+)\n + ^copy[ ]to[ ](?P<copy_to>[^\r\n]+)(?:\n|$))? + (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))? + (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))? + (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+) + \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? + (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))? + (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))? + (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))? + """, re.VERBOSE | re.MULTILINE) diff --git a/rhodecode/lib/vcs/backends/hg/inmemory.py b/rhodecode/lib/vcs/backends/hg/inmemory.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/hg/inmemory.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +HG inmemory module +""" + +from rhodecode.lib.datelib import date_to_timestamp_plus_offset +from rhodecode.lib.utils import safe_str +from rhodecode.lib.vcs.backends.base import BaseInMemoryCommit +from rhodecode.lib.vcs.exceptions import RepositoryError + + +class MercurialInMemoryCommit(BaseInMemoryCommit): + + def commit(self, message, author, parents=None, branch=None, date=None, + **kwargs): + """ + Performs in-memory commit (doesn't check workdir in any way) and + returns newly created `MercurialCommit`. Updates repository's + `commit_ids`. + + :param message: message of the commit + :param author: full username, i.e. "Joe Doe <joe.doe@example.com>" + :param parents: single parent or sequence of parents from which commit + would be derived + :param date: `datetime.datetime` instance. Defaults to + ``datetime.datetime.now()``. + :param branch: Optional. Branch name as unicode. Will use the backend's + default if not given. + + :raises `RepositoryError`: if any error occurs while committing + """ + self.check_integrity(parents) + + if not isinstance(message, unicode) or not isinstance(author, unicode): + # TODO: johbo: Should be a TypeError + raise RepositoryError('Given message and author needs to be ' + 'an <unicode> instance got %r & %r instead' + % (type(message), type(author))) + + if branch is None: + branch = self.repository.DEFAULT_BRANCH_NAME + kwargs['branch'] = safe_str(branch) + + message = safe_str(message) + author = safe_str(author) + + parent_ids = [p.raw_id if p else None for p in self.parents] + + ENCODING = "UTF-8" + + updated = [] + for node in self.added + self.changed: + if node.is_binary: + content = node.content + else: + content = node.content.encode(ENCODING) + updated.append({ + 'path': node.path, + 'content': content, + 'mode': node.mode, + }) + + removed = [node.path for node in self.removed] + + date, tz = date_to_timestamp_plus_offset(date) + + new_id = self.repository._remote.commitctx( + message=message, parents=parent_ids, + commit_time=date, commit_timezone=tz, user=author, + files=self.get_paths(), extra=kwargs, removed=removed, + updated=updated) + + self.repository.commit_ids.append(new_id) + self.repository._rebuild_cache(self.repository.commit_ids) + self.repository.branches = self.repository._get_branches() + tip = self.repository.get_commit() + self.reset() + return tip diff --git a/rhodecode/lib/vcs/backends/hg/repository.py b/rhodecode/lib/vcs/backends/hg/repository.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/hg/repository.py @@ -0,0 +1,770 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +HG repository module +""" + +import binascii +import os +import re +import shutil +import urllib + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.datelib import ( + date_fromtimestamp, makedate, date_to_timestamp_plus_offset, + date_astimestamp) +from rhodecode.lib.utils import safe_unicode, safe_str +from rhodecode.lib.vcs import connection +from rhodecode.lib.vcs.backends.base import ( + BaseRepository, CollectionGenerator, Config, MergeResponse, + MergeFailureReason) +from rhodecode.lib.vcs.backends.hg.commit import MercurialCommit +from rhodecode.lib.vcs.backends.hg.diff import MercurialDiff +from rhodecode.lib.vcs.backends.hg.inmemory import MercurialInMemoryCommit +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import ( + EmptyRepositoryError, RepositoryError, TagAlreadyExistError, + TagDoesNotExistError, CommitDoesNotExistError) + +hexlify = binascii.hexlify +nullid = "\0" * 20 + + +class MercurialRepository(BaseRepository): + """ + Mercurial repository backend + """ + DEFAULT_BRANCH_NAME = 'default' + + def __init__(self, repo_path, config=None, create=False, src_url=None, + update_after_clone=False, with_wire=None): + """ + Raises RepositoryError if repository could not be find at the given + ``repo_path``. + + :param repo_path: local path of the repository + :param config: config object containing the repo configuration + :param create=False: if set to True, would try to create repository if + it does not exist rather than raising exception + :param src_url=None: would try to clone repository from given location + :param update_after_clone=False: sets update of working copy after + making a clone + """ + self.path = safe_str(os.path.abspath(repo_path)) + self.config = config if config else Config() + self._remote = connection.Hg( + self.path, self.config, with_wire=with_wire) + + self._init_repo(create, src_url, update_after_clone) + + # caches + self._commit_ids = {} + + @LazyProperty + def commit_ids(self): + """ + Returns list of commit ids, in ascending order. Being lazy + attribute allows external tools to inject shas from cache. + """ + commit_ids = self._get_all_commit_ids() + self._rebuild_cache(commit_ids) + return commit_ids + + def _rebuild_cache(self, commit_ids): + self._commit_ids = dict((commit_id, index) + for index, commit_id in enumerate(commit_ids)) + + @LazyProperty + def branches(self): + return self._get_branches() + + @LazyProperty + def branches_closed(self): + return self._get_branches(active=False, closed=True) + + @LazyProperty + def branches_all(self): + all_branches = {} + all_branches.update(self.branches) + all_branches.update(self.branches_closed) + return all_branches + + def _get_branches(self, active=True, closed=False): + """ + Gets branches for this repository + Returns only not closed active branches by default + + :param active: return also active branches + :param closed: return also closed branches + + """ + if self.is_empty(): + return {} + + def get_name(ctx): + return ctx[0] + + _branches = [(safe_unicode(n), hexlify(h),) for n, h in + self._remote.branches(active, closed).items()] + + return OrderedDict(sorted(_branches, key=get_name, reverse=False)) + + @LazyProperty + def tags(self): + """ + Gets tags for this repository + """ + return self._get_tags() + + def _get_tags(self): + if self.is_empty(): + return {} + + def get_name(ctx): + return ctx[0] + + _tags = [(safe_unicode(n), hexlify(h),) for n, h in + self._remote.tags().items()] + + return OrderedDict(sorted(_tags, key=get_name, reverse=True)) + + def tag(self, name, user, commit_id=None, message=None, date=None, + **kwargs): + """ + Creates and returns a tag for the given ``commit_id``. + + :param name: name for new tag + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param commit_id: commit id for which new tag would be created + :param message: message of the tag's commit + :param date: date of tag's commit + + :raises TagAlreadyExistError: if tag with same name already exists + """ + if name in self.tags: + raise TagAlreadyExistError("Tag %s already exists" % name) + commit = self.get_commit(commit_id=commit_id) + local = kwargs.setdefault('local', False) + + if message is None: + message = "Added tag %s for commit %s" % (name, commit.short_id) + + date, tz = date_to_timestamp_plus_offset(date) + + self._remote.tag( + name, commit.raw_id, message, local, user, date, tz) + + # Reinitialize tags + self.tags = self._get_tags() + tag_id = self.tags[name] + + return self.get_commit(commit_id=tag_id) + + def remove_tag(self, name, user, message=None, date=None): + """ + Removes tag with the given `name`. + + :param name: name of the tag to be removed + :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" + :param message: message of the tag's removal commit + :param date: date of tag's removal commit + + :raises TagDoesNotExistError: if tag with given name does not exists + """ + if name not in self.tags: + raise TagDoesNotExistError("Tag %s does not exist" % name) + if message is None: + message = "Removed tag %s" % name + local = False + + date, tz = date_to_timestamp_plus_offset(date) + + self._remote.tag(name, nullid, message, local, user, date, tz) + self.tags = self._get_tags() + + @LazyProperty + def bookmarks(self): + """ + Gets bookmarks for this repository + """ + return self._get_bookmarks() + + def _get_bookmarks(self): + if self.is_empty(): + return {} + + def get_name(ctx): + return ctx[0] + + _bookmarks = [ + (safe_unicode(n), hexlify(h)) for n, h in + self._remote.bookmarks().items()] + + return OrderedDict(sorted(_bookmarks, key=get_name)) + + def _get_all_commit_ids(self): + return self._remote.get_all_commit_ids('visible') + + def get_diff( + self, commit1, commit2, path='', ignore_whitespace=False, + context=3, path1=None): + """ + Returns (git like) *diff*, as plain text. Shows changes introduced by + `commit2` since `commit1`. + + :param commit1: Entry point from which diff is shown. Can be + ``self.EMPTY_COMMIT`` - in this case, patch showing all + the changes since empty state of the repository until `commit2` + :param commit2: Until which commit changes should be shown. + :param ignore_whitespace: If set to ``True``, would not show whitespace + changes. Defaults to ``False``. + :param context: How many lines before/after changed lines should be + shown. Defaults to ``3``. + """ + self._validate_diff_commits(commit1, commit2) + if path1 is not None and path1 != path: + raise ValueError("Diff of two different paths not supported.") + + if path: + file_filter = [self.path, path] + else: + file_filter = None + + diff = self._remote.diff( + commit1.raw_id, commit2.raw_id, file_filter=file_filter, + opt_git=True, opt_ignorews=ignore_whitespace, + context=context) + return MercurialDiff(diff) + + def strip(self, commit_id, branch=None): + self._remote.strip(commit_id, update=False, backup="none") + + self.commit_ids = self._get_all_commit_ids() + self._rebuild_cache(self.commit_ids) + + def get_common_ancestor(self, commit_id1, commit_id2, repo2): + if commit_id1 == commit_id2: + return commit_id1 + + ancestors = self._remote.revs_from_revspec( + "ancestor(id(%s), id(%s))", commit_id1, commit_id2, + other_path=repo2.path) + return repo2[ancestors[0]].raw_id if ancestors else None + + def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None): + if commit_id1 == commit_id2: + commits = [] + else: + if merge: + indexes = self._remote.revs_from_revspec( + "ancestors(id(%s)) - ancestors(id(%s)) - id(%s)", + commit_id2, commit_id1, commit_id1, other_path=repo2.path) + else: + indexes = self._remote.revs_from_revspec( + "id(%s)..id(%s) - id(%s)", commit_id1, commit_id2, + commit_id1, other_path=repo2.path) + + commits = [repo2.get_commit(commit_idx=idx, pre_load=pre_load) + for idx in indexes] + + return commits + + @staticmethod + def check_url(url, config): + """ + Function will check given url and try to verify if it's a valid + link. Sometimes it may happened that mercurial will issue basic + auth request that can cause whole API to hang when used from python + or other external calls. + + On failures it'll raise urllib2.HTTPError, exception is also thrown + when the return code is non 200 + """ + # check first if it's not an local url + if os.path.isdir(url) or url.startswith('file:'): + return True + + # Request the _remote to verify the url + return connection.Hg.check_url(url, config.serialize()) + + @staticmethod + def is_valid_repository(path): + return os.path.isdir(os.path.join(path, '.hg')) + + def _init_repo(self, create, src_url=None, update_after_clone=False): + """ + Function will check for mercurial repository in given path. If there + is no repository in that path it will raise an exception unless + `create` parameter is set to True - in that case repository would + be created. + + If `src_url` is given, would try to clone repository from the + location at given clone_point. Additionally it'll make update to + working copy accordingly to `update_after_clone` flag. + """ + if create and os.path.exists(self.path): + raise RepositoryError( + "Cannot create repository at %s, location already exist" + % self.path) + + if src_url: + url = str(self._get_url(src_url)) + MercurialRepository.check_url(url, self.config) + + self._remote.clone(url, self.path, update_after_clone) + + # Don't try to create if we've already cloned repo + create = False + + if create: + os.makedirs(self.path, mode=0755) + + self._remote.localrepository(create) + + @LazyProperty + def in_memory_commit(self): + return MercurialInMemoryCommit(self) + + @LazyProperty + def description(self): + description = self._remote.get_config_value( + 'web', 'description', untrusted=True) + return safe_unicode(description or self.DEFAULT_DESCRIPTION) + + @LazyProperty + def contact(self): + contact = ( + self._remote.get_config_value("web", "contact") or + self._remote.get_config_value("ui", "username")) + return safe_unicode(contact or self.DEFAULT_CONTACT) + + @LazyProperty + def last_change(self): + """ + Returns last change made on this repository as + `datetime.datetime` object + """ + return date_fromtimestamp(self._get_mtime(), makedate()[1]) + + def _get_mtime(self): + try: + return date_astimestamp(self.get_commit().date) + except RepositoryError: + # fallback to filesystem + cl_path = os.path.join(self.path, '.hg', "00changelog.i") + st_path = os.path.join(self.path, '.hg', "store") + if os.path.exists(cl_path): + return os.stat(cl_path).st_mtime + else: + return os.stat(st_path).st_mtime + + def _sanitize_commit_idx(self, idx): + # Note: Mercurial has ``int(-1)`` reserved as not existing id_or_idx + # number. A `long` is treated in the correct way though. So we convert + # `int` to `long` here to make sure it is handled correctly. + if isinstance(idx, int): + return long(idx) + return idx + + def _get_url(self, url): + """ + Returns normalized url. If schema is not given, would fall + to filesystem + (``file:///``) schema. + """ + url = url.encode('utf8') + if url != 'default' and '://' not in url: + url = "file:" + urllib.pathname2url(url) + return url + + def get_hook_location(self): + """ + returns absolute path to location where hooks are stored + """ + return os.path.join(self.path, '.hg', '.hgrc') + + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): + """ + Returns ``MercurialCommit`` object representing repository's + commit at the given `commit_id` or `commit_idx`. + """ + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + + if commit_id is not None: + self._validate_commit_id(commit_id) + try: + idx = self._commit_ids[commit_id] + return MercurialCommit(self, commit_id, idx, pre_load=pre_load) + except KeyError: + pass + elif commit_idx is not None: + self._validate_commit_idx(commit_idx) + commit_idx = self._sanitize_commit_idx(commit_idx) + try: + id_ = self.commit_ids[commit_idx] + if commit_idx < 0: + commit_idx += len(self.commit_ids) + return MercurialCommit( + self, id_, commit_idx, pre_load=pre_load) + except IndexError: + commit_id = commit_idx + else: + commit_id = "tip" + + # TODO Paris: Ugly hack to "serialize" long for msgpack + if isinstance(commit_id, long): + commit_id = float(commit_id) + + if isinstance(commit_id, unicode): + commit_id = safe_str(commit_id) + + raw_id, idx = self._remote.lookup(commit_id, both=True) + + return MercurialCommit(self, raw_id, idx, pre_load=pre_load) + + def get_commits( + self, start_id=None, end_id=None, start_date=None, end_date=None, + branch_name=None, pre_load=None): + """ + Returns generator of ``MercurialCommit`` objects from start to end + (both are inclusive) + + :param start_id: None, str(commit_id) + :param end_id: None, str(commit_id) + :param start_date: if specified, commits with commit date less than + ``start_date`` would be filtered out from returned set + :param end_date: if specified, commits with commit date greater than + ``end_date`` would be filtered out from returned set + :param branch_name: if specified, commits not reachable from given + branch would be filtered out from returned set + + :raise BranchDoesNotExistError: If given ``branch_name`` does not + exist. + :raise CommitDoesNotExistError: If commit for given ``start`` or + ``end`` could not be found. + """ + # actually we should check now if it's not an empty repo + branch_ancestors = False + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + self._validate_branch_name(branch_name) + + if start_id is not None: + self._validate_commit_id(start_id) + c_start = self.get_commit(commit_id=start_id) + start_pos = self._commit_ids[c_start.raw_id] + else: + start_pos = None + + if end_id is not None: + self._validate_commit_id(end_id) + c_end = self.get_commit(commit_id=end_id) + end_pos = max(0, self._commit_ids[c_end.raw_id]) + else: + end_pos = None + + if None not in [start_id, end_id] and start_pos > end_pos: + raise RepositoryError( + "Start commit '%s' cannot be after end commit '%s'" % + (start_id, end_id)) + + if end_pos is not None: + end_pos += 1 + + commit_filter = [] + if branch_name and not branch_ancestors: + commit_filter.append('branch("%s")' % branch_name) + elif branch_name and branch_ancestors: + commit_filter.append('ancestors(branch("%s"))' % branch_name) + if start_date and not end_date: + commit_filter.append('date(">%s")' % start_date) + if end_date and not start_date: + commit_filter.append('date("<%s")' % end_date) + if start_date and end_date: + commit_filter.append( + 'date(">%s") and date("<%s")' % (start_date, end_date)) + + # TODO: johbo: Figure out a simpler way for this solution + collection_generator = CollectionGenerator + if commit_filter: + commit_filter = map(safe_str, commit_filter) + revisions = self._remote.rev_range(commit_filter) + collection_generator = MercurialIndexBasedCollectionGenerator + else: + revisions = self.commit_ids + + if start_pos or end_pos: + revisions = revisions[start_pos:end_pos] + + return collection_generator(self, revisions, pre_load=pre_load) + + def pull(self, url, commit_ids=None): + """ + Tries to pull changes from external location. + + :param commit_ids: Optional. Can be set to a list of commit ids + which shall be pulled from the other repository. + """ + url = self._get_url(url) + self._remote.pull(url, commit_ids=commit_ids) + + def _local_clone(self, clone_path): + """ + Create a local clone of the current repo. + """ + self._remote.clone(self.path, clone_path, update_after_clone=True, + hooks=False) + + def _update(self, revision, clean=False): + """ + Update the working copty to the specified revision. + """ + self._remote.update(revision, clean=clean) + + def _identify(self): + """ + Return the current state of the working directory. + """ + return self._remote.identify().strip().rstrip('+') + + def _heads(self, branch=None): + """ + Return the commit ids of the repository heads. + """ + return self._remote.heads(branch=branch).strip().split(' ') + + def _ancestor(self, revision1, revision2): + """ + Return the common ancestor of the two revisions. + """ + return self._remote.ancestor( + revision1, revision2).strip().split(':')[-1] + + def _local_push( + self, revision, repository_path, push_branches=False, + enable_hooks=False): + """ + Push the given revision to the specified repository. + + :param push_branches: allow to create branches in the target repo. + """ + self._remote.push( + [revision], repository_path, hooks=enable_hooks, + push_branches=push_branches) + + def _local_merge(self, target_ref, merge_message, user_name, user_email, + source_ref): + """ + Merge the given source_revision into the checked out revision. + + Returns the commit id of the merge and a boolean indicating if the + commit needs to be pushed. + """ + self._update(target_ref.commit_id) + + ancestor = self._ancestor(target_ref.commit_id, source_ref.commit_id) + is_the_same_branch = self._is_the_same_branch(target_ref, source_ref) + + if ancestor == source_ref.commit_id: + # Nothing to do, the changes were already integrated + return target_ref.commit_id, False + + elif ancestor == target_ref.commit_id and is_the_same_branch: + # In this case we should force a commit message + return source_ref.commit_id, True + + if settings.HG_USE_REBASE_FOR_MERGING: + try: + bookmark_name = 'rcbook%s%s' % (source_ref.commit_id, + target_ref.commit_id) + self.bookmark(bookmark_name, revision=source_ref.commit_id) + self._remote.rebase( + source=source_ref.commit_id, dest=target_ref.commit_id) + self._update(bookmark_name) + return self._identify(), True + except RepositoryError: + # Cleanup any rebase leftovers + self._remote.rebase(abort=True) + self._remote.update(clean=True) + raise + else: + try: + self._remote.merge(source_ref.commit_id) + self._remote.commit( + message=safe_str(merge_message), + username=safe_str('%s <%s>' % (user_name, user_email))) + return self._identify(), True + except RepositoryError: + # Cleanup any merge leftovers + self._remote.update(clean=True) + raise + + def _is_the_same_branch(self, target_ref, source_ref): + return ( + self._get_branch_name(target_ref) == + self._get_branch_name(source_ref)) + + def _get_branch_name(self, ref): + if ref.type == 'branch': + return ref.name + return self._remote.ctx_branch(ref.commit_id) + + def _get_shadow_repository_path(self, workspace_id): + # The name of the shadow repository must start with '.', so it is + # skipped by 'rhodecode.lib.utils.get_filesystem_repos'. + return os.path.join( + os.path.dirname(self.path), + '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id)) + + def _maybe_prepare_merge_workspace(self, workspace_id, unused_target_ref): + shadow_repository_path = self._get_shadow_repository_path(workspace_id) + if not os.path.exists(shadow_repository_path): + self._local_clone(shadow_repository_path) + + return shadow_repository_path + + def cleanup_merge_workspace(self, workspace_id): + shadow_repository_path = self._get_shadow_repository_path(workspace_id) + shutil.rmtree(shadow_repository_path, ignore_errors=True) + + def _merge_repo(self, shadow_repository_path, target_ref, + source_repo, source_ref, merge_message, + merger_name, merger_email, dry_run=False): + if target_ref.commit_id not in self._heads(): + return MergeResponse( + False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD) + + if (target_ref.type == 'branch' and + len(self._heads(target_ref.name)) != 1): + return MergeResponse( + False, False, None, + MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS) + + shadow_repo = self._get_shadow_instance(shadow_repository_path) + + self._validate_pull_reference(target_ref) + shadow_repo._local_pull(self.path, target_ref) + try: + source_repo._validate_pull_reference(source_ref) + shadow_repo._local_pull(source_repo.path, source_ref) + except CommitDoesNotExistError: + return MergeResponse( + False, False, None, MergeFailureReason.MISSING_COMMIT) + + merge_commit_id = None + merge_failure_reason = MergeFailureReason.NONE + + try: + merge_commit_id, needs_push = shadow_repo._local_merge( + target_ref, merge_message, merger_name, merger_email, + source_ref) + merge_possible = True + except RepositoryError: + merge_possible = False + merge_failure_reason = MergeFailureReason.MERGE_FAILED + + if merge_possible and not dry_run: + if needs_push: + # In case the target is a bookmark, update it, so after pushing + # the bookmarks is also updated in the target. + if target_ref.type == 'book': + shadow_repo.bookmark( + target_ref.name, revision=merge_commit_id) + + try: + shadow_repo_with_hooks = self._get_shadow_instance( + shadow_repository_path, + enable_hooks=True) + # Note: the push_branches option will push any new branch + # defined in the source repository to the target. This may + # be dangerous as branches are permanent in Mercurial. + # This feature was requested in issue #441. + shadow_repo_with_hooks._local_push( + merge_commit_id, self.path, push_branches=True, + enable_hooks=True) + merge_succeeded = True + except RepositoryError: + merge_succeeded = False + merge_failure_reason = MergeFailureReason.PUSH_FAILED + else: + merge_succeeded = True + else: + merge_succeeded = False + + if dry_run: + merge_commit_id = None + + return MergeResponse( + merge_possible, merge_succeeded, merge_commit_id, + merge_failure_reason) + + def _get_shadow_instance( + self, shadow_repository_path, enable_hooks=False): + config = self.config.copy() + if not enable_hooks: + config.clear_section('hooks') + return MercurialRepository(shadow_repository_path, config) + + def _validate_pull_reference(self, reference): + if not (reference.name in self.bookmarks or + reference.name in self.branches or + self.get_commit(reference.commit_id)): + raise CommitDoesNotExistError( + 'Unknown branch, bookmark or commit id') + + def _local_pull(self, repository_path, reference): + """ + Fetch a branch, bookmark or commit from a local repository. + """ + repository_path = os.path.abspath(repository_path) + if repository_path == self.path: + raise ValueError('Cannot pull from the same repository') + + reference_type_to_option_name = { + 'book': 'bookmark', + 'branch': 'branch', + } + option_name = reference_type_to_option_name.get( + reference.type, 'revision') + + if option_name == 'revision': + ref = reference.commit_id + else: + ref = reference.name + + options = {option_name: [ref]} + self._remote.pull_cmd(repository_path, hooks=False, **options) + + def bookmark(self, bookmark, revision=None): + if isinstance(bookmark, unicode): + bookmark = safe_str(bookmark) + self._remote.bookmark(bookmark, revision=revision) + + +class MercurialIndexBasedCollectionGenerator(CollectionGenerator): + + def _commit_factory(self, commit_id): + return self.repo.get_commit( + commit_idx=commit_id, pre_load=self.pre_load) diff --git a/rhodecode/lib/vcs/backends/svn/__init__.py b/rhodecode/lib/vcs/backends/svn/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/svn/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SVN module +""" + +from rhodecode.lib.vcs.backends.svn.commit import SubversionCommit +from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository diff --git a/rhodecode/lib/vcs/backends/svn/commit.py b/rhodecode/lib/vcs/backends/svn/commit.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/svn/commit.py @@ -0,0 +1,230 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SVN commit module +""" + + +import dateutil.parser +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils import safe_str, safe_unicode +from rhodecode.lib.vcs import nodes, path as vcspath +from rhodecode.lib.vcs.backends import base +from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError + + +_SVN_PROP_TRUE = '*' + + +class SubversionCommit(base.BaseCommit): + """ + Subversion specific implementation of commits + + .. attribute:: branch + + The Subversion backend does not support to assign branches to + specific commits. This attribute has always the value `None`. + + """ + + def __init__(self, repository, commit_id): + self.repository = repository + self.idx = self.repository._get_commit_idx(commit_id) + self._svn_rev = self.idx + 1 + self._remote = repository._remote + # TODO: handling of raw_id should be a method on repository itself, + # which knows how to translate commit index and commit id + self.raw_id = commit_id + self.short_id = commit_id + self.id = 'r%s' % (commit_id, ) + + # TODO: Implement the following placeholder attributes + self.nodes = {} + self.tags = [] + + @property + def author(self): + return safe_unicode(self._properties.get('svn:author')) + + @property + def date(self): + return _date_from_svn_properties(self._properties) + + @property + def message(self): + return safe_unicode(self._properties.get('svn:log')) + + @LazyProperty + def _properties(self): + return self._remote.revision_properties(self._svn_rev) + + @LazyProperty + def parents(self): + parent_idx = self.idx - 1 + if parent_idx >= 0: + parent = self.repository.get_commit(commit_idx=parent_idx) + return [parent] + return [] + + @LazyProperty + def children(self): + child_idx = self.idx + 1 + if child_idx < len(self.repository.commit_ids): + child = self.repository.get_commit(commit_idx=child_idx) + return [child] + return [] + + def get_file_mode(self, path): + # Note: Subversion flags files which are executable with a special + # property `svn:executable` which is set to the value ``"*"``. + if self._get_file_property(path, 'svn:executable') == _SVN_PROP_TRUE: + return base.FILEMODE_EXECUTABLE + else: + return base.FILEMODE_DEFAULT + + def is_link(self, path): + # Note: Subversion has a flag for special files, the content of the + # file contains the type of that file. + if self._get_file_property(path, 'svn:special') == _SVN_PROP_TRUE: + return self.get_file_content(path).startswith('link') + return False + + def _get_file_property(self, path, name): + file_properties = self._remote.node_properties( + safe_str(path), self._svn_rev) + return file_properties.get(name) + + def get_file_content(self, path): + path = self._fix_path(path) + return self._remote.get_file_content(safe_str(path), self._svn_rev) + + def get_file_size(self, path): + path = self._fix_path(path) + return self._remote.get_file_size(safe_str(path), self._svn_rev) + + def get_file_history(self, path, limit=None, pre_load=None): + path = safe_str(self._fix_path(path)) + history = self._remote.node_history(path, self._svn_rev, limit) + return [ + self.repository.get_commit(commit_id=str(svn_rev)) + for svn_rev in history] + + def get_file_annotate(self, path, pre_load=None): + result = self._remote.file_annotate(safe_str(path), self._svn_rev) + + for zero_based_line_no, svn_rev, content in result: + commit_id = str(svn_rev) + line_no = zero_based_line_no + 1 + yield ( + line_no, + commit_id, + lambda: self.repository.get_commit(commit_id=commit_id), + content) + + def get_node(self, path): + path = self._fix_path(path) + if path not in self.nodes: + + if path == '': + node = nodes.RootNode(commit=self) + else: + node_type = self._remote.get_node_type( + safe_str(path), self._svn_rev) + if node_type == 'dir': + node = nodes.DirNode(path, commit=self) + elif node_type == 'file': + node = nodes.FileNode(path, commit=self) + else: + raise NodeDoesNotExistError(self.no_node_at_path(path)) + + self.nodes[path] = node + return self.nodes[path] + + def get_nodes(self, path): + if self._get_kind(path) != nodes.NodeKind.DIR: + raise CommitError( + "Directory does not exist for commit %s at " + " '%s'" % (self.raw_id, path)) + path = self._fix_path(path) + + path_nodes = [] + for name, kind in self._remote.get_nodes( + safe_str(path), revision=self._svn_rev): + node_path = vcspath.join(path, name) + if kind == 'dir': + node = nodes.DirNode(node_path, commit=self) + elif kind == 'file': + node = nodes.FileNode(node_path, commit=self) + else: + raise ValueError("Node kind %s not supported." % (kind, )) + self.nodes[node_path] = node + path_nodes.append(node) + + return path_nodes + + def _get_kind(self, path): + path = self._fix_path(path) + kind = self._remote.get_node_type(path, self._svn_rev) + if kind == 'file': + return nodes.NodeKind.FILE + elif kind == 'dir': + return nodes.NodeKind.DIR + else: + raise CommitError( + "Node does not exist at the given path '%s'" % (path, )) + + @LazyProperty + def _changes_cache(self): + return self._remote.revision_changes(self._svn_rev) + + @LazyProperty + def affected_files(self): + changed_files = set() + for files in self._changes_cache.itervalues(): + changed_files.update(files) + return list(changed_files) + + @property + def added(self): + return nodes.AddedFileNodesGenerator( + self._changes_cache['added'], self) + + @property + def changed(self): + return nodes.ChangedFileNodesGenerator( + self._changes_cache['changed'], self) + + @property + def removed(self): + return nodes.RemovedFileNodesGenerator( + self._changes_cache['removed'], self) + + +def _date_from_svn_properties(properties): + """ + Parses the date out of given svn properties. + + :return: :class:`datetime.datetime` instance. The object is naive. + """ + aware_date = dateutil.parser.parse(properties.get('svn:date')) + local_date = aware_date.astimezone(dateutil.tz.tzlocal()) + return local_date.replace(tzinfo=None) diff --git a/rhodecode/lib/vcs/backends/svn/diff.py b/rhodecode/lib/vcs/backends/svn/diff.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/svn/diff.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +SVN diff module +""" + +import re + +from rhodecode.lib.vcs.backends import base + + +class SubversionDiff(base.Diff): + + _header_re = re.compile(r""" + #^diff[ ]--git + [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n + (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n + ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n + ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))? + (?:^old[ ]mode[ ](?P<old_mode>\d+)\n + ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))? + (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))? + (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))? + (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+) + \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? + (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))? + (?:^---[ ](a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))? + (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))? + """, re.VERBOSE | re.MULTILINE) diff --git a/rhodecode/lib/vcs/backends/svn/inmemory.py b/rhodecode/lib/vcs/backends/svn/inmemory.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/svn/inmemory.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +SVN inmemory module +""" + +from rhodecode.lib.datelib import date_astimestamp +from rhodecode.lib.utils import safe_str +from rhodecode.lib.vcs.backends import base + + +class SubversionInMemoryCommit(base.BaseInMemoryCommit): + + def commit(self, message, author, parents=None, branch=None, date=None, + **kwargs): + if branch not in (None, self.repository.DEFAULT_BRANCH_NAME): + raise NotImplementedError("Branches are not yet supported") + + self.check_integrity(parents) + + message = safe_str(message) + author = safe_str(author) + + updated = [] + for node in self.added: + node_data = { + 'path': node.path, + 'content': safe_str(node.content), + 'mode': node.mode, + } + if node.is_binary: + node_data['properties'] = { + 'svn:mime-type': 'application/octet-stream' + } + updated.append(node_data) + for node in self.changed: + updated.append({ + 'path': node.path, + 'content': safe_str(node.content), + 'mode': node.mode, + }) + + removed = [] + for node in self.removed: + removed.append({ + 'path': node.path, + }) + + timestamp = date_astimestamp(date) if date else None + svn_rev = self.repository._remote.commit( + message=message, author=author, timestamp=timestamp, + updated=updated, removed=removed) + + # TODO: Find a nicer way. If commit_ids is not yet evaluated, then + # we should not add the commit_id, if it is already evaluated, it + # will not be evaluated again. + commit_id = str(svn_rev) + if commit_id not in self.repository.commit_ids: + self.repository.commit_ids.append(commit_id) + tip = self.repository.get_commit() + self.reset() + return tip diff --git a/rhodecode/lib/vcs/backends/svn/repository.py b/rhodecode/lib/vcs/backends/svn/repository.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/backends/svn/repository.py @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SVN repository module +""" + +import logging +import os +import urllib + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.datelib import date_astimestamp +from rhodecode.lib.utils import safe_str, safe_unicode +from rhodecode.lib.vcs import connection, path as vcspath +from rhodecode.lib.vcs.backends import base +from rhodecode.lib.vcs.backends.svn.commit import ( + SubversionCommit, _date_from_svn_properties) +from rhodecode.lib.vcs.backends.svn.diff import SubversionDiff +from rhodecode.lib.vcs.backends.svn.inmemory import SubversionInMemoryCommit +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import ( + CommitDoesNotExistError, EmptyRepositoryError, RepositoryError, + VCSError, NodeDoesNotExistError) + + +log = logging.getLogger(__name__) + + +class SubversionRepository(base.BaseRepository): + """ + Subversion backend implementation + + .. important:: + + It is very important to distinguish the commit index and the commit id + which is assigned by Subversion. The first one is always handled as an + `int` by this implementation. The commit id assigned by Subversion on + the other side will always be a `str`. + + There is a specific trap since the first commit will have the index + ``0`` but the svn id will be ``"1"``. + + """ + + # Note: Subversion does not really have a default branch name. + DEFAULT_BRANCH_NAME = None + + contact = base.BaseRepository.DEFAULT_CONTACT + description = base.BaseRepository.DEFAULT_DESCRIPTION + + def __init__(self, repo_path, config=None, create=False, src_url=None, + **kwargs): + self.path = safe_str(os.path.abspath(repo_path)) + self.config = config if config else base.Config() + self._remote = connection.Svn( + self.path, self.config) + + self._init_repo(create, src_url) + + self.bookmarks = {} + + def _init_repo(self, create, src_url): + if create and os.path.exists(self.path): + raise RepositoryError( + "Cannot create repository at %s, location already exist" + % self.path) + + if create: + self._remote.create_repository(settings.SVN_COMPATIBLE_VERSION) + if src_url: + src_url = _sanitize_url(src_url) + self._remote.import_remote_repository(src_url) + else: + self._check_path() + + @LazyProperty + def commit_ids(self): + head = self._remote.lookup(None) + return [str(r) for r in xrange(1, head + 1)] + + @LazyProperty + def branches(self): + return self._tags_or_branches('vcs_svn_branch') + + @LazyProperty + def branches_closed(self): + return {} + + @LazyProperty + def branches_all(self): + # TODO: johbo: Implement proper branch support + all_branches = {} + all_branches.update(self.branches) + all_branches.update(self.branches_closed) + return all_branches + + @LazyProperty + def tags(self): + return self._tags_or_branches('vcs_svn_tag') + + def _tags_or_branches(self, config_section): + found_items = {} + + if self.is_empty(): + return {} + + for pattern in self._patterns_from_section(config_section): + pattern = vcspath.sanitize(pattern) + tip = self.get_commit() + try: + if pattern.endswith('*'): + basedir = tip.get_node(vcspath.dirname(pattern)) + directories = basedir.dirs + else: + directories = (tip.get_node(pattern), ) + except NodeDoesNotExistError: + continue + found_items.update( + (safe_unicode(n.path), + self.commit_ids[-1]) + for n in directories) + + def get_name(item): + return item[0] + + return OrderedDict(sorted(found_items.items(), key=get_name)) + + def _patterns_from_section(self, section): + return (pattern for key, pattern in self.config.items(section)) + + def get_common_ancestor(self, commit_id1, commit_id2, repo2): + if self != repo2: + raise ValueError( + "Subversion does not support getting common ancestor of" + " different repositories.") + + if int(commit_id1) < int(commit_id2): + return commit_id1 + return commit_id2 + + def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None): + # TODO: johbo: Implement better comparison, this is a very naive + # version which does not allow to compare branches, tags or folders + # at all. + if repo2 != self: + raise ValueError( + "Subversion does not support comparison of of different " + "repositories.") + + if commit_id1 == commit_id2: + return [] + + commit_idx1 = self._get_commit_idx(commit_id1) + commit_idx2 = self._get_commit_idx(commit_id2) + + commits = [ + self.get_commit(commit_idx=idx) + for idx in range(commit_idx1 + 1, commit_idx2 + 1)] + + return commits + + def _get_commit_idx(self, commit_id): + try: + svn_rev = int(commit_id) + except: + # TODO: johbo: this might be only one case, HEAD, check this + svn_rev = self._remote.lookup(commit_id) + commit_idx = svn_rev - 1 + if commit_idx >= len(self.commit_ids): + raise CommitDoesNotExistError( + "Commit at index %s does not exist." % (commit_idx, )) + return commit_idx + + @staticmethod + def check_url(url, config): + """ + Check if `url` is a valid source to import a Subversion repository. + """ + # convert to URL if it's a local directory + if os.path.isdir(url): + url = 'file://' + urllib.pathname2url(url) + return connection.Svn.check_url(url, config.serialize()) + + @staticmethod + def is_valid_repository(path): + try: + SubversionRepository(path) + return True + except VCSError: + pass + return False + + def _check_path(self): + if not os.path.exists(self.path): + raise VCSError('Path "%s" does not exist!' % (self.path, )) + if not self._remote.is_path_valid_repository(self.path): + raise VCSError( + 'Path "%s" does not contain a Subversion repository' % + (self.path, )) + + @LazyProperty + def last_change(self): + """ + Returns last change made on this repository as + `datetime.datetime` object. + """ + # Subversion always has a first commit which has id "0" and contains + # what we are looking for. + last_id = len(self.commit_ids) + properties = self._remote.revision_properties(last_id) + return _date_from_svn_properties(properties) + + @LazyProperty + def in_memory_commit(self): + return SubversionInMemoryCommit(self) + + def get_hook_location(self): + """ + returns absolute path to location where hooks are stored + """ + return os.path.join(self.path, 'hooks') + + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + if commit_id is not None: + self._validate_commit_id(commit_id) + elif commit_idx is not None: + self._validate_commit_idx(commit_idx) + try: + commit_id = self.commit_ids[commit_idx] + except IndexError: + raise CommitDoesNotExistError + + commit_id = self._sanitize_commit_id(commit_id) + commit = SubversionCommit(repository=self, commit_id=commit_id) + return commit + + def get_commits( + self, start_id=None, end_id=None, start_date=None, end_date=None, + branch_name=None, pre_load=None): + if self.is_empty(): + raise EmptyRepositoryError("There are no commit_ids yet") + self._validate_branch_name(branch_name) + + if start_id is not None: + self._validate_commit_id(start_id) + if end_id is not None: + self._validate_commit_id(end_id) + + start_raw_id = self._sanitize_commit_id(start_id) + start_pos = self.commit_ids.index(start_raw_id) if start_id else None + end_raw_id = self._sanitize_commit_id(end_id) + end_pos = max(0, self.commit_ids.index(end_raw_id)) if end_id else None + + if None not in [start_id, end_id] and start_pos > end_pos: + raise RepositoryError( + "Start commit '%s' cannot be after end commit '%s'" % + (start_id, end_id)) + if end_pos is not None: + end_pos += 1 + + # Date based filtering + if start_date or end_date: + start_raw_id, end_raw_id = self._remote.lookup_interval( + date_astimestamp(start_date) if start_date else None, + date_astimestamp(end_date) if end_date else None) + start_pos = start_raw_id - 1 + end_pos = end_raw_id + + commit_ids = self.commit_ids + + # TODO: johbo: Reconsider impact of DEFAULT_BRANCH_NAME here + if branch_name not in [None, self.DEFAULT_BRANCH_NAME]: + svn_rev = long(self.commit_ids[-1]) + commit_ids = self._remote.node_history( + path=branch_name, revision=svn_rev, limit=None) + commit_ids = [str(i) for i in reversed(commit_ids)] + + if start_pos or end_pos: + commit_ids = commit_ids[start_pos:end_pos] + return base.CollectionGenerator(self, commit_ids, pre_load=pre_load) + + def _sanitize_commit_id(self, commit_id): + if commit_id and commit_id.isdigit(): + if int(commit_id) <= len(self.commit_ids): + return commit_id + else: + raise CommitDoesNotExistError( + "Commit %s does not exist." % (commit_id, )) + if commit_id not in [ + None, 'HEAD', 'tip', self.DEFAULT_BRANCH_NAME]: + raise CommitDoesNotExistError( + "Commit id %s not understood." % (commit_id, )) + svn_rev = self._remote.lookup('HEAD') + return str(svn_rev) + + def get_diff( + self, commit1, commit2, path=None, ignore_whitespace=False, + context=3, path1=None): + self._validate_diff_commits(commit1, commit2) + svn_rev1 = long(commit1.raw_id) + svn_rev2 = long(commit2.raw_id) + diff = self._remote.diff( + svn_rev1, svn_rev2, path1=path1, path2=path, + ignore_whitespace=ignore_whitespace, context=context) + return SubversionDiff(diff) + + +def _sanitize_url(url): + if '://' not in url: + url = 'file://' + urllib.pathname2url(url) + return url diff --git a/rhodecode/lib/vcs/client.py b/rhodecode/lib/vcs/client.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/client.py @@ -0,0 +1,284 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Provides the implementation of various client utilities to reach the vcsserver. +""" + + +import copy +import logging +import threading +import urlparse +import uuid +import weakref +from urllib2 import URLError + +import msgpack +import Pyro4 +import requests +from Pyro4.errors import CommunicationError, ConnectionClosedError, DaemonError + +from rhodecode.lib.vcs import exceptions +from rhodecode.lib.vcs.conf import settings + +log = logging.getLogger(__name__) + + +# TODO: mikhail: Keep it in sync with vcsserver's +# HTTPApplication.ALLOWED_EXCEPTIONS +EXCEPTIONS_MAP = { + 'KeyError': KeyError, + 'URLError': URLError, +} + + +class HTTPRepoMaker(object): + def __init__(self, server_and_port, backend_endpoint): + self.url = urlparse.urljoin( + 'http://%s' % server_and_port, backend_endpoint) + + def __call__(self, path, config, with_wire=None): + log.debug('HTTPRepoMaker call on %s', path) + return HTTPRemoteRepo(path, config, self.url, with_wire=with_wire) + + def __getattr__(self, name): + def f(*args, **kwargs): + return self._call(name, *args, **kwargs) + return f + + @exceptions.map_vcs_exceptions + def _call(self, name, *args, **kwargs): + payload = { + 'id': str(uuid.uuid4()), + 'method': name, + 'params': {'args': args, 'kwargs': kwargs} + } + return _remote_call(self.url, payload, EXCEPTIONS_MAP) + + +class VcsHttpProxy(object): + + CHUNK_SIZE = 16384 + + def __init__(self, server_and_port, backend_endpoint): + adapter = requests.adapters.HTTPAdapter(max_retries=5) + self.base_url = urlparse.urljoin( + 'http://%s' % server_and_port, backend_endpoint) + self.session = requests.Session() + self.session.mount('http://', adapter) + + def handle(self, environment, input_data, *args, **kwargs): + data = { + 'environment': environment, + 'input_data': input_data, + 'args': args, + 'kwargs': kwargs + } + result = self.session.post( + self.base_url, msgpack.packb(data), stream=True) + return self._get_result(result) + + def _deserialize_and_raise(self, error): + exception = Exception(error['message']) + try: + exception._vcs_kind = error['_vcs_kind'] + except KeyError: + pass + raise exception + + def _iterate(self, result): + unpacker = msgpack.Unpacker() + for line in result.iter_content(chunk_size=self.CHUNK_SIZE): + unpacker.feed(line) + for chunk in unpacker: + yield chunk + + def _get_result(self, result): + iterator = self._iterate(result) + error = iterator.next() + if error: + self._deserialize_and_raise(error) + + status = iterator.next() + headers = iterator.next() + + return iterator, status, headers + + +class HTTPRemoteRepo(object): + def __init__(self, path, config, url, with_wire=None): + self.url = url + self._wire = { + "path": path, + "config": config, + "context": str(uuid.uuid4()), + } + if with_wire: + self._wire.update(with_wire) + + def __getattr__(self, name): + def f(*args, **kwargs): + return self._call(name, *args, **kwargs) + return f + + @exceptions.map_vcs_exceptions + def _call(self, name, *args, **kwargs): + log.debug('Calling %s@%s', self.url, name) + # TODO: oliver: This is currently necessary pre-call since the + # config object is being changed for hooking scenarios + wire = copy.deepcopy(self._wire) + wire["config"] = wire["config"].serialize() + payload = { + 'id': str(uuid.uuid4()), + 'method': name, + 'params': {'wire': wire, 'args': args, 'kwargs': kwargs} + } + return _remote_call(self.url, payload, EXCEPTIONS_MAP) + + def __getitem__(self, key): + return self.revision(key) + + +def _remote_call(url, payload, exceptions_map): + response = requests.post(url, data=msgpack.packb(payload)) + response = msgpack.unpackb(response.content) + error = response.get('error') + if error: + type_ = error.get('type', 'Exception') + exc = exceptions_map.get(type_, Exception) + exc = exc(error.get('message')) + try: + exc._vcs_kind = error['_vcs_kind'] + except KeyError: + pass + raise exc + return response.get('result') + + +class RepoMaker(object): + + def __init__(self, proxy_factory): + self._proxy_factory = proxy_factory + + def __call__(self, path, config, with_wire=None): + log.debug('RepoMaker call on %s', path) + return RemoteRepo( + path, config, remote_proxy=self._proxy_factory(), + with_wire=with_wire) + + def __getattr__(self, name): + remote_proxy = self._proxy_factory() + func = _get_proxy_method(remote_proxy, name) + return _wrap_remote_call(remote_proxy, func) + + +class ThreadlocalProxyFactory(object): + """ + Creates one Pyro4 proxy per thread on demand. + """ + + def __init__(self, remote_uri): + self._remote_uri = remote_uri + self._thread_local = threading.local() + + def __call__(self): + if not hasattr(self._thread_local, 'proxy'): + self._thread_local.proxy = Pyro4.Proxy(self._remote_uri) + return self._thread_local.proxy + + +class RemoteRepo(object): + + def __init__(self, path, config, remote_proxy, with_wire=None): + self._wire = { + "path": path, + "config": config, + "context": uuid.uuid4(), + } + if with_wire: + self._wire.update(with_wire) + self._remote_proxy = remote_proxy + self.refs = RefsWrapper(self) + + def __getattr__(self, name): + log.debug('Calling %s@%s', self._remote_proxy, name) + # TODO: oliver: This is currently necessary pre-call since the + # config object is being changed for hooking scenarios + wire = copy.deepcopy(self._wire) + wire["config"] = wire["config"].serialize() + + try: + func = _get_proxy_method(self._remote_proxy, name) + except DaemonError as e: + if e.message == 'unknown object': + raise exceptions.VCSBackendNotSupportedError + else: + raise + + return _wrap_remote_call(self._remote_proxy, func, wire) + + def __getitem__(self, key): + return self.revision(key) + + +def _get_proxy_method(proxy, name): + try: + return getattr(proxy, name) + except CommunicationError: + raise CommunicationError( + 'Unable to connect to remote pyro server %s' % proxy) + + +def _wrap_remote_call(proxy, func, *args): + all_args = list(args) + + @exceptions.map_vcs_exceptions + def caller(*args, **kwargs): + all_args.extend(args) + try: + return func(*all_args, **kwargs) + except ConnectionClosedError: + log.debug('Connection to VCSServer closed, trying to reconnect.') + proxy._pyroReconnect(tries=settings.PYRO_RECONNECT_TRIES) + + return func(*all_args, **kwargs) + + return caller + + +class RefsWrapper(object): + + def __init__(self, repo): + self._repo = weakref.proxy(repo) + + def __setitem__(self, key, value): + self._repo._assign_ref(key, value) + + +class FunctionWrapper(object): + + def __init__(self, func, wire): + self._func = func + self._wire = wire + + @exceptions.map_vcs_exceptions + def __call__(self, *args, **kwargs): + return self._func(self._wire, *args, **kwargs) diff --git a/rhodecode/lib/vcs/client_http.py b/rhodecode/lib/vcs/client_http.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/client_http.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Client for the VCSServer implemented based on HTTP. + + +Status +------ + +This client implementation shall eventually replace the Pyro4 based +implementation. +""" + +import copy +import logging +import urllib2 +import urlparse +import uuid + +import msgpack +import requests + +from . import exceptions + + +log = logging.getLogger(__name__) + + +# TODO: mikhail: Keep it in sync with vcsserver's +# HTTPApplication.ALLOWED_EXCEPTIONS +EXCEPTIONS_MAP = { + 'KeyError': KeyError, + 'URLError': urllib2.URLError, +} + + +class RepoMaker(object): + + def __init__(self, server_and_port, backend_endpoint, session): + self.url = urlparse.urljoin( + 'http://%s' % server_and_port, backend_endpoint) + self._session = session + + def __call__(self, path, config, with_wire=None): + log.debug('RepoMaker call on %s', path) + return RemoteRepo( + path, config, self.url, self._session, with_wire=with_wire) + + def __getattr__(self, name): + def f(*args, **kwargs): + return self._call(name, *args, **kwargs) + return f + + @exceptions.map_vcs_exceptions + def _call(self, name, *args, **kwargs): + payload = { + 'id': str(uuid.uuid4()), + 'method': name, + 'params': {'args': args, 'kwargs': kwargs} + } + return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session) + + +class RemoteRepo(object): + + def __init__(self, path, config, url, session, with_wire=None): + self.url = url + self._session = session + self._wire = { + "path": path, + "config": config, + "context": str(uuid.uuid4()), + } + if with_wire: + self._wire.update(with_wire) + + # johbo: Trading complexity for performance. Avoiding the call to + # log.debug brings a few percent gain even if is is not active. + if log.isEnabledFor(logging.DEBUG): + self._call = self._call_with_logging + + def __getattr__(self, name): + def f(*args, **kwargs): + return self._call(name, *args, **kwargs) + return f + + @exceptions.map_vcs_exceptions + def _call(self, name, *args, **kwargs): + # TODO: oliver: This is currently necessary pre-call since the + # config object is being changed for hooking scenarios + wire = copy.deepcopy(self._wire) + wire["config"] = wire["config"].serialize() + payload = { + 'id': str(uuid.uuid4()), + 'method': name, + 'params': {'wire': wire, 'args': args, 'kwargs': kwargs} + } + return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session) + + def _call_with_logging(self, name, *args, **kwargs): + log.debug('Calling %s@%s', self.url, name) + return RemoteRepo._call(self, name, *args, **kwargs) + + def __getitem__(self, key): + return self.revision(key) + + +class RemoteObject(object): + + def __init__(self, url, session): + self._url = url + self._session = session + + # johbo: Trading complexity for performance. Avoiding the call to + # log.debug brings a few percent gain even if is is not active. + if log.isEnabledFor(logging.DEBUG): + self._call = self._call_with_logging + + def __getattr__(self, name): + def f(*args, **kwargs): + return self._call(name, *args, **kwargs) + return f + + @exceptions.map_vcs_exceptions + def _call(self, name, *args, **kwargs): + payload = { + 'id': str(uuid.uuid4()), + 'method': name, + 'params': {'args': args, 'kwargs': kwargs} + } + return _remote_call(self._url, payload, EXCEPTIONS_MAP, self._session) + + def _call_with_logging(self, name, *args, **kwargs): + log.debug('Calling %s@%s', self._url, name) + return RemoteObject._call(self, name, *args, **kwargs) + + +def _remote_call(url, payload, exceptions_map, session): + response = session.post(url, data=msgpack.packb(payload)) + response = msgpack.unpackb(response.content) + error = response.get('error') + if error: + type_ = error.get('type', 'Exception') + exc = exceptions_map.get(type_, Exception) + exc = exc(error.get('message')) + try: + exc._vcs_kind = error['_vcs_kind'] + except KeyError: + pass + raise exc + return response.get('result') + + +class VcsHttpProxy(object): + + CHUNK_SIZE = 16384 + + def __init__(self, server_and_port, backend_endpoint): + adapter = requests.adapters.HTTPAdapter(max_retries=5) + self.base_url = urlparse.urljoin( + 'http://%s' % server_and_port, backend_endpoint) + self.session = requests.Session() + self.session.mount('http://', adapter) + + def handle(self, environment, input_data, *args, **kwargs): + data = { + 'environment': environment, + 'input_data': input_data, + 'args': args, + 'kwargs': kwargs + } + result = self.session.post( + self.base_url, msgpack.packb(data), stream=True) + return self._get_result(result) + + def _deserialize_and_raise(self, error): + exception = Exception(error['message']) + try: + exception._vcs_kind = error['_vcs_kind'] + except KeyError: + pass + raise exception + + def _iterate(self, result): + unpacker = msgpack.Unpacker() + for line in result.iter_content(chunk_size=self.CHUNK_SIZE): + unpacker.feed(line) + for chunk in unpacker: + yield chunk + + def _get_result(self, result): + iterator = self._iterate(result) + error = iterator.next() + if error: + self._deserialize_and_raise(error) + + status = iterator.next() + headers = iterator.next() + + return iterator, status, headers diff --git a/rhodecode/lib/vcs/conf/__init__.py b/rhodecode/lib/vcs/conf/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/conf/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/lib/vcs/conf/mtypes.py b/rhodecode/lib/vcs/conf/mtypes.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/conf/mtypes.py @@ -0,0 +1,1206 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +TYPES_MAP = [ + {'.jpg': 'image/jpg', + '.mid': 'audio/midi', + '.midi': 'audio/midi', + '.pct': 'image/pict', + '.pic': 'image/pict', + '.pict': 'image/pict', + '.rtf': 'application/rtf', + '.xul': 'text/xul'}, + {'.123': 'application/vnd.lotus-1-2-3', + '.3dml': 'text/vnd.in3d.3dml', + '.3g2': 'video/3gpp2', + '.3gp': 'video/3gpp', + '.7z': 'application/x-7z-compressed', + '.ASM': 'text/x-nasm', + '.C': 'text/x-c++hdr', + '.COB': 'text/x-cobol', + '.CPP': 'text/x-c++hdr', + '.CPY': 'text/x-cobol', + '.F': 'text/x-fortran', + '.F90': 'text/x-fortran', + '.H': 'text/x-c++hdr', + '.R': 'text/S-plus', + '.Rd': 'text/x-r-doc', + '.S': 'text/S-plus', + '.[1234567]': 'application/x-troff', + '.a': 'application/octet-stream', + '.aab': 'application/x-authorware-bin', + '.aac': 'audio/x-aac', + '.aam': 'application/x-authorware-map', + '.aas': 'application/x-authorware-seg', + '.abap': 'text/x-abap', + '.abw': 'application/x-abiword', + '.ac': 'application/pkix-attr-cert', + '.acc': 'application/vnd.americandynamics.acc', + '.ace': 'application/x-ace-compressed', + '.acu': 'application/vnd.acucobol', + '.acutc': 'application/vnd.acucorp', + '.ada': 'text/x-ada', + '.adb': 'text/x-ada', + '.adp': 'audio/adpcm', + '.ads': 'text/x-ada', + '.aep': 'application/vnd.audiograph', + '.afm': 'application/x-font-type1', + '.afp': 'application/vnd.ibm.modcap', + '.ahead': 'application/vnd.ahead.space', + '.ahk': 'text/x-autohotkey', + '.ahkl': 'text/x-autohotkey', + '.ai': 'application/postscript', + '.aif': 'audio/x-aiff', + '.aifc': 'audio/x-aiff', + '.aiff': 'audio/x-aiff', + '.air': 'application/vnd.adobe.air-application-installer-package+zip', + '.ait': 'application/vnd.dvb.ait', + '.aj': 'text/x-aspectj', + '.ami': 'application/vnd.amiga.ami', + '.apk': 'application/vnd.android.package-archive', + '.application': 'application/x-ms-application', + '.apr': 'application/vnd.lotus-approach', + '.as': 'application/x-actionscript3', + '.asc': 'application/pgp-signature', + '.asf': 'video/x-ms-asf', + '.asm': 'text/x-asm', + '.aso': 'application/vnd.accpac.simply.aso', + '.aspx': 'application/x-aspx', + '.asx': 'video/x-ms-asf', + '.asy': 'text/x-asymptote', + '.atc': 'application/vnd.acucorp', + '.atom': 'application/atom+xml', + '.atomcat': 'application/atomcat+xml', + '.atomsvc': 'application/atomsvc+xml', + '.atx': 'application/vnd.antix.game-component', + '.au': 'audio/basic', + '.au3': 'text/x-autoit', + '.aux': 'text/x-tex', + '.avi': 'video/x-msvideo', + '.aw': 'application/applixware', + '.awk': 'application/x-awk', + '.azf': 'application/vnd.airzip.filesecure.azf', + '.azs': 'application/vnd.airzip.filesecure.azs', + '.azw': 'application/vnd.amazon.ebook', + '.b': 'application/x-brainfuck', + '.bas': 'text/x-vbnet', + '.bash': 'text/x-sh', + '.bat': 'application/x-msdownload', + '.bcpio': 'application/x-bcpio', + '.bdf': 'application/x-font-bdf', + '.bdm': 'application/vnd.syncml.dm+wbxml', + '.bed': 'application/vnd.realvnc.bed', + '.befunge': 'application/x-befunge', + '.bf': 'application/x-brainfuck', + '.bh2': 'application/vnd.fujitsu.oasysprs', + '.bin': 'application/octet-stream', + '.bmi': 'application/vnd.bmi', + '.bmp': 'image/bmp', + '.bmx': 'text/x-bmx', + '.boo': 'text/x-boo', + '.book': 'application/vnd.framemaker', + '.box': 'application/vnd.previewsystems.box', + '.boz': 'application/x-bzip2', + '.bpk': 'application/octet-stream', + '.btif': 'image/prs.btif', + '.bz': 'application/x-bzip', + '.bz2': 'application/x-bzip2', + '.c': 'text/x-c', + '.c++': 'text/x-c++hdr', + '.c++-objdump': 'text/x-cpp-objdump', + '.c-objdump': 'text/x-c-objdump', + '.c11amc': 'application/vnd.cluetrust.cartomobile-config', + '.c11amz': 'application/vnd.cluetrust.cartomobile-config-pkg', + '.c4d': 'application/vnd.clonk.c4group', + '.c4f': 'application/vnd.clonk.c4group', + '.c4g': 'application/vnd.clonk.c4group', + '.c4p': 'application/vnd.clonk.c4group', + '.c4u': 'application/vnd.clonk.c4group', + '.cab': 'application/vnd.ms-cab-compressed', + '.car': 'application/vnd.curl.car', + '.cat': 'application/vnd.ms-pki.seccat', + '.cc': 'text/x-c', + '.cct': 'application/x-director', + '.ccxml': 'application/ccxml+xml', + '.cdbcmsg': 'application/vnd.contact.cmsg', + '.cdf': 'application/x-netcdf', + '.cdkey': 'application/vnd.mediastation.cdkey', + '.cdmia': 'application/cdmi-capability', + '.cdmic': 'application/cdmi-container', + '.cdmid': 'application/cdmi-domain', + '.cdmio': 'application/cdmi-object', + '.cdmiq': 'application/cdmi-queue', + '.cdx': 'chemical/x-cdx', + '.cdxml': 'application/vnd.chemdraw+xml', + '.cdy': 'application/vnd.cinderella', + '.cer': 'application/pkix-cert', + '.ceylon': 'text/x-ceylon', + '.cfc': 'application/x-coldfusion', + '.cfg': 'text/x-ini', + '.cfm': 'application/x-coldfusion', + '.cfml': 'application/x-coldfusion', + '.cgm': 'image/cgm', + '.chat': 'application/x-chat', + '.chm': 'application/vnd.ms-htmlhelp', + '.chrt': 'application/vnd.kde.kchart', + '.cif': 'chemical/x-cif', + '.cii': 'application/vnd.anser-web-certificate-issue-initiation', + '.cil': 'application/vnd.ms-artgalry', + '.cl': 'text/x-common-lisp', + '.cla': 'application/vnd.claymore', + '.class': 'application/java-vm', + '.clj': 'text/x-clojure', + '.clkk': 'application/vnd.crick.clicker.keyboard', + '.clkp': 'application/vnd.crick.clicker.palette', + '.clkt': 'application/vnd.crick.clicker.template', + '.clkw': 'application/vnd.crick.clicker.wordbank', + '.clkx': 'application/vnd.crick.clicker', + '.clp': 'application/x-msclip', + '.cls': 'text/x-openedge', + '.cmake': 'text/x-cmake', + '.cmc': 'application/vnd.cosmocaller', + '.cmd': 'application/x-dos-batch', + '.cmdf': 'chemical/x-cmdf', + '.cml': 'chemical/x-cml', + '.cmp': 'application/vnd.yellowriver-custom-menu', + '.cmx': 'image/x-cmx', + '.cob': 'text/x-cobol', + '.cod': 'application/vnd.rim.cod', + '.coffee': 'text/coffeescript', + '.com': 'application/x-msdownload', + '.conf': 'text/plain', + '.cp': 'text/x-c++hdr', + '.cpio': 'application/x-cpio', + '.cpp': 'text/x-c', + '.cpp-objdump': 'text/x-cpp-objdump', + '.cpt': 'application/mac-compactpro', + '.cpy': 'text/x-cobol', + '.crd': 'application/x-mscardfile', + '.crl': 'application/pkix-crl', + '.croc': 'text/x-crocsrc', + '.crt': 'application/x-x509-ca-cert', + '.cryptonote': 'application/vnd.rig.cryptonote', + '.cs': 'text/x-csharp', + '.csh': 'application/x-csh', + '.csml': 'chemical/x-csml', + '.csp': 'application/vnd.commonspace', + '.css': 'text/css', + '.cst': 'application/x-director', + '.csv': 'text/csv', + '.cu': 'application/cu-seeme', + '.cuh': 'text/x-cuda', + '.curl': 'text/vnd.curl', + '.cww': 'application/prs.cww', + '.cxt': 'application/x-director', + '.cxx': 'text/x-c', + '.cxx-objdump': 'text/x-cpp-objdump', + '.d': 'text/x-dsrc', + '.d-objdump': 'text/x-d-objdump', + '.dae': 'model/vnd.collada+xml', + '.daf': 'application/vnd.mobius.daf', + '.dart': 'text/x-dart', + '.dataless': 'application/vnd.fdsn.seed', + '.davmount': 'application/davmount+xml', + '.dcr': 'application/x-director', + '.dcurl': 'text/vnd.curl.dcurl', + '.dd2': 'application/vnd.oma.dd2+xml', + '.ddd': 'application/vnd.fujixerox.ddd', + '.deb': 'application/x-debian-package', + '.def': 'text/plain', + '.deploy': 'application/octet-stream', + '.der': 'application/x-x509-ca-cert', + '.dfac': 'application/vnd.dreamfactory', + '.dg': 'text/x-dg', + '.di': 'text/x-dsrc', + '.dic': 'text/x-c', + '.dif': 'video/x-dv', + '.diff': 'text/x-diff', + '.dir': 'application/x-director', + '.dis': 'application/vnd.mobius.dis', + '.dist': 'application/octet-stream', + '.distz': 'application/octet-stream', + '.djv': 'image/vnd.djvu', + '.djvu': 'image/vnd.djvu', + '.dll': 'application/x-msdownload', + '.dmg': 'application/octet-stream', + '.dms': 'application/octet-stream', + '.dna': 'application/vnd.dna', + '.doc': 'application/msword', + '.docm': 'application/vnd.ms-word.document.macroenabled.12', + '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + '.dot': 'application/msword', + '.dotm': 'application/vnd.ms-word.template.macroenabled.12', + '.dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + '.dp': 'application/vnd.osgi.dp', + '.dpg': 'application/vnd.dpgraph', + '.dra': 'audio/vnd.dra', + '.dsc': 'text/prs.lines.tag', + '.dssc': 'application/dssc+der', + '.dtb': 'application/x-dtbook+xml', + '.dtd': 'application/xml-dtd', + '.dts': 'audio/vnd.dts', + '.dtshd': 'audio/vnd.dts.hd', + '.duby': 'text/x-ruby', + '.duel': 'text/x-duel', + '.dump': 'application/octet-stream', + '.dv': 'video/x-dv', + '.dvi': 'application/x-dvi', + '.dwf': 'model/vnd.dwf', + '.dwg': 'image/vnd.dwg', + '.dxf': 'image/vnd.dxf', + '.dxp': 'application/vnd.spotfire.dxp', + '.dxr': 'application/x-director', + '.dyl': 'text/x-dylan', + '.dylan': 'text/x-dylan', + '.dylan-console': 'text/x-dylan-console', + '.ebuild': 'text/x-sh', + '.ec': 'text/x-echdr', + '.ecelp4800': 'audio/vnd.nuera.ecelp4800', + '.ecelp7470': 'audio/vnd.nuera.ecelp7470', + '.ecelp9600': 'audio/vnd.nuera.ecelp9600', + '.ecl': 'text/x-ecl', + '.eclass': 'text/x-sh', + '.ecma': 'application/ecmascript', + '.edm': 'application/vnd.novadigm.edm', + '.edx': 'application/vnd.novadigm.edx', + '.efif': 'application/vnd.picsel', + '.eh': 'text/x-echdr', + '.ei6': 'application/vnd.pg.osasli', + '.el': 'text/x-common-lisp', + '.elc': 'application/octet-stream', + '.eml': 'message/rfc822', + '.emma': 'application/emma+xml', + '.eol': 'audio/vnd.digital-winds', + '.eot': 'application/vnd.ms-fontobject', + '.eps': 'application/postscript', + '.epub': 'application/epub+zip', + '.erl': 'text/x-erlang', + '.erl-sh': 'text/x-erl-shellsession', + '.es': 'text/x-erlang', + '.es3': 'application/vnd.eszigno3+xml', + '.escript': 'text/x-erlang', + '.esf': 'application/vnd.epson.esf', + '.et3': 'application/vnd.eszigno3+xml', + '.etx': 'text/x-setext', + '.evoque': 'application/x-evoque', + '.ex': 'text/x-elixir', + '.exe': 'application/x-msdownload', + '.exi': 'application/exi', + '.exs': 'text/x-elixir', + '.ext': 'application/vnd.novadigm.ext', + '.ez': 'application/andrew-inset', + '.ez2': 'application/vnd.ezpix-album', + '.ez3': 'application/vnd.ezpix-package', + '.f': 'text/x-fortran', + '.f4v': 'video/x-f4v', + '.f77': 'text/x-fortran', + '.f90': 'text/x-fortran', + '.factor': 'text/x-factor', + '.fan': 'application/x-fantom', + '.fancypack': 'text/x-fancysrc', + '.fbs': 'image/vnd.fastbidsheet', + '.fcs': 'application/vnd.isac.fcs', + '.fdf': 'application/vnd.fdf', + '.fe_launch': 'application/vnd.denovo.fcselayout-link', + '.feature': 'text/x-gherkin', + '.fg5': 'application/vnd.fujitsu.oasysgp', + '.fgd': 'application/x-director', + '.fh': 'image/x-freehand', + '.fh4': 'image/x-freehand', + '.fh5': 'image/x-freehand', + '.fh7': 'image/x-freehand', + '.fhc': 'image/x-freehand', + '.fig': 'application/x-xfig', + '.fli': 'video/x-fli', + '.flo': 'application/vnd.micrografx.flo', + '.flv': 'video/x-flv', + '.flw': 'application/vnd.kde.kivio', + '.flx': 'text/vnd.fmi.flexstor', + '.flxh': 'text/x-felix', + '.fly': 'text/vnd.fly', + '.fm': 'application/vnd.framemaker', + '.fnc': 'application/vnd.frogans.fnc', + '.for': 'text/x-fortran', + '.fpx': 'image/vnd.fpx', + '.frag': 'text/x-glslsrc', + '.frame': 'application/vnd.framemaker', + '.fs': 'text/x-fsharp', + '.fsc': 'application/vnd.fsc.weblaunch', + '.fsi': 'text/x-fsharp', + '.fst': 'image/vnd.fst', + '.ftc': 'application/vnd.fluxtime.clip', + '.fti': 'application/vnd.anser-web-funds-transfer-initiation', + '.fun': 'text/x-standardml', + '.fvt': 'video/vnd.fvt', + '.fxp': 'application/vnd.adobe.fxp', + '.fxpl': 'application/vnd.adobe.fxp', + '.fy': 'text/x-fancysrc', + '.fzs': 'application/vnd.fuzzysheet', + '.g2w': 'application/vnd.geoplan', + '.g3': 'image/g3fax', + '.g3w': 'application/vnd.geospace', + '.gac': 'application/vnd.groove-account', + '.gdc': 'text/x-gooddata-cl', + '.gdl': 'model/vnd.gdl', + '.gemspec': 'text/x-ruby', + '.geo': 'application/vnd.dynageo', + '.gex': 'application/vnd.geometry-explorer', + '.ggb': 'application/vnd.geogebra.file', + '.ggt': 'application/vnd.geogebra.tool', + '.ghf': 'application/vnd.groove-help', + '.gif': 'image/gif', + '.gim': 'application/vnd.groove-identity-message', + '.gmx': 'application/vnd.gmx', + '.gnumeric': 'application/x-gnumeric', + '.go': 'text/x-gosrc', + '.gph': 'application/vnd.flographit', + '.gqf': 'application/vnd.grafeq', + '.gqs': 'application/vnd.grafeq', + '.gram': 'application/srgs', + '.gre': 'application/vnd.geometry-explorer', + '.groovy': 'text/x-groovy', + '.grv': 'application/vnd.groove-injector', + '.grxml': 'application/srgs+xml', + '.gs': 'text/x-gosu', + '.gsf': 'application/x-font-ghostscript', + '.gsp': 'text/x-gosu', + '.gst': 'text/x-gosu-template', + '.gsx': 'text/x-gosu', + '.gtar': 'application/x-gtar', + '.gtm': 'application/vnd.groove-tool-message', + '.gtw': 'model/vnd.gtw', + '.gv': 'text/vnd.graphviz', + '.gxt': 'application/vnd.geonext', + '.h': 'text/x-c', + '.h++': 'text/x-c++hdr', + '.h261': 'video/h261', + '.h263': 'video/h263', + '.h264': 'video/h264', + '.hal': 'application/vnd.hal+xml', + '.haml': 'text/x-haml', + '.hbci': 'application/vnd.hbci', + '.hdf': 'application/x-hdf', + '.hdp': 'text/x-dylan-lid', + '.hh': 'text/x-c', + '.hlp': 'application/winhlp', + '.hpgl': 'application/vnd.hp-hpgl', + '.hpid': 'application/vnd.hp-hpid', + '.hpp': 'text/x-c++hdr', + '.hps': 'application/vnd.hp-hps', + '.hqx': 'application/mac-binhex40', + '.hrl': 'text/x-erlang', + '.hs': 'text/x-haskell', + '.htke': 'application/vnd.kenameaapp', + '.htm': 'text/html', + '.html': 'text/html', + '.hvd': 'application/vnd.yamaha.hv-dic', + '.hvp': 'application/vnd.yamaha.hv-voice', + '.hvs': 'application/vnd.yamaha.hv-script', + '.hx': 'text/haxe', + '.hxx': 'text/x-c++hdr', + '.hy': 'text/x-hybris', + '.hyb': 'text/x-hybris', + '.i2g': 'application/vnd.intergeo', + '.icc': 'application/vnd.iccprofile', + '.ice': 'x-conference/x-cooltalk', + '.icm': 'application/vnd.iccprofile', + '.ico': 'image/x-icon', + '.ics': 'text/calendar', + '.idc': 'text/x-chdr', + '.ief': 'image/ief', + '.ifb': 'text/calendar', + '.ifm': 'application/vnd.shana.informed.formdata', + '.iges': 'model/iges', + '.igl': 'application/vnd.igloader', + '.igm': 'application/vnd.insors.igm', + '.igs': 'model/iges', + '.igx': 'application/vnd.micrografx.igx', + '.iif': 'application/vnd.shana.informed.interchange', + '.ik': 'text/x-iokesrc', + '.imp': 'application/vnd.accpac.simply.imp', + '.ims': 'application/vnd.ms-ims', + '.in': 'text/plain', + '.inc': 'text/x-povray', + '.ini': 'text/x-ini', + '.intr': 'text/x-dylan', + '.io': 'text/x-iosrc', + '.ipfix': 'application/ipfix', + '.ipk': 'application/vnd.shana.informed.package', + '.irm': 'application/vnd.ibm.rights-management', + '.irp': 'application/vnd.irepository.package+xml', + '.iso': 'application/octet-stream', + '.itp': 'application/vnd.shana.informed.formtemplate', + '.ivp': 'application/vnd.immervision-ivp', + '.ivu': 'application/vnd.immervision-ivu', + '.j': 'text/x-objective-j', + '.jad': 'text/vnd.sun.j2me.app-descriptor', + '.jade': 'text/x-jade', + '.jam': 'application/vnd.jam', + '.jar': 'application/java-archive', + '.java': 'text/x-java-source', + '.jbst': 'text/x-duel', + '.jisp': 'application/vnd.jisp', + '.jl': 'text/x-julia', + '.jlt': 'application/vnd.hp-jlyt', + '.jnlp': 'application/x-java-jnlp-file', + '.joda': 'application/vnd.joost.joda-archive', + '.jp2': 'image/jp2', + '.jpe': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.jpg': 'image/jpeg', + '.jpgm': 'video/jpm', + '.jpgv': 'video/jpeg', + '.jpm': 'video/jpm', + '.js': 'application/javascript', + '.json': 'application/json', + '.jsp': 'application/x-jsp', + '.kar': 'audio/midi', + '.karbon': 'application/vnd.kde.karbon', + '.kfo': 'application/vnd.kde.kformula', + '.kia': 'application/vnd.kidspiration', + '.kid': 'application/x-genshi', + '.kk': 'text/x-koka', + '.kki': 'text/x-koka', + '.kml': 'application/vnd.google-earth.kml+xml', + '.kmz': 'application/vnd.google-earth.kmz', + '.kne': 'application/vnd.kinar', + '.knp': 'application/vnd.kinar', + '.kon': 'application/vnd.kde.kontour', + '.kpr': 'application/vnd.kde.kpresenter', + '.kpt': 'application/vnd.kde.kpresenter', + '.ksh': 'text/plain', + '.ksp': 'application/vnd.kde.kspread', + '.kt': 'text/x-kotlin', + '.ktr': 'application/vnd.kahootz', + '.ktx': 'image/ktx', + '.ktz': 'application/vnd.kahootz', + '.kwd': 'application/vnd.kde.kword', + '.kwt': 'application/vnd.kde.kword', + '.lasso': 'text/x-lasso', + '.lasso[89]': 'text/x-lasso', + '.lasxml': 'application/vnd.las.las+xml', + '.latex': 'application/x-latex', + '.lbd': 'application/vnd.llamagraphics.life-balance.desktop', + '.lbe': 'application/vnd.llamagraphics.life-balance.exchange+xml', + '.les': 'application/vnd.hhe.lesson-player', + '.less': 'text/x-less', + '.lgt': 'text/x-logtalk', + '.lha': 'application/octet-stream', + '.lhs': 'text/x-literate-haskell', + '.lid': 'text/x-dylan-lid', + '.link66': 'application/vnd.route66.link66+xml', + '.lisp': 'text/x-common-lisp', + '.list': 'text/plain', + '.list3820': 'application/vnd.ibm.modcap', + '.listafp': 'application/vnd.ibm.modcap', + '.ll': 'text/x-llvm', + '.log': 'text/plain', + '.lostxml': 'application/lost+xml', + '.lrf': 'application/octet-stream', + '.lrm': 'application/vnd.ms-lrm', + '.ls': 'text/x-livescript', + '.lsp': 'text/x-newlisp', + '.ltf': 'application/vnd.frogans.ltf', + '.ltx': 'text/x-latex', + '.lua': 'text/x-lua', + '.lvp': 'audio/vnd.lucent.voice', + '.lwp': 'application/vnd.lotus-wordpro', + '.lzh': 'application/octet-stream', + '.m': 'text/octave', + '.m13': 'application/x-msmediaview', + '.m14': 'application/x-msmediaview', + '.m1v': 'video/mpeg', + '.m21': 'application/mp21', + '.m2a': 'audio/mpeg', + '.m2v': 'video/mpeg', + '.m3a': 'audio/mpeg', + '.m3u': 'audio/x-mpegurl', + '.m3u8': 'application/x-mpegurl', + '.m4a': 'audio/mp4a-latm', + '.m4p': 'audio/mp4a-latm', + '.m4u': 'video/vnd.mpegurl', + '.m4v': 'video/x-m4v', + '.ma': 'application/mathematica', + '.mac': 'image/x-macpaint', + '.mads': 'application/mads+xml', + '.mag': 'application/vnd.ecowin.chart', + '.mak': 'text/x-makefile', + '.maker': 'application/vnd.framemaker', + '.mako': 'application/x-mako', + '.man': 'text/troff', + '.manifest': 'text/cache-manifest', + '.maql': 'text/x-gooddata-maql', + '.markdown': 'text/x-markdown', + '.mathml': 'application/mathml+xml', + '.mb': 'application/mathematica', + '.mbk': 'application/vnd.mobius.mbk', + '.mbox': 'application/mbox', + '.mc': 'application/x-mason', + '.mc1': 'application/vnd.medcalcdata', + '.mcd': 'application/vnd.mcd', + '.mcurl': 'text/vnd.curl.mcurl', + '.md': 'text/x-minidsrc', + '.mdb': 'application/x-msaccess', + '.mdi': 'image/vnd.ms-modi', + '.mdown': 'text/x-markdown', + '.me': 'text/troff', + '.mesh': 'model/mesh', + '.meta4': 'application/metalink4+xml', + '.mets': 'application/mets+xml', + '.mfm': 'application/vnd.mfmp', + '.mgp': 'application/vnd.osgeo.mapguide.package', + '.mgz': 'application/vnd.proteus.magazine', + '.mht': 'message/rfc822', + '.mhtml': 'message/rfc822', + '.mi': 'application/x-mason', + '.mid': 'audio/midi', + '.midi': 'audio/midi', + '.mif': 'application/vnd.mif', + '.mime': 'message/rfc822', + '.mj2': 'video/mj2', + '.mjp2': 'video/mj2', + '.ml': 'text/x-ocaml', + '.mli': 'text/x-ocaml', + '.mll': 'text/x-ocaml', + '.mlp': 'application/vnd.dolby.mlp', + '.mly': 'text/x-ocaml', + '.mm': 'text/x-objective-c++', + '.mmd': 'application/vnd.chipnuts.karaoke-mmd', + '.mmf': 'application/vnd.smaf', + '.mmr': 'image/vnd.fujixerox.edmics-mmr', + '.mny': 'application/x-msmoney', + '.mo': 'text/x-modelica', + '.mobi': 'application/x-mobipocket-ebook', + '.mobipocket-ebook': 'application/octet-stream', + '.mod': 'text/x-modula2', + '.mods': 'application/mods+xml', + '.monkey': 'text/x-monkey', + '.moo': 'text/x-moocode', + '.moon': 'text/x-moonscript', + '.mov': 'video/quicktime', + '.movie': 'video/x-sgi-movie', + '.mp2': 'audio/mpeg', + '.mp21': 'application/mp21', + '.mp2a': 'audio/mpeg', + '.mp3': 'audio/mpeg', + '.mp4': 'video/mp4', + '.mp4a': 'audio/mp4', + '.mp4s': 'application/mp4', + '.mp4v': 'video/mp4', + '.mpa': 'video/mpeg', + '.mpc': 'application/vnd.mophun.certificate', + '.mpe': 'video/mpeg', + '.mpeg': 'video/mpeg', + '.mpg': 'video/mpeg', + '.mpg4': 'video/mp4', + '.mpga': 'audio/mpeg', + '.mpkg': 'application/vnd.apple.installer+xml', + '.mpm': 'application/vnd.blueice.multipass', + '.mpn': 'application/vnd.mophun.application', + '.mpp': 'application/vnd.ms-project', + '.mpt': 'application/vnd.ms-project', + '.mpy': 'application/vnd.ibm.minipay', + '.mqy': 'application/vnd.mobius.mqy', + '.mrc': 'application/marc', + '.mrcx': 'application/marcxml+xml', + '.ms': 'text/troff', + '.mscml': 'application/mediaservercontrol+xml', + '.mseed': 'application/vnd.fdsn.mseed', + '.mseq': 'application/vnd.mseq', + '.msf': 'application/vnd.epson.msf', + '.msh': 'model/mesh', + '.msi': 'application/x-msdownload', + '.msl': 'application/vnd.mobius.msl', + '.msty': 'application/vnd.muvee.style', + '.mts': 'model/vnd.mts', + '.mus': 'application/vnd.musician', + '.musicxml': 'application/vnd.recordare.musicxml+xml', + '.mvb': 'application/x-msmediaview', + '.mwf': 'application/vnd.mfer', + '.mxf': 'application/mxf', + '.mxl': 'application/vnd.recordare.musicxml', + '.mxml': 'application/xv+xml', + '.mxs': 'application/vnd.triscape.mxs', + '.mxu': 'video/vnd.mpegurl', + '.myt': 'application/x-myghty', + '.n': 'text/x-nemerle', + '.n-gage': 'application/vnd.nokia.n-gage.symbian.install', + '.n3': 'text/n3', + '.nb': 'application/mathematica', + '.nbp': 'application/vnd.wolfram.player', + '.nc': 'application/x-netcdf', + '.ncx': 'application/x-dtbncx+xml', + '.ngdat': 'application/vnd.nokia.n-gage.data', + '.nim': 'text/x-nimrod', + '.nimrod': 'text/x-nimrod', + '.nl': 'text/x-newlisp', + '.nlu': 'application/vnd.neurolanguage.nlu', + '.nml': 'application/vnd.enliven', + '.nnd': 'application/vnd.noblenet-directory', + '.nns': 'application/vnd.noblenet-sealer', + '.nnw': 'application/vnd.noblenet-web', + '.npx': 'image/vnd.net-fpx', + '.ns2': 'text/x-newspeak', + '.nsf': 'application/vnd.lotus-notes', + '.nsh': 'text/x-nsis', + '.nsi': 'text/x-nsis', + '.nws': 'message/rfc822', + '.o': 'application/octet-stream', + '.oa2': 'application/vnd.fujitsu.oasys2', + '.oa3': 'application/vnd.fujitsu.oasys3', + '.oas': 'application/vnd.fujitsu.oasys', + '.obd': 'application/x-msbinder', + '.obj': 'application/octet-stream', + '.objdump': 'text/x-objdump', + '.oda': 'application/oda', + '.odb': 'application/vnd.oasis.opendocument.database', + '.odc': 'application/vnd.oasis.opendocument.chart', + '.odf': 'application/vnd.oasis.opendocument.formula', + '.odft': 'application/vnd.oasis.opendocument.formula-template', + '.odg': 'application/vnd.oasis.opendocument.graphics', + '.odi': 'application/vnd.oasis.opendocument.image', + '.odm': 'application/vnd.oasis.opendocument.text-master', + '.odp': 'application/vnd.oasis.opendocument.presentation', + '.ods': 'application/vnd.oasis.opendocument.spreadsheet', + '.odt': 'application/vnd.oasis.opendocument.text', + '.oga': 'audio/ogg', + '.ogg': 'audio/ogg', + '.ogv': 'video/ogg', + '.ogx': 'application/ogg', + '.onepkg': 'application/onenote', + '.onetmp': 'application/onenote', + '.onetoc': 'application/onenote', + '.onetoc2': 'application/onenote', + '.ooc': 'text/x-ooc', + '.opa': 'text/x-opa', + '.opf': 'application/oebps-package+xml', + '.oprc': 'application/vnd.palm', + '.org': 'application/vnd.lotus-organizer', + '.osf': 'application/vnd.yamaha.openscoreformat', + '.osfpvg': 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + '.otc': 'application/vnd.oasis.opendocument.chart-template', + '.otf': 'application/x-font-otf', + '.otg': 'application/vnd.oasis.opendocument.graphics-template', + '.oth': 'application/vnd.oasis.opendocument.text-web', + '.oti': 'application/vnd.oasis.opendocument.image-template', + '.otp': 'application/vnd.oasis.opendocument.presentation-template', + '.ots': 'application/vnd.oasis.opendocument.spreadsheet-template', + '.ott': 'application/vnd.oasis.opendocument.text-template', + '.oxt': 'application/vnd.openofficeorg.extension', + '.p': 'text/x-pascal', + '.p10': 'application/pkcs10', + '.p12': 'application/x-pkcs12', + '.p7b': 'application/x-pkcs7-certificates', + '.p7c': 'application/pkcs7-mime', + '.p7m': 'application/pkcs7-mime', + '.p7r': 'application/x-pkcs7-certreqresp', + '.p7s': 'application/pkcs7-signature', + '.p8': 'application/pkcs8', + '.pas': 'text/x-pascal', + '.patch': 'text/x-diff', + '.paw': 'application/vnd.pawaafile', + '.pbd': 'application/vnd.powerbuilder6', + '.pbm': 'image/x-portable-bitmap', + '.pcf': 'application/x-font-pcf', + '.pcl': 'application/vnd.hp-pcl', + '.pclxl': 'application/vnd.hp-pclxl', + '.pct': 'image/x-pict', + '.pcurl': 'application/vnd.curl.pcurl', + '.pcx': 'image/x-pcx', + '.pdb': 'application/vnd.palm', + '.pdf': 'application/pdf', + '.pfa': 'application/x-font-type1', + '.pfb': 'application/x-font-type1', + '.pfm': 'application/x-font-type1', + '.pfr': 'application/font-tdpfr', + '.pfx': 'application/x-pkcs12', + '.pgm': 'image/x-portable-graymap', + '.pgn': 'application/x-chess-pgn', + '.pgp': 'application/pgp-encrypted', + '.php': 'text/x-php', + '.php[345]': 'text/x-php', + '.phtml': 'application/x-php', + '.pic': 'image/x-pict', + '.pict': 'image/pict', + '.pkg': 'application/octet-stream', + '.pki': 'application/pkixcmp', + '.pkipath': 'application/pkix-pkipath', + '.pl': 'text/plain', + '.plb': 'application/vnd.3gpp.pic-bw-large', + '.plc': 'application/vnd.mobius.plc', + '.plf': 'application/vnd.pocketlearn', + '.plot': 'text/x-gnuplot', + '.pls': 'application/pls+xml', + '.plt': 'text/x-gnuplot', + '.pm': 'text/x-perl', + '.pml': 'application/vnd.ctc-posml', + '.png': 'image/png', + '.pnm': 'image/x-portable-anymap', + '.pnt': 'image/x-macpaint', + '.pntg': 'image/x-macpaint', + '.po': 'application/x-gettext', + '.portpkg': 'application/vnd.macports.portpkg', + '.pot': 'application/vnd.ms-powerpoint', + '.potm': 'application/vnd.ms-powerpoint.template.macroenabled.12', + '.potx': 'application/vnd.openxmlformats-officedocument.presentationml.template', + '.pov': 'text/x-povray', + '.ppa': 'application/vnd.ms-powerpoint', + '.ppam': 'application/vnd.ms-powerpoint.addin.macroenabled.12', + '.ppd': 'application/vnd.cups-ppd', + '.ppm': 'image/x-portable-pixmap', + '.pps': 'application/vnd.ms-powerpoint', + '.ppsm': 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + '.ppsx': 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + '.ppt': 'application/vnd.ms-powerpoint', + '.pptm': 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + '.pqa': 'application/vnd.palm', + '.prc': 'application/x-mobipocket-ebook', + '.pre': 'application/vnd.lotus-freelance', + '.prf': 'application/pics-rules', + '.pro': 'text/idl', + '.prolog': 'text/x-prolog', + '.properties': 'text/x-properties', + '.ps': 'application/postscript', + '.ps1': 'text/x-powershell', + '.psb': 'application/vnd.3gpp.pic-bw-small', + '.psd': 'image/vnd.adobe.photoshop', + '.psf': 'application/x-font-linux-psf', + '.pskcxml': 'application/pskc+xml', + '.ptid': 'application/vnd.pvi.ptid1', + '.pub': 'application/x-mspublisher', + '.pvb': 'application/vnd.3gpp.pic-bw-var', + '.pwn': 'application/vnd.3m.post-it-notes', + '.pwz': 'application/vnd.ms-powerpoint', + '.pxd': 'text/x-cython', + '.pxi': 'text/x-cython', + '.py': 'text/x-python', + '.py3tb': 'text/x-python3-traceback', + '.pya': 'audio/vnd.ms-playready.media.pya', + '.pyc': 'application/x-python-code', + '.pyo': 'application/x-python-code', + '.pypylog': 'application/x-pypylog', + '.pytb': 'text/x-python-traceback', + '.pyv': 'video/vnd.ms-playready.media.pyv', + '.pyw': 'text/x-python', + '.pyx': 'text/x-cython', + '.qam': 'application/vnd.epson.quickanime', + '.qbo': 'application/vnd.intu.qbo', + '.qfx': 'application/vnd.intu.qfx', + '.qml': 'application/x-qml', + '.qps': 'application/vnd.publishare-delta-tree', + '.qt': 'video/quicktime', + '.qti': 'image/x-quicktime', + '.qtif': 'image/x-quicktime', + '.qwd': 'application/vnd.quark.quarkxpress', + '.qwt': 'application/vnd.quark.quarkxpress', + '.qxb': 'application/vnd.quark.quarkxpress', + '.qxd': 'application/vnd.quark.quarkxpress', + '.qxl': 'application/vnd.quark.quarkxpress', + '.qxt': 'application/vnd.quark.quarkxpress', + '.r': 'text/x-rebol', + '.r3': 'text/x-rebol', + '.ra': 'audio/x-pn-realaudio', + '.rake': 'text/x-ruby', + '.ram': 'audio/x-pn-realaudio', + '.rar': 'application/x-rar-compressed', + '.ras': 'image/x-cmu-raster', + '.rb': 'text/x-ruby', + '.rbw': 'text/x-ruby', + '.rbx': 'text/x-ruby', + '.rc': 'text/x-stsrc', + '.rcprofile': 'application/vnd.ipunplugged.rcprofile', + '.rdf': 'application/rdf+xml', + '.rdz': 'application/vnd.data-vision.rdz', + '.reg': 'text/x-windows-registry', + '.rep': 'application/vnd.businessobjects', + '.res': 'application/x-dtbresource+xml', + '.rest': 'text/x-rst', + '.rgb': 'image/x-rgb', + '.rhtml': 'text/html+ruby', + '.rif': 'application/reginfo+xml', + '.rip': 'audio/vnd.rip', + '.rkt': 'text/x-racket', + '.rktl': 'text/x-racket', + '.rl': 'application/resource-lists+xml', + '.rlc': 'image/vnd.fujixerox.edmics-rlc', + '.rld': 'application/resource-lists-diff+xml', + '.rm': 'application/vnd.rn-realmedia', + '.rmi': 'audio/midi', + '.rmp': 'audio/x-pn-realaudio-plugin', + '.rms': 'application/vnd.jcp.javame.midlet-rms', + '.rnc': 'application/relax-ng-compact-syntax', + '.robot': 'text/x-robotframework', + '.roff': 'text/troff', + '.rp9': 'application/vnd.cloanto.rp9', + '.rpss': 'application/vnd.nokia.radio-presets', + '.rpst': 'application/vnd.nokia.radio-preset', + '.rq': 'application/sparql-query', + '.rs': 'application/rls-services+xml', + '.rsd': 'application/rsd+xml', + '.rss': 'application/rss+xml', + '.rst': 'text/x-rst', + '.rtf': 'application/rtf', + '.rtx': 'text/richtext', + '.s': 'text/x-asm', + '.saf': 'application/vnd.yamaha.smaf-audio', + '.sage': 'text/x-python', + '.sass': 'text/x-sass', + '.sbml': 'application/sbml+xml', + '.sc': 'application/vnd.ibm.secure-container', + '.scala': 'text/x-scala', + '.scaml': 'text/x-scaml', + '.scd': 'application/x-msschedule', + '.sce': 'text/scilab', + '.sci': 'text/scilab', + '.scm': 'application/vnd.lotus-screencam', + '.scq': 'application/scvp-cv-request', + '.scs': 'application/scvp-cv-response', + '.scss': 'text/x-scss', + '.scurl': 'text/vnd.curl.scurl', + '.sda': 'application/vnd.stardivision.draw', + '.sdc': 'application/vnd.stardivision.calc', + '.sdd': 'application/vnd.stardivision.impress', + '.sdkd': 'application/vnd.solent.sdkm+xml', + '.sdkm': 'application/vnd.solent.sdkm+xml', + '.sdp': 'application/sdp', + '.sdw': 'application/vnd.stardivision.writer', + '.see': 'application/vnd.seemail', + '.seed': 'application/vnd.fdsn.seed', + '.sema': 'application/vnd.sema', + '.semd': 'application/vnd.semd', + '.semf': 'application/vnd.semf', + '.ser': 'application/java-serialized-object', + '.setpay': 'application/set-payment-initiation', + '.setreg': 'application/set-registration-initiation', + '.sfd-hdstx': 'application/vnd.hydrostatix.sof-data', + '.sfs': 'application/vnd.spotfire.sfs', + '.sgl': 'application/vnd.stardivision.writer-global', + '.sgm': 'text/sgml', + '.sgml': 'text/sgml', + '.sh': 'application/x-sh', + '.sh-session': 'application/x-shell-session', + '.shar': 'application/x-shar', + '.shell-session': 'application/x-sh-session', + '.shf': 'application/shf+xml', + '.sig': 'application/pgp-signature', + '.silo': 'model/mesh', + '.sis': 'application/vnd.symbian.install', + '.sisx': 'application/vnd.symbian.install', + '.sit': 'application/x-stuffit', + '.sitx': 'application/x-stuffitx', + '.skd': 'application/vnd.koan', + '.skm': 'application/vnd.koan', + '.skp': 'application/vnd.koan', + '.skt': 'application/vnd.koan', + '.sldm': 'application/vnd.ms-powerpoint.slide.macroenabled.12', + '.sldx': 'application/vnd.openxmlformats-officedocument.presentationml.slide', + '.slt': 'application/vnd.epson.salt', + '.sm': 'application/vnd.stepmania.stepchart', + '.smali': 'text/smali', + '.smf': 'application/vnd.stardivision.math', + '.smi': 'application/smil+xml', + '.smil': 'application/smil+xml', + '.sml': 'text/x-standardml', + '.snd': 'audio/basic', + '.snf': 'application/x-font-snf', + '.snobol': 'text/x-snobol', + '.so': 'application/octet-stream', + '.sp': 'text/x-sourcepawn', + '.spc': 'application/x-pkcs7-certificates', + '.spec': 'text/x-rpm-spec', + '.spf': 'application/vnd.yamaha.smaf-phrase', + '.spl': 'application/x-futuresplash', + '.spot': 'text/vnd.in3d.spot', + '.spp': 'application/scvp-vp-response', + '.spq': 'application/scvp-vp-request', + '.spt': 'application/x-cheetah', + '.spx': 'audio/ogg', + '.sql': 'text/x-sql', + '.sqlite3-console': 'text/x-sqlite3-console', + '.src': 'application/x-wais-source', + '.sru': 'application/sru+xml', + '.srx': 'application/sparql-results+xml', + '.ss': 'text/x-scheme', + '.sse': 'application/vnd.kodak-descriptor', + '.ssf': 'application/vnd.epson.ssf', + '.ssml': 'application/ssml+xml', + '.ssp': 'application/x-ssp', + '.st': 'application/vnd.sailingtracker.track', + '.stc': 'application/vnd.sun.xml.calc.template', + '.std': 'application/vnd.sun.xml.draw.template', + '.stf': 'application/vnd.wt.stf', + '.sti': 'application/vnd.sun.xml.impress.template', + '.stk': 'application/hyperstudio', + '.stl': 'application/vnd.ms-pki.stl', + '.str': 'application/vnd.pg.format', + '.stw': 'application/vnd.sun.xml.writer.template', + '.sub': 'image/vnd.dvb.subtitle', + '.sus': 'application/vnd.sus-calendar', + '.susp': 'application/vnd.sus-calendar', + '.sv': 'text/x-systemverilog', + '.sv4cpio': 'application/x-sv4cpio', + '.sv4crc': 'application/x-sv4crc', + '.svc': 'application/vnd.dvb.service', + '.svd': 'application/vnd.svd', + '.svg': 'image/svg+xml', + '.svgz': 'image/svg+xml', + '.svh': 'text/x-systemverilog', + '.swa': 'application/x-director', + '.swf': 'application/x-shockwave-flash', + '.swi': 'application/vnd.aristanetworks.swi', + '.sxc': 'application/vnd.sun.xml.calc', + '.sxd': 'application/vnd.sun.xml.draw', + '.sxg': 'application/vnd.sun.xml.writer.global', + '.sxi': 'application/vnd.sun.xml.impress', + '.sxm': 'application/vnd.sun.xml.math', + '.sxw': 'application/vnd.sun.xml.writer', + '.t': 'text/troff', + '.tac': 'text/x-python', + '.tao': 'application/vnd.tao.intent-module-archive', + '.tar': 'application/x-tar', + '.tcap': 'application/vnd.3gpp2.tcap', + '.tcl': 'application/x-tcl', + '.tcsh': 'application/x-csh', + '.tea': 'text/x-tea', + '.teacher': 'application/vnd.smart.teacher', + '.tei': 'application/tei+xml', + '.teicorpus': 'application/tei+xml', + '.tex': 'application/x-tex', + '.texi': 'application/x-texinfo', + '.texinfo': 'application/x-texinfo', + '.text': 'text/plain', + '.tfi': 'application/thraud+xml', + '.tfm': 'application/x-tex-tfm', + '.thmx': 'application/vnd.ms-officetheme', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.tmo': 'application/vnd.tmobile-livetv', + '.tmpl': 'application/x-cheetah', + '.toc': 'text/x-tex', + '.torrent': 'application/x-bittorrent', + '.tpl': 'application/vnd.groove-tool-template', + '.tpt': 'application/vnd.trid.tpt', + '.tr': 'text/troff', + '.tra': 'application/vnd.trueapp', + '.trm': 'application/x-msterminal', + '.ts': 'video/mp2t', + '.tsd': 'application/timestamped-data', + '.tst': 'text/scilab', + '.tsv': 'text/tab-separated-values', + '.ttc': 'application/x-font-ttf', + '.ttf': 'application/x-font-ttf', + '.ttl': 'text/turtle', + '.twd': 'application/vnd.simtech-mindmapper', + '.twds': 'application/vnd.simtech-mindmapper', + '.txd': 'application/vnd.genomatix.tuxedo', + '.txf': 'application/vnd.mobius.txf', + '.txt': 'text/plain', + '.u': 'application/x-urbiscript', + '.u32': 'application/x-authorware-bin', + '.udeb': 'application/x-debian-package', + '.ufd': 'application/vnd.ufdl', + '.ufdl': 'application/vnd.ufdl', + '.umj': 'application/vnd.umajin', + '.unityweb': 'application/vnd.unity', + '.uoml': 'application/vnd.uoml+xml', + '.uri': 'text/uri-list', + '.uris': 'text/uri-list', + '.urls': 'text/uri-list', + '.ustar': 'application/x-ustar', + '.utz': 'application/vnd.uiq.theme', + '.uu': 'text/x-uuencode', + '.uva': 'audio/vnd.dece.audio', + '.uvd': 'application/vnd.dece.data', + '.uvf': 'application/vnd.dece.data', + '.uvg': 'image/vnd.dece.graphic', + '.uvh': 'video/vnd.dece.hd', + '.uvi': 'image/vnd.dece.graphic', + '.uvm': 'video/vnd.dece.mobile', + '.uvp': 'video/vnd.dece.pd', + '.uvs': 'video/vnd.dece.sd', + '.uvt': 'application/vnd.dece.ttml+xml', + '.uvu': 'video/vnd.uvvu.mp4', + '.uvv': 'video/vnd.dece.video', + '.uvva': 'audio/vnd.dece.audio', + '.uvvd': 'application/vnd.dece.data', + '.uvvf': 'application/vnd.dece.data', + '.uvvg': 'image/vnd.dece.graphic', + '.uvvh': 'video/vnd.dece.hd', + '.uvvi': 'image/vnd.dece.graphic', + '.uvvm': 'video/vnd.dece.mobile', + '.uvvp': 'video/vnd.dece.pd', + '.uvvs': 'video/vnd.dece.sd', + '.uvvt': 'application/vnd.dece.ttml+xml', + '.uvvu': 'video/vnd.uvvu.mp4', + '.uvvv': 'video/vnd.dece.video', + '.uvvx': 'application/vnd.dece.unspecified', + '.uvx': 'application/vnd.dece.unspecified', + '.v': 'text/x-verilog', + '.vala': 'text/x-vala', + '.vapi': 'text/x-vala', + '.vark': 'text/x-gosu', + '.vb': 'text/vbscript', + '.vcd': 'application/x-cdlink', + '.vcf': 'text/x-vcard', + '.vcg': 'application/vnd.groove-vcard', + '.vcs': 'text/x-vcalendar', + '.vcx': 'application/vnd.vcx', + '.vert': 'text/x-glslsrc', + '.vhd': 'text/x-vhdl', + '.vhdl': 'text/x-vhdl', + '.vim': 'text/x-vim', + '.vis': 'application/vnd.visionary', + '.viv': 'video/vnd.vivo', + '.vor': 'application/vnd.stardivision.writer', + '.vox': 'application/x-authorware-bin', + '.vrml': 'model/vrml', + '.vsd': 'application/vnd.visio', + '.vsf': 'application/vnd.vsf', + '.vss': 'application/vnd.visio', + '.vst': 'application/vnd.visio', + '.vsw': 'application/vnd.visio', + '.vtu': 'model/vnd.vtu', + '.vxml': 'application/voicexml+xml', + '.w3d': 'application/x-director', + '.wad': 'application/x-doom', + '.wav': 'audio/x-wav', + '.wax': 'audio/x-ms-wax', + '.wbmp': 'image/vnd.wap.wbmp', + '.wbs': 'application/vnd.criticaltools.wbs+xml', + '.wbxml': 'application/vnd.wap.wbxml', + '.wcm': 'application/vnd.ms-works', + '.wdb': 'application/vnd.ms-works', + '.weba': 'audio/webm', + '.webm': 'video/webm', + '.webp': 'image/webp', + '.weechatlog': 'text/x-irclog', + '.wg': 'application/vnd.pmi.widget', + '.wgt': 'application/widget', + '.wiz': 'application/msword', + '.wks': 'application/vnd.ms-works', + '.wlua': 'text/x-lua', + '.wm': 'video/x-ms-wm', + '.wma': 'audio/x-ms-wma', + '.wmd': 'application/x-ms-wmd', + '.wmf': 'application/x-msmetafile', + '.wml': 'text/vnd.wap.wml', + '.wmlc': 'application/vnd.wap.wmlc', + '.wmls': 'text/vnd.wap.wmlscript', + '.wmlsc': 'application/vnd.wap.wmlscriptc', + '.wmv': 'video/x-ms-wmv', + '.wmx': 'video/x-ms-wmx', + '.wmz': 'application/x-ms-wmz', + '.woff': 'application/x-font-woff', + '.wpd': 'application/vnd.wordperfect', + '.wpl': 'application/vnd.ms-wpl', + '.wps': 'application/vnd.ms-works', + '.wqd': 'application/vnd.wqd', + '.wri': 'application/x-mswrite', + '.wrl': 'model/vrml', + '.wsdl': 'application/wsdl+xml', + '.wspolicy': 'application/wspolicy+xml', + '.wtb': 'application/vnd.webturbo', + '.wvx': 'video/x-ms-wvx', + '.x': 'text/x-logos', + '.x32': 'application/x-authorware-bin', + '.x3d': 'application/vnd.hzn-3d-crossword', + '.xap': 'application/x-silverlight-app', + '.xar': 'application/vnd.xara', + '.xbap': 'application/x-ms-xbap', + '.xbd': 'application/vnd.fujixerox.docuworks.binder', + '.xbm': 'image/x-xbitmap', + '.xdf': 'application/xcap-diff+xml', + '.xdm': 'application/vnd.syncml.dm+xml', + '.xdp': 'application/vnd.adobe.xdp+xml', + '.xdssc': 'application/dssc+xml', + '.xdw': 'application/vnd.fujixerox.docuworks', + '.xenc': 'application/xenc+xml', + '.xer': 'application/patch-ops-error+xml', + '.xfdf': 'application/vnd.adobe.xfdf', + '.xfdl': 'application/vnd.xfdl', + '.xht': 'application/xhtml+xml', + '.xhtml': 'application/xhtml+xml', + '.xhvml': 'application/xv+xml', + '.xi': 'text/x-logos', + '.xif': 'image/vnd.xiff', + '.xla': 'application/vnd.ms-excel', + '.xlam': 'application/vnd.ms-excel.addin.macroenabled.12', + '.xlb': 'application/vnd.ms-excel', + '.xlc': 'application/vnd.ms-excel', + '.xlm': 'application/vnd.ms-excel', + '.xls': 'application/vnd.ms-excel', + '.xlsb': 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + '.xlsm': 'application/vnd.ms-excel.sheet.macroenabled.12', + '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + '.xlt': 'application/vnd.ms-excel', + '.xltm': 'application/vnd.ms-excel.template.macroenabled.12', + '.xltx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + '.xlw': 'application/vnd.ms-excel', + '.xm': 'text/x-logos', + '.xmi': 'text/x-logos', + '.xml': 'application/xml', + '.xo': 'application/vnd.olpc-sugar', + '.xop': 'application/xop+xml', + '.xpdl': 'application/xml', + '.xpi': 'application/x-xpinstall', + '.xpl': 'application/xsl+xml', + '.xpm': 'image/x-xpixmap', + '.xpr': 'application/vnd.is-xpr', + '.xps': 'application/vnd.ms-xpsdocument', + '.xpw': 'application/vnd.intercon.formnet', + '.xpx': 'application/vnd.intercon.formnet', + '.xq': 'application/xquery', + '.xql': 'application/xquery', + '.xqm': 'application/xquery', + '.xquery': 'application/xquery', + '.xqy': 'application/xquery', + '.xsd': 'application/xml', + '.xsl': 'application/xml', + '.xslt': 'application/xslt+xml', + '.xsm': 'application/vnd.syncml+xml', + '.xspf': 'application/xspf+xml', + '.xtend': 'text/x-xtend', + '.xul': 'application/vnd.mozilla.xul+xml', + '.xvm': 'application/xv+xml', + '.xvml': 'application/xv+xml', + '.xwd': 'image/x-xwindowdump', + '.xyz': 'chemical/x-xyz', + '.yaml': 'text/x-yaml', + '.yang': 'application/yang', + '.yin': 'application/yin+xml', + '.yml': 'text/x-yaml', + '.zaz': 'application/vnd.zzazz.deck+xml', + '.zip': 'application/zip', + '.zir': 'application/vnd.zul', + '.zirz': 'application/vnd.zul', + '.zmm': 'application/vnd.handheld-entertainment+xml'} +] + + +def get_mimetypes_db(extra_types=None): + import mimetypes + types_map = TYPES_MAP + if extra_types: + types_map = TYPES_MAP[::] # copy the initial version for extending + types_map[1].update(extra_types) + db = mimetypes.MimeTypes() + db.types_map = types_map + return db diff --git a/rhodecode/lib/vcs/conf/settings.py b/rhodecode/lib/vcs/conf/settings.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/conf/settings.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Internal settings for vcs-lib +""" + +# list of default encoding used in safe_unicode/safe_str methods +DEFAULT_ENCODINGS = ['utf8'] + +# Optional arguments to rev-filter, it has to be a list +# It can also be ['--branches', '--tags'] +GIT_REV_FILTER = ['--all'] + +HG_USE_REBASE_FOR_MERGING = False + +# Compatibility version when creating SVN repositories. None means newest. +# Other available options are: pre-1.4-compatible, pre-1.5-compatible, +# pre-1.6-compatible, pre-1.8-compatible +SVN_COMPATIBLE_VERSION = None + +ALIASES = ['hg', 'git', 'svn'] + +BACKENDS = { + 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository', + 'git': 'rhodecode.lib.vcs.backends.git.GitRepository', + 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository', +} + +# TODO: Remove once controllers/files.py is adjusted +ARCHIVE_SPECS = { + 'tbz2': ('application/x-bzip2', '.tar.bz2'), + 'tgz': ('application/x-gzip', '.tar.gz'), + 'zip': ('application/zip', '.zip'), +} + +PYRO_PORT = 9900 + +PYRO_GIT = 'git_remote' +PYRO_HG = 'hg_remote' +PYRO_SVN = 'svn_remote' +PYRO_VCSSERVER = 'vcs_server' +PYRO_GIT_REMOTE_WSGI = 'git_remote_wsgi' +PYRO_HG_REMOTE_WSGI = 'hg_remote_wsgi' + +PYRO_RECONNECT_TRIES = 15 +""" +How many retries to reconnect will be performed if the connection was lost. + +Each try takes 2s. Doing 15 means that we will give it up to 30s for a +connection to be re-established. +""" + + +def pyro_remote(object_id, server_and_port): + return "PYRO:%s@%s" % (object_id, server_and_port) + + +def available_aliases(): + """ + Mercurial is required for the system to work, so in case vcs.backends does + not include it, we make sure it will be available internally + TODO: anderson: refactor vcs.backends so it won't be necessary, VCS server + should be responsible to dictate available backends. + """ + aliases = ALIASES[:] + if 'hg' not in aliases: + aliases += ['hg'] + return aliases diff --git a/rhodecode/lib/vcs/connection.py b/rhodecode/lib/vcs/connection.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/connection.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Holds connection for remote server. +""" + + +def _not_initialized(*args, **kwargs): + """Placeholder for objects which have to be initialized first.""" + raise Exception("rhodecode.lib.vcs is not yet initialized") + +# TODO: figure out a nice default value for these things +Git = _not_initialized +Hg = _not_initialized +Svn = _not_initialized diff --git a/rhodecode/lib/vcs/exceptions.py b/rhodecode/lib/vcs/exceptions.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/exceptions.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Custom vcs exceptions module. +""" + +import functools +import urllib2 + + +class VCSError(Exception): + pass + + +class RepositoryError(VCSError): + pass + + +class RepositoryRequirementError(RepositoryError): + pass + + +class VCSBackendNotSupportedError(VCSError): + """ + Exception raised when VCSServer does not support requested backend + """ + + +class EmptyRepositoryError(RepositoryError): + pass + + +class TagAlreadyExistError(RepositoryError): + pass + + +class TagDoesNotExistError(RepositoryError): + pass + + +class BranchAlreadyExistError(RepositoryError): + pass + + +class BranchDoesNotExistError(RepositoryError): + pass + + +class CommitError(RepositoryError): + """ + Exceptions related to an existing commit + """ + + +class CommitDoesNotExistError(CommitError): + pass + + +class CommittingError(RepositoryError): + """ + Exceptions happening while creating a new commit + """ + + +class NothingChangedError(CommittingError): + pass + + +class NodeError(VCSError): + pass + + +class RemovedFileNodeError(NodeError): + pass + + +class NodeAlreadyExistsError(CommittingError): + pass + + +class NodeAlreadyChangedError(CommittingError): + pass + + +class NodeDoesNotExistError(CommittingError): + pass + + +class NodeNotChangedError(CommittingError): + pass + + +class NodeAlreadyAddedError(CommittingError): + pass + + +class NodeAlreadyRemovedError(CommittingError): + pass + + +class ImproperArchiveTypeError(VCSError): + pass + + +class CommandError(VCSError): + pass + + +class UnhandledException(VCSError): + """ + Signals that something unexpected went wrong. + + This usually means we have a programming error on the side of the VCSServer + and should inspect the logfile of the VCSServer to find more details. + """ + + +_EXCEPTION_MAP = { + 'abort': RepositoryError, + 'archive': ImproperArchiveTypeError, + 'error': RepositoryError, + 'lookup': CommitDoesNotExistError, + 'repo_locked': RepositoryError, + 'requirement': RepositoryRequirementError, + 'unhandled': UnhandledException, + # TODO: johbo: Define our own exception for this and stop abusing + # urllib's exception class. + 'url_error': urllib2.URLError, +} + + +def map_vcs_exceptions(func): + """ + Utility to decorate functions so that plain exceptions are translated. + + The translation is based on `exc_map` which maps a `str` indicating + the error type into an exception class representing this error inside + of the vcs layer. + """ + + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception as e: + + # The error middleware adds information if it finds + # __traceback_info__ in a frame object. This way the remote + # traceback information is made available in error reports. + remote_tb = getattr(e, '_pyroTraceback', None) + if remote_tb: + __traceback_info__ = ( + 'Found Pyro4 remote traceback information:\n\n' + + '\n'.join(remote_tb)) + + # Avoid that remote_tb also appears in the frame + del remote_tb + + # Special vcs errors had an attribute "_vcs_kind" which is used + # to translate them to the proper exception class in the vcs + # client layer. + kind = getattr(e, '_vcs_kind', None) + if kind: + raise _EXCEPTION_MAP[kind](*e.args) + else: + raise + + return wrapper diff --git a/rhodecode/lib/vcs/nodes.py b/rhodecode/lib/vcs/nodes.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/nodes.py @@ -0,0 +1,738 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Module holding everything related to vcs nodes, with vcs2 architecture. +""" + + +import stat + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib.utils import safe_unicode, safe_str +from rhodecode.lib.vcs import path as vcspath +from rhodecode.lib.vcs.backends.base import EmptyCommit, FILEMODE_DEFAULT +from rhodecode.lib.vcs.conf.mtypes import get_mimetypes_db +from rhodecode.lib.vcs.exceptions import NodeError, RemovedFileNodeError + +LARGEFILE_PREFIX = '.hglf' + + +class NodeKind: + SUBMODULE = -1 + DIR = 1 + FILE = 2 + LARGEFILE = 3 + + +class NodeState: + ADDED = u'added' + CHANGED = u'changed' + NOT_CHANGED = u'not changed' + REMOVED = u'removed' + + +class NodeGeneratorBase(object): + """ + Base class for removed added and changed filenodes, it's a lazy generator + class that will create filenodes only on iteration or call + + The len method doesn't need to create filenodes at all + """ + + def __init__(self, current_paths, cs): + self.cs = cs + self.current_paths = current_paths + + def __call__(self): + return [n for n in self] + + def __getslice__(self, i, j): + for p in self.current_paths[i:j]: + yield self.cs.get_node(p) + + def __len__(self): + return len(self.current_paths) + + def __iter__(self): + for p in self.current_paths: + yield self.cs.get_node(p) + + +class AddedFileNodesGenerator(NodeGeneratorBase): + """ + Class holding added files for current commit + """ + + +class ChangedFileNodesGenerator(NodeGeneratorBase): + """ + Class holding changed files for current commit + """ + + +class RemovedFileNodesGenerator(NodeGeneratorBase): + """ + Class holding removed files for current commit + """ + def __iter__(self): + for p in self.current_paths: + yield RemovedFileNode(path=p) + + def __getslice__(self, i, j): + for p in self.current_paths[i:j]: + yield RemovedFileNode(path=p) + + +class Node(object): + """ + Simplest class representing file or directory on repository. SCM backends + should use ``FileNode`` and ``DirNode`` subclasses rather than ``Node`` + directly. + + Node's ``path`` cannot start with slash as we operate on *relative* paths + only. Moreover, every single node is identified by the ``path`` attribute, + so it cannot end with slash, too. Otherwise, path could lead to mistakes. + """ + + commit = None + + def __init__(self, path, kind): + self._validate_path(path) # can throw exception if path is invalid + self.path = safe_str(path.rstrip('/')) # we store paths as str + if path == '' and kind != NodeKind.DIR: + raise NodeError("Only DirNode and its subclasses may be " + "initialized with empty path") + self.kind = kind + + if self.is_root() and not self.is_dir(): + raise NodeError("Root node cannot be FILE kind") + + def _validate_path(self, path): + if path.startswith('/'): + raise NodeError( + "Cannot initialize Node objects with slash at " + "the beginning as only relative paths are supported. " + "Got %s" % (path,)) + + @LazyProperty + def parent(self): + parent_path = self.get_parent_path() + if parent_path: + if self.commit: + return self.commit.get_node(parent_path) + return DirNode(parent_path) + return None + + @LazyProperty + def unicode_path(self): + return safe_unicode(self.path) + + @LazyProperty + def dir_path(self): + """ + Returns name of the directory from full path of this vcs node. Empty + string is returned if there's no directory in the path + """ + _parts = self.path.rstrip('/').rsplit('/', 1) + if len(_parts) == 2: + return safe_unicode(_parts[0]) + return u'' + + @LazyProperty + def name(self): + """ + Returns name of the node so if its path + then only last part is returned. + """ + return safe_unicode(self.path.rstrip('/').split('/')[-1]) + + @property + def kind(self): + return self._kind + + @kind.setter + def kind(self, kind): + if hasattr(self, '_kind'): + raise NodeError("Cannot change node's kind") + else: + self._kind = kind + # Post setter check (path's trailing slash) + if self.path.endswith('/'): + raise NodeError("Node's path cannot end with slash") + + def __cmp__(self, other): + """ + Comparator using name of the node, needed for quick list sorting. + """ + kind_cmp = cmp(self.kind, other.kind) + if kind_cmp: + return kind_cmp + return cmp(self.name, other.name) + + def __eq__(self, other): + for attr in ['name', 'path', 'kind']: + if getattr(self, attr) != getattr(other, attr): + return False + if self.is_file(): + if self.content != other.content: + return False + else: + # For DirNode's check without entering each dir + self_nodes_paths = list(sorted(n.path for n in self.nodes)) + other_nodes_paths = list(sorted(n.path for n in self.nodes)) + if self_nodes_paths != other_nodes_paths: + return False + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return '<%s %r>' % (self.__class__.__name__, self.path) + + def __str__(self): + return self.__repr__() + + def __unicode__(self): + return self.name + + def get_parent_path(self): + """ + Returns node's parent path or empty string if node is root. + """ + if self.is_root(): + return '' + return vcspath.dirname(self.path.rstrip('/')) + '/' + + def is_file(self): + """ + Returns ``True`` if node's kind is ``NodeKind.FILE``, ``False`` + otherwise. + """ + return self.kind == NodeKind.FILE + + def is_dir(self): + """ + Returns ``True`` if node's kind is ``NodeKind.DIR``, ``False`` + otherwise. + """ + return self.kind == NodeKind.DIR + + def is_root(self): + """ + Returns ``True`` if node is a root node and ``False`` otherwise. + """ + return self.kind == NodeKind.DIR and self.path == '' + + def is_submodule(self): + """ + Returns ``True`` if node's kind is ``NodeKind.SUBMODULE``, ``False`` + otherwise. + """ + return self.kind == NodeKind.SUBMODULE + + def is_largefile(self): + """ + Returns ``True`` if node's kind is ``NodeKind.LARGEFILE``, ``False`` + otherwise + """ + return self.kind == NodeKind.LARGEFILE + + def is_link(self): + if self.commit: + return self.commit.is_link(self.path) + return False + + @LazyProperty + def added(self): + return self.state is NodeState.ADDED + + @LazyProperty + def changed(self): + return self.state is NodeState.CHANGED + + @LazyProperty + def not_changed(self): + return self.state is NodeState.NOT_CHANGED + + @LazyProperty + def removed(self): + return self.state is NodeState.REMOVED + + +class FileNode(Node): + """ + Class representing file nodes. + + :attribute: path: path to the node, relative to repository's root + :attribute: content: if given arbitrary sets content of the file + :attribute: commit: if given, first time content is accessed, callback + :attribute: mode: stat mode for a node. Default is `FILEMODE_DEFAULT`. + """ + + def __init__(self, path, content=None, commit=None, mode=None): + """ + Only one of ``content`` and ``commit`` may be given. Passing both + would raise ``NodeError`` exception. + + :param path: relative path to the node + :param content: content may be passed to constructor + :param commit: if given, will use it to lazily fetch content + :param mode: ST_MODE (i.e. 0100644) + """ + if content and commit: + raise NodeError("Cannot use both content and commit") + super(FileNode, self).__init__(path, kind=NodeKind.FILE) + self.commit = commit + self._content = content + self._mode = mode or FILEMODE_DEFAULT + + @LazyProperty + def mode(self): + """ + Returns lazily mode of the FileNode. If `commit` is not set, would + use value given at initialization or `FILEMODE_DEFAULT` (default). + """ + if self.commit: + mode = self.commit.get_file_mode(self.path) + else: + mode = self._mode + return mode + + def _get_content(self): + if self.commit: + content = self.commit.get_file_content(self.path) + else: + content = self._content + return content + + @property + def content(self): + """ + Returns lazily content of the FileNode. If possible, would try to + decode content from UTF-8. + """ + content = self._get_content() + + if bool(content and '\0' in content): + return content + return safe_unicode(content) + + @LazyProperty + def size(self): + if self.commit: + return self.commit.get_file_size(self.path) + raise NodeError( + "Cannot retrieve size of the file without related " + "commit attribute") + + @LazyProperty + def message(self): + if self.commit: + return self.last_commit.message + raise NodeError( + "Cannot retrieve message of the file without related " + "commit attribute") + + @LazyProperty + def last_commit(self): + if self.commit: + pre_load = ["author", "date", "message"] + return self.commit.get_file_commit(self.path, pre_load=pre_load) + raise NodeError( + "Cannot retrieve last commit of the file without " + "related commit attribute") + + def get_mimetype(self): + """ + Mimetype is calculated based on the file's content. If ``_mimetype`` + attribute is available, it will be returned (backends which store + mimetypes or can easily recognize them, should set this private + attribute to indicate that type should *NOT* be calculated). + """ + + if hasattr(self, '_mimetype'): + if (isinstance(self._mimetype, (tuple, list,)) and + len(self._mimetype) == 2): + return self._mimetype + else: + raise NodeError('given _mimetype attribute must be an 2 ' + 'element list or tuple') + + db = get_mimetypes_db() + mtype, encoding = db.guess_type(self.name) + + if mtype is None: + if self.is_binary: + mtype = 'application/octet-stream' + encoding = None + else: + mtype = 'text/plain' + encoding = None + + # try with pygments + try: + from pygments.lexers import get_lexer_for_filename + mt = get_lexer_for_filename(self.name).mimetypes + except Exception: + mt = None + + if mt: + mtype = mt[0] + + return mtype, encoding + + @LazyProperty + def mimetype(self): + """ + Wrapper around full mimetype info. It returns only type of fetched + mimetype without the encoding part. use get_mimetype function to fetch + full set of (type,encoding) + """ + return self.get_mimetype()[0] + + @LazyProperty + def mimetype_main(self): + return self.mimetype.split('/')[0] + + @LazyProperty + def lexer(self): + """ + Returns pygment's lexer class. Would try to guess lexer taking file's + content, name and mimetype. + """ + from pygments import lexers + try: + lexer = lexers.guess_lexer_for_filename(self.name, self.content, stripnl=False) + except lexers.ClassNotFound: + lexer = lexers.TextLexer(stripnl=False) + # returns first alias + return lexer + + @LazyProperty + def lexer_alias(self): + """ + Returns first alias of the lexer guessed for this file. + """ + return self.lexer.aliases[0] + + @LazyProperty + def history(self): + """ + Returns a list of commit for this file in which the file was changed + """ + if self.commit is None: + raise NodeError('Unable to get commit for this FileNode') + return self.commit.get_file_history(self.path) + + @LazyProperty + def annotate(self): + """ + Returns a list of three element tuples with lineno, commit and line + """ + if self.commit is None: + raise NodeError('Unable to get commit for this FileNode') + pre_load = ["author", "date", "message"] + return self.commit.get_file_annotate(self.path, pre_load=pre_load) + + @LazyProperty + def state(self): + if not self.commit: + raise NodeError( + "Cannot check state of the node if it's not " + "linked with commit") + elif self.path in (node.path for node in self.commit.added): + return NodeState.ADDED + elif self.path in (node.path for node in self.commit.changed): + return NodeState.CHANGED + else: + return NodeState.NOT_CHANGED + + @property + def is_binary(self): + """ + Returns True if file has binary content. + """ + _bin = '\0' in self._get_content() + return _bin + + @LazyProperty + def extension(self): + """Returns filenode extension""" + return self.name.split('.')[-1] + + @property + def is_executable(self): + """ + Returns ``True`` if file has executable flag turned on. + """ + return bool(self.mode & stat.S_IXUSR) + + def get_largefile_node(self): + """ + Try to return a Mercurial FileNode from this node. It does internal + checks inside largefile store, if that file exist there it will + create special instance of LargeFileNode which can get content from + LF store. + """ + if self.commit and self.path.startswith(LARGEFILE_PREFIX): + largefile_path = self.path.split(LARGEFILE_PREFIX)[-1].lstrip('/') + return self.commit.get_largefile_node(largefile_path) + + def lines(self, count_empty=False): + all_lines, empty_lines = 0, 0 + + if not self.is_binary: + content = self._get_content() + if count_empty: + all_lines = 0 + empty_lines = 0 + for line in content.splitlines(True): + if line == '\n': + empty_lines += 1 + all_lines += 1 + + return all_lines, all_lines - empty_lines + else: + # fast method + empty_lines = all_lines = content.count('\n') + if all_lines == 0 and content: + # one-line without a newline + empty_lines = all_lines = 1 + + return all_lines, empty_lines + + def __repr__(self): + return '<%s %r @ %s>' % (self.__class__.__name__, self.path, + getattr(self.commit, 'short_id', '')) + + +class RemovedFileNode(FileNode): + """ + Dummy FileNode class - trying to access any public attribute except path, + name, kind or state (or methods/attributes checking those two) would raise + RemovedFileNodeError. + """ + ALLOWED_ATTRIBUTES = [ + 'name', 'path', 'state', 'is_root', 'is_file', 'is_dir', 'kind', + 'added', 'changed', 'not_changed', 'removed' + ] + + def __init__(self, path): + """ + :param path: relative path to the node + """ + super(RemovedFileNode, self).__init__(path=path) + + def __getattribute__(self, attr): + if attr.startswith('_') or attr in RemovedFileNode.ALLOWED_ATTRIBUTES: + return super(RemovedFileNode, self).__getattribute__(attr) + raise RemovedFileNodeError( + "Cannot access attribute %s on RemovedFileNode" % attr) + + @LazyProperty + def state(self): + return NodeState.REMOVED + + +class DirNode(Node): + """ + DirNode stores list of files and directories within this node. + Nodes may be used standalone but within repository context they + lazily fetch data within same repositorty's commit. + """ + + def __init__(self, path, nodes=(), commit=None): + """ + Only one of ``nodes`` and ``commit`` may be given. Passing both + would raise ``NodeError`` exception. + + :param path: relative path to the node + :param nodes: content may be passed to constructor + :param commit: if given, will use it to lazily fetch content + """ + if nodes and commit: + raise NodeError("Cannot use both nodes and commit") + super(DirNode, self).__init__(path, NodeKind.DIR) + self.commit = commit + self._nodes = nodes + + @LazyProperty + def content(self): + raise NodeError( + "%s represents a dir and has no `content` attribute" % self) + + @LazyProperty + def nodes(self): + if self.commit: + nodes = self.commit.get_nodes(self.path) + else: + nodes = self._nodes + self._nodes_dict = dict((node.path, node) for node in nodes) + return sorted(nodes) + + @LazyProperty + def files(self): + return sorted((node for node in self.nodes if node.is_file())) + + @LazyProperty + def dirs(self): + return sorted((node for node in self.nodes if node.is_dir())) + + def __iter__(self): + for node in self.nodes: + yield node + + def get_node(self, path): + """ + Returns node from within this particular ``DirNode``, so it is now + allowed to fetch, i.e. node located at 'docs/api/index.rst' from node + 'docs'. In order to access deeper nodes one must fetch nodes between + them first - this would work:: + + docs = root.get_node('docs') + docs.get_node('api').get_node('index.rst') + + :param: path - relative to the current node + + .. note:: + To access lazily (as in example above) node have to be initialized + with related commit object - without it node is out of + context and may know nothing about anything else than nearest + (located at same level) nodes. + """ + try: + path = path.rstrip('/') + if path == '': + raise NodeError("Cannot retrieve node without path") + self.nodes # access nodes first in order to set _nodes_dict + paths = path.split('/') + if len(paths) == 1: + if not self.is_root(): + path = '/'.join((self.path, paths[0])) + else: + path = paths[0] + return self._nodes_dict[path] + elif len(paths) > 1: + if self.commit is None: + raise NodeError( + "Cannot access deeper nodes without commit") + else: + path1, path2 = paths[0], '/'.join(paths[1:]) + return self.get_node(path1).get_node(path2) + else: + raise KeyError + except KeyError: + raise NodeError("Node does not exist at %s" % path) + + @LazyProperty + def state(self): + raise NodeError("Cannot access state of DirNode") + + @LazyProperty + def size(self): + size = 0 + for root, dirs, files in self.commit.walk(self.path): + for f in files: + size += f.size + + return size + + def __repr__(self): + return '<%s %r @ %s>' % (self.__class__.__name__, self.path, + getattr(self.commit, 'short_id', '')) + + +class RootNode(DirNode): + """ + DirNode being the root node of the repository. + """ + + def __init__(self, nodes=(), commit=None): + super(RootNode, self).__init__(path='', nodes=nodes, commit=commit) + + def __repr__(self): + return '<%s>' % self.__class__.__name__ + + +class SubModuleNode(Node): + """ + represents a SubModule of Git or SubRepo of Mercurial + """ + is_binary = False + size = 0 + + def __init__(self, name, url=None, commit=None, alias=None): + self.path = name + self.kind = NodeKind.SUBMODULE + self.alias = alias + + # we have to use EmptyCommit here since this can point to svn/git/hg + # submodules we cannot get from repository + self.commit = EmptyCommit(str(commit), alias=alias) + self.url = url or self._extract_submodule_url() + + def __repr__(self): + return '<%s %r @ %s>' % (self.__class__.__name__, self.path, + getattr(self.commit, 'short_id', '')) + + def _extract_submodule_url(self): + # TODO: find a way to parse gits submodule file and extract the + # linking URL + return self.path + + @LazyProperty + def name(self): + """ + Returns name of the node so if its path + then only last part is returned. + """ + org = safe_unicode(self.path.rstrip('/').split('/')[-1]) + return u'%s @ %s' % (org, self.commit.short_id) + + +class LargeFileNode(FileNode): + + def _validate_path(self, path): + """ + we override check since the LargeFileNode path is system absolute + """ + + def _get_content(self): + if self.commit: + with open(self.path, 'rb') as f: + content = f.read() + else: + content = self._content + return content + + @property + def content(self): + """ + Returns lazily content of the `FileNode`. If possible, would try to + decode content from UTF-8. + """ + content = self._get_content() + + if bool(content and '\0' in content): + return content + return safe_unicode(content) diff --git a/rhodecode/lib/vcs/path.py b/rhodecode/lib/vcs/path.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/path.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Utility functions to handle vcs paths. +""" + +# Note: Instead of re-implementing things which are provided by posixpath +# we forward import them here. +from posixpath import join, dirname, relpath, split + + +def sanitize(path): + """ + Sanitizes path into a canonical vcs path + """ + return path.lstrip('/') diff --git a/rhodecode/lib/vcs/utils/__init__.py b/rhodecode/lib/vcs/utils/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/utils/__init__.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +This module provides some useful tools for ``vcs`` like annotate/diff html +output. It also includes some internal helpers. +""" + + +def author_email(author): + """ + returns email address of given author. + If any of <,> sign are found, it fallbacks to regex findall() + and returns first found result or empty string + + Regex taken from http://www.regular-expressions.info/email.html + """ + import re + if not author: + return '' + + r = author.find('>') + l = author.find('<') + + if l == -1 or r == -1: + # fallback to regex match of email out of a string + email_re = re.compile(r"""[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!""" + r"""#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z""" + r"""0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]""" + r"""*[a-z0-9])?""", re.IGNORECASE) + m = re.findall(email_re, author) + return m[0] if m else '' + + return author[l + 1:r].strip() + + +def author_name(author): + """ + get name of author, or else username. + It'll try to find an email in the author string and just cut it off + to get the username + """ + + if not author or not '@' in author: + return author + else: + return author.replace(author_email(author), '').replace('<', '')\ + .replace('>', '').strip() diff --git a/rhodecode/lib/vcs/utils/helpers.py b/rhodecode/lib/vcs/utils/helpers.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/utils/helpers.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Utilities aimed to help achieve mostly basic tasks. +""" + + +from __future__ import division + +import re +import os +import time +import datetime +import logging + +from rhodecode.lib.vcs.conf import settings +from rhodecode.lib.vcs.exceptions import VCSError, VCSBackendNotSupportedError + + +log = logging.getLogger(__name__) + + +def get_scm(path, search_path_up=False, explicit_alias=None): + """ + Returns one of alias from ``ALIASES`` (in order of precedence same as + shortcuts given in ``ALIASES``) and top working dir path for the given + argument. If no scm-specific directory is found or more than one scm is + found at that directory, ``VCSError`` is raised. + + :param search_path_up: if set to ``True``, this function would try to + move up to parent directory every time no scm is recognized for the + currently checked path. Default: ``False``. + :param explicit_alias: can be one of available backend aliases, when given + it will return given explicit alias in repositories under more than one + version control, if explicit_alias is different than found it will raise + VCSError + """ + if not os.path.isdir(path): + raise VCSError("Given path %s is not a directory" % path) + + def get_scms(path): + return [(scm, path) for scm in get_scms_for_path(path)] + + found_scms = get_scms(path) + while not found_scms and search_path_up: + newpath = os.path.abspath(os.path.join(path, os.pardir)) + if newpath == path: + break + path = newpath + found_scms = get_scms(path) + + if len(found_scms) > 1: + for scm in found_scms: + if scm[0] == explicit_alias: + return scm + found = ', '.join((x[0] for x in found_scms)) + raise VCSError( + 'More than one [%s] scm found at given path %s' % (found, path)) + + if len(found_scms) is 0: + raise VCSError('No scm found at given path %s' % path) + + return found_scms[0] + + +def get_scm_backend(backend_type): + from rhodecode.lib.vcs.backends import get_backend + return get_backend(backend_type) + + +def get_scms_for_path(path): + """ + Returns all scm's found at the given path. If no scm is recognized + - empty list is returned. + + :param path: path to directory which should be checked. May be callable. + + :raises VCSError: if given ``path`` is not a directory + """ + from rhodecode.lib.vcs.backends import get_backend + if hasattr(path, '__call__'): + path = path() + if not os.path.isdir(path): + raise VCSError("Given path %r is not a directory" % path) + + result = [] + for key in settings.available_aliases(): + try: + backend = get_backend(key) + except VCSBackendNotSupportedError: + log.warning('VCSBackendNotSupportedError: %s not supported', key) + continue + if backend.is_valid_repository(path): + result.append(key) + return result + + +def parse_datetime(text): + """ + Parses given text and returns ``datetime.datetime`` instance or raises + ``ValueError``. + + :param text: string of desired date/datetime or something more verbose, + like *yesterday*, *2weeks 3days*, etc. + """ + + text = text.strip().lower() + + INPUT_FORMATS = ( + '%Y-%m-%d %H:%M:%S', + '%Y-%m-%d %H:%M', + '%Y-%m-%d', + '%m/%d/%Y %H:%M:%S', + '%m/%d/%Y %H:%M', + '%m/%d/%Y', + '%m/%d/%y %H:%M:%S', + '%m/%d/%y %H:%M', + '%m/%d/%y', + ) + for format in INPUT_FORMATS: + try: + return datetime.datetime(*time.strptime(text, format)[:6]) + except ValueError: + pass + + # Try descriptive texts + if text == 'tomorrow': + future = datetime.datetime.now() + datetime.timedelta(days=1) + args = future.timetuple()[:3] + (23, 59, 59) + return datetime.datetime(*args) + elif text == 'today': + return datetime.datetime(*datetime.datetime.today().timetuple()[:3]) + elif text == 'now': + return datetime.datetime.now() + elif text == 'yesterday': + past = datetime.datetime.now() - datetime.timedelta(days=1) + return datetime.datetime(*past.timetuple()[:3]) + else: + days = 0 + matched = re.match( + r'^((?P<weeks>\d+) ?w(eeks?)?)? ?((?P<days>\d+) ?d(ays?)?)?$', text) + if matched: + groupdict = matched.groupdict() + if groupdict['days']: + days += int(matched.groupdict()['days']) + if groupdict['weeks']: + days += int(matched.groupdict()['weeks']) * 7 + past = datetime.datetime.now() - datetime.timedelta(days=days) + return datetime.datetime(*past.timetuple()[:3]) + + raise ValueError('Wrong date: "%s"' % text) diff --git a/rhodecode/lib/vcs/utils/imports.py b/rhodecode/lib/vcs/utils/imports.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/utils/imports.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from rhodecode.lib.vcs.exceptions import VCSError + + +def import_class(class_path): + """ + Returns class from the given path. + + For example, in order to get class located at + ``vcs.backends.hg.MercurialRepository``: + + try: + hgrepo = import_class('vcs.backends.hg.MercurialRepository') + except VCSError: + # hadle error + """ + splitted = class_path.split('.') + mod_path = '.'.join(splitted[:-1]) + class_name = splitted[-1] + try: + class_mod = __import__(mod_path, {}, {}, [class_name]) + except ImportError as err: + msg = "There was problem while trying to import backend class. "\ + "Original error was:\n%s" % err + raise VCSError(msg) + cls = getattr(class_mod, class_name) + + return cls diff --git a/rhodecode/lib/vcs/utils/paths.py b/rhodecode/lib/vcs/utils/paths.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/vcs/utils/paths.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os.path + + +def get_dirs_for_path(*paths): + """Return list of directories, including intermediate.""" + for path in paths: + head = path + while head: + head, tail = os.path.split(head) + if head: + yield head + else: + # We don't need to yield empty path + break diff --git a/rhodecode/model/__init__.py b/rhodecode/model/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/__init__.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +The application's model objects + +:example: + + .. code-block:: python + + from paste.deploy import appconfig + from pylons import config + from sqlalchemy import engine_from_config + from rhodecode.config.environment import load_environment + + conf = appconfig('config:development.ini', relative_to = './../../') + load_environment(conf.global_conf, conf.local_conf) + + engine = engine_from_config(config, 'sqlalchemy.') + init_model(engine) + # RUN YOUR CODE HERE + +""" + + +import logging + +from pylons import config + +from rhodecode.model import meta, db +from rhodecode.lib.utils2 import obfuscate_url_pw + +log = logging.getLogger(__name__) + + +def init_model(engine, encryption_key=None): + """ + Initializes db session, bind the engine with the metadata, + Call this before using any of the tables or classes in the model, + preferably once in application start + + :param engine: engine to bind to + """ + engine_str = obfuscate_url_pw(str(engine.url)) + log.info("initializing db for %s", engine_str) + meta.Base.metadata.bind = engine + db.ENCRYPTION_KEY = encryption_key + + +def init_model_encryption(migration_models): + migration_models.ENCRYPTION_KEY = config['beaker.session.secret'] + db.ENCRYPTION_KEY = config['beaker.session.secret'] + + +class BaseModel(object): + """ + Base Model for all RhodeCode models, it adds sql alchemy session + into instance of model + + :param sa: If passed it reuses this session instead of creating a new one + """ + + cls = None # override in child class + + def __init__(self, sa=None): + if sa is not None: + self.sa = sa + else: + self.sa = meta.Session() + + def _get_instance(self, cls, instance, callback=None): + """ + Gets instance of given cls using some simple lookup mechanism. + + :param cls: class to fetch + :param instance: int or Instance + :param callback: callback to call if all lookups failed + """ + + if isinstance(instance, cls): + return instance + elif isinstance(instance, (int, long)): + return cls.get(instance) + else: + if instance: + if callback is None: + raise Exception( + 'given object must be int, long or Instance of %s ' + 'got %s, no callback provided' % (cls, type(instance)) + ) + else: + return callback(instance) + + def _get_user(self, user): + """ + Helper method to get user by ID, or username fallback + + :param user: UserID, username, or User instance + """ + return self._get_instance( + db.User, user, callback=db.User.get_by_username) + + def _get_user_group(self, user_group): + """ + Helper method to get user by ID, or username fallback + + :param user_group: UserGroupID, user_group_name, or UserGroup instance + """ + return self._get_instance( + db.UserGroup, user_group, callback=db.UserGroup.get_by_group_name) + + def _get_repo(self, repository): + """ + Helper method to get repository by ID, or repository name + + :param repository: RepoID, repository name or Repository Instance + """ + return self._get_instance( + db.Repository, repository, callback=db.Repository.get_by_repo_name) + + def _get_perm(self, permission): + """ + Helper method to get permission by ID, or permission name + + :param permission: PermissionID, permission_name or Permission instance + """ + return self._get_instance( + db.Permission, permission, callback=db.Permission.get_by_key) + + @classmethod + def get_all(cls): + """ + Returns all instances of what is defined in `cls` class variable + """ + return cls.cls.getAll() diff --git a/rhodecode/model/auth_token.py b/rhodecode/model/auth_token.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/auth_token.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +authentication tokens model for RhodeCode +""" + +import time +import logging +import traceback +from sqlalchemy import or_ + +from rhodecode.model import BaseModel +from rhodecode.model.db import UserApiKeys +from rhodecode.model.meta import Session + +log = logging.getLogger(__name__) + + +class AuthTokenModel(BaseModel): + cls = UserApiKeys + + def create(self, user, description, lifetime=-1, role=UserApiKeys.ROLE_ALL): + """ + :param user: user or user_id + :param description: description of ApiKey + :param lifetime: expiration time in seconds + :param role: role for the apikey + """ + from rhodecode.lib.auth import generate_auth_token + + user = self._get_user(user) + + new_auth_token = UserApiKeys() + new_auth_token.api_key = generate_auth_token(user.username) + new_auth_token.user_id = user.user_id + new_auth_token.description = description + new_auth_token.role = role + new_auth_token.expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 + Session().add(new_auth_token) + + return new_auth_token + + def delete(self, api_key, user=None): + """ + Deletes given api_key, if user is set it also filters the object for + deletion by given user. + """ + api_key = UserApiKeys.query().filter(UserApiKeys.api_key == api_key) + + if user: + user = self._get_user(user) + api_key = api_key.filter(UserApiKeys.user_id == user.user_id) + + api_key = api_key.scalar() + try: + Session().delete(api_key) + except Exception: + log.error(traceback.format_exc()) + raise + + def get_auth_tokens(self, user, show_expired=True): + user = self._get_user(user) + user_auth_tokens = UserApiKeys.query()\ + .filter(UserApiKeys.user_id == user.user_id) + if not show_expired: + user_auth_tokens = user_auth_tokens\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time())) + return user_auth_tokens diff --git a/rhodecode/model/changeset_status.py b/rhodecode/model/changeset_status.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/changeset_status.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Changeset status conttroller +""" + +import itertools +import logging +from collections import defaultdict + +from rhodecode.model import BaseModel +from rhodecode.model.db import ChangesetStatus, ChangesetComment, PullRequest +from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError +from rhodecode.lib.markup_renderer import ( + DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) + +log = logging.getLogger(__name__) + + +class ChangesetStatusModel(BaseModel): + + cls = ChangesetStatus + + def __get_changeset_status(self, changeset_status): + return self._get_instance(ChangesetStatus, changeset_status) + + def __get_pull_request(self, pull_request): + return self._get_instance(PullRequest, pull_request) + + def _get_status_query(self, repo, revision, pull_request, + with_revisions=False): + repo = self._get_repo(repo) + + q = ChangesetStatus.query()\ + .filter(ChangesetStatus.repo == repo) + if not with_revisions: + q = q.filter(ChangesetStatus.version == 0) + + if revision: + q = q.filter(ChangesetStatus.revision == revision) + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + # TODO: johbo: Think about the impact of this join, there must + # be a reason why ChangesetStatus and ChanagesetComment is linked + # to the pull request. Might be that we want to do the same for + # the pull_request_version_id. + q = q.join(ChangesetComment).filter( + ChangesetStatus.pull_request == pull_request, + ChangesetComment.pull_request_version_id == None) + else: + raise Exception('Please specify revision or pull_request') + q = q.order_by(ChangesetStatus.version.asc()) + return q + + def calculate_status(self, statuses_by_reviewers): + """ + Given the approval statuses from reviewers, calculates final approval + status. There can only be 3 results, all approved, all rejected. If + there is no consensus the PR is under review. + + :param statuses_by_reviewers: + """ + votes = defaultdict(int) + reviewers_number = len(statuses_by_reviewers) + for user, statuses in statuses_by_reviewers: + if statuses: + ver, latest = statuses[0] + votes[latest.status] += 1 + else: + votes[ChangesetStatus.DEFAULT] += 1 + + # all approved + if votes.get(ChangesetStatus.STATUS_APPROVED) == reviewers_number: + return ChangesetStatus.STATUS_APPROVED + + # all rejected + if votes.get(ChangesetStatus.STATUS_REJECTED) == reviewers_number: + return ChangesetStatus.STATUS_REJECTED + + return ChangesetStatus.STATUS_UNDER_REVIEW + + def get_statuses(self, repo, revision=None, pull_request=None, + with_revisions=False): + q = self._get_status_query(repo, revision, pull_request, + with_revisions) + return q.all() + + def get_status(self, repo, revision=None, pull_request=None, as_str=True): + """ + Returns latest status of changeset for given revision or for given + pull request. Statuses are versioned inside a table itself and + version == 0 is always the current one + + :param repo: + :param revision: 40char hash or None + :param pull_request: pull_request reference + :param as_str: return status as string not object + """ + q = self._get_status_query(repo, revision, pull_request) + + # need to use first here since there can be multiple statuses + # returned from pull_request + status = q.first() + if as_str: + status = status.status if status else status + st = status or ChangesetStatus.DEFAULT + return str(st) + return status + + def _render_auto_status_message( + self, status, commit_id=None, pull_request=None): + """ + render the message using DEFAULT_COMMENTS_RENDERER (RST renderer), + so it's always looking the same disregarding on which default + renderer system is using. + + :param status: status text to change into + :param commit_id: the commit_id we change the status for + :param pull_request: the pull request we change the status for + """ + + new_status = ChangesetStatus.get_status_lbl(status) + + params = { + 'new_status_label': new_status, + 'pull_request': pull_request, + 'commit_id': commit_id, + } + renderer = RstTemplateRenderer() + return renderer.render('auto_status_change.mako', **params) + + def set_status(self, repo, status, user, comment=None, revision=None, + pull_request=None, dont_allow_on_closed_pull_request=False): + """ + Creates new status for changeset or updates the old ones bumping their + version, leaving the current status at + + :param repo: + :param revision: + :param status: + :param user: + :param comment: + :param dont_allow_on_closed_pull_request: don't allow a status change + if last status was for pull request and it's closed. We shouldn't + mess around this manually + """ + repo = self._get_repo(repo) + + q = ChangesetStatus.query() + + if revision: + q = q.filter(ChangesetStatus.repo == repo) + q = q.filter(ChangesetStatus.revision == revision) + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + q = q.filter(ChangesetStatus.repo == pull_request.source_repo) + q = q.filter(ChangesetStatus.revision.in_(pull_request.revisions)) + cur_statuses = q.all() + + # if statuses exists and last is associated with a closed pull request + # we need to check if we can allow this status change + if (dont_allow_on_closed_pull_request and cur_statuses + and getattr(cur_statuses[0].pull_request, 'status', '') + == PullRequest.STATUS_CLOSED): + raise StatusChangeOnClosedPullRequestError( + 'Changing status on closed pull request is not allowed' + ) + + # update all current statuses with older version + if cur_statuses: + for st in cur_statuses: + st.version += 1 + self.sa.add(st) + + def _create_status(user, repo, status, comment, revision, pull_request): + new_status = ChangesetStatus() + new_status.author = self._get_user(user) + new_status.repo = self._get_repo(repo) + new_status.status = status + new_status.comment = comment + new_status.revision = revision + new_status.pull_request = pull_request + return new_status + + if not comment: + from rhodecode.model.comment import ChangesetCommentsModel + comment = ChangesetCommentsModel().create( + text=self._render_auto_status_message( + status, commit_id=revision, pull_request=pull_request), + repo=repo, + user=user, + pull_request=pull_request, + send_email=False, renderer=DEFAULT_COMMENTS_RENDERER + ) + + if revision: + new_status = _create_status( + user=user, repo=repo, status=status, comment=comment, + revision=revision, pull_request=pull_request) + self.sa.add(new_status) + return new_status + elif pull_request: + # pull request can have more than one revision associated to it + # we need to create new version for each one + new_statuses = [] + repo = pull_request.source_repo + for rev in pull_request.revisions: + new_status = _create_status( + user=user, repo=repo, status=status, comment=comment, + revision=rev, pull_request=pull_request) + new_statuses.append(new_status) + self.sa.add(new_status) + return new_statuses + + def reviewers_statuses(self, pull_request): + _commit_statuses = self.get_statuses( + pull_request.source_repo, + pull_request=pull_request, + with_revisions=True) + + commit_statuses = defaultdict(list) + for st in _commit_statuses: + commit_statuses[st.author.username] += [st] + + pull_request_reviewers = [] + + def version(commit_status): + return commit_status.version + + for o in pull_request.reviewers: + if not o.user: + continue + st = commit_statuses.get(o.user.username, None) + if st: + st = [(x, list(y)[0]) + for x, y in (itertools.groupby(sorted(st, key=version), + version))] + + pull_request_reviewers.append([o.user, st]) + return pull_request_reviewers + + def calculated_review_status(self, pull_request, reviewers_statuses=None): + """ + calculate pull request status based on reviewers, it should be a list + of two element lists. + + :param reviewers_statuses: + """ + reviewers = reviewers_statuses or self.reviewers_statuses(pull_request) + return self.calculate_status(reviewers) diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/comment.py @@ -0,0 +1,459 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +comments model for RhodeCode +""" + +import logging +import traceback +import collections + +from sqlalchemy.sql.expression import null +from sqlalchemy.sql.functions import coalesce + +from rhodecode.lib import helpers as h, diffs +from rhodecode.lib.utils import action_logger +from rhodecode.lib.utils2 import extract_mentioned_users +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + ChangesetComment, User, Notification, PullRequest) +from rhodecode.model.notification import NotificationModel +from rhodecode.model.meta import Session +from rhodecode.model.settings import VcsSettingsModel +from rhodecode.model.notification import EmailNotificationModel + +log = logging.getLogger(__name__) + + +class ChangesetCommentsModel(BaseModel): + + cls = ChangesetComment + + DIFF_CONTEXT_BEFORE = 3 + DIFF_CONTEXT_AFTER = 3 + + def __get_commit_comment(self, changeset_comment): + return self._get_instance(ChangesetComment, changeset_comment) + + def __get_pull_request(self, pull_request): + return self._get_instance(PullRequest, pull_request) + + def _extract_mentions(self, s): + user_objects = [] + for username in extract_mentioned_users(s): + user_obj = User.get_by_username(username, case_insensitive=True) + if user_obj: + user_objects.append(user_obj) + return user_objects + + def _get_renderer(self, global_renderer='rst'): + try: + # try reading from visual context + from pylons import tmpl_context + global_renderer = tmpl_context.visual.default_renderer + except AttributeError: + log.debug("Renderer not set, falling back " + "to default renderer '%s'", global_renderer) + except Exception: + log.error(traceback.format_exc()) + return global_renderer + + def create(self, text, repo, user, revision=None, pull_request=None, + f_path=None, line_no=None, status_change=None, closing_pr=False, + send_email=True, renderer=None): + """ + Creates new comment for commit or pull request. + IF status_change is not none this comment is associated with a + status change of commit or commit associated with pull request + + :param text: + :param repo: + :param user: + :param revision: + :param pull_request: + :param f_path: + :param line_no: + :param status_change: + :param closing_pr: + :param send_email: + """ + if not text: + log.warning('Missing text for comment, skipping...') + return + + if not renderer: + renderer = self._get_renderer() + + repo = self._get_repo(repo) + user = self._get_user(user) + comment = ChangesetComment() + comment.renderer = renderer + comment.repo = repo + comment.author = user + comment.text = text + comment.f_path = f_path + comment.line_no = line_no + + #TODO (marcink): fix this and remove revision as param + commit_id = revision + pull_request_id = pull_request + + commit_obj = None + pull_request_obj = None + + if commit_id: + notification_type = EmailNotificationModel.TYPE_COMMIT_COMMENT + # do a lookup, so we don't pass something bad here + commit_obj = repo.scm_instance().get_commit(commit_id=commit_id) + comment.revision = commit_obj.raw_id + + elif pull_request_id: + notification_type = EmailNotificationModel.TYPE_PULL_REQUEST_COMMENT + pull_request_obj = self.__get_pull_request(pull_request_id) + comment.pull_request = pull_request_obj + else: + raise Exception('Please specify commit or pull_request_id') + + Session().add(comment) + Session().flush() + + if send_email: + kwargs = { + 'user': user, + 'renderer_type': renderer, + 'repo_name': repo.repo_name, + 'status_change': status_change, + 'comment_body': text, + 'comment_file': f_path, + 'comment_line': line_no, + } + + if commit_obj: + recipients = ChangesetComment.get_users( + revision=commit_obj.raw_id) + # add commit author if it's in RhodeCode system + cs_author = User.get_from_cs_author(commit_obj.author) + if not cs_author: + # use repo owner if we cannot extract the author correctly + cs_author = repo.user + recipients += [cs_author] + + commit_comment_url = h.url( + 'changeset_home', + repo_name=repo.repo_name, + revision=commit_obj.raw_id, + anchor='comment-%s' % comment.comment_id, + qualified=True,) + + target_repo_url = h.link_to( + repo.repo_name, + h.url('summary_home', + repo_name=repo.repo_name, qualified=True)) + + # commit specifics + kwargs.update({ + 'commit': commit_obj, + 'commit_message': commit_obj.message, + 'commit_target_repo': target_repo_url, + 'commit_comment_url': commit_comment_url, + }) + + elif pull_request_obj: + # get the current participants of this pull request + recipients = ChangesetComment.get_users( + pull_request_id=pull_request_obj.pull_request_id) + # add pull request author + recipients += [pull_request_obj.author] + + # add the reviewers to notification + recipients += [x.user for x in pull_request_obj.reviewers] + + pr_target_repo = pull_request_obj.target_repo + pr_source_repo = pull_request_obj.source_repo + + pr_comment_url = h.url( + 'pullrequest_show', + repo_name=pr_target_repo.repo_name, + pull_request_id=pull_request_obj.pull_request_id, + anchor='comment-%s' % comment.comment_id, + qualified=True,) + + # set some variables for email notification + pr_target_repo_url = h.url( + 'summary_home', repo_name=pr_target_repo.repo_name, + qualified=True) + + pr_source_repo_url = h.url( + 'summary_home', repo_name=pr_source_repo.repo_name, + qualified=True) + + # pull request specifics + kwargs.update({ + 'pull_request': pull_request_obj, + 'pr_id': pull_request_obj.pull_request_id, + 'pr_target_repo': pr_target_repo, + 'pr_target_repo_url': pr_target_repo_url, + 'pr_source_repo': pr_source_repo, + 'pr_source_repo_url': pr_source_repo_url, + 'pr_comment_url': pr_comment_url, + 'pr_closing': closing_pr, + }) + + # pre-generate the subject for notification itself + (subject, + _h, _e, # we don't care about those + body_plaintext) = EmailNotificationModel().render_email( + notification_type, **kwargs) + + mention_recipients = set( + self._extract_mentions(text)).difference(recipients) + + # create notification objects, and emails + NotificationModel().create( + created_by=user, + notification_subject=subject, + notification_body=body_plaintext, + notification_type=notification_type, + recipients=recipients, + mention_recipients=mention_recipients, + email_kwargs=kwargs, + ) + + action = ( + 'user_commented_pull_request:{}'.format( + comment.pull_request.pull_request_id) + if comment.pull_request + else 'user_commented_revision:{}'.format(comment.revision) + ) + action_logger(user, action, comment.repo) + + return comment + + def delete(self, comment): + """ + Deletes given comment + + :param comment_id: + """ + comment = self.__get_commit_comment(comment) + Session().delete(comment) + + return comment + + def get_all_comments(self, repo_id, revision=None, pull_request=None): + q = ChangesetComment.query()\ + .filter(ChangesetComment.repo_id == repo_id) + if revision: + q = q.filter(ChangesetComment.revision == revision) + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + q = q.filter(ChangesetComment.pull_request == pull_request) + else: + raise Exception('Please specify commit or pull_request') + q = q.order_by(ChangesetComment.created_on) + return q.all() + + def get_comments(self, repo_id, revision=None, pull_request=None): + """ + Gets main comments based on revision or pull_request_id + + :param repo_id: + :param revision: + :param pull_request: + """ + + q = ChangesetComment.query()\ + .filter(ChangesetComment.repo_id == repo_id)\ + .filter(ChangesetComment.line_no == None)\ + .filter(ChangesetComment.f_path == None) + if revision: + q = q.filter(ChangesetComment.revision == revision) + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + q = q.filter(ChangesetComment.pull_request == pull_request) + else: + raise Exception('Please specify commit or pull_request') + q = q.order_by(ChangesetComment.created_on) + return q.all() + + def get_inline_comments(self, repo_id, revision=None, pull_request=None): + q = self._get_inline_comments_query(repo_id, revision, pull_request) + return self._group_comments_by_path_and_line_number(q) + + def get_outdated_comments(self, repo_id, pull_request): + # TODO: johbo: Remove `repo_id`, it is not needed to find the comments + # of a pull request. + q = self._all_inline_comments_of_pull_request(pull_request) + q = q.filter( + ChangesetComment.display_state == + ChangesetComment.COMMENT_OUTDATED + ).order_by(ChangesetComment.comment_id.asc()) + + return self._group_comments_by_path_and_line_number(q) + + def _get_inline_comments_query(self, repo_id, revision, pull_request): + # TODO: johbo: Split this into two methods: One for PR and one for + # commit. + if revision: + q = Session().query(ChangesetComment).filter( + ChangesetComment.repo_id == repo_id, + ChangesetComment.line_no != null(), + ChangesetComment.f_path != null(), + ChangesetComment.revision == revision) + + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + if ChangesetCommentsModel.use_outdated_comments(pull_request): + q = self._visible_inline_comments_of_pull_request(pull_request) + else: + q = self._all_inline_comments_of_pull_request(pull_request) + + else: + raise Exception('Please specify commit or pull_request_id') + q = q.order_by(ChangesetComment.comment_id.asc()) + return q + + def _group_comments_by_path_and_line_number(self, q): + comments = q.all() + paths = collections.defaultdict(lambda: collections.defaultdict(list)) + for co in comments: + paths[co.f_path][co.line_no].append(co) + return paths + + @classmethod + def needed_extra_diff_context(cls): + return max(cls.DIFF_CONTEXT_BEFORE, cls.DIFF_CONTEXT_AFTER) + + def outdate_comments(self, pull_request, old_diff_data, new_diff_data): + if not ChangesetCommentsModel.use_outdated_comments(pull_request): + return + + comments = self._visible_inline_comments_of_pull_request(pull_request) + comments_to_outdate = comments.all() + + for comment in comments_to_outdate: + self._outdate_one_comment(comment, old_diff_data, new_diff_data) + + def _outdate_one_comment(self, comment, old_diff_proc, new_diff_proc): + diff_line = _parse_comment_line_number(comment.line_no) + + try: + old_context = old_diff_proc.get_context_of_line( + path=comment.f_path, diff_line=diff_line) + new_context = new_diff_proc.get_context_of_line( + path=comment.f_path, diff_line=diff_line) + except (diffs.LineNotInDiffException, + diffs.FileNotInDiffException): + comment.display_state = ChangesetComment.COMMENT_OUTDATED + return + + if old_context == new_context: + return + + if self._should_relocate_diff_line(diff_line): + new_diff_lines = new_diff_proc.find_context( + path=comment.f_path, context=old_context, + offset=self.DIFF_CONTEXT_BEFORE) + if not new_diff_lines: + comment.display_state = ChangesetComment.COMMENT_OUTDATED + else: + new_diff_line = self._choose_closest_diff_line( + diff_line, new_diff_lines) + comment.line_no = _diff_to_comment_line_number(new_diff_line) + else: + comment.display_state = ChangesetComment.COMMENT_OUTDATED + + def _should_relocate_diff_line(self, diff_line): + """ + Checks if relocation shall be tried for the given `diff_line`. + + If a comment points into the first lines, then we can have a situation + that after an update another line has been added on top. In this case + we would find the context still and move the comment around. This + would be wrong. + """ + should_relocate = ( + (diff_line.new and diff_line.new > self.DIFF_CONTEXT_BEFORE) or + (diff_line.old and diff_line.old > self.DIFF_CONTEXT_BEFORE)) + return should_relocate + + def _choose_closest_diff_line(self, diff_line, new_diff_lines): + candidate = new_diff_lines[0] + best_delta = _diff_line_delta(diff_line, candidate) + for new_diff_line in new_diff_lines[1:]: + delta = _diff_line_delta(diff_line, new_diff_line) + if delta < best_delta: + candidate = new_diff_line + best_delta = delta + return candidate + + def _visible_inline_comments_of_pull_request(self, pull_request): + comments = self._all_inline_comments_of_pull_request(pull_request) + comments = comments.filter( + coalesce(ChangesetComment.display_state, '') != + ChangesetComment.COMMENT_OUTDATED) + return comments + + def _all_inline_comments_of_pull_request(self, pull_request): + comments = Session().query(ChangesetComment)\ + .filter(ChangesetComment.line_no != None)\ + .filter(ChangesetComment.f_path != None)\ + .filter(ChangesetComment.pull_request == pull_request) + return comments + + @staticmethod + def use_outdated_comments(pull_request): + settings_model = VcsSettingsModel(repo=pull_request.target_repo) + settings = settings_model.get_general_settings() + return settings.get('rhodecode_use_outdated_comments', False) + + +def _parse_comment_line_number(line_no): + """ + Parses line numbers of the form "(o|n)\d+" and returns them in a tuple. + """ + old_line = None + new_line = None + if line_no.startswith('o'): + old_line = int(line_no[1:]) + elif line_no.startswith('n'): + new_line = int(line_no[1:]) + else: + raise ValueError("Comment lines have to start with either 'o' or 'n'.") + return diffs.DiffLineNumber(old_line, new_line) + + +def _diff_to_comment_line_number(diff_line): + if diff_line.new is not None: + return u'n{}'.format(diff_line.new) + elif diff_line.old is not None: + return u'o{}'.format(diff_line.old) + return u'' + + +def _diff_line_delta(a, b): + if None not in (a.new, b.new): + return abs(a.new - b.new) + elif None not in (a.old, b.old): + return abs(a.old - b.old) + else: + raise ValueError( + "Cannot compute delta between {} and {}".format(a, b)) diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/db.py @@ -0,0 +1,3427 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Database Models for RhodeCode Enterprise +""" + +import os +import sys +import time +import hashlib +import logging +import datetime +import warnings +import ipaddress +import functools +import traceback +import collections + + +from sqlalchemy import * +from sqlalchemy.exc import IntegrityError +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import ( + relationship, joinedload, class_mapper, validates, aliased) +from sqlalchemy.sql.expression import true +from beaker.cache import cache_region, region_invalidate +from webob.exc import HTTPNotFound +from zope.cachedescriptors.property import Lazy as LazyProperty + +from pylons import url +from pylons.i18n.translation import lazy_ugettext as _ + +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.utils.helpers import get_scm +from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, MergeFailureReason) +from rhodecode.lib.utils2 import ( + str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, + time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.encrypt import AESCipher + +from rhodecode.model.meta import Base, Session + +URL_SEP = '/' +log = logging.getLogger(__name__) + +# ============================================================================= +# BASE CLASSES +# ============================================================================= + +# this is propagated from .ini file beaker.session.secret +# and initialized at environment.py +ENCRYPTION_KEY = None + +# used to sort permissions by types, '#' used here is not allowed to be in +# usernames, and it's very early in sorted string.printable table. +PERMISSION_TYPE_SORT = { + 'admin': '####', + 'write': '###', + 'read': '##', + 'none': '#', +} + + +def display_sort(obj): + """ + Sort function used to sort permissions in .permissions() function of + Repository, RepoGroup, UserGroup. Also it put the default user in front + of all other resources + """ + + if obj.username == User.DEFAULT_USER: + return '#####' + prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '') + return prefix + obj.username + + +def _hash_key(k): + return md5_safe(k) + + +class EncryptedTextValue(TypeDecorator): + """ + Special column for encrypted long text data, use like:: + + value = Column("encrypted_value", EncryptedValue(), nullable=False) + + This column is intelligent so if value is in unencrypted form it return + unencrypted form, but on save it always encrypts + """ + impl = Text + + def process_bind_param(self, value, dialect): + if not value: + return value + if value.startswith('enc$aes$'): + # protect against double encrypting if someone manually starts + # doing + raise ValueError('value needs to be in unencrypted format, ie. ' + 'not starting with enc$aes$') + return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value) + + def process_result_value(self, value, dialect): + if not value: + return value + + parts = value.split('$', 3) + if not len(parts) == 3: + # probably not encrypted values + return value + else: + if parts[0] != 'enc': + # parts ok but without our header ? + return value + + # at that stage we know it's our encryption + decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) + return decrypted_data + + +class BaseModel(object): + """ + Base Model for all classes + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """ + return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + + # also use __json__() if present to get additional fields + _json_attr = getattr(self, '__json__', None) + if _json_attr: + # update with attributes from __json__ + if callable(_json_attr): + _json_attr = _json_attr() + for k, val in _json_attr.iteritems(): + d[k] = val + return d + + def get_appstruct(self): + """return list with keys and values tuples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session().query(cls) + + @classmethod + def get(cls, id_): + if id_: + return cls.query().get(id_) + + @classmethod + def get_or_404(cls, id_): + try: + id_ = int(id_) + except (TypeError, ValueError): + raise HTTPNotFound + + res = cls.query().get(id_) + if not res: + raise HTTPNotFound + return res + + @classmethod + def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): + return cls.query().all() + + @classmethod + def delete(cls, id_): + obj = cls.query().get(id_) + Session().delete(obj) + + def __repr__(self): + if hasattr(self, '__unicode__'): + # python repr needs to return str + try: + return safe_str(self.__unicode__()) + except UnicodeDecodeError: + pass + return '<DB:%s>' % (self.__class__.__name__) + + +class RhodeCodeSetting(Base, BaseModel): + __tablename__ = 'rhodecode_settings' + __table_args__ = ( + UniqueConstraint('app_settings_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + SETTINGS_TYPES = { + 'str': safe_str, + 'int': safe_int, + 'unicode': safe_unicode, + 'bool': str2bool, + 'list': functools.partial(aslist, sep=',') + } + DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions' + GLOBAL_CONF_KEY = 'app_settings' + + app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None) + _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None) + _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None) + + def __init__(self, key='', val='', type='unicode'): + self.app_settings_name = key + self.app_settings_type = type + self.app_settings_value = val + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + _type = self.app_settings_type + if _type: + _type = self.app_settings_type.split('.')[0] + # decode the encrypted value + if 'encrypted' in self.app_settings_type: + cipher = EncryptedTextValue() + v = safe_unicode(cipher.process_result_value(v, None)) + + converter = self.SETTINGS_TYPES.get(_type) or \ + self.SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + val = safe_unicode(val) + # encode the encrypted value + if 'encrypted' in self.app_settings_type: + cipher = EncryptedTextValue() + val = safe_unicode(cipher.process_bind_param(val, None)) + self._app_settings_value = val + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + if val.split('.')[0] not in self.SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (self.SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.app_settings_name, self.app_settings_value, + self.app_settings_type + ) + + +class RhodeCodeUi(Base, BaseModel): + __tablename__ = 'rhodecode_ui' + __table_args__ = ( + UniqueConstraint('ui_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + HOOK_REPO_SIZE = 'changegroup.repo_size' + # HG + HOOK_PRE_PULL = 'preoutgoing.pre_pull' + HOOK_PULL = 'outgoing.pull_logger' + HOOK_PRE_PUSH = 'prechangegroup.pre_push' + HOOK_PUSH = 'changegroup.push_logger' + + # TODO: johbo: Unify way how hooks are configured for git and hg, + # git part is currently hardcoded. + + # SVN PATTERNS + SVN_BRANCH_ID = 'vcs_svn_branch' + SVN_TAG_ID = 'vcs_svn_tag' + + ui_id = Column( + "ui_id", Integer(), nullable=False, unique=True, default=None, + primary_key=True) + ui_section = Column( + "ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column( + "ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column( + "ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column( + "ui_active", Boolean(), nullable=True, unique=None, default=True) + + def __repr__(self): + return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section, + self.ui_key, self.ui_value) + + +class RepoRhodeCodeSetting(Base, BaseModel): + __tablename__ = 'repo_rhodecode_settings' + __table_args__ = ( + UniqueConstraint( + 'app_settings_name', 'repository_id', + name='uq_repo_rhodecode_setting_name_repo_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + app_settings_id = Column( + "app_settings_id", Integer(), nullable=False, unique=True, + default=None, primary_key=True) + app_settings_name = Column( + "app_settings_name", String(255), nullable=True, unique=None, + default=None) + _app_settings_value = Column( + "app_settings_value", String(4096), nullable=True, unique=None, + default=None) + _app_settings_type = Column( + "app_settings_type", String(255), nullable=True, unique=None, + default=None) + + repository = relationship('Repository') + + def __init__(self, repository_id, key='', val='', type='unicode'): + self.repository_id = repository_id + self.app_settings_name = key + self.app_settings_type = type + self.app_settings_value = val + + @validates('_app_settings_value') + def validate_settings_value(self, key, val): + assert type(val) == unicode + return val + + @hybrid_property + def app_settings_value(self): + v = self._app_settings_value + type_ = self.app_settings_type + SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES + converter = SETTINGS_TYPES.get(type_) or SETTINGS_TYPES['unicode'] + return converter(v) + + @app_settings_value.setter + def app_settings_value(self, val): + """ + Setter that will always make sure we use unicode in app_settings_value + + :param val: + """ + self._app_settings_value = safe_unicode(val) + + @hybrid_property + def app_settings_type(self): + return self._app_settings_type + + @app_settings_type.setter + def app_settings_type(self, val): + SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES + if val not in SETTINGS_TYPES: + raise Exception('type must be one of %s got %s' + % (SETTINGS_TYPES.keys(), val)) + self._app_settings_type = val + + def __unicode__(self): + return u"<%s('%s:%s:%s[%s]')>" % ( + self.__class__.__name__, self.repository.repo_name, + self.app_settings_name, self.app_settings_value, + self.app_settings_type + ) + + +class RepoRhodeCodeUi(Base, BaseModel): + __tablename__ = 'repo_rhodecode_ui' + __table_args__ = ( + UniqueConstraint( + 'repository_id', 'ui_section', 'ui_key', + name='uq_repo_rhodecode_ui_repository_id_section_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + repository_id = Column( + "repository_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + ui_id = Column( + "ui_id", Integer(), nullable=False, unique=True, default=None, + primary_key=True) + ui_section = Column( + "ui_section", String(255), nullable=True, unique=None, default=None) + ui_key = Column( + "ui_key", String(255), nullable=True, unique=None, default=None) + ui_value = Column( + "ui_value", String(255), nullable=True, unique=None, default=None) + ui_active = Column( + "ui_active", Boolean(), nullable=True, unique=None, default=True) + + repository = relationship('Repository') + + def __repr__(self): + return '<%s[%s:%s]%s=>%s]>' % ( + self.__class__.__name__, self.repository.repo_name, + self.ui_section, self.ui_key, self.ui_value) + + +class User(Base, BaseModel): + __tablename__ = 'users' + __table_args__ = ( + UniqueConstraint('username'), UniqueConstraint('email'), + Index('u_username_idx', 'username'), + Index('u_email_idx', 'email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + DEFAULT_USER = 'default' + DEFAULT_USER_EMAIL = 'anonymous@rhodecode.org' + DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}' + + user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + username = Column("username", String(255), nullable=True, unique=None, default=None) + password = Column("password", String(255), nullable=True, unique=None, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) + name = Column("firstname", String(255), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(255), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=None, default=None) + last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) + extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None) + extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data + + user_log = relationship('UserLog') + user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') + + repositories = relationship('Repository') + repository_groups = relationship('RepoGroup') + user_groups = relationship('UserGroup') + + user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') + followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all') + + repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') + repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all') + user_group_to_perm = relationship('UserUserGroupToPerm', primaryjoin='UserUserGroupToPerm.user_id==User.user_id', cascade='all') + + group_member = relationship('UserGroupMember', cascade='all') + + notifications = relationship('UserNotification', cascade='all') + # notifications assigned to this user + user_created_notifications = relationship('Notification', cascade='all') + # comments created by this user + user_comments = relationship('ChangesetComment', cascade='all') + # user profile extra info + user_emails = relationship('UserEmailMap', cascade='all') + user_ip_map = relationship('UserIpMap', cascade='all') + user_auth_tokens = relationship('UserApiKeys', cascade='all') + # gists + user_gists = relationship('Gist', cascade='all') + # user pull requests + user_pull_requests = relationship('PullRequest', cascade='all') + # external identities + extenal_identities = relationship( + 'ExternalIdentity', + primaryjoin="User.user_id==ExternalIdentity.local_user_id", + cascade='all') + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.user_id, self.username) + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + @property + def firstname(self): + # alias for future + return self.name + + @property + def emails(self): + other = UserEmailMap.query().filter(UserEmailMap.user==self).all() + return [self.email] + [x.email for x in other] + + @property + def auth_tokens(self): + return [self.api_key] + [x.api_key for x in self.extra_auth_tokens] + + @property + def extra_auth_tokens(self): + return UserApiKeys.query().filter(UserApiKeys.user == self).all() + + @property + def feed_token(self): + feed_tokens = UserApiKeys.query()\ + .filter(UserApiKeys.user == self)\ + .filter(UserApiKeys.role == UserApiKeys.ROLE_FEED)\ + .all() + if feed_tokens: + return feed_tokens[0].api_key + else: + # use the main token so we don't end up with nothing... + return self.api_key + + @classmethod + def extra_valid_auth_tokens(cls, user, role=None): + tokens = UserApiKeys.query().filter(UserApiKeys.user == user)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time())) + if role: + tokens = tokens.filter(or_(UserApiKeys.role == role, + UserApiKeys.role == UserApiKeys.ROLE_ALL)) + return tokens.all() + + @property + def ip_addresses(self): + ret = UserIpMap.query().filter(UserIpMap.user == self).all() + return [x.ip_addr for x in ret] + + @property + def username_and_name(self): + return '%s (%s %s)' % (self.username, self.firstname, self.lastname) + + @property + def username_or_name_or_email(self): + full_name = self.full_name if self.full_name is not ' ' else None + return self.username or full_name or self.email + + @property + def full_name(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def full_name_or_username(self): + return ('%s %s' % (self.firstname, self.lastname) + if (self.firstname and self.lastname) else self.username) + + @property + def full_contact(self): + return '%s %s <%s>' % (self.firstname, self.lastname, self.email) + + @property + def short_contact(self): + return '%s %s' % (self.firstname, self.lastname) + + @property + def is_admin(self): + return self.admin + + @property + def AuthUser(self): + """ + Returns instance of AuthUser for this user + """ + from rhodecode.lib.auth import AuthUser + return AuthUser(user_id=self.user_id, api_key=self.api_key, + username=self.username) + + @hybrid_property + def user_data(self): + if not self._user_data: + return {} + + try: + return json.loads(self._user_data) + except TypeError: + return {} + + @user_data.setter + def user_data(self, val): + if not isinstance(val, dict): + raise Exception('user_data must be dict, got %s' % type(val)) + try: + self._user_data = json.dumps(val) + except Exception: + log.error(traceback.format_exc()) + + @classmethod + def get_by_username(cls, username, case_insensitive=False, cache=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.username) == func.lower(username)) + else: + q = cls.query().filter(cls.username == username) + + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_user_%s" % _hash_key(username))) + return q.scalar() + + @classmethod + def get_by_auth_token(cls, auth_token, cache=False, fallback=True): + q = cls.query().filter(cls.api_key == auth_token) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_auth_token_%s" % auth_token)) + res = q.scalar() + + if fallback and not res: + #fallback to additional keys + _res = UserApiKeys.query()\ + .filter(UserApiKeys.api_key == auth_token)\ + .filter(or_(UserApiKeys.expires == -1, + UserApiKeys.expires >= time.time()))\ + .first() + if _res: + res = _res.user + return res + + @classmethod + def get_by_email(cls, email, case_insensitive=False, cache=False): + + if case_insensitive: + q = cls.query().filter(func.lower(cls.email) == func.lower(email)) + + else: + q = cls.query().filter(cls.email == email) + + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_key_%s" % email)) + + ret = q.scalar() + if ret is None: + q = UserEmailMap.query() + # try fetching in alternate email map + if case_insensitive: + q = q.filter(func.lower(UserEmailMap.email) == func.lower(email)) + else: + q = q.filter(UserEmailMap.email == email) + q = q.options(joinedload(UserEmailMap.user)) + if cache: + q = q.options(FromCache("sql_cache_short", + "get_email_map_key_%s" % email)) + ret = getattr(q.scalar(), 'user', None) + + return ret + + @classmethod + def get_from_cs_author(cls, author): + """ + Tries to get User objects out of commit author string + + :param author: + """ + from rhodecode.lib.helpers import email, author_name + # Valid email in the attribute passed, see if they're in the system + _email = email(author) + if _email: + user = cls.get_by_email(_email, case_insensitive=True) + if user: + return user + # Maybe we can match by username? + _author = author_name(author) + user = cls.get_by_username(_author, case_insensitive=True) + if user: + return user + + def update_userdata(self, **kwargs): + usr = self + old = usr.user_data + old.update(**kwargs) + usr.user_data = old + Session().add(usr) + log.debug('updated userdata with ', kwargs) + + def update_lastlogin(self): + """Update user lastlogin""" + self.last_login = datetime.datetime.now() + Session().add(self) + log.debug('updated user %s lastlogin', self.username) + + def update_lastactivity(self): + """Update user lastactivity""" + usr = self + old = usr.user_data + old.update({'last_activity': time.time()}) + usr.user_data = old + Session().add(usr) + log.debug('updated user %s lastactivity', usr.username) + + def update_password(self, new_password, change_api_key=False): + from rhodecode.lib.auth import get_crypt_password,generate_auth_token + + self.password = get_crypt_password(new_password) + if change_api_key: + self.api_key = generate_auth_token(self.username) + Session().add(self) + + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + + @classmethod + def get_all_super_admins(cls): + """ + Returns all admin accounts sorted by username + """ + return User.query().filter(User.admin == true())\ + .order_by(User.username.asc()).all() + + @classmethod + def get_default_user(cls, cache=False): + user = User.get_by_username(User.DEFAULT_USER, cache=cache) + if user is None: + raise Exception('Missing default account!') + return user + + def _get_default_perms(self, user, suffix=''): + from rhodecode.model.permission import PermissionModel + return PermissionModel().get_default_perms(user.user_perms, suffix) + + def get_default_perms(self, suffix=''): + return self._get_default_perms(self, suffix) + + def get_api_data(self, include_secrets=False, details='full'): + """ + Common function for generating user related data for API + + :param include_secrets: By default secrets in the API data will be replaced + by a placeholder value to prevent exposing this data by accident. In case + this data shall be exposed, set this flag to ``True``. + + :param details: details can be 'basic|full' basic gives only a subset of + the available user information that includes user_id, name and emails. + """ + user = self + user_data = self.user_data + data = { + 'user_id': user.user_id, + 'username': user.username, + 'firstname': user.name, + 'lastname': user.lastname, + 'email': user.email, + 'emails': user.emails, + } + if details == 'basic': + return data + + api_key_length = 40 + api_key_replacement = '*' * api_key_length + + extras = { + 'api_key': api_key_replacement, + 'api_keys': [api_key_replacement], + 'active': user.active, + 'admin': user.admin, + 'extern_type': user.extern_type, + 'extern_name': user.extern_name, + 'last_login': user.last_login, + 'ip_addresses': user.ip_addresses, + 'language': user_data.get('language') + } + data.update(extras) + + if include_secrets: + data['api_key'] = user.api_key + data['api_keys'] = user.auth_tokens + return data + + def __json__(self): + data = { + 'full_name': self.full_name, + 'full_name_or_username': self.full_name_or_username, + 'short_contact': self.short_contact, + 'full_contact': self.full_contact, + } + data.update(self.get_api_data()) + return data + + +class UserApiKeys(Base, BaseModel): + __tablename__ = 'user_api_keys' + __table_args__ = ( + Index('uak_api_key_idx', 'api_key'), + Index('uak_api_key_expires_idx', 'api_key', 'expires'), + UniqueConstraint('api_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + # ApiKey role + ROLE_ALL = 'token_role_all' + ROLE_HTTP = 'token_role_http' + ROLE_VCS = 'token_role_vcs' + ROLE_API = 'token_role_api' + ROLE_FEED = 'token_role_feed' + ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED] + + user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + api_key = Column("api_key", String(255), nullable=False, unique=True) + description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + expires = Column('expires', Float(53), nullable=False) + role = Column('role', String(255), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + user = relationship('User', lazy='joined') + + @classmethod + def _get_role_name(cls, role): + return { + cls.ROLE_ALL: _('all'), + cls.ROLE_HTTP: _('http/web interface'), + cls.ROLE_VCS: _('vcs (git/hg protocol)'), + cls.ROLE_API: _('api calls'), + cls.ROLE_FEED: _('feed access'), + }.get(role, role) + + @property + def expired(self): + if self.expires == -1: + return False + return time.time() > self.expires + + @property + def role_humanized(self): + return self._get_role_name(self.role) + + +class UserEmailMap(Base, BaseModel): + __tablename__ = 'user_email_map' + __table_args__ = ( + Index('uem_email_idx', 'email'), + UniqueConstraint('email'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + _email = Column("email", String(255), nullable=True, unique=False, default=None) + user = relationship('User', lazy='joined') + + @validates('_email') + def validate_email(self, key, email): + # check if this email is not main one + main_email = Session().query(User).filter(User.email == email).scalar() + if main_email is not None: + raise AttributeError('email %s is present is user table' % email) + return email + + @hybrid_property + def email(self): + return self._email + + @email.setter + def email(self, val): + self._email = val.lower() if val else None + + +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + __mapper_args__ = {} + + ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None) + active = Column("active", Boolean(), nullable=True, unique=None, default=True) + description = Column("description", String(10000), nullable=True, unique=None, default=None) + user = relationship('User', lazy='joined') + + @classmethod + def _get_ip_range(cls, ip_addr): + net = ipaddress.ip_network(ip_addr, strict=False) + return [str(net.network_address), str(net.broadcast_address)] + + def __json__(self): + return { + 'ip_addr': self.ip_addr, + 'ip_range': self._get_ip_range(self.ip_addr), + } + + def __unicode__(self): + return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__, + self.user_id, self.ip_addr) + +class UserLog(Base, BaseModel): + __tablename__ = 'user_logs' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + username = Column("username", String(255), nullable=True, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) + repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None) + action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None) + action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.repository_name, + self.action) + + @property + def action_as_day(self): + return datetime.date(*self.action_date.timetuple()[:3]) + + user = relationship('User') + repository = relationship('Repository', cascade='') + + +class UserGroup(Base, BaseModel): + __tablename__ = 'users_groups' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None) + user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None) + users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) + inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data + + members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") + users_group_to_perm = relationship('UserGroupToPerm', cascade='all') + users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all') + user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all') + + user = relationship('User') + + @hybrid_property + def group_data(self): + if not self._group_data: + return {} + + try: + return json.loads(self._group_data) + except TypeError: + return {} + + @group_data.setter + def group_data(self, val): + try: + self._group_data = json.dumps(val) + except Exception: + log.error(traceback.format_exc()) + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) + + @classmethod + def get_by_group_name(cls, group_name, cache=False, + case_insensitive=False): + if case_insensitive: + q = cls.query().filter(func.lower(cls.users_group_name) == + func.lower(group_name)) + + else: + q = cls.query().filter(cls.users_group_name == group_name) + if cache: + q = q.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return q.scalar() + + @classmethod + def get(cls, user_group_id, cache=False): + user_group = cls.query() + if cache: + user_group = user_group.options(FromCache("sql_cache_short", + "get_users_group_%s" % user_group_id)) + return user_group.get(user_group_id) + + def permissions(self, with_admins=True, with_owner=True): + q = UserUserGroupToPerm.query().filter(UserUserGroupToPerm.user_group == self) + q = q.options(joinedload(UserUserGroupToPerm.user_group), + joinedload(UserUserGroupToPerm.user), + joinedload(UserUserGroupToPerm.permission),) + + # get owners and admins and permissions. We do a trick of re-writing + # objects from sqlalchemy to named-tuples due to sqlalchemy session + # has a global reference and changing one object propagates to all + # others. This means if admin is also an owner admin_row that change + # would propagate to both objects + perm_rows = [] + for _usr in q.all(): + usr = AttributeDict(_usr.user.get_dict()) + usr.permission = _usr.permission.permission_name + perm_rows.append(usr) + + # filter the perm rows by 'default' first and then sort them by + # admin,write,read,none permissions sorted again alphabetically in + # each group + perm_rows = sorted(perm_rows, key=display_sort) + + _admin_perm = 'usergroup.admin' + owner_row = [] + if with_owner: + usr = AttributeDict(self.user.get_dict()) + usr.owner_row = True + usr.permission = _admin_perm + owner_row.append(usr) + + super_admin_rows = [] + if with_admins: + for usr in User.get_all_super_admins(): + # if this admin is also owner, don't double the record + if usr.user_id == owner_row[0].user_id: + owner_row[0].admin_row = True + else: + usr = AttributeDict(usr.get_dict()) + usr.admin_row = True + usr.permission = _admin_perm + super_admin_rows.append(usr) + + return super_admin_rows + owner_row + perm_rows + + def permission_user_groups(self): + q = UserGroupUserGroupToPerm.query().filter(UserGroupUserGroupToPerm.target_user_group == self) + q = q.options(joinedload(UserGroupUserGroupToPerm.user_group), + joinedload(UserGroupUserGroupToPerm.target_user_group), + joinedload(UserGroupUserGroupToPerm.permission),) + + perm_rows = [] + for _user_group in q.all(): + usr = AttributeDict(_user_group.user_group.get_dict()) + usr.permission = _user_group.permission.permission_name + perm_rows.append(usr) + + return perm_rows + + def _get_default_perms(self, user_group, suffix=''): + from rhodecode.model.permission import PermissionModel + return PermissionModel().get_default_perms(user_group.users_group_to_perm, suffix) + + def get_default_perms(self, suffix=''): + return self._get_default_perms(self, suffix) + + def get_api_data(self, with_group_members=True, include_secrets=False): + """ + :param include_secrets: See :meth:`User.get_api_data`, this parameter is + basically forwarded. + + """ + user_group = self + + data = { + 'users_group_id': user_group.users_group_id, + 'group_name': user_group.users_group_name, + 'group_description': user_group.user_group_description, + 'active': user_group.users_group_active, + 'owner': user_group.user.username, + } + if with_group_members: + users = [] + for user in user_group.members: + user = user.user + users.append(user.get_api_data(include_secrets=include_secrets)) + data['users'] = users + + return data + + +class UserGroupMember(Base, BaseModel): + __tablename__ = 'users_groups_members' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + + user = relationship('User', lazy='joined') + users_group = relationship('UserGroup') + + def __init__(self, gr_id='', u_id=''): + self.users_group_id = gr_id + self.user_id = u_id + + +class RepositoryField(Base, BaseModel): + __tablename__ = 'repositories_fields' + __table_args__ = ( + UniqueConstraint('repository_id', 'field_key'), # no-multi field + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields + + repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + field_key = Column("field_key", String(250)) + field_label = Column("field_label", String(1024), nullable=False) + field_value = Column("field_value", String(10000), nullable=False) + field_desc = Column("field_desc", String(1024), nullable=False) + field_type = Column("field_type", String(255), nullable=False, unique=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repository = relationship('Repository') + + @property + def field_key_prefixed(self): + return 'ex_%s' % self.field_key + + @classmethod + def un_prefix_key(cls, key): + if key.startswith(cls.PREFIX): + return key[len(cls.PREFIX):] + return key + + @classmethod + def get_by_key_name(cls, key, repo): + row = cls.query()\ + .filter(cls.repository == repo)\ + .filter(cls.field_key == key).scalar() + return row + + +class Repository(Base, BaseModel): + __tablename__ = 'repositories' + __table_args__ = ( + Index('r_repo_name_idx', 'repo_name', mysql_length=255), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}' + DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}' + + STATE_CREATED = 'repo_state_created' + STATE_PENDING = 'repo_state_pending' + STATE_ERROR = 'repo_state_error' + + LOCK_AUTOMATIC = 'lock_auto' + LOCK_API = 'lock_api' + LOCK_WEB = 'lock_web' + LOCK_PULL = 'lock_pull' + + NAME_SEP = URL_SEP + + repo_id = Column( + "repo_id", Integer(), nullable=False, unique=True, default=None, + primary_key=True) + _repo_name = Column( + "repo_name", Text(), nullable=False, default=None) + _repo_name_hash = Column( + "repo_name_hash", String(255), nullable=False, unique=True) + repo_state = Column("repo_state", String(255), nullable=True) + + clone_uri = Column( + "clone_uri", EncryptedTextValue(), nullable=True, unique=False, + default=None) + repo_type = Column( + "repo_type", String(255), nullable=False, unique=False, default=None) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=False, default=None) + private = Column( + "private", Boolean(), nullable=True, unique=None, default=None) + enable_statistics = Column( + "statistics", Boolean(), nullable=True, unique=None, default=True) + enable_downloads = Column( + "downloads", Boolean(), nullable=True, unique=None, default=True) + description = Column( + "description", String(10000), nullable=True, unique=None, default=None) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=True, unique=None, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=True, unique=None, + default=datetime.datetime.now) + _landing_revision = Column( + "landing_revision", String(255), nullable=False, unique=False, + default=None) + enable_locking = Column( + "enable_locking", Boolean(), nullable=False, unique=None, + default=False) + _locked = Column( + "locked", String(255), nullable=True, unique=False, default=None) + _changeset_cache = Column( + "changeset_cache", LargeBinary(), nullable=True) # JSON data + + fork_id = Column( + "fork_id", Integer(), ForeignKey('repositories.repo_id'), + nullable=True, unique=False, default=None) + group_id = Column( + "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, + unique=False, default=None) + + user = relationship('User') + fork = relationship('Repository', remote_side=repo_id) + group = relationship('RepoGroup') + repo_to_perm = relationship( + 'UserRepoToPerm', cascade='all', + order_by='UserRepoToPerm.repo_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + stats = relationship('Statistics', cascade='all', uselist=False) + + followers = relationship( + 'UserFollowing', + primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', + cascade='all') + extra_fields = relationship( + 'RepositoryField', cascade="all, delete, delete-orphan") + logs = relationship('UserLog') + comments = relationship( + 'ChangesetComment', cascade="all, delete, delete-orphan") + pull_requests_source = relationship( + 'PullRequest', + primaryjoin='PullRequest.source_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + pull_requests_target = relationship( + 'PullRequest', + primaryjoin='PullRequest.target_repo_id==Repository.repo_id', + cascade="all, delete, delete-orphan") + ui = relationship('RepoRhodeCodeUi', cascade="all") + settings = relationship('RepoRhodeCodeSetting', cascade="all") + + def __unicode__(self): + return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, + safe_unicode(self.repo_name)) + + @hybrid_property + def landing_rev(self): + # always should return [rev_type, rev] + if self._landing_revision: + _rev_info = self._landing_revision.split(':') + if len(_rev_info) < 2: + _rev_info.insert(0, 'rev') + return [_rev_info[0], _rev_info[1]] + return [None, None] + + @landing_rev.setter + def landing_rev(self, val): + if ':' not in val: + raise ValueError('value must be delimited with `:` and consist ' + 'of <rev_type>:<rev>, got %s instead' % val) + self._landing_revision = val + + @hybrid_property + def locked(self): + if self._locked: + user_id, timelocked, reason = self._locked.split(':') + lock_values = int(user_id), timelocked, reason + else: + lock_values = [None, None, None] + return lock_values + + @locked.setter + def locked(self, val): + if val and isinstance(val, (list, tuple)): + self._locked = ':'.join(map(str, val)) + else: + self._locked = None + + @hybrid_property + def changeset_cache(self): + from rhodecode.lib.vcs.backends.base import EmptyCommit + dummy = EmptyCommit().__json__() + if not self._changeset_cache: + return dummy + try: + return json.loads(self._changeset_cache) + except TypeError: + return dummy + except Exception: + log.error(traceback.format_exc()) + return dummy + + @changeset_cache.setter + def changeset_cache(self, val): + try: + self._changeset_cache = json.dumps(val) + except Exception: + log.error(traceback.format_exc()) + + @hybrid_property + def repo_name(self): + return self._repo_name + + @repo_name.setter + def repo_name(self, value): + self._repo_name = value + self._repo_name_hash = hashlib.sha1(safe_str(value)).hexdigest() + + @classmethod + def normalize_repo_name(cls, repo_name): + """ + Normalizes os specific repo_name to the format internally stored inside + dabatabase using URL_SEP + + :param cls: + :param repo_name: + """ + return cls.NAME_SEP.join(repo_name.split(os.sep)) + + @classmethod + def get_by_repo_name(cls, repo_name): + q = Session().query(cls).filter(cls.repo_name == repo_name) + q = q.options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .options(joinedload(Repository.group)) + return q.scalar() + + @classmethod + def get_by_full_path(cls, repo_full_path): + repo_name = repo_full_path.split(cls.base_path(), 1)[-1] + repo_name = cls.normalize_repo_name(repo_name) + return cls.get_by_repo_name(repo_name.strip(URL_SEP)) + + @classmethod + def get_repo_forks(cls, repo_id): + return cls.query().filter(Repository.fork_id == repo_id) + + @classmethod + def base_path(cls): + """ + Returns base path when all repos are stored + + :param cls: + """ + q = Session().query(RhodeCodeUi)\ + .filter(RhodeCodeUi.ui_key == cls.NAME_SEP) + q = q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @classmethod + def is_valid(cls, repo_name): + """ + returns True if given repo name is a valid filesystem repository + + :param cls: + :param repo_name: + """ + from rhodecode.lib.utils import is_valid_repo + + return is_valid_repo(repo_name, cls.base_path()) + + @classmethod + def get_all_repos(cls, user_id=Optional(None), group_id=Optional(None), + case_insensitive=True): + q = Repository.query() + + if not isinstance(user_id, Optional): + q = q.filter(Repository.user_id == user_id) + + if not isinstance(group_id, Optional): + q = q.filter(Repository.group_id == group_id) + + if case_insensitive: + q = q.order_by(func.lower(Repository.repo_name)) + else: + q = q.order_by(Repository.repo_name) + return q.all() + + @property + def forks(self): + """ + Return forks of this repo + """ + return Repository.get_repo_forks(self.repo_id) + + @property + def parent(self): + """ + Returns fork parent + """ + return self.fork + + @property + def just_name(self): + return self.repo_name.split(self.NAME_SEP)[-1] + + @property + def groups_with_parents(self): + groups = [] + if self.group is None: + return groups + + cur_gr = self.group + groups.insert(0, cur_gr) + while 1: + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + groups.insert(0, gr) + + return groups + + @property + def groups_and_repo(self): + return self.groups_with_parents, self + + @LazyProperty + def repo_path(self): + """ + Returns base full path for that repository means where it actually + exists on a filesystem + """ + q = Session().query(RhodeCodeUi).filter( + RhodeCodeUi.ui_key == self.NAME_SEP) + q = q.options(FromCache("sql_cache_short", "repository_repo_path")) + return q.one().ui_value + + @property + def repo_full_path(self): + p = [self.repo_path] + # we need to split the name by / since this is how we store the + # names in the database, but that eventually needs to be converted + # into a valid system path + p += self.repo_name.split(self.NAME_SEP) + return os.path.join(*map(safe_unicode, p)) + + @property + def cache_keys(self): + """ + Returns associated cache keys for that repo + """ + return CacheKey.query()\ + .filter(CacheKey.cache_args == self.repo_name)\ + .order_by(CacheKey.cache_key)\ + .all() + + def get_new_name(self, repo_name): + """ + returns new full repository name based on assigned group and new new + + :param group_name: + """ + path_prefix = self.group.full_path_splitted if self.group else [] + return self.NAME_SEP.join(path_prefix + [repo_name]) + + @property + def _config(self): + """ + Returns db based config object. + """ + from rhodecode.lib.utils import make_db_config + return make_db_config(clear_session=False, repo=self) + + def permissions(self, with_admins=True, with_owner=True): + q = UserRepoToPerm.query().filter(UserRepoToPerm.repository == self) + q = q.options(joinedload(UserRepoToPerm.repository), + joinedload(UserRepoToPerm.user), + joinedload(UserRepoToPerm.permission),) + + # get owners and admins and permissions. We do a trick of re-writing + # objects from sqlalchemy to named-tuples due to sqlalchemy session + # has a global reference and changing one object propagates to all + # others. This means if admin is also an owner admin_row that change + # would propagate to both objects + perm_rows = [] + for _usr in q.all(): + usr = AttributeDict(_usr.user.get_dict()) + usr.permission = _usr.permission.permission_name + perm_rows.append(usr) + + # filter the perm rows by 'default' first and then sort them by + # admin,write,read,none permissions sorted again alphabetically in + # each group + perm_rows = sorted(perm_rows, key=display_sort) + + _admin_perm = 'repository.admin' + owner_row = [] + if with_owner: + usr = AttributeDict(self.user.get_dict()) + usr.owner_row = True + usr.permission = _admin_perm + owner_row.append(usr) + + super_admin_rows = [] + if with_admins: + for usr in User.get_all_super_admins(): + # if this admin is also owner, don't double the record + if usr.user_id == owner_row[0].user_id: + owner_row[0].admin_row = True + else: + usr = AttributeDict(usr.get_dict()) + usr.admin_row = True + usr.permission = _admin_perm + super_admin_rows.append(usr) + + return super_admin_rows + owner_row + perm_rows + + def permission_user_groups(self): + q = UserGroupRepoToPerm.query().filter( + UserGroupRepoToPerm.repository == self) + q = q.options(joinedload(UserGroupRepoToPerm.repository), + joinedload(UserGroupRepoToPerm.users_group), + joinedload(UserGroupRepoToPerm.permission),) + + perm_rows = [] + for _user_group in q.all(): + usr = AttributeDict(_user_group.users_group.get_dict()) + usr.permission = _user_group.permission.permission_name + perm_rows.append(usr) + + return perm_rows + + def get_api_data(self, include_secrets=False): + """ + Common function for generating repo api data + + :param include_secrets: See :meth:`User.get_api_data`. + + """ + # TODO: mikhail: Here there is an anti-pattern, we probably need to + # move this methods on models level. + from rhodecode.model.settings import SettingsModel + + repo = self + _user_id, _time, _reason = self.locked + + data = { + 'repo_id': repo.repo_id, + 'repo_name': repo.repo_name, + 'repo_type': repo.repo_type, + 'clone_uri': repo.clone_uri, + 'private': repo.private, + 'created_on': repo.created_on, + 'description': repo.description, + 'landing_rev': repo.landing_rev, + 'owner': repo.user.username, + 'fork_of': repo.fork.repo_name if repo.fork else None, + 'enable_statistics': repo.enable_statistics, + 'enable_locking': repo.enable_locking, + 'enable_downloads': repo.enable_downloads, + 'last_changeset': repo.changeset_cache, + 'locked_by': User.get(_user_id).get_api_data( + include_secrets=include_secrets) if _user_id else None, + 'locked_date': time_to_datetime(_time) if _time else None, + 'lock_reason': _reason if _reason else None, + } + + # TODO: mikhail: should be per-repo settings here + rc_config = SettingsModel().get_all_settings() + repository_fields = str2bool( + rc_config.get('rhodecode_repository_fields')) + if repository_fields: + for f in self.extra_fields: + data[f.field_key_prefixed] = f.field_value + + return data + + @classmethod + def lock(cls, repo, user_id, lock_time=None, lock_reason=None): + if not lock_time: + lock_time = time.time() + if not lock_reason: + lock_reason = cls.LOCK_AUTOMATIC + repo.locked = [user_id, lock_time, lock_reason] + Session().add(repo) + Session().commit() + + @classmethod + def unlock(cls, repo): + repo.locked = None + Session().add(repo) + Session().commit() + + @classmethod + def getlock(cls, repo): + return repo.locked + + def is_user_lock(self, user_id): + if self.lock[0]: + lock_user_id = safe_int(self.lock[0]) + user_id = safe_int(user_id) + # both are ints, and they are equal + return all([lock_user_id, user_id]) and lock_user_id == user_id + + return False + + def get_locking_state(self, action, user_id, only_when_enabled=True): + """ + Checks locking on this repository, if locking is enabled and lock is + present returns a tuple of make_lock, locked, locked_by. + make_lock can have 3 states None (do nothing) True, make lock + False release lock, This value is later propagated to hooks, which + do the locking. Think about this as signals passed to hooks what to do. + + """ + # TODO: johbo: This is part of the business logic and should be moved + # into the RepositoryModel. + + if action not in ('push', 'pull'): + raise ValueError("Invalid action value: %s" % repr(action)) + + # defines if locked error should be thrown to user + currently_locked = False + # defines if new lock should be made, tri-state + make_lock = None + repo = self + user = User.get(user_id) + + lock_info = repo.locked + + if repo and (repo.enable_locking or not only_when_enabled): + if action == 'push': + # check if it's already locked !, if it is compare users + locked_by_user_id = lock_info[0] + if user.user_id == locked_by_user_id: + log.debug( + 'Got `push` action from user %s, now unlocking', user) + # unlock if we have push from user who locked + make_lock = False + else: + # we're not the same user who locked, ban with + # code defined in settings (default is 423 HTTP Locked) ! + log.debug('Repo %s is currently locked by %s', repo, user) + currently_locked = True + elif action == 'pull': + # [0] user [1] date + if lock_info[0] and lock_info[1]: + log.debug('Repo %s is currently locked by %s', repo, user) + currently_locked = True + else: + log.debug('Setting lock on repo %s by %s', repo, user) + make_lock = True + + else: + log.debug('Repository %s do not have locking enabled', repo) + + log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s', + make_lock, currently_locked, lock_info) + + from rhodecode.lib.auth import HasRepoPermissionAny + perm_check = HasRepoPermissionAny('repository.write', 'repository.admin') + if make_lock and not perm_check(repo_name=repo.repo_name, user=user): + # if we don't have at least write permission we cannot make a lock + log.debug('lock state reset back to FALSE due to lack ' + 'of at least read permission') + make_lock = False + + return make_lock, currently_locked, lock_info + + @property + def last_db_change(self): + return self.updated_on + + @property + def clone_uri_hidden(self): + clone_uri = self.clone_uri + if clone_uri: + import urlobject + url_obj = urlobject.URLObject(self.clone_uri) + if url_obj.password: + clone_uri = url_obj.with_password('*****') + return clone_uri + + def clone_url(self, **override): + qualified_home_url = url('home', qualified=True) + + uri_tmpl = None + if 'with_id' in override: + uri_tmpl = self.DEFAULT_CLONE_URI_ID + del override['with_id'] + + if 'uri_tmpl' in override: + uri_tmpl = override['uri_tmpl'] + del override['uri_tmpl'] + + # we didn't override our tmpl from **overrides + if not uri_tmpl: + uri_tmpl = self.DEFAULT_CLONE_URI + try: + from pylons import tmpl_context as c + uri_tmpl = c.clone_uri_tmpl + except Exception: + # in any case if we call this outside of request context, + # ie, not having tmpl_context set up + pass + + return get_clone_url(uri_tmpl=uri_tmpl, + qualifed_home_url=qualified_home_url, + repo_name=self.repo_name, + repo_id=self.repo_id, **override) + + def set_state(self, state): + self.repo_state = state + Session().add(self) + #========================================================================== + # SCM PROPERTIES + #========================================================================== + + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): + return get_commit_safe( + self.scm_instance(), commit_id, commit_idx, pre_load=pre_load) + + def get_changeset(self, rev=None, pre_load=None): + warnings.warn("Use get_commit", DeprecationWarning) + commit_id = None + commit_idx = None + if isinstance(rev, basestring): + commit_id = rev + else: + commit_idx = rev + return self.get_commit(commit_id=commit_id, commit_idx=commit_idx, + pre_load=pre_load) + + def get_landing_commit(self): + """ + Returns landing commit, or if that doesn't exist returns the tip + """ + _rev_type, _rev = self.landing_rev + commit = self.get_commit(_rev) + if isinstance(commit, EmptyCommit): + return self.get_commit() + return commit + + def update_commit_cache(self, cs_cache=None, config=None): + """ + Update cache of last changeset for repository, keys should be:: + + short_id + raw_id + revision + parents + message + date + author + + :param cs_cache: + """ + from rhodecode.lib.vcs.backends.base import BaseChangeset + if cs_cache is None: + # use no-cache version here + scm_repo = self.scm_instance(cache=False, config=config) + if scm_repo: + cs_cache = scm_repo.get_commit( + pre_load=["author", "date", "message", "parents"]) + else: + cs_cache = EmptyCommit() + + if isinstance(cs_cache, BaseChangeset): + cs_cache = cs_cache.__json__() + + def is_outdated(new_cs_cache): + if new_cs_cache['raw_id'] != self.changeset_cache['raw_id']: + return True + return False + + # check if we have maybe already latest cached revision + if is_outdated(cs_cache) or not self.changeset_cache: + _default = datetime.datetime.fromtimestamp(0) + last_change = cs_cache.get('date') or _default + log.debug('updated repo %s with new cs cache %s', + self.repo_name, cs_cache) + self.updated_on = last_change + self.changeset_cache = cs_cache + Session().add(self) + Session().commit() + else: + log.debug('Skipping update_commit_cache for repo:`%s` ' + 'commit already with latest changes', self.repo_name) + + @property + def tip(self): + return self.get_commit('tip') + + @property + def author(self): + return self.tip.author + + @property + def last_change(self): + return self.scm_instance().last_change + + def get_comments(self, revisions=None): + """ + Returns comments for this repository grouped by revisions + + :param revisions: filter query by revisions only + """ + cmts = ChangesetComment.query()\ + .filter(ChangesetComment.repo == self) + if revisions: + cmts = cmts.filter(ChangesetComment.revision.in_(revisions)) + grouped = collections.defaultdict(list) + for cmt in cmts.all(): + grouped[cmt.revision].append(cmt) + return grouped + + def statuses(self, revisions=None): + """ + Returns statuses for this repository + + :param revisions: list of revisions to get statuses for + """ + statuses = ChangesetStatus.query()\ + .filter(ChangesetStatus.repo == self)\ + .filter(ChangesetStatus.version == 0) + + if revisions: + # Try doing the filtering in chunks to avoid hitting limits + size = 500 + status_results = [] + for chunk in xrange(0, len(revisions), size): + status_results += statuses.filter( + ChangesetStatus.revision.in_( + revisions[chunk: chunk+size]) + ).all() + else: + status_results = statuses.all() + + grouped = {} + + # maybe we have open new pullrequest without a status? + stat = ChangesetStatus.STATUS_UNDER_REVIEW + status_lbl = ChangesetStatus.get_status_lbl(stat) + for pr in PullRequest.query().filter(PullRequest.source_repo == self).all(): + for rev in pr.revisions: + pr_id = pr.pull_request_id + pr_repo = pr.target_repo.repo_name + grouped[rev] = [stat, status_lbl, pr_id, pr_repo] + + for stat in status_results: + pr_id = pr_repo = None + if stat.pull_request: + pr_id = stat.pull_request.pull_request_id + pr_repo = stat.pull_request.target_repo.repo_name + grouped[stat.revision] = [str(stat.status), stat.status_lbl, + pr_id, pr_repo] + return grouped + + # ========================================================================== + # SCM CACHE INSTANCE + # ========================================================================== + + def scm_instance(self, **kwargs): + import rhodecode + + # Passing a config will not hit the cache currently only used + # for repo2dbmapper + config = kwargs.pop('config', None) + cache = kwargs.pop('cache', None) + full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache')) + # if cache is NOT defined use default global, else we have a full + # control over cache behaviour + if cache is None and full_cache and not config: + return self._get_instance_cached() + return self._get_instance(cache=bool(cache), config=config) + + def _get_instance_cached(self): + @cache_region('long_term') + def _get_repo(cache_key): + return self._get_instance() + + invalidator_context = CacheKey.repo_context_cache( + _get_repo, self.repo_name, None) + + with invalidator_context as context: + context.invalidate() + repo = context.compute() + + return repo + + def _get_instance(self, cache=True, config=None): + repo_full_path = self.repo_full_path + try: + vcs_alias = get_scm(repo_full_path)[0] + log.debug( + 'Creating instance of %s repository from %s', + vcs_alias, repo_full_path) + backend = get_backend(vcs_alias) + except VCSError: + log.exception( + 'Perhaps this repository is in db and not in ' + 'filesystem run rescan repositories with ' + '"destroy old data" option from admin panel') + return + + config = config or self._config + custom_wire = { + 'cache': cache # controls the vcs.remote cache + } + repo = backend( + safe_str(repo_full_path), config=config, create=False, + with_wire=custom_wire) + + return repo + + def __json__(self): + return {'landing_rev': self.landing_rev} + + def get_dict(self): + + # Since we transformed `repo_name` to a hybrid property, we need to + # keep compatibility with the code which uses `repo_name` field. + + result = super(Repository, self).get_dict() + result['repo_name'] = result.pop('_repo_name', None) + return result + + +class RepoGroup(Base, BaseModel): + __tablename__ = 'groups' + __table_args__ = ( + UniqueConstraint('group_name', 'group_parent_id'), + CheckConstraint('group_id != group_parent_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + __mapper_args__ = {'order_by': 'group_name'} + + CHOICES_SEPARATOR = '/' # used to generate select2 choices for nested groups + + group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + group_name = Column("group_name", String(255), nullable=False, unique=True, default=None) + group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) + group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None) + enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + + repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') + users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') + parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') + + def __init__(self, group_name='', parent_group=None): + self.group_name = group_name + self.parent_group = parent_group + + def __unicode__(self): + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) + + @classmethod + def _generate_choice(cls, repo_group): + from webhelpers.html import literal as _literal + _name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k)) + return repo_group.group_id, _name(repo_group.full_path_splitted) + + @classmethod + def groups_choices(cls, groups=None, show_empty_group=True): + if not groups: + groups = cls.query().all() + + repo_groups = [] + if show_empty_group: + repo_groups = [('-1', u'-- %s --' % _('No parent'))] + + repo_groups.extend([cls._generate_choice(x) for x in groups]) + + repo_groups = sorted( + repo_groups, key=lambda t: t[1].split(cls.CHOICES_SEPARATOR)[0]) + return repo_groups + + @classmethod + def url_sep(cls): + return URL_SEP + + @classmethod + def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): + if case_insensitive: + gr = cls.query().filter(func.lower(cls.group_name) + == func.lower(group_name)) + else: + gr = cls.query().filter(cls.group_name == group_name) + if cache: + gr = gr.options(FromCache( + "sql_cache_short", + "get_group_%s" % _hash_key(group_name))) + return gr.scalar() + + @classmethod + def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None), + case_insensitive=True): + q = RepoGroup.query() + + if not isinstance(user_id, Optional): + q = q.filter(RepoGroup.user_id == user_id) + + if not isinstance(group_id, Optional): + q = q.filter(RepoGroup.group_parent_id == group_id) + + if case_insensitive: + q = q.order_by(func.lower(RepoGroup.group_name)) + else: + q = q.order_by(RepoGroup.group_name) + return q.all() + + @property + def parents(self): + parents_recursion_limit = 10 + groups = [] + if self.parent_group is None: + return groups + cur_gr = self.parent_group + groups.insert(0, cur_gr) + cnt = 0 + while 1: + cnt += 1 + gr = getattr(cur_gr, 'parent_group', None) + cur_gr = cur_gr.parent_group + if gr is None: + break + if cnt == parents_recursion_limit: + # this will prevent accidental infinit loops + log.error(('more than %s parents found for group %s, stopping ' + 'recursive parent fetching' % (parents_recursion_limit, self))) + break + + groups.insert(0, gr) + return groups + + @property + def children(self): + return RepoGroup.query().filter(RepoGroup.parent_group == self) + + @property + def name(self): + return self.group_name.split(RepoGroup.url_sep())[-1] + + @property + def full_path(self): + return self.group_name + + @property + def full_path_splitted(self): + return self.group_name.split(RepoGroup.url_sep()) + + @property + def repositories(self): + return Repository.query()\ + .filter(Repository.group == self)\ + .order_by(Repository.repo_name) + + @property + def repositories_recursive_count(self): + cnt = self.repositories.count() + + def children_count(group): + cnt = 0 + for child in group.children: + cnt += child.repositories.count() + cnt += children_count(child) + return cnt + + return cnt + children_count(self) + + def _recursive_objects(self, include_repos=True): + all_ = [] + + def _get_members(root_gr): + if include_repos: + for r in root_gr.repositories: + all_.append(r) + childs = root_gr.children.all() + if childs: + for gr in childs: + all_.append(gr) + _get_members(gr) + + _get_members(self) + return [self] + all_ + + def recursive_groups_and_repos(self): + """ + Recursive return all groups, with repositories in those groups + """ + return self._recursive_objects() + + def recursive_groups(self): + """ + Returns all children groups for this group including children of children + """ + return self._recursive_objects(include_repos=False) + + def get_new_name(self, group_name): + """ + returns new full group name based on parent and new name + + :param group_name: + """ + path_prefix = (self.parent_group.full_path_splitted if + self.parent_group else []) + return RepoGroup.url_sep().join(path_prefix + [group_name]) + + def permissions(self, with_admins=True, with_owner=True): + q = UserRepoGroupToPerm.query().filter(UserRepoGroupToPerm.group == self) + q = q.options(joinedload(UserRepoGroupToPerm.group), + joinedload(UserRepoGroupToPerm.user), + joinedload(UserRepoGroupToPerm.permission),) + + # get owners and admins and permissions. We do a trick of re-writing + # objects from sqlalchemy to named-tuples due to sqlalchemy session + # has a global reference and changing one object propagates to all + # others. This means if admin is also an owner admin_row that change + # would propagate to both objects + perm_rows = [] + for _usr in q.all(): + usr = AttributeDict(_usr.user.get_dict()) + usr.permission = _usr.permission.permission_name + perm_rows.append(usr) + + # filter the perm rows by 'default' first and then sort them by + # admin,write,read,none permissions sorted again alphabetically in + # each group + perm_rows = sorted(perm_rows, key=display_sort) + + _admin_perm = 'group.admin' + owner_row = [] + if with_owner: + usr = AttributeDict(self.user.get_dict()) + usr.owner_row = True + usr.permission = _admin_perm + owner_row.append(usr) + + super_admin_rows = [] + if with_admins: + for usr in User.get_all_super_admins(): + # if this admin is also owner, don't double the record + if usr.user_id == owner_row[0].user_id: + owner_row[0].admin_row = True + else: + usr = AttributeDict(usr.get_dict()) + usr.admin_row = True + usr.permission = _admin_perm + super_admin_rows.append(usr) + + return super_admin_rows + owner_row + perm_rows + + def permission_user_groups(self): + q = UserGroupRepoGroupToPerm.query().filter(UserGroupRepoGroupToPerm.group == self) + q = q.options(joinedload(UserGroupRepoGroupToPerm.group), + joinedload(UserGroupRepoGroupToPerm.users_group), + joinedload(UserGroupRepoGroupToPerm.permission),) + + perm_rows = [] + for _user_group in q.all(): + usr = AttributeDict(_user_group.users_group.get_dict()) + usr.permission = _user_group.permission.permission_name + perm_rows.append(usr) + + return perm_rows + + def get_api_data(self): + """ + Common function for generating api data + + """ + group = self + data = { + 'group_id': group.group_id, + 'group_name': group.group_name, + 'group_description': group.group_description, + 'parent_group': group.parent_group.group_name if group.parent_group else None, + 'repositories': [x.repo_name for x in group.repositories], + 'owner': group.user.username, + } + return data + + +class Permission(Base, BaseModel): + __tablename__ = 'permissions' + __table_args__ = ( + Index('p_perm_name_idx', 'permission_name'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + PERMS = [ + ('hg.admin', _('RhodeCode Super Administrator')), + + ('repository.none', _('Repository no access')), + ('repository.read', _('Repository read access')), + ('repository.write', _('Repository write access')), + ('repository.admin', _('Repository admin access')), + + ('group.none', _('Repository group no access')), + ('group.read', _('Repository group read access')), + ('group.write', _('Repository group write access')), + ('group.admin', _('Repository group admin access')), + + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + + ('hg.repogroup.create.false', _('Repository Group creation disabled')), + ('hg.repogroup.create.true', _('Repository Group creation enabled')), + + ('hg.usergroup.create.false', _('User Group creation disabled')), + ('hg.usergroup.create.true', _('User Group creation enabled')), + + ('hg.create.none', _('Repository creation disabled')), + ('hg.create.repository', _('Repository creation enabled')), + ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')), + ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')), + + ('hg.fork.none', _('Repository forking disabled')), + ('hg.fork.repository', _('Repository forking enabled')), + + ('hg.register.none', _('Registration disabled')), + ('hg.register.manual_activate', _('User Registration with manual account activation')), + ('hg.register.auto_activate', _('User Registration with automatic account activation')), + + ('hg.extern_activate.manual', _('Manual activation of external account')), + ('hg.extern_activate.auto', _('Automatic activation of external account')), + + ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')), + ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')), + ] + + # definition of system default permissions for DEFAULT user + DEFAULT_USER_PERMISSIONS = [ + 'repository.read', + 'group.read', + 'usergroup.read', + 'hg.create.repository', + 'hg.repogroup.create.false', + 'hg.usergroup.create.false', + 'hg.create.write_on_repogroup.true', + 'hg.fork.repository', + 'hg.register.manual_activate', + 'hg.extern_activate.auto', + 'hg.inherit_default_perms.true', + ] + + # defines which permissions are more important higher the more important + # Weight defines which permissions are more important. + # The higher number the more important. + PERM_WEIGHTS = { + 'repository.none': 0, + 'repository.read': 1, + 'repository.write': 3, + 'repository.admin': 4, + + 'group.none': 0, + 'group.read': 1, + 'group.write': 3, + 'group.admin': 4, + + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + + 'hg.repogroup.create.false': 0, + 'hg.repogroup.create.true': 1, + + 'hg.usergroup.create.false': 0, + 'hg.usergroup.create.true': 1, + + 'hg.fork.none': 0, + 'hg.fork.repository': 1, + 'hg.create.none': 0, + 'hg.create.repository': 1 + } + + permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None) + + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, self.permission_id, self.permission_name + ) + + @classmethod + def get_by_key(cls, key): + return cls.query().filter(cls.permission_name == key).scalar() + + @classmethod + def get_default_repo_perms(cls, user_id, repo_id=None): + q = Session().query(UserRepoToPerm, Repository, Permission)\ + .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\ + .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\ + .filter(UserRepoToPerm.user_id == user_id) + if repo_id: + q = q.filter(UserRepoToPerm.repository_id == repo_id) + return q.all() + + @classmethod + def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None): + q = Session().query(UserGroupRepoToPerm, Repository, Permission)\ + .join( + Permission, + UserGroupRepoToPerm.permission_id == Permission.permission_id)\ + .join( + Repository, + UserGroupRepoToPerm.repository_id == Repository.repo_id)\ + .join( + UserGroup, + UserGroupRepoToPerm.users_group_id == + UserGroup.users_group_id)\ + .join( + UserGroupMember, + UserGroupRepoToPerm.users_group_id == + UserGroupMember.users_group_id)\ + .filter( + UserGroupMember.user_id == user_id, + UserGroup.users_group_active == true()) + if repo_id: + q = q.filter(UserGroupRepoToPerm.repository_id == repo_id) + return q.all() + + @classmethod + def get_default_group_perms(cls, user_id, repo_group_id=None): + q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\ + .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\ + .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ + .filter(UserRepoGroupToPerm.user_id == user_id) + if repo_group_id: + q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id) + return q.all() + + @classmethod + def get_default_group_perms_from_user_group( + cls, user_id, repo_group_id=None): + q = Session().query(UserGroupRepoGroupToPerm, RepoGroup, Permission)\ + .join( + Permission, + UserGroupRepoGroupToPerm.permission_id == + Permission.permission_id)\ + .join( + RepoGroup, + UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id)\ + .join( + UserGroup, + UserGroupRepoGroupToPerm.users_group_id == + UserGroup.users_group_id)\ + .join( + UserGroupMember, + UserGroupRepoGroupToPerm.users_group_id == + UserGroupMember.users_group_id)\ + .filter( + UserGroupMember.user_id == user_id, + UserGroup.users_group_active == true()) + if repo_group_id: + q = q.filter(UserGroupRepoGroupToPerm.group_id == repo_group_id) + return q.all() + + @classmethod + def get_default_user_group_perms(cls, user_id, user_group_id=None): + q = Session().query(UserUserGroupToPerm, UserGroup, Permission)\ + .join((Permission, UserUserGroupToPerm.permission_id == Permission.permission_id))\ + .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\ + .filter(UserUserGroupToPerm.user_id == user_id) + if user_group_id: + q = q.filter(UserUserGroupToPerm.user_group_id == user_group_id) + return q.all() + + @classmethod + def get_default_user_group_perms_from_user_group( + cls, user_id, user_group_id=None): + TargetUserGroup = aliased(UserGroup, name='target_user_group') + q = Session().query(UserGroupUserGroupToPerm, UserGroup, Permission)\ + .join( + Permission, + UserGroupUserGroupToPerm.permission_id == + Permission.permission_id)\ + .join( + TargetUserGroup, + UserGroupUserGroupToPerm.target_user_group_id == + TargetUserGroup.users_group_id)\ + .join( + UserGroup, + UserGroupUserGroupToPerm.user_group_id == + UserGroup.users_group_id)\ + .join( + UserGroupMember, + UserGroupUserGroupToPerm.user_group_id == + UserGroupMember.users_group_id)\ + .filter( + UserGroupMember.user_id == user_id, + UserGroup.users_group_active == true()) + if user_group_id: + q = q.filter( + UserGroupUserGroupToPerm.user_group_id == user_group_id) + + return q.all() + + +class UserRepoToPerm(Base, BaseModel): + __tablename__ = 'repo_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'repository_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + repository = relationship('Repository') + permission = relationship('Permission') + + @classmethod + def create(cls, user, repository, permission): + n = cls() + n.user = user + n.repository = repository + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + @classmethod + def create(cls, user, user_group, permission): + n = cls() + n.user = user + n.user_group = user_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) + + +class UserToPerm(Base, BaseModel): + __tablename__ = 'user_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + permission = relationship('Permission', lazy='joined') + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.permission) + + +class UserGroupRepoToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_to_perm' + __table_args__ = ( + UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + repository = relationship('Repository') + + @classmethod + def create(cls, users_group, repository, permission): + n = cls() + n.users_group = users_group + n.repository = repository + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository) + + +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'), + CheckConstraint('target_user_group_id != user_group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + @classmethod + def create(cls, target_user_group, user_group, permission): + n = cls() + n.target_user_group = target_user_group + n.user_group = user_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + +class UserGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'permission_id',), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + + +class UserRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'user_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + group = relationship('RepoGroup') + permission = relationship('Permission') + + @classmethod + def create(cls, user, repository_group, permission): + n = cls() + n.user = user + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + +class UserGroupRepoGroupToPerm(Base, BaseModel): + __tablename__ = 'users_group_repo_group_to_perm' + __table_args__ = ( + UniqueConstraint('users_group_id', 'group_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + + users_group = relationship('UserGroup') + permission = relationship('Permission') + group = relationship('RepoGroup') + + @classmethod + def create(cls, user_group, repository_group, permission): + n = cls() + n.users_group = user_group + n.group = repository_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group) + + +class Statistics(Base, BaseModel): + __tablename__ = 'statistics' + __table_args__ = ( + UniqueConstraint('repository_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) + stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data + commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data + + repository = relationship('Repository', single_parent=True) + + +class UserFollowing(Base, BaseModel): + __tablename__ = 'user_followings' + __table_args__ = ( + UniqueConstraint('user_id', 'follows_repository_id'), + UniqueConstraint('user_id', 'follows_user_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + + user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) + follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) + follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + + user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') + + follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') + follows_repository = relationship('Repository', order_by='Repository.repo_name') + + @classmethod + def get_repo_followers(cls, repo_id): + return cls.query().filter(cls.follows_repo_id == repo_id) + + +class CacheKey(Base, BaseModel): + __tablename__ = 'cache_invalidation' + __table_args__ = ( + UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + CACHE_TYPE_ATOM = 'ATOM' + CACHE_TYPE_RSS = 'RSS' + CACHE_TYPE_README = 'README' + + cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None) + cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) + + def __init__(self, cache_key, cache_args=''): + self.cache_key = cache_key + self.cache_args = cache_args + self.cache_active = False + + def __unicode__(self): + return u"<%s('%s:%s[%s]')>" % ( + self.__class__.__name__, + self.cache_id, self.cache_key, self.cache_active) + + def _cache_key_partition(self): + prefix, repo_name, suffix = self.cache_key.partition(self.cache_args) + return prefix, repo_name, suffix + + def get_prefix(self): + """ + Try to extract prefix from existing cache key. The key could consist + of prefix, repo_name, suffix + """ + # this returns prefix, repo_name, suffix + return self._cache_key_partition()[0] + + def get_suffix(self): + """ + get suffix that might have been used in _get_cache_key to + generate self.cache_key. Only used for informational purposes + in repo_edit.html. + """ + # prefix, repo_name, suffix + return self._cache_key_partition()[2] + + @classmethod + def delete_all_cache(cls): + """ + Delete all cache keys from database. + Should only be run when all instances are down and all entries + thus stale. + """ + cls.query().delete() + Session().commit() + + @classmethod + def get_cache_key(cls, repo_name, cache_type): + """ + + Generate a cache key for this process of RhodeCode instance. + Prefix most likely will be process id or maybe explicitly set + instance_id from .ini file. + """ + import rhodecode + prefix = safe_unicode(rhodecode.CONFIG.get('instance_id') or '') + + repo_as_unicode = safe_unicode(repo_name) + key = u'{}_{}'.format(repo_as_unicode, cache_type) \ + if cache_type else repo_as_unicode + + return u'{}{}'.format(prefix, key) + + @classmethod + def set_invalidate(cls, repo_name, delete=False): + """ + Mark all caches of a repo as invalid in the database. + """ + + try: + qry = Session().query(cls).filter(cls.cache_args == repo_name) + if delete: + log.debug('cache objects deleted for repo %s', + safe_str(repo_name)) + qry.delete() + else: + log.debug('cache objects marked as invalid for repo %s', + safe_str(repo_name)) + qry.update({"cache_active": False}) + + Session().commit() + except Exception: + log.error(traceback.format_exc()) + Session().rollback() + + @classmethod + def get_active_cache(cls, cache_key): + inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar() + if inv_obj: + return inv_obj + return None + + @classmethod + def repo_context_cache(cls, compute_func, repo_name, cache_type): + """ + @cache_region('long_term') + def _heavy_calculation(cache_key): + return 'result' + + cache_context = CacheKey.repo_context_cache( + _heavy_calculation, repo_name, cache_type) + + with cache_context as context: + context.invalidate() + computed = context.compute() + + assert computed == 'result' + """ + from rhodecode.lib import caches + return caches.InvalidationContext(compute_func, repo_name, cache_type) + + +class ChangesetComment(Base, BaseModel): + __tablename__ = 'changeset_comments' + __table_args__ = ( + Index('cc_revision_idx', 'revision'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + COMMENT_OUTDATED = u'comment_outdated' + + comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + revision = Column('revision', String(40), nullable=True) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True) + line_no = Column('line_no', Unicode(10), nullable=True) + hl_lines = Column('hl_lines', Unicode(512), nullable=True) + f_path = Column('f_path', Unicode(1000), nullable=True) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) + text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + renderer = Column('renderer', Unicode(64), nullable=True) + display_state = Column('display_state', Unicode(128), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") + pull_request = relationship('PullRequest', lazy='joined') + pull_request_version = relationship('PullRequestVersion') + + @classmethod + def get_users(cls, revision=None, pull_request_id=None): + """ + Returns user associated with this ChangesetComment. ie those + who actually commented + + :param cls: + :param revision: + """ + q = Session().query(User)\ + .join(ChangesetComment.author) + if revision: + q = q.filter(cls.revision == revision) + elif pull_request_id: + q = q.filter(cls.pull_request_id == pull_request_id) + return q.all() + + def render(self, mentions=False): + from rhodecode.lib import helpers as h + return h.render(self.text, renderer=self.renderer, mentions=mentions) + + def __repr__(self): + if self.comment_id: + return '<DB:ChangesetComment #%s>' % self.comment_id + else: + return '<DB:ChangesetComment at %#x>' % id(self) + + +class ChangesetStatus(Base, BaseModel): + __tablename__ = 'changeset_statuses' + __table_args__ = ( + Index('cs_revision_idx', 'revision'), + Index('cs_version_idx', 'version'), + UniqueConstraint('repo_id', 'revision', 'version'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' + + STATUSES = [ + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), + ] + + changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) + repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None) + revision = Column('revision', String(40), nullable=False) + status = Column('status', String(128), nullable=False, default=DEFAULT) + changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id')) + modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) + version = Column('version', Integer(), nullable=False, default=0) + pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True) + + author = relationship('User', lazy='joined') + repo = relationship('Repository') + comment = relationship('ChangesetComment', lazy='joined') + pull_request = relationship('PullRequest', lazy='joined') + + def __unicode__(self): + return u"<%s('%s[%s]:%s')>" % ( + self.__class__.__name__, + self.status, self.version, self.author + ) + + @classmethod + def get_status_lbl(cls, value): + return dict(cls.STATUSES).get(value) + + @property + def status_lbl(self): + return ChangesetStatus.get_status_lbl(self.status) + + +class _PullRequestBase(BaseModel): + """ + Common attributes of pull request and version entries. + """ + + # .status values + STATUS_NEW = u'new' + STATUS_OPEN = u'open' + STATUS_CLOSED = u'closed' + + title = Column('title', Unicode(255), nullable=True) + description = Column( + 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), + nullable=True) + # new/open/closed status of pull request (not approve/reject/etc) + status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW) + created_on = Column( + 'created_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + updated_on = Column( + 'updated_on', DateTime(timezone=False), nullable=False, + default=datetime.datetime.now) + + @declared_attr + def user_id(cls): + return Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=False, + unique=None) + + # 500 revisions max + _revisions = Column( + 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) + + @declared_attr + def source_repo_id(cls): + # TODO: dan: rename column to source_repo_id + return Column( + 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + source_ref = Column('org_ref', Unicode(255), nullable=False) + + @declared_attr + def target_repo_id(cls): + # TODO: dan: rename column to target_repo_id + return Column( + 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'), + nullable=False) + + target_ref = Column('other_ref', Unicode(255), nullable=False) + + # TODO: dan: rename column to last_merge_source_rev + _last_merge_source_rev = Column( + 'last_merge_org_rev', String(40), nullable=True) + # TODO: dan: rename column to last_merge_target_rev + _last_merge_target_rev = Column( + 'last_merge_other_rev', String(40), nullable=True) + _last_merge_status = Column('merge_status', Integer(), nullable=True) + merge_rev = Column('merge_rev', String(40), nullable=True) + + @hybrid_property + def revisions(self): + return self._revisions.split(':') if self._revisions else [] + + @revisions.setter + def revisions(self, val): + self._revisions = ':'.join(val) + + @declared_attr + def author(cls): + return relationship('User', lazy='joined') + + @declared_attr + def source_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.source_repo_id==Repository.repo_id' % cls.__name__) + + @property + def source_ref_parts(self): + refs = self.source_ref.split(':') + return Reference(refs[0], refs[1], refs[2]) + + @declared_attr + def target_repo(cls): + return relationship( + 'Repository', + primaryjoin='%s.target_repo_id==Repository.repo_id' % cls.__name__) + + @property + def target_ref_parts(self): + refs = self.target_ref.split(':') + return Reference(refs[0], refs[1], refs[2]) + + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '<DB:PullRequest #%s>' % self.pull_request_id + else: + return '<DB:PullRequest at %#x>' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan") + + def is_closed(self): + return self.status == self.STATUS_CLOSED + + def get_api_data(self): + from rhodecode.model.pull_request import PullRequestModel + pull_request = self + merge_status = PullRequestModel().merge_status(pull_request) + data = { + 'pull_request_id': pull_request.pull_request_id, + 'url': url('pullrequest_show', + repo_name=pull_request.target_repo.repo_name, + pull_request_id=pull_request.pull_request_id, + qualified=True), + 'title': pull_request.title, + 'description': pull_request.description, + 'status': pull_request.status, + 'created_on': pull_request.created_on, + 'updated_on': pull_request.updated_on, + 'commit_ids': pull_request.revisions, + 'review_status': pull_request.calculated_review_status(), + 'mergeable': { + 'status': merge_status[0], + 'message': unicode(merge_status[1]), + }, + 'source': { + 'clone_url': pull_request.source_repo.clone_url(), + 'repository': pull_request.source_repo.repo_name, + 'reference': { + 'name': pull_request.source_ref_parts.name, + 'type': pull_request.source_ref_parts.type, + 'commit_id': pull_request.source_ref_parts.commit_id, + }, + }, + 'target': { + 'clone_url': pull_request.target_repo.clone_url(), + 'repository': pull_request.target_repo.repo_name, + 'reference': { + 'name': pull_request.target_ref_parts.name, + 'type': pull_request.target_ref_parts.type, + 'commit_id': pull_request.target_ref_parts.commit_id, + }, + }, + 'author': pull_request.author.get_api_data(include_secrets=False, + details='basic'), + 'reviewers': [ + { + 'user': reviewer.get_api_data(include_secrets=False, + details='basic'), + 'review_status': st[0][1].status if st else 'not_reviewed', + } + for reviewer, st in pull_request.reviewers_statuses() + ] + } + + return data + + def __json__(self): + return { + 'revisions': self.revisions, + } + + def calculated_review_status(self): + # TODO: anderson: 13.05.15 Used only on templates/my_account_pullrequests.html + # because it's tricky on how to use ChangesetStatusModel from there + warnings.warn("Use calculated_review_status from ChangesetStatusModel", DeprecationWarning) + from rhodecode.model.changeset_status import ChangesetStatusModel + return ChangesetStatusModel().calculated_review_status(self) + + def reviewers_statuses(self): + warnings.warn("Use reviewers_statuses from ChangesetStatusModel", DeprecationWarning) + from rhodecode.model.changeset_status import ChangesetStatusModel + return ChangesetStatusModel().reviewers_statuses(self) + + +class PullRequestVersion(Base, _PullRequestBase): + __tablename__ = 'pull_request_versions' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_version_id = Column( + 'pull_request_version_id', Integer(), nullable=False, primary_key=True) + pull_request_id = Column( + 'pull_request_id', Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + pull_request = relationship('PullRequest') + + def __repr__(self): + if self.pull_request_version_id: + return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id + else: + return '<DB:PullRequestVersion at %#x>' % id(self) + + +class PullRequestReviewers(Base, BaseModel): + __tablename__ = 'pull_request_reviewers' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + def __init__(self, user=None, pull_request=None): + self.user = user + self.pull_request = pull_request + + pull_requests_reviewers_id = Column( + 'pull_requests_reviewers_id', Integer(), nullable=False, + primary_key=True) + pull_request_id = Column( + "pull_request_id", Integer(), + ForeignKey('pull_requests.pull_request_id'), nullable=False) + user_id = Column( + "user_id", Integer(), ForeignKey('users.user_id'), nullable=True) + + user = relationship('User') + pull_request = relationship('PullRequest') + + +class Notification(Base, BaseModel): + __tablename__ = 'notifications' + __table_args__ = ( + Index('notification_type_idx', 'type'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + TYPE_CHANGESET_COMMENT = u'cs_comment' + TYPE_MESSAGE = u'message' + TYPE_MENTION = u'mention' + TYPE_REGISTRATION = u'registration' + TYPE_PULL_REQUEST = u'pull_request' + TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment' + + notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) + subject = Column('subject', Unicode(512), nullable=True) + body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True) + created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + type_ = Column('type', Unicode(255)) + + created_by_user = relationship('User') + notifications_to_users = relationship('UserNotification', lazy='joined', + cascade="all, delete, delete-orphan") + + @property + def recipients(self): + return [x.user for x in UserNotification.query()\ + .filter(UserNotification.notification == self)\ + .order_by(UserNotification.user_id.asc()).all()] + + @classmethod + def create(cls, created_by, subject, body, recipients, type_=None): + if type_ is None: + type_ = Notification.TYPE_MESSAGE + + notification = cls() + notification.created_by_user = created_by + notification.subject = subject + notification.body = body + notification.type_ = type_ + notification.created_on = datetime.datetime.now() + + for u in recipients: + assoc = UserNotification() + assoc.notification = notification + + # if created_by is inside recipients mark his notification + # as read + if u.user_id == created_by.user_id: + assoc.read = True + + u.notifications.append(assoc) + Session().add(notification) + + return notification + + @property + def description(self): + from rhodecode.model.notification import NotificationModel + return NotificationModel().make_description(self) + + +class UserNotification(Base, BaseModel): + __tablename__ = 'user_to_notification' + __table_args__ = ( + UniqueConstraint('user_id', 'notification_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) + notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) + read = Column('read', Boolean, default=False) + sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) + + user = relationship('User', lazy="joined") + notification = relationship('Notification', lazy="joined", + order_by=lambda: Notification.created_on.desc(),) + + def mark_as_read(self): + self.read = True + Session().add(self) + + +class Gist(Base, BaseModel): + __tablename__ = 'gists' + __table_args__ = ( + Index('g_gist_access_id_idx', 'gist_access_id'), + Index('g_created_on_idx', 'created_on'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True} + ) + GIST_PUBLIC = u'public' + GIST_PRIVATE = u'private' + DEFAULT_FILENAME = u'gistfile1.txt' + + ACL_LEVEL_PUBLIC = u'acl_public' + ACL_LEVEL_PRIVATE = u'acl_private' + + gist_id = Column('gist_id', Integer(), primary_key=True) + gist_access_id = Column('gist_access_id', Unicode(250)) + gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql')) + gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True) + gist_expires = Column('gist_expires', Float(53), nullable=False) + gist_type = Column('gist_type', Unicode(128), nullable=False) + created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + acl_level = Column('acl_level', Unicode(128), nullable=True) + + owner = relationship('User') + + def __repr__(self): + return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id) + + @classmethod + def get_or_404(cls, id_): + res = cls.query().filter(cls.gist_access_id == id_).scalar() + if not res: + raise HTTPNotFound + return res + + @classmethod + def get_by_access_id(cls, gist_access_id): + return cls.query().filter(cls.gist_access_id == gist_access_id).scalar() + + def gist_url(self): + import rhodecode + alias_url = rhodecode.CONFIG.get('gist_alias_url') + if alias_url: + return alias_url.replace('{gistid}', self.gist_access_id) + + return url('gist', gist_id=self.gist_access_id, qualified=True) + + @classmethod + def base_path(cls): + """ + Returns base path when all gists are stored + + :param cls: + """ + from rhodecode.model.gist import GIST_STORE_LOC + q = Session().query(RhodeCodeUi)\ + .filter(RhodeCodeUi.ui_key == URL_SEP) + q = q.options(FromCache("sql_cache_short", "repository_repo_path")) + return os.path.join(q.one().ui_value, GIST_STORE_LOC) + + def get_api_data(self): + """ + Common function for generating gist related data for API + """ + gist = self + data = { + 'gist_id': gist.gist_id, + 'type': gist.gist_type, + 'access_id': gist.gist_access_id, + 'description': gist.gist_description, + 'url': gist.gist_url(), + 'expires': gist.gist_expires, + 'created_on': gist.created_on, + 'modified_at': gist.modified_at, + 'content': None, + 'acl_level': gist.acl_level, + } + return data + + def __json__(self): + data = dict( + ) + data.update(self.get_api_data()) + return data + # SCM functions + + def scm_instance(self, **kwargs): + from rhodecode.lib.vcs import get_repo + base_path = self.base_path() + return get_repo(os.path.join(*map(safe_str, + [base_path, self.gist_access_id]))) + + +class DbMigrateVersion(Base, BaseModel): + __tablename__ = 'db_migrate_version' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + repository_id = Column('repository_id', String(250), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) + + +class ExternalIdentity(Base, BaseModel): + __tablename__ = 'external_identities' + __table_args__ = ( + Index('local_user_id_idx', 'local_user_id'), + Index('external_id_idx', 'external_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'}) + + external_id = Column('external_id', Unicode(255), default=u'', + primary_key=True) + external_username = Column('external_username', Unicode(1024), default=u'') + local_user_id = Column('local_user_id', Integer(), + ForeignKey('users.user_id'), primary_key=True) + provider_name = Column('provider_name', Unicode(255), default=u'', + primary_key=True) + access_token = Column('access_token', String(1024), default=u'') + alt_token = Column('alt_token', String(1024), default=u'') + token_secret = Column('token_secret', String(1024), default=u'') + + @classmethod + def by_external_id_and_provider(cls, external_id, provider_name, + local_user_id=None): + """ + Returns ExternalIdentity instance based on search params + + :param external_id: + :param provider_name: + :return: ExternalIdentity + """ + query = cls.query() + query = query.filter(cls.external_id == external_id) + query = query.filter(cls.provider_name == provider_name) + if local_user_id: + query = query.filter(cls.local_user_id == local_user_id) + return query.first() + + @classmethod + def user_by_external_id_and_provider(cls, external_id, provider_name): + """ + Returns User instance based on search params + + :param external_id: + :param provider_name: + :return: User + """ + query = User.query() + query = query.filter(cls.external_id == external_id) + query = query.filter(cls.provider_name == provider_name) + query = query.filter(User.user_id == cls.local_user_id) + return query.first() + + @classmethod + def by_local_user_id(cls, local_user_id): + """ + Returns all tokens for user + + :param local_user_id: + :return: ExternalIdentity + """ + query = cls.query() + query = query.filter(cls.local_user_id == local_user_id) + return query diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/forms.py @@ -0,0 +1,547 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +this is forms validation classes +http://formencode.org/module-formencode.validators.html +for list off all availible validators + +we can create our own validators + +The table below outlines the options which can be used in a schema in addition to the validators themselves +pre_validators [] These validators will be applied before the schema +chained_validators [] These validators will be applied after the schema +allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present +filter_extra_fields False If True, then keys that aren't associated with a validator are removed +if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value. +ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already + + +<name> = formencode.validators.<name of validator> +<name> must equal form name +list=[1,2,3,4,5] +for SELECT use formencode.All(OneOf(list), Int()) + +""" + +import logging + +import formencode +from formencode import All, Pipe + +from pylons.i18n.translation import _ + +from rhodecode import BACKENDS +from rhodecode.model import validators as v + +log = logging.getLogger(__name__) + + +def LoginForm(): + class _LoginForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + username = v.UnicodeString( + strip=True, + min=1, + not_empty=True, + messages={ + 'empty': _(u'Please enter a login'), + 'tooShort': _(u'Enter a value %(min)i characters long or more') + } + ) + + password = v.UnicodeString( + strip=False, + min=3, + not_empty=True, + messages={ + 'empty': _(u'Please enter a password'), + 'tooShort': _(u'Enter %(min)i characters or more')} + ) + + remember = v.StringBoolean(if_missing=False) + + chained_validators = [v.ValidAuth()] + return _LoginForm + + +def PasswordChangeForm(username): + class _PasswordChangeForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + current_password = v.ValidOldPassword(username)(not_empty=True) + new_password = All(v.ValidPassword(), v.UnicodeString(strip=False, min=6)) + new_password_confirmation = All(v.ValidPassword(), v.UnicodeString(strip=False, min=6)) + + chained_validators = [v.ValidPasswordsMatch('new_password', + 'new_password_confirmation')] + return _PasswordChangeForm + + +def UserForm(edit=False, available_languages=[], old_data={}): + class _UserForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + username = All(v.UnicodeString(strip=True, min=1, not_empty=True), + v.ValidUsername(edit, old_data)) + if edit: + new_password = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=False) + ) + password_confirmation = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=False), + ) + admin = v.StringBoolean(if_missing=False) + else: + password = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=True) + ) + password_confirmation = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=False) + ) + + password_change = v.StringBoolean(if_missing=False) + create_repo_group = v.StringBoolean(if_missing=False) + + active = v.StringBoolean(if_missing=False) + firstname = v.UnicodeString(strip=True, min=1, not_empty=False) + lastname = v.UnicodeString(strip=True, min=1, not_empty=False) + email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data)) + extern_name = v.UnicodeString(strip=True) + extern_type = v.UnicodeString(strip=True) + language = v.OneOf(available_languages, hideList=False, + testValueList=True, if_missing=None) + chained_validators = [v.ValidPasswordsMatch()] + return _UserForm + + +def UserGroupForm(edit=False, old_data={}, available_members=[]): + class _UserGroupForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + users_group_name = All( + v.UnicodeString(strip=True, min=1, not_empty=True), + v.ValidUserGroup(edit, old_data) + ) + user_group_description = v.UnicodeString(strip=True, min=1, + not_empty=False) + + users_group_active = v.StringBoolean(if_missing=False) + + if edit: + users_group_members = v.OneOf( + available_members, hideList=False, testValueList=True, + if_missing=None, not_empty=False + ) + #this is user group owner + user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) + + return _UserGroupForm + + +def RepoGroupForm(edit=False, old_data={}, available_groups=[], + can_create_in_root=False): + class _RepoGroupForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + + group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), + v.SlugifyName(),) + group_description = v.UnicodeString(strip=True, min=1, + not_empty=False) + group_copy_permissions = v.StringBoolean(if_missing=False) + + group_parent_id = v.OneOf(available_groups, hideList=False, + testValueList=True, not_empty=True) + enable_locking = v.StringBoolean(if_missing=False) + chained_validators = [v.ValidRepoGroup(edit, old_data, can_create_in_root)] + + if edit: + #this is repo group owner + user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) + + return _RepoGroupForm + + +def RegisterForm(edit=False, old_data={}): + class _RegisterForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + username = All( + v.ValidUsername(edit, old_data), + v.UnicodeString(strip=True, min=1, not_empty=True) + ) + password = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=True) + ) + password_confirmation = All( + v.ValidPassword(), + v.UnicodeString(strip=False, min=6, not_empty=True) + ) + active = v.StringBoolean(if_missing=False) + firstname = v.UnicodeString(strip=True, min=1, not_empty=False) + lastname = v.UnicodeString(strip=True, min=1, not_empty=False) + email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data)) + + chained_validators = [v.ValidPasswordsMatch()] + + return _RegisterForm + + +def PasswordResetForm(): + class _PasswordResetForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + email = All(v.ValidSystemEmail(), v.Email(not_empty=True)) + return _PasswordResetForm + + +def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None): + old_data = old_data or {} + repo_groups = repo_groups or [] + landing_revs = landing_revs or [] + supported_backends = BACKENDS.keys() + + class _RepoForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), + v.SlugifyName()) + repo_group = All(v.CanWriteGroup(old_data), + v.OneOf(repo_groups, hideList=True)) + repo_type = v.OneOf(supported_backends, required=False, + if_missing=old_data.get('repo_type')) + repo_description = v.UnicodeString(strip=True, min=1, not_empty=False) + repo_private = v.StringBoolean(if_missing=False) + repo_landing_rev = v.OneOf(landing_revs, hideList=True) + repo_copy_permissions = v.StringBoolean(if_missing=False) + clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False)) + + repo_enable_statistics = v.StringBoolean(if_missing=False) + repo_enable_downloads = v.StringBoolean(if_missing=False) + repo_enable_locking = v.StringBoolean(if_missing=False) + + if edit: + # this is repo owner + user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) + clone_uri_change = v.UnicodeString( + not_empty=False, if_missing=v.Missing) + + chained_validators = [v.ValidCloneUri(), + v.ValidRepoName(edit, old_data)] + return _RepoForm + + +def RepoPermsForm(): + class _RepoPermsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + chained_validators = [v.ValidPerms(type_='repo')] + return _RepoPermsForm + + +def RepoGroupPermsForm(valid_recursive_choices): + class _RepoGroupPermsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + recursive = v.OneOf(valid_recursive_choices) + chained_validators = [v.ValidPerms(type_='repo_group')] + return _RepoGroupPermsForm + + +def UserGroupPermsForm(): + class _UserPermsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + chained_validators = [v.ValidPerms(type_='user_group')] + return _UserPermsForm + + +def RepoFieldForm(): + class _RepoFieldForm(formencode.Schema): + filter_extra_fields = True + allow_extra_fields = True + + new_field_key = All(v.FieldKey(), + v.UnicodeString(strip=True, min=3, not_empty=True)) + new_field_value = v.UnicodeString(not_empty=False, if_missing=u'') + new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'], + if_missing='str') + new_field_label = v.UnicodeString(not_empty=False) + new_field_desc = v.UnicodeString(not_empty=False) + + return _RepoFieldForm + + +def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(), + repo_groups=[], landing_revs=[]): + class _RepoForkForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), + v.SlugifyName()) + repo_group = All(v.CanWriteGroup(), + v.OneOf(repo_groups, hideList=True)) + repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends)) + description = v.UnicodeString(strip=True, min=1, not_empty=True) + private = v.StringBoolean(if_missing=False) + copy_permissions = v.StringBoolean(if_missing=False) + fork_parent_id = v.UnicodeString() + chained_validators = [v.ValidForkName(edit, old_data)] + landing_rev = v.OneOf(landing_revs, hideList=True) + + return _RepoForkForm + + +def ApplicationSettingsForm(): + class _ApplicationSettingsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False) + rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True) + rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False) + rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False) + rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False) + rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False) + + return _ApplicationSettingsForm + + +def ApplicationVisualisationForm(): + class _ApplicationVisualisationForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + rhodecode_show_public_icon = v.StringBoolean(if_missing=False) + rhodecode_show_private_icon = v.StringBoolean(if_missing=False) + rhodecode_stylify_metatags = v.StringBoolean(if_missing=False) + + rhodecode_repository_fields = v.StringBoolean(if_missing=False) + rhodecode_lightweight_journal = v.StringBoolean(if_missing=False) + rhodecode_dashboard_items = v.Int(min=5, not_empty=True) + rhodecode_admin_grid_items = v.Int(min=5, not_empty=True) + rhodecode_show_version = v.StringBoolean(if_missing=False) + rhodecode_use_gravatar = v.StringBoolean(if_missing=False) + rhodecode_markup_renderer = v.OneOf(['markdown', 'rst']) + rhodecode_gravatar_url = v.UnicodeString(min=3) + rhodecode_clone_uri_tmpl = v.UnicodeString(min=3) + rhodecode_support_url = v.UnicodeString() + rhodecode_show_revision_number = v.StringBoolean(if_missing=False) + rhodecode_show_sha_length = v.Int(min=4, not_empty=True) + + return _ApplicationVisualisationForm + + +class _BaseVcsSettingsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + hooks_changegroup_repo_size = v.StringBoolean(if_missing=False) + hooks_changegroup_push_logger = v.StringBoolean(if_missing=False) + hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False) + + extensions_largefiles = v.StringBoolean(if_missing=False) + phases_publish = v.StringBoolean(if_missing=False) + + rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False) + rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False) + + +def ApplicationUiSettingsForm(): + class _ApplicationUiSettingsForm(_BaseVcsSettingsForm): + web_push_ssl = v.StringBoolean(if_missing=False) + paths_root_path = All( + v.ValidPath(), + v.UnicodeString(strip=True, min=1, not_empty=True) + ) + extensions_hgsubversion = v.StringBoolean(if_missing=False) + extensions_hggit = v.StringBoolean(if_missing=False) + new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch') + new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag') + + return _ApplicationUiSettingsForm + + +def RepoVcsSettingsForm(repo_name): + class _RepoVcsSettingsForm(_BaseVcsSettingsForm): + inherit_global_settings = v.StringBoolean(if_missing=False) + new_svn_branch = v.ValidSvnPattern( + section='vcs_svn_branch', repo_name=repo_name) + new_svn_tag = v.ValidSvnPattern( + section='vcs_svn_tag', repo_name=repo_name) + + return _RepoVcsSettingsForm + + +def LabsSettingsForm(): + class _LabSettingsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + + rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False) + rhodecode_proxy_subversion_http_requests = v.StringBoolean( + if_missing=False) + rhodecode_subversion_http_server_url = v.UnicodeString( + strip=True, if_missing=None) + + return _LabSettingsForm + + +def ApplicationPermissionsForm(register_choices, extern_activate_choices): + class _DefaultPermissionsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + anonymous = v.StringBoolean(if_missing=False) + default_register = v.OneOf(register_choices) + default_register_message = v.UnicodeString() + default_extern_activate = v.OneOf(extern_activate_choices) + + return _DefaultPermissionsForm + + +def ObjectPermissionsForm(repo_perms_choices, group_perms_choices, + user_group_perms_choices): + class _ObjectPermissionsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + overwrite_default_repo = v.StringBoolean(if_missing=False) + overwrite_default_group = v.StringBoolean(if_missing=False) + overwrite_default_user_group = v.StringBoolean(if_missing=False) + default_repo_perm = v.OneOf(repo_perms_choices) + default_group_perm = v.OneOf(group_perms_choices) + default_user_group_perm = v.OneOf(user_group_perms_choices) + + return _ObjectPermissionsForm + + +def UserPermissionsForm(create_choices, create_on_write_choices, + repo_group_create_choices, user_group_create_choices, + fork_choices, inherit_default_permissions_choices): + class _DefaultPermissionsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + anonymous = v.StringBoolean(if_missing=False) + + default_repo_create = v.OneOf(create_choices) + default_repo_create_on_write = v.OneOf(create_on_write_choices) + default_user_group_create = v.OneOf(user_group_create_choices) + default_repo_group_create = v.OneOf(repo_group_create_choices) + default_fork_create = v.OneOf(fork_choices) + default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices) + + return _DefaultPermissionsForm + + +def UserIndividualPermissionsForm(): + class _DefaultPermissionsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + inherit_default_permissions = v.StringBoolean(if_missing=False) + + return _DefaultPermissionsForm + + +def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()): + class _DefaultsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + default_repo_type = v.OneOf(supported_backends) + default_repo_private = v.StringBoolean(if_missing=False) + default_repo_enable_statistics = v.StringBoolean(if_missing=False) + default_repo_enable_downloads = v.StringBoolean(if_missing=False) + default_repo_enable_locking = v.StringBoolean(if_missing=False) + + return _DefaultsForm + + +def AuthSettingsForm(): + class _AuthSettingsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + auth_plugins = All(v.ValidAuthPlugins(), + v.UniqueListFromString()(not_empty=True)) + + return _AuthSettingsForm + + +def UserExtraEmailForm(): + class _UserExtraEmailForm(formencode.Schema): + email = All(v.UniqSystemEmail(), v.Email(not_empty=True)) + return _UserExtraEmailForm + + +def UserExtraIpForm(): + class _UserExtraIpForm(formencode.Schema): + ip = v.ValidIp()(not_empty=True) + return _UserExtraIpForm + + +def PullRequestForm(repo_id): + class _PullRequestForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + + user = v.UnicodeString(strip=True, required=True) + source_repo = v.UnicodeString(strip=True, required=True) + source_ref = v.UnicodeString(strip=True, required=True) + target_repo = v.UnicodeString(strip=True, required=True) + target_ref = v.UnicodeString(strip=True, required=True) + revisions = All(#v.NotReviewedRevisions(repo_id)(), + v.UniqueList()(not_empty=True)) + review_members = v.UniqueList(convert=int)(not_empty=True) + + pullrequest_title = v.UnicodeString(strip=True, required=True) + pullrequest_desc = v.UnicodeString(strip=True, required=False) + + return _PullRequestForm + + +def GistForm(lifetime_options, acl_level_options): + class _GistForm(formencode.Schema): + + gistid = All(v.UniqGistId(), v.UnicodeString(strip=True, min=3, not_empty=False, if_missing=None)) + filename = All(v.BasePath()(), + v.UnicodeString(strip=True, required=False)) + description = v.UnicodeString(required=False, if_missing=u'') + lifetime = v.OneOf(lifetime_options) + mimetype = v.UnicodeString(required=False, if_missing=None) + content = v.UnicodeString(required=True, not_empty=True) + public = v.UnicodeString(required=False, if_missing=u'') + private = v.UnicodeString(required=False, if_missing=u'') + acl_level = v.OneOf(acl_level_options) + + return _GistForm + + +def IssueTrackerPatternsForm(): + class _IssueTrackerPatternsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + chained_validators = [v.ValidPattern()] + return _IssueTrackerPatternsForm diff --git a/rhodecode/model/gist.py b/rhodecode/model/gist.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/gist.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +gist model for RhodeCode +""" + +import os +import time +import logging +import traceback +import shutil + +from rhodecode.lib.utils2 import ( + safe_unicode, unique_id, safe_int, time_to_datetime, AttributeDict) +from rhodecode.lib.ext_json import json +from rhodecode.model import BaseModel +from rhodecode.model.db import Gist +from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import ScmModel + +log = logging.getLogger(__name__) + +GIST_STORE_LOC = '.rc_gist_store' +GIST_METADATA_FILE = '.rc_gist_metadata' + + +class GistModel(BaseModel): + cls = Gist + + def _get_gist(self, gist): + """ + Helper method to get gist by ID, or gist_access_id as a fallback + + :param gist: GistID, gist_access_id, or Gist instance + """ + return self._get_instance(Gist, gist, callback=Gist.get_by_access_id) + + def __delete_gist(self, gist): + """ + removes gist from filesystem + + :param gist: gist object + """ + root_path = RepoModel().repos_path + rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id) + log.info("Removing %s", rm_path) + shutil.rmtree(rm_path) + + def _store_metadata(self, repo, gist_id, gist_access_id, user_id, username, + gist_type, gist_expires, gist_acl_level): + """ + store metadata inside the gist repo, this can be later used for imports + or gist identification. Currently we use this inside RhodeCode tools + to do cleanup of gists that are in storage but not in database. + """ + metadata = { + 'metadata_version': '2', + 'gist_db_id': gist_id, + 'gist_access_id': gist_access_id, + 'gist_owner_id': user_id, + 'gist_owner_username': username, + 'gist_type': gist_type, + 'gist_expires': gist_expires, + 'gist_updated': time.time(), + 'gist_acl_level': gist_acl_level, + } + metadata_file = os.path.join(repo.path, '.hg', GIST_METADATA_FILE) + with open(metadata_file, 'wb') as f: + f.write(json.dumps(metadata)) + + def get_gist(self, gist): + return self._get_gist(gist) + + def get_gist_files(self, gist_access_id, revision=None): + """ + Get files for given gist + + :param gist_access_id: + """ + repo = Gist.get_by_access_id(gist_access_id) + commit = repo.scm_instance().get_commit(commit_id=revision) + return commit, [n for n in commit.get_node('/')] + + def create(self, description, owner, gist_mapping, + gist_type=Gist.GIST_PUBLIC, lifetime=-1, gist_id=None, + gist_acl_level=Gist.ACL_LEVEL_PRIVATE): + """ + Create a gist + + :param description: description of the gist + :param owner: user who created this gist + :param gist_mapping: mapping {filename:{'content':content},...} + :param gist_type: type of gist private/public + :param lifetime: in minutes, -1 == forever + :param gist_acl_level: acl level for this gist + """ + owner = self._get_user(owner) + gist_id = safe_unicode(gist_id or unique_id(20)) + lifetime = safe_int(lifetime, -1) + gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 + expiration = (time_to_datetime(gist_expires) + if gist_expires != -1 else 'forever') + log.debug('set GIST expiration date to: %s', expiration) + # create the Database version + gist = Gist() + gist.gist_description = description + gist.gist_access_id = gist_id + gist.gist_owner = owner.user_id + gist.gist_expires = gist_expires + gist.gist_type = safe_unicode(gist_type) + gist.acl_level = gist_acl_level + self.sa.add(gist) + self.sa.flush() + if gist_type == Gist.GIST_PUBLIC: + # use DB ID for easy to use GIST ID + gist_id = safe_unicode(gist.gist_id) + gist.gist_access_id = gist_id + self.sa.add(gist) + + gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id) + log.debug('Creating new %s GIST repo in %s', gist_type, gist_repo_path) + repo = RepoModel()._create_filesystem_repo( + repo_name=gist_id, repo_type='hg', repo_group=GIST_STORE_LOC, + use_global_config=True) + + processed_mapping = {} + for filename in gist_mapping: + if filename != os.path.basename(filename): + raise Exception('Filename cannot be inside a directory') + + content = gist_mapping[filename]['content'] + # TODO: expand support for setting explicit lexers +# if lexer is None: +# try: +# guess_lexer = pygments.lexers.guess_lexer_for_filename +# lexer = guess_lexer(filename,content) +# except pygments.util.ClassNotFound: +# lexer = 'text' + processed_mapping[filename] = {'content': content} + + # now create single multifile commit + message = 'added file' + message += 's: ' if len(processed_mapping) > 1 else ': ' + message += ', '.join([x for x in processed_mapping]) + + # fake RhodeCode Repository object + fake_repo = AttributeDict({ + 'repo_name': gist_repo_path, + 'scm_instance': lambda *args, **kwargs: repo, + }) + + ScmModel().create_nodes( + user=owner.user_id, repo=fake_repo, + message=message, + nodes=processed_mapping, + trigger_push_hook=False + ) + + self._store_metadata(repo, gist.gist_id, gist.gist_access_id, + owner.user_id, owner.username, gist.gist_type, + gist.gist_expires, gist_acl_level) + return gist + + def delete(self, gist, fs_remove=True): + gist = self._get_gist(gist) + try: + self.sa.delete(gist) + if fs_remove: + self.__delete_gist(gist) + else: + log.debug('skipping removal from filesystem') + except Exception: + log.error(traceback.format_exc()) + raise + + def update(self, gist, description, owner, gist_mapping, gist_type, + lifetime, gist_acl_level): + gist = self._get_gist(gist) + gist_repo = gist.scm_instance() + + lifetime = safe_int(lifetime, -1) + if lifetime == 0: # preserve old value + gist_expires = gist.gist_expires + else: + gist_expires = ( + time.time() + (lifetime * 60) if lifetime != -1 else -1) + + # calculate operation type based on given data + gist_mapping_op = {} + for k, v in gist_mapping.items(): + # add, mod, del + if not v['org_filename'] and v['filename']: + op = 'add' + elif v['org_filename'] and not v['filename']: + op = 'del' + else: + op = 'mod' + + v['op'] = op + gist_mapping_op[k] = v + + gist.gist_description = description + gist.gist_expires = gist_expires + gist.owner = owner + gist.gist_type = gist_type + gist.acl_level = gist_acl_level + self.sa.add(gist) + self.sa.flush() + + message = 'updated file' + message += 's: ' if len(gist_mapping) > 1 else ': ' + message += ', '.join([x for x in gist_mapping]) + + # fake RhodeCode Repository object + fake_repo = AttributeDict({ + 'repo_name': gist_repo.path, + 'scm_instance': lambda *args, **kwargs: gist_repo, + }) + + self._store_metadata(gist_repo, gist.gist_id, gist.gist_access_id, + owner.user_id, owner.username, gist.gist_type, + gist.gist_expires, gist_acl_level) + + # this can throw NodeNotChangedError, if changes we're trying to commit + # are not actually changes... + ScmModel().update_nodes( + user=owner.user_id, + repo=fake_repo, + message=message, + nodes=gist_mapping_op, + trigger_push_hook=False + ) + + return gist diff --git a/rhodecode/model/login_session.py b/rhodecode/model/login_session.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/login_session.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Login and cookies session model for RhodeCode +""" + +import logging + +from pylons import session, tmpl_context as c +from rhodecode.model import BaseModel + + +log = logging.getLogger(__name__) + + +class LoginSession(BaseModel): + cls = None + + def destroy_user_session(self): + cur_user = c.rhodecode_user + log.info('Deleting session for user: `%s`', cur_user) + session.delete() + diff --git a/rhodecode/model/meta.py b/rhodecode/model/meta.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/meta.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +SQLAlchemy Metadata and Session object +""" + +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import scoped_session, sessionmaker +from beaker import cache + +from rhodecode.lib import caching_query + + +# Beaker CacheManager. A home base for cache configurations. +cache_manager = cache.CacheManager() + +__all__ = ['Base', 'Session'] +# +# SQLAlchemy session manager. Updated by model.init_model() +# +Session = scoped_session( + sessionmaker( + query_cls=caching_query.query_callable(cache_manager), + expire_on_commit=True, + ) + ) + +# The declarative Base +Base = declarative_base() + +#to use cache use this in query +#.options(FromCache("sqlalchemy_cache_type", "cachekey")) diff --git a/rhodecode/model/notification.py b/rhodecode/model/notification.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/notification.py @@ -0,0 +1,366 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Model for notifications +""" + + +import logging +import traceback + +from pylons import tmpl_context as c +from pylons.i18n.translation import _, ungettext +from sqlalchemy.sql.expression import false, true +from mako import exceptions + +import rhodecode +from rhodecode.lib import helpers as h +from rhodecode.lib.utils import PartialRenderer +from rhodecode.model import BaseModel +from rhodecode.model.db import Notification, User, UserNotification +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel + +log = logging.getLogger(__name__) + + +class NotificationModel(BaseModel): + + cls = Notification + + def __get_notification(self, notification): + if isinstance(notification, Notification): + return notification + elif isinstance(notification, (int, long)): + return Notification.get(notification) + else: + if notification: + raise Exception('notification must be int, long or Instance' + ' of Notification got %s' % type(notification)) + + def create( + self, created_by, notification_subject, notification_body, + notification_type=Notification.TYPE_MESSAGE, recipients=None, + mention_recipients=None, with_email=True, email_kwargs=None): + """ + + Creates notification of given type + + :param created_by: int, str or User instance. User who created this + notification + :param notification_subject: subject of notification itself + :param notification_body: body of notification text + :param notification_type: type of notification, based on that we + pick templates + + :param recipients: list of int, str or User objects, when None + is given send to all admins + :param mention_recipients: list of int, str or User objects, + that were mentioned + :param with_email: send email with this notification + :param email_kwargs: dict with arguments to generate email + """ + + from rhodecode.lib.celerylib import tasks, run_task + + if recipients and not getattr(recipients, '__iter__', False): + raise Exception('recipients must be an iterable object') + + created_by_obj = self._get_user(created_by) + # default MAIN body if not given + email_kwargs = email_kwargs or {'body': notification_body} + mention_recipients = mention_recipients or set() + + if not created_by_obj: + raise Exception('unknown user %s' % created_by) + + if recipients is None: + # recipients is None means to all admins + recipients_objs = User.query().filter(User.admin == true()).all() + log.debug('sending notifications %s to admins: %s', + notification_type, recipients_objs) + else: + recipients_objs = [] + for u in recipients: + obj = self._get_user(u) + if obj: + recipients_objs.append(obj) + else: # we didn't find this user, log the error and carry on + log.error('cannot notify unknown user %r', u) + + recipients_objs = set(recipients_objs) + if not recipients_objs: + raise Exception('no valid recipients specified') + + log.debug('sending notifications %s to %s', + notification_type, recipients_objs) + + # add mentioned users into recipients + final_recipients = set(recipients_objs).union(mention_recipients) + notification = Notification.create( + created_by=created_by_obj, subject=notification_subject, + body=notification_body, recipients=final_recipients, + type_=notification_type + ) + + if not with_email: # skip sending email, and just create notification + return notification + + # don't send email to person who created this comment + rec_objs = set(recipients_objs).difference(set([created_by_obj])) + + # now notify all recipients in question + + for recipient in rec_objs.union(mention_recipients): + # inject current recipient + email_kwargs['recipient'] = recipient + email_kwargs['mention'] = recipient in mention_recipients + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + notification_type, **email_kwargs) + + log.debug( + 'Creating notification email task for user:`%s`', recipient) + task = run_task( + tasks.send_email, recipient.email, subject, + email_body_plaintext, email_body) + log.debug('Created email task: %s', task) + + return notification + + def delete(self, user, notification): + # we don't want to remove actual notification just the assignment + try: + notification = self.__get_notification(notification) + user = self._get_user(user) + if notification and user: + obj = UserNotification.query()\ + .filter(UserNotification.user == user)\ + .filter(UserNotification.notification == notification)\ + .one() + Session().delete(obj) + return True + except Exception: + log.error(traceback.format_exc()) + raise + + def get_for_user(self, user, filter_=None): + """ + Get mentions for given user, filter them if filter dict is given + + :param user: + :param filter: + """ + user = self._get_user(user) + + q = UserNotification.query()\ + .filter(UserNotification.user == user)\ + .join(( + Notification, UserNotification.notification_id == + Notification.notification_id)) + + if filter_: + q = q.filter(Notification.type_.in_(filter_)) + + return q.all() + + def mark_read(self, user, notification): + try: + notification = self.__get_notification(notification) + user = self._get_user(user) + if notification and user: + obj = UserNotification.query()\ + .filter(UserNotification.user == user)\ + .filter(UserNotification.notification == notification)\ + .one() + obj.read = True + Session().add(obj) + return True + except Exception: + log.error(traceback.format_exc()) + raise + + def mark_all_read_for_user(self, user, filter_=None): + user = self._get_user(user) + q = UserNotification.query()\ + .filter(UserNotification.user == user)\ + .filter(UserNotification.read == false())\ + .join(( + Notification, UserNotification.notification_id == + Notification.notification_id)) + if filter_: + q = q.filter(Notification.type_.in_(filter_)) + + # this is a little inefficient but sqlalchemy doesn't support + # update on joined tables :( + for obj in q.all(): + obj.read = True + Session().add(obj) + + def get_unread_cnt_for_user(self, user): + user = self._get_user(user) + return UserNotification.query()\ + .filter(UserNotification.read == false())\ + .filter(UserNotification.user == user).count() + + def get_unread_for_user(self, user): + user = self._get_user(user) + return [x.notification for x in UserNotification.query() + .filter(UserNotification.read == false()) + .filter(UserNotification.user == user).all()] + + def get_user_notification(self, user, notification): + user = self._get_user(user) + notification = self.__get_notification(notification) + + return UserNotification.query()\ + .filter(UserNotification.notification == notification)\ + .filter(UserNotification.user == user).scalar() + + def make_description(self, notification, show_age=True): + """ + Creates a human readable description based on properties + of notification object + """ + + _map = { + notification.TYPE_CHANGESET_COMMENT: [ + _('%(user)s commented on commit %(date_or_age)s'), + _('%(user)s commented on commit at %(date_or_age)s'), + ], + notification.TYPE_MESSAGE: [ + _('%(user)s sent message %(date_or_age)s'), + _('%(user)s sent message at %(date_or_age)s'), + ], + notification.TYPE_MENTION: [ + _('%(user)s mentioned you %(date_or_age)s'), + _('%(user)s mentioned you at %(date_or_age)s'), + ], + notification.TYPE_REGISTRATION: [ + _('%(user)s registered in RhodeCode %(date_or_age)s'), + _('%(user)s registered in RhodeCode at %(date_or_age)s'), + ], + notification.TYPE_PULL_REQUEST: [ + _('%(user)s opened new pull request %(date_or_age)s'), + _('%(user)s opened new pull request at %(date_or_age)s'), + ], + notification.TYPE_PULL_REQUEST_COMMENT: [ + _('%(user)s commented on pull request %(date_or_age)s'), + _('%(user)s commented on pull request at %(date_or_age)s'), + ], + } + + templates = _map[notification.type_] + + if show_age: + template = templates[0] + date_or_age = h.age(notification.created_on) + else: + template = templates[1] + date_or_age = h.format_date(notification.created_on) + + return template % { + 'user': notification.created_by_user.username, + 'date_or_age': date_or_age, + } + + +class EmailNotificationModel(BaseModel): + TYPE_COMMIT_COMMENT = Notification.TYPE_CHANGESET_COMMENT + TYPE_REGISTRATION = Notification.TYPE_REGISTRATION + TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST + TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT + TYPE_MAIN = Notification.TYPE_MESSAGE + + TYPE_PASSWORD_RESET = 'password_reset' + TYPE_PASSWORD_RESET_CONFIRMATION = 'password_reset_confirmation' + TYPE_EMAIL_TEST = 'email_test' + TYPE_TEST = 'test' + + email_types = { + TYPE_MAIN: 'email_templates/main.mako', + TYPE_TEST: 'email_templates/test.mako', + TYPE_EMAIL_TEST: 'email_templates/email_test.mako', + TYPE_REGISTRATION: 'email_templates/user_registration.mako', + TYPE_PASSWORD_RESET: 'email_templates/password_reset.mako', + TYPE_PASSWORD_RESET_CONFIRMATION: 'email_templates/password_reset_confirmation.mako', + TYPE_COMMIT_COMMENT: 'email_templates/commit_comment.mako', + TYPE_PULL_REQUEST: 'email_templates/pull_request_review.mako', + TYPE_PULL_REQUEST_COMMENT: 'email_templates/pull_request_comment.mako', + } + + def __init__(self): + """ + Example usage:: + + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + EmailNotificationModel.TYPE_TEST, **email_kwargs) + + """ + super(EmailNotificationModel, self).__init__() + + def _update_kwargs_for_render(self, kwargs): + """ + Inject params required for Mako rendering + + :param kwargs: + :return: + """ + _kwargs = { + 'instance_url': h.url('home', qualified=True) + } + _kwargs.update(kwargs) + return _kwargs + + def get_renderer(self, type_): + template_name = self.email_types[type_] + return PartialRenderer(template_name) + + def render_email(self, type_, **kwargs): + """ + renders template for email, and returns a tuple of + (subject, email_headers, email_body) + """ + # translator and helpers inject + _kwargs = self._update_kwargs_for_render(kwargs) + + email_template = self.get_renderer(type_) + + subject = email_template.render('subject', **_kwargs) + + try: + headers = email_template.render('headers', **_kwargs) + except AttributeError: + # it's not defined in template, ok we can skip it + headers = '' + + try: + body_plaintext = email_template.render('body_plaintext', **_kwargs) + except AttributeError: + # it's not defined in template, ok we can skip it + body_plaintext = '' + + # render WHOLE template + body = email_template.render(None, **_kwargs) + + return subject, headers, body, body_plaintext diff --git a/rhodecode/model/permission.py b/rhodecode/model/permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/permission.py @@ -0,0 +1,470 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +permissions model for RhodeCode +""" + + +import logging +import traceback + +from sqlalchemy.exc import DatabaseError + +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm, + UserUserGroupToPerm, UserGroup, UserGroupToPerm) +from rhodecode.lib.utils2 import str2bool, safe_int + +log = logging.getLogger(__name__) + + +class PermissionModel(BaseModel): + """ + Permissions model for RhodeCode + """ + + cls = Permission + global_perms = { + 'default_repo_create': None, + # special case for create repos on write access to group + 'default_repo_create_on_write': None, + 'default_repo_group_create': None, + 'default_user_group_create': None, + 'default_fork_create': None, + 'default_inherit_default_permissions': None, + + 'default_register': None, + 'default_extern_activate': None, + + # object permissions below + 'default_repo_perm': None, + 'default_group_perm': None, + 'default_user_group_perm': None, + } + + def set_global_permission_choices(self, c_obj, translator): + c_obj.repo_perms_choices = [ + ('repository.none', translator('None'),), + ('repository.read', translator('Read'),), + ('repository.write', translator('Write'),), + ('repository.admin', translator('Admin'),)] + + c_obj.group_perms_choices = [ + ('group.none', translator('None'),), + ('group.read', translator('Read'),), + ('group.write', translator('Write'),), + ('group.admin', translator('Admin'),)] + + c_obj.user_group_perms_choices = [ + ('usergroup.none', translator('None'),), + ('usergroup.read', translator('Read'),), + ('usergroup.write', translator('Write'),), + ('usergroup.admin', translator('Admin'),)] + + c_obj.register_choices = [ + ('hg.register.none', translator('Disabled')), + ('hg.register.manual_activate', translator('Allowed with manual account activation')), + ('hg.register.auto_activate', translator('Allowed with automatic account activation')),] + + c_obj.extern_activate_choices = [ + ('hg.extern_activate.manual', translator('Manual activation of external account')), + ('hg.extern_activate.auto', translator('Automatic activation of external account')),] + + c_obj.repo_create_choices = [ + ('hg.create.none', translator('Disabled')), + ('hg.create.repository', translator('Enabled'))] + + c_obj.repo_create_on_write_choices = [ + ('hg.create.write_on_repogroup.false', translator('Disabled')), + ('hg.create.write_on_repogroup.true', translator('Enabled'))] + + c_obj.user_group_create_choices = [ + ('hg.usergroup.create.false', translator('Disabled')), + ('hg.usergroup.create.true', translator('Enabled'))] + + c_obj.repo_group_create_choices = [ + ('hg.repogroup.create.false', translator('Disabled')), + ('hg.repogroup.create.true', translator('Enabled'))] + + c_obj.fork_choices = [ + ('hg.fork.none', translator('Disabled')), + ('hg.fork.repository', translator('Enabled'))] + + c_obj.inherit_default_permission_choices = [ + ('hg.inherit_default_perms.false', translator('Disabled')), + ('hg.inherit_default_perms.true', translator('Enabled'))] + + def get_default_perms(self, object_perms, suffix): + defaults = {} + for perm in object_perms: + # perms + if perm.permission.permission_name.startswith('repository.'): + defaults['default_repo_perm' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('group.'): + defaults['default_group_perm' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('usergroup.'): + defaults['default_user_group_perm' + suffix] = perm.permission.permission_name + + # creation of objects + if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'): + defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name + + elif perm.permission.permission_name.startswith('hg.create.'): + defaults['default_repo_create' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('hg.fork.'): + defaults['default_fork_create' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('hg.inherit_default_perms.'): + defaults['default_inherit_default_permissions' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('hg.repogroup.'): + defaults['default_repo_group_create' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('hg.usergroup.'): + defaults['default_user_group_create' + suffix] = perm.permission.permission_name + + # registration and external account activation + if perm.permission.permission_name.startswith('hg.register.'): + defaults['default_register' + suffix] = perm.permission.permission_name + + if perm.permission.permission_name.startswith('hg.extern_activate.'): + defaults['default_extern_activate' + suffix] = perm.permission.permission_name + + return defaults + + def _make_new_user_perm(self, user, perm_name): + log.debug('Creating new user permission:%s', perm_name) + new = UserToPerm() + new.user = user + new.permission = Permission.get_by_key(perm_name) + return new + + def _make_new_user_group_perm(self, user_group, perm_name): + log.debug('Creating new user group permission:%s', perm_name) + new = UserGroupToPerm() + new.users_group = user_group + new.permission = Permission.get_by_key(perm_name) + return new + + def _keep_perm(self, perm_name, keep_fields): + def get_pat(field_name): + return { + # global perms + 'default_repo_create': 'hg.create.', + # special case for create repos on write access to group + 'default_repo_create_on_write': 'hg.create.write_on_repogroup.', + 'default_repo_group_create': 'hg.repogroup.create.', + 'default_user_group_create': 'hg.usergroup.create.', + 'default_fork_create': 'hg.fork.', + 'default_inherit_default_permissions': 'hg.inherit_default_perms.', + + # application perms + 'default_register': 'hg.register.', + 'default_extern_activate': 'hg.extern_activate.', + + # object permissions below + 'default_repo_perm': 'repository.', + 'default_group_perm': 'group.', + 'default_user_group_perm': 'usergroup.', + }[field_name] + for field in keep_fields: + pat = get_pat(field) + if perm_name.startswith(pat): + return True + return False + + def _clear_object_perm(self, object_perms, preserve=None): + preserve = preserve or [] + _deleted = [] + for perm in object_perms: + perm_name = perm.permission.permission_name + if not self._keep_perm(perm_name, keep_fields=preserve): + _deleted.append(perm_name) + self.sa.delete(perm) + return _deleted + + def _clear_user_perms(self, user_id, preserve=None): + perms = self.sa.query(UserToPerm)\ + .filter(UserToPerm.user_id == user_id)\ + .all() + return self._clear_object_perm(perms, preserve=preserve) + + def _clear_user_group_perms(self, user_group_id, preserve=None): + perms = self.sa.query(UserGroupToPerm)\ + .filter(UserGroupToPerm.users_group_id == user_group_id)\ + .all() + return self._clear_object_perm(perms, preserve=preserve) + + def _set_new_object_perms(self, obj_type, object, form_result, preserve=None): + # clear current entries, to make this function idempotent + # it will fix even if we define more permissions or permissions + # are somehow missing + preserve = preserve or [] + _global_perms = self.global_perms.copy() + if obj_type not in ['user', 'user_group']: + raise ValueError("obj_type must be on of 'user' or 'user_group'") + if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS): + raise Exception('Inconsistent permissions definition') + + if obj_type == 'user': + self._clear_user_perms(object.user_id, preserve) + if obj_type == 'user_group': + self._clear_user_group_perms(object.users_group_id, preserve) + + # now kill the keys that we want to preserve from the form. + for key in preserve: + del _global_perms[key] + + for k in _global_perms.copy(): + _global_perms[k] = form_result[k] + + # at that stage we validate all are passed inside form_result + for _perm_key, perm_value in _global_perms.items(): + if perm_value is None: + raise ValueError('Missing permission for %s' % (_perm_key,)) + + if obj_type == 'user': + p = self._make_new_user_perm(object, perm_value) + self.sa.add(p) + if obj_type == 'user_group': + p = self._make_new_user_group_perm(object, perm_value) + self.sa.add(p) + + def _set_new_user_perms(self, user, form_result, preserve=None): + return self._set_new_object_perms( + 'user', user, form_result, preserve) + + def _set_new_user_group_perms(self, user_group, form_result, preserve=None): + return self._set_new_object_perms( + 'user_group', user_group, form_result, preserve) + + def set_new_user_perms(self, user, form_result): + # calculate what to preserve from what is given in form_result + preserve = set(self.global_perms.keys()).difference(set(form_result.keys())) + return self._set_new_user_perms(user, form_result, preserve) + + def set_new_user_group_perms(self, user_group, form_result): + # calculate what to preserve from what is given in form_result + preserve = set(self.global_perms.keys()).difference(set(form_result.keys())) + return self._set_new_user_group_perms(user_group, form_result, preserve) + + def create_permissions(self): + """ + Create permissions for whole system + """ + for p in Permission.PERMS: + if not Permission.get_by_key(p[0]): + new_perm = Permission() + new_perm.permission_name = p[0] + new_perm.permission_longname = p[0] # translation err with p[1] + self.sa.add(new_perm) + + def _create_default_object_permission(self, obj_type, obj, obj_perms, + force=False): + if obj_type not in ['user', 'user_group']: + raise ValueError("obj_type must be on of 'user' or 'user_group'") + + def _get_group(perm_name): + return '.'.join(perm_name.split('.')[:1]) + + defined_perms_groups = map( + _get_group, (x.permission.permission_name for x in obj_perms)) + log.debug('GOT ALREADY DEFINED:%s', obj_perms) + + if force: + self._clear_object_perm(obj_perms) + self.sa.commit() + defined_perms_groups = [] + # for every default permission that needs to be created, we check if + # it's group is already defined, if it's not we create default perm + for perm_name in Permission.DEFAULT_USER_PERMISSIONS: + gr = _get_group(perm_name) + if gr not in defined_perms_groups: + log.debug('GR:%s not found, creating permission %s', + gr, perm_name) + if obj_type == 'user': + new_perm = self._make_new_user_perm(obj, perm_name) + self.sa.add(new_perm) + if obj_type == 'user_group': + new_perm = self._make_new_user_group_perm(obj, perm_name) + self.sa.add(new_perm) + + def create_default_user_permissions(self, user, force=False): + """ + Creates only missing default permissions for user, if force is set it + resets the default permissions for that user + + :param user: + :param force: + """ + user = self._get_user(user) + obj_perms = UserToPerm.query().filter(UserToPerm.user == user).all() + return self._create_default_object_permission( + 'user', user, obj_perms, force) + + def create_default_user_group_permissions(self, user_group, force=False): + """ + Creates only missing default permissions for user group, if force is set it + resets the default permissions for that user group + + :param user_group: + :param force: + """ + user_group = self._get_user_group(user_group) + obj_perms = UserToPerm.query().filter(UserGroupToPerm.users_group == user_group).all() + return self._create_default_object_permission( + 'user_group', user_group, obj_perms, force) + + def update_application_permissions(self, form_result): + if 'perm_user_id' in form_result: + perm_user = User.get(safe_int(form_result['perm_user_id'])) + else: + # used mostly to do lookup for default user + perm_user = User.get_by_username(form_result['perm_user_name']) + + try: + # stage 1 set anonymous access + if perm_user.username == User.DEFAULT_USER: + perm_user.active = str2bool(form_result['anonymous']) + self.sa.add(perm_user) + + # stage 2 reset defaults and set them from form data + self._set_new_user_perms(perm_user, form_result, preserve=[ + 'default_repo_perm', + 'default_group_perm', + 'default_user_group_perm', + + 'default_repo_group_create', + 'default_user_group_create', + 'default_repo_create_on_write', + 'default_repo_create', + 'default_fork_create', + 'default_inherit_default_permissions',]) + + self.sa.commit() + except (DatabaseError,): + log.error(traceback.format_exc()) + self.sa.rollback() + raise + + def update_user_permissions(self, form_result): + if 'perm_user_id' in form_result: + perm_user = User.get(safe_int(form_result['perm_user_id'])) + else: + # used mostly to do lookup for default user + perm_user = User.get_by_username(form_result['perm_user_name']) + try: + # stage 2 reset defaults and set them from form data + self._set_new_user_perms(perm_user, form_result, preserve=[ + 'default_repo_perm', + 'default_group_perm', + 'default_user_group_perm', + + 'default_register', + 'default_extern_activate']) + self.sa.commit() + except (DatabaseError,): + log.error(traceback.format_exc()) + self.sa.rollback() + raise + + def update_user_group_permissions(self, form_result): + if 'perm_user_group_id' in form_result: + perm_user_group = UserGroup.get(safe_int(form_result['perm_user_group_id'])) + else: + # used mostly to do lookup for default user + perm_user_group = UserGroup.get_by_group_name(form_result['perm_user_group_name']) + try: + # stage 2 reset defaults and set them from form data + self._set_new_user_group_perms(perm_user_group, form_result, preserve=[ + 'default_repo_perm', + 'default_group_perm', + 'default_user_group_perm', + + 'default_register', + 'default_extern_activate']) + self.sa.commit() + except (DatabaseError,): + log.error(traceback.format_exc()) + self.sa.rollback() + raise + + def update_object_permissions(self, form_result): + if 'perm_user_id' in form_result: + perm_user = User.get(safe_int(form_result['perm_user_id'])) + else: + # used mostly to do lookup for default user + perm_user = User.get_by_username(form_result['perm_user_name']) + try: + + # stage 2 reset defaults and set them from form data + self._set_new_user_perms(perm_user, form_result, preserve=[ + 'default_repo_group_create', + 'default_user_group_create', + 'default_repo_create_on_write', + 'default_repo_create', + 'default_fork_create', + 'default_inherit_default_permissions', + + 'default_register', + 'default_extern_activate']) + + # overwrite default repo permissions + if form_result['overwrite_default_repo']: + _def_name = form_result['default_repo_perm'].split('repository.')[-1] + _def = Permission.get_by_key('repository.' + _def_name) + for r2p in self.sa.query(UserRepoToPerm)\ + .filter(UserRepoToPerm.user == perm_user)\ + .all(): + # don't reset PRIVATE repositories + if not r2p.repository.private: + r2p.permission = _def + self.sa.add(r2p) + + # overwrite default repo group permissions + if form_result['overwrite_default_group']: + _def_name = form_result['default_group_perm'].split('group.')[-1] + _def = Permission.get_by_key('group.' + _def_name) + for g2p in self.sa.query(UserRepoGroupToPerm)\ + .filter(UserRepoGroupToPerm.user == perm_user)\ + .all(): + g2p.permission = _def + self.sa.add(g2p) + + # overwrite default user group permissions + if form_result['overwrite_default_user_group']: + _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1] + # user groups + _def = Permission.get_by_key('usergroup.' + _def_name) + for g2p in self.sa.query(UserUserGroupToPerm)\ + .filter(UserUserGroupToPerm.user == perm_user)\ + .all(): + g2p.permission = _def + self.sa.add(g2p) + self.sa.commit() + except (DatabaseError,): + log.exception('Failed to set default object permissions') + self.sa.rollback() + raise diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/pull_request.py @@ -0,0 +1,1128 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +pull request model for RhodeCode +""" + +from collections import namedtuple +import json +import logging +import datetime + +from pylons.i18n.translation import _ +from pylons.i18n.translation import lazy_ugettext + +import rhodecode +from rhodecode.lib import helpers as h, hooks_utils, diffs +from rhodecode.lib.compat import OrderedDict +from rhodecode.lib.hooks_daemon import prepare_callback_daemon +from rhodecode.lib.markup_renderer import ( + DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) +from rhodecode.lib.utils import action_logger +from rhodecode.lib.utils2 import safe_unicode, safe_str, md5_safe +from rhodecode.lib.vcs.backends.base import ( + Reference, MergeResponse, MergeFailureReason) +from rhodecode.lib.vcs.exceptions import ( + CommitDoesNotExistError, EmptyRepositoryError) +from rhodecode.model import BaseModel +from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.model.comment import ChangesetCommentsModel +from rhodecode.model.db import ( + PullRequest, PullRequestReviewers, Notification, ChangesetStatus, + PullRequestVersion, ChangesetComment) +from rhodecode.model.meta import Session +from rhodecode.model.notification import NotificationModel, \ + EmailNotificationModel +from rhodecode.model.scm import ScmModel +from rhodecode.model.settings import VcsSettingsModel + + +log = logging.getLogger(__name__) + + +class PullRequestModel(BaseModel): + + cls = PullRequest + + DIFF_CONTEXT = 3 + + MERGE_STATUS_MESSAGES = { + MergeFailureReason.NONE: lazy_ugettext( + 'This pull request can be automatically merged.'), + MergeFailureReason.UNKNOWN: lazy_ugettext( + 'This pull request cannot be merged because of an unhandled' + ' exception.'), + MergeFailureReason.MERGE_FAILED: lazy_ugettext( + 'This pull request cannot be merged because of conflicts.'), + MergeFailureReason.PUSH_FAILED: lazy_ugettext( + 'This pull request could not be merged because push to target' + ' failed.'), + MergeFailureReason.TARGET_IS_NOT_HEAD: lazy_ugettext( + 'This pull request cannot be merged because the target is not a' + ' head.'), + MergeFailureReason.HG_SOURCE_HAS_MORE_BRANCHES: lazy_ugettext( + 'This pull request cannot be merged because the source contains' + ' more branches than the target.'), + MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS: lazy_ugettext( + 'This pull request cannot be merged because the target has' + ' multiple heads.'), + MergeFailureReason.TARGET_IS_LOCKED: lazy_ugettext( + 'This pull request cannot be merged because the target repository' + ' is locked.'), + MergeFailureReason.MISSING_COMMIT: lazy_ugettext( + 'This pull request cannot be merged because the target or the ' + 'source reference is missing.'), + } + + def __get_pull_request(self, pull_request): + return self._get_instance(PullRequest, pull_request) + + def _check_perms(self, perms, pull_request, user, api=False): + if not api: + return h.HasRepoPermissionAny(*perms)( + user=user, repo_name=pull_request.target_repo.repo_name) + else: + return h.HasRepoPermissionAnyApi(*perms)( + user=user, repo_name=pull_request.target_repo.repo_name) + + def check_user_read(self, pull_request, user, api=False): + _perms = ('repository.admin', 'repository.write', 'repository.read',) + return self._check_perms(_perms, pull_request, user, api) + + def check_user_merge(self, pull_request, user, api=False): + _perms = ('repository.admin', 'repository.write', 'hg.admin',) + return self._check_perms(_perms, pull_request, user, api) + + def check_user_update(self, pull_request, user, api=False): + owner = user.user_id == pull_request.user_id + return self.check_user_merge(pull_request, user, api) or owner + + def check_user_change_status(self, pull_request, user, api=False): + reviewer = user.user_id in [x.user_id for x in + pull_request.reviewers] + return self.check_user_update(pull_request, user, api) or reviewer + + def get(self, pull_request): + return self.__get_pull_request(pull_request) + + def _prepare_get_all_query(self, repo_name, source=False, statuses=None, + opened_by=None, order_by=None, + order_dir='desc'): + repo = self._get_repo(repo_name) + q = PullRequest.query() + # source or target + if source: + q = q.filter(PullRequest.source_repo == repo) + else: + q = q.filter(PullRequest.target_repo == repo) + + # closed,opened + if statuses: + q = q.filter(PullRequest.status.in_(statuses)) + + # opened by filter + if opened_by: + q = q.filter(PullRequest.user_id.in_(opened_by)) + + if order_by: + order_map = { + 'name_raw': PullRequest.pull_request_id, + 'title': PullRequest.title, + 'updated_on_raw': PullRequest.updated_on + } + if order_dir == 'asc': + q = q.order_by(order_map[order_by].asc()) + else: + q = q.order_by(order_map[order_by].desc()) + + return q + + def count_all(self, repo_name, source=False, statuses=None, + opened_by=None): + """ + Count the number of pull requests for a specific repository. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :returns: int number of pull requests + """ + q = self._prepare_get_all_query( + repo_name, source=source, statuses=statuses, opened_by=opened_by) + + return q.count() + + def get_all(self, repo_name, source=False, statuses=None, opened_by=None, + offset=0, length=None, order_by=None, order_dir='desc'): + """ + Get all pull requests for a specific repository. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :param offset: pagination offset + :param length: length of returned list + :param order_by: order of the returned list + :param order_dir: 'asc' or 'desc' ordering direction + :returns: list of pull requests + """ + q = self._prepare_get_all_query( + repo_name, source=source, statuses=statuses, opened_by=opened_by, + order_by=order_by, order_dir=order_dir) + + if length: + pull_requests = q.limit(length).offset(offset).all() + else: + pull_requests = q.all() + + return pull_requests + + def count_awaiting_review(self, repo_name, source=False, statuses=None, + opened_by=None): + """ + Count the number of pull requests for a specific repository that are + awaiting review. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :returns: int number of pull requests + """ + pull_requests = self.get_awaiting_review( + repo_name, source=source, statuses=statuses, opened_by=opened_by) + + return len(pull_requests) + + def get_awaiting_review(self, repo_name, source=False, statuses=None, + opened_by=None, offset=0, length=None, + order_by=None, order_dir='desc'): + """ + Get all pull requests for a specific repository that are awaiting + review. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :param offset: pagination offset + :param length: length of returned list + :param order_by: order of the returned list + :param order_dir: 'asc' or 'desc' ordering direction + :returns: list of pull requests + """ + pull_requests = self.get_all( + repo_name, source=source, statuses=statuses, opened_by=opened_by, + order_by=order_by, order_dir=order_dir) + + _filtered_pull_requests = [] + for pr in pull_requests: + status = pr.calculated_review_status() + if status in [ChangesetStatus.STATUS_NOT_REVIEWED, + ChangesetStatus.STATUS_UNDER_REVIEW]: + _filtered_pull_requests.append(pr) + if length: + return _filtered_pull_requests[offset:offset+length] + else: + return _filtered_pull_requests + + def count_awaiting_my_review(self, repo_name, source=False, statuses=None, + opened_by=None, user_id=None): + """ + Count the number of pull requests for a specific repository that are + awaiting review from a specific user. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :param user_id: reviewer user of the pull request + :returns: int number of pull requests + """ + pull_requests = self.get_awaiting_my_review( + repo_name, source=source, statuses=statuses, opened_by=opened_by, + user_id=user_id) + + return len(pull_requests) + + def get_awaiting_my_review(self, repo_name, source=False, statuses=None, + opened_by=None, user_id=None, offset=0, + length=None, order_by=None, order_dir='desc'): + """ + Get all pull requests for a specific repository that are awaiting + review from a specific user. + + :param repo_name: target or source repo + :param source: boolean flag to specify if repo_name refers to source + :param statuses: list of pull request statuses + :param opened_by: author user of the pull request + :param user_id: reviewer user of the pull request + :param offset: pagination offset + :param length: length of returned list + :param order_by: order of the returned list + :param order_dir: 'asc' or 'desc' ordering direction + :returns: list of pull requests + """ + pull_requests = self.get_all( + repo_name, source=source, statuses=statuses, opened_by=opened_by, + order_by=order_by, order_dir=order_dir) + + _my = PullRequestModel().get_not_reviewed(user_id) + my_participation = [] + for pr in pull_requests: + if pr in _my: + my_participation.append(pr) + _filtered_pull_requests = my_participation + if length: + return _filtered_pull_requests[offset:offset+length] + else: + return _filtered_pull_requests + + def get_not_reviewed(self, user_id): + return [ + x.pull_request for x in PullRequestReviewers.query().filter( + PullRequestReviewers.user_id == user_id).all() + ] + + def get_versions(self, pull_request): + """ + returns version of pull request sorted by ID descending + """ + return PullRequestVersion.query()\ + .filter(PullRequestVersion.pull_request == pull_request)\ + .order_by(PullRequestVersion.pull_request_version_id.asc())\ + .all() + + def create(self, created_by, source_repo, source_ref, target_repo, + target_ref, revisions, reviewers, title, description=None): + created_by_user = self._get_user(created_by) + source_repo = self._get_repo(source_repo) + target_repo = self._get_repo(target_repo) + + pull_request = PullRequest() + pull_request.source_repo = source_repo + pull_request.source_ref = source_ref + pull_request.target_repo = target_repo + pull_request.target_ref = target_ref + pull_request.revisions = revisions + pull_request.title = title + pull_request.description = description + pull_request.author = created_by_user + + Session().add(pull_request) + Session().flush() + + # members / reviewers + for user_id in set(reviewers): + user = self._get_user(user_id) + reviewer = PullRequestReviewers(user, pull_request) + Session().add(reviewer) + + # Set approval status to "Under Review" for all commits which are + # part of this pull request. + ChangesetStatusModel().set_status( + repo=target_repo, + status=ChangesetStatus.STATUS_UNDER_REVIEW, + user=created_by_user, + pull_request=pull_request + ) + + self.notify_reviewers(pull_request, reviewers) + self._trigger_pull_request_hook( + pull_request, created_by_user, 'create') + + return pull_request + + def _trigger_pull_request_hook(self, pull_request, user, action): + pull_request = self.__get_pull_request(pull_request) + target_scm = pull_request.target_repo.scm_instance() + if action == 'create': + trigger_hook = hooks_utils.trigger_log_create_pull_request_hook + elif action == 'merge': + trigger_hook = hooks_utils.trigger_log_merge_pull_request_hook + elif action == 'close': + trigger_hook = hooks_utils.trigger_log_close_pull_request_hook + elif action == 'review_status_change': + trigger_hook = hooks_utils.trigger_log_review_pull_request_hook + elif action == 'update': + trigger_hook = hooks_utils.trigger_log_update_pull_request_hook + else: + return + + trigger_hook( + username=user.username, + repo_name=pull_request.target_repo.repo_name, + repo_alias=target_scm.alias, + pull_request=pull_request) + + def _get_commit_ids(self, pull_request): + """ + Return the commit ids of the merged pull request. + + This method is not dealing correctly yet with the lack of autoupdates + nor with the implicit target updates. + For example: if a commit in the source repo is already in the target it + will be reported anyways. + """ + merge_rev = pull_request.merge_rev + if merge_rev is None: + raise ValueError('This pull request was not merged yet') + + commit_ids = list(pull_request.revisions) + if merge_rev not in commit_ids: + commit_ids.append(merge_rev) + + return commit_ids + + def merge(self, pull_request, user, extras): + merge_state = self._merge_pull_request(pull_request, user, extras) + if merge_state.executed: + self._comment_and_close_pr(pull_request, user, merge_state) + self._log_action('user_merged_pull_request', user, pull_request) + return merge_state + + def _merge_pull_request(self, pull_request, user, extras): + target_vcs = pull_request.target_repo.scm_instance() + source_vcs = pull_request.source_repo.scm_instance() + target_ref = self._refresh_reference( + pull_request.target_ref_parts, target_vcs) + + message = _( + 'Merge pull request #%(pr_id)s from ' + '%(source_repo)s %(source_ref_name)s\n\n %(pr_title)s') % { + 'pr_id': pull_request.pull_request_id, + 'source_repo': source_vcs.name, + 'source_ref_name': pull_request.source_ref_parts.name, + 'pr_title': pull_request.title + } + + workspace_id = self._workspace_id(pull_request) + protocol = rhodecode.CONFIG.get('vcs.hooks.protocol') + use_direct_calls = rhodecode.CONFIG.get('vcs.hooks.direct_calls') + + callback_daemon, extras = prepare_callback_daemon( + extras, protocol=protocol, use_direct_calls=use_direct_calls) + + with callback_daemon: + # TODO: johbo: Implement a clean way to run a config_override + # for a single call. + target_vcs.config.set( + 'rhodecode', 'RC_SCM_DATA', json.dumps(extras)) + merge_state = target_vcs.merge( + target_ref, source_vcs, pull_request.source_ref_parts, + workspace_id, user_name=user.username, + user_email=user.email, message=message) + return merge_state + + def _comment_and_close_pr(self, pull_request, user, merge_state): + pull_request.merge_rev = merge_state.merge_commit_id + pull_request.updated_on = datetime.datetime.now() + + ChangesetCommentsModel().create( + text=unicode(_('Pull request merged and closed')), + repo=pull_request.target_repo.repo_id, + user=user.user_id, + pull_request=pull_request.pull_request_id, + f_path=None, + line_no=None, + closing_pr=True + ) + + Session().add(pull_request) + Session().flush() + # TODO: paris: replace invalidation with less radical solution + ScmModel().mark_for_invalidation( + pull_request.target_repo.repo_name) + self._trigger_pull_request_hook(pull_request, user, 'merge') + + def has_valid_update_type(self, pull_request): + source_ref_type = pull_request.source_ref_parts.type + return source_ref_type in ['book', 'branch', 'tag'] + + def update_commits(self, pull_request): + """ + Get the updated list of commits for the pull request + and return the new pull request version and the list + of commits processed by this update action + """ + + pull_request = self.__get_pull_request(pull_request) + source_ref_type = pull_request.source_ref_parts.type + source_ref_name = pull_request.source_ref_parts.name + source_ref_id = pull_request.source_ref_parts.commit_id + + if not self.has_valid_update_type(pull_request): + log.debug( + "Skipping update of pull request %s due to ref type: %s", + pull_request, source_ref_type) + return (None, None) + + source_repo = pull_request.source_repo.scm_instance() + source_commit = source_repo.get_commit(commit_id=source_ref_name) + if source_ref_id == source_commit.raw_id: + log.debug("Nothing changed in pull request %s", pull_request) + return (None, None) + + # Finally there is a need for an update + pull_request_version = self._create_version_from_snapshot(pull_request) + self._link_comments_to_version(pull_request_version) + + target_ref_type = pull_request.target_ref_parts.type + target_ref_name = pull_request.target_ref_parts.name + target_ref_id = pull_request.target_ref_parts.commit_id + target_repo = pull_request.target_repo.scm_instance() + + if target_ref_type in ('tag', 'branch', 'book'): + target_commit = target_repo.get_commit(target_ref_name) + else: + target_commit = target_repo.get_commit(target_ref_id) + + # re-compute commit ids + old_commit_ids = set(pull_request.revisions) + pre_load = ["author", "branch", "date", "message"] + commit_ranges = target_repo.compare( + target_commit.raw_id, source_commit.raw_id, source_repo, merge=True, + pre_load=pre_load) + + ancestor = target_repo.get_common_ancestor( + target_commit.raw_id, source_commit.raw_id, source_repo) + + pull_request.source_ref = '%s:%s:%s' % ( + source_ref_type, source_ref_name, source_commit.raw_id) + pull_request.target_ref = '%s:%s:%s' % ( + target_ref_type, target_ref_name, ancestor) + pull_request.revisions = [ + commit.raw_id for commit in reversed(commit_ranges)] + pull_request.updated_on = datetime.datetime.now() + Session().add(pull_request) + new_commit_ids = set(pull_request.revisions) + + changes = self._calculate_commit_id_changes( + old_commit_ids, new_commit_ids) + + old_diff_data, new_diff_data = self._generate_update_diffs( + pull_request, pull_request_version) + + ChangesetCommentsModel().outdate_comments( + pull_request, old_diff_data=old_diff_data, + new_diff_data=new_diff_data) + + file_changes = self._calculate_file_changes( + old_diff_data, new_diff_data) + + # Add an automatic comment to the pull request + update_comment = ChangesetCommentsModel().create( + text=self._render_update_message(changes, file_changes), + repo=pull_request.target_repo, + user=pull_request.author, + pull_request=pull_request, + send_email=False, renderer=DEFAULT_COMMENTS_RENDERER) + + # Update status to "Under Review" for added commits + for commit_id in changes.added: + ChangesetStatusModel().set_status( + repo=pull_request.source_repo, + status=ChangesetStatus.STATUS_UNDER_REVIEW, + comment=update_comment, + user=pull_request.author, + pull_request=pull_request, + revision=commit_id) + + log.debug( + 'Updated pull request %s, added_ids: %s, common_ids: %s, ' + 'removed_ids: %s', pull_request.pull_request_id, + changes.added, changes.common, changes.removed) + log.debug('Updated pull request with the following file changes: %s', + file_changes) + + log.info( + "Updated pull request %s from commit %s to commit %s, " + "stored new version %s of this pull request.", + pull_request.pull_request_id, source_ref_id, + pull_request.source_ref_parts.commit_id, + pull_request_version.pull_request_version_id) + Session().commit() + self._trigger_pull_request_hook(pull_request, pull_request.author, + 'update') + return (pull_request_version, changes) + + def _create_version_from_snapshot(self, pull_request): + version = PullRequestVersion() + version.title = pull_request.title + version.description = pull_request.description + version.status = pull_request.status + version.created_on = pull_request.created_on + version.updated_on = pull_request.updated_on + version.user_id = pull_request.user_id + version.source_repo = pull_request.source_repo + version.source_ref = pull_request.source_ref + version.target_repo = pull_request.target_repo + version.target_ref = pull_request.target_ref + + version._last_merge_source_rev = pull_request._last_merge_source_rev + version._last_merge_target_rev = pull_request._last_merge_target_rev + version._last_merge_status = pull_request._last_merge_status + version.merge_rev = pull_request.merge_rev + + version.revisions = pull_request.revisions + version.pull_request = pull_request + Session().add(version) + Session().flush() + + return version + + def _generate_update_diffs(self, pull_request, pull_request_version): + diff_context = ( + self.DIFF_CONTEXT + + ChangesetCommentsModel.needed_extra_diff_context()) + old_diff = self._get_diff_from_pr_or_version( + pull_request_version, context=diff_context) + new_diff = self._get_diff_from_pr_or_version( + pull_request, context=diff_context) + + old_diff_data = diffs.DiffProcessor(old_diff) + old_diff_data.prepare() + new_diff_data = diffs.DiffProcessor(new_diff) + new_diff_data.prepare() + + return old_diff_data, new_diff_data + + def _link_comments_to_version(self, pull_request_version): + """ + Link all unlinked comments of this pull request to the given version. + + :param pull_request_version: The `PullRequestVersion` to which + the comments shall be linked. + + """ + pull_request = pull_request_version.pull_request + comments = ChangesetComment.query().filter( + # TODO: johbo: Should we query for the repo at all here? + # Pending decision on how comments of PRs are to be related + # to either the source repo, the target repo or no repo at all. + ChangesetComment.repo_id == pull_request.target_repo.repo_id, + ChangesetComment.pull_request == pull_request, + ChangesetComment.pull_request_version == None) + + # TODO: johbo: Find out why this breaks if it is done in a bulk + # operation. + for comment in comments: + comment.pull_request_version_id = ( + pull_request_version.pull_request_version_id) + Session().add(comment) + + def _calculate_commit_id_changes(self, old_ids, new_ids): + added = new_ids.difference(old_ids) + common = old_ids.intersection(new_ids) + removed = old_ids.difference(new_ids) + return ChangeTuple(added, common, removed) + + def _calculate_file_changes(self, old_diff_data, new_diff_data): + + old_files = OrderedDict() + for diff_data in old_diff_data.parsed_diff: + old_files[diff_data['filename']] = md5_safe(diff_data['raw_diff']) + + added_files = [] + modified_files = [] + removed_files = [] + for diff_data in new_diff_data.parsed_diff: + new_filename = diff_data['filename'] + new_hash = md5_safe(diff_data['raw_diff']) + + old_hash = old_files.get(new_filename) + if not old_hash: + # file is not present in old diff, means it's added + added_files.append(new_filename) + else: + if new_hash != old_hash: + modified_files.append(new_filename) + # now remove a file from old, since we have seen it already + del old_files[new_filename] + + # removed files is when there are present in old, but not in NEW, + # since we remove old files that are present in new diff, left-overs + # if any should be the removed files + removed_files.extend(old_files.keys()) + + return FileChangeTuple(added_files, modified_files, removed_files) + + def _render_update_message(self, changes, file_changes): + """ + render the message using DEFAULT_COMMENTS_RENDERER (RST renderer), + so it's always looking the same disregarding on which default + renderer system is using. + + :param changes: changes named tuple + :param file_changes: file changes named tuple + + """ + new_status = ChangesetStatus.get_status_lbl( + ChangesetStatus.STATUS_UNDER_REVIEW) + + changed_files = ( + file_changes.added + file_changes.modified + file_changes.removed) + + params = { + 'under_review_label': new_status, + 'added_commits': changes.added, + 'removed_commits': changes.removed, + 'changed_files': changed_files, + 'added_files': file_changes.added, + 'modified_files': file_changes.modified, + 'removed_files': file_changes.removed, + } + renderer = RstTemplateRenderer() + return renderer.render('pull_request_update.mako', **params) + + def edit(self, pull_request, title, description): + pull_request = self.__get_pull_request(pull_request) + if pull_request.is_closed(): + raise ValueError('This pull request is closed') + if title: + pull_request.title = title + pull_request.description = description + pull_request.updated_on = datetime.datetime.now() + Session().add(pull_request) + + def update_reviewers(self, pull_request, reviewers_ids): + reviewers_ids = set(reviewers_ids) + pull_request = self.__get_pull_request(pull_request) + current_reviewers = PullRequestReviewers.query()\ + .filter(PullRequestReviewers.pull_request == + pull_request).all() + current_reviewers_ids = set([x.user.user_id for x in current_reviewers]) + + ids_to_add = reviewers_ids.difference(current_reviewers_ids) + ids_to_remove = current_reviewers_ids.difference(reviewers_ids) + + log.debug("Adding %s reviewers", ids_to_add) + log.debug("Removing %s reviewers", ids_to_remove) + changed = False + for uid in ids_to_add: + changed = True + _usr = self._get_user(uid) + reviewer = PullRequestReviewers(_usr, pull_request) + Session().add(reviewer) + + self.notify_reviewers(pull_request, ids_to_add) + + for uid in ids_to_remove: + changed = True + reviewer = PullRequestReviewers.query()\ + .filter(PullRequestReviewers.user_id == uid, + PullRequestReviewers.pull_request == pull_request)\ + .scalar() + if reviewer: + Session().delete(reviewer) + if changed: + pull_request.updated_on = datetime.datetime.now() + Session().add(pull_request) + + return ids_to_add, ids_to_remove + + def notify_reviewers(self, pull_request, reviewers_ids): + # notification to reviewers + if not reviewers_ids: + return + + pull_request_obj = pull_request + # get the current participants of this pull request + recipients = reviewers_ids + notification_type = EmailNotificationModel.TYPE_PULL_REQUEST + + pr_source_repo = pull_request_obj.source_repo + pr_target_repo = pull_request_obj.target_repo + + pr_url = h.url( + 'pullrequest_show', + repo_name=pr_target_repo.repo_name, + pull_request_id=pull_request_obj.pull_request_id, + qualified=True,) + + # set some variables for email notification + pr_target_repo_url = h.url( + 'summary_home', + repo_name=pr_target_repo.repo_name, + qualified=True) + + pr_source_repo_url = h.url( + 'summary_home', + repo_name=pr_source_repo.repo_name, + qualified=True) + + # pull request specifics + pull_request_commits = [ + (x.raw_id, x.message) + for x in map(pr_source_repo.get_commit, pull_request.revisions)] + + kwargs = { + 'user': pull_request.author, + 'pull_request': pull_request_obj, + 'pull_request_commits': pull_request_commits, + + 'pull_request_target_repo': pr_target_repo, + 'pull_request_target_repo_url': pr_target_repo_url, + + 'pull_request_source_repo': pr_source_repo, + 'pull_request_source_repo_url': pr_source_repo_url, + + 'pull_request_url': pr_url, + } + + # pre-generate the subject for notification itself + (subject, + _h, _e, # we don't care about those + body_plaintext) = EmailNotificationModel().render_email( + notification_type, **kwargs) + + # create notification objects, and emails + NotificationModel().create( + created_by=pull_request.author, + notification_subject=subject, + notification_body=body_plaintext, + notification_type=notification_type, + recipients=recipients, + email_kwargs=kwargs, + ) + + def delete(self, pull_request): + pull_request = self.__get_pull_request(pull_request) + self._cleanup_merge_workspace(pull_request) + Session().delete(pull_request) + + def close_pull_request(self, pull_request, user): + pull_request = self.__get_pull_request(pull_request) + self._cleanup_merge_workspace(pull_request) + pull_request.status = PullRequest.STATUS_CLOSED + pull_request.updated_on = datetime.datetime.now() + Session().add(pull_request) + self._trigger_pull_request_hook( + pull_request, pull_request.author, 'close') + self._log_action('user_closed_pull_request', user, pull_request) + + def close_pull_request_with_comment(self, pull_request, user, repo, + message=None): + status = ChangesetStatus.STATUS_REJECTED + + if not message: + message = ( + _('Status change %(transition_icon)s %(status)s') % { + 'transition_icon': '>', + 'status': ChangesetStatus.get_status_lbl(status)}) + + internal_message = _('Closing with') + ' ' + message + + comm = ChangesetCommentsModel().create( + text=internal_message, + repo=repo.repo_id, + user=user.user_id, + pull_request=pull_request.pull_request_id, + f_path=None, + line_no=None, + status_change=ChangesetStatus.get_status_lbl(status), + closing_pr=True + ) + + ChangesetStatusModel().set_status( + repo.repo_id, + status, + user.user_id, + comm, + pull_request=pull_request.pull_request_id + ) + Session().flush() + + PullRequestModel().close_pull_request( + pull_request.pull_request_id, user) + + def merge_status(self, pull_request): + if not self._is_merge_enabled(pull_request): + return False, _('Server-side pull request merging is disabled.') + if pull_request.is_closed(): + return False, _('This pull request is closed.') + merge_possible, msg = self._check_repo_requirements( + target=pull_request.target_repo, source=pull_request.source_repo) + if not merge_possible: + return merge_possible, msg + + try: + resp = self._try_merge(pull_request) + status = resp.possible, self.merge_status_message( + resp.failure_reason) + except NotImplementedError: + status = False, _('Pull request merging is not supported.') + + return status + + def _check_repo_requirements(self, target, source): + """ + Check if `target` and `source` have compatible requirements. + + Currently this is just checking for largefiles. + """ + target_has_largefiles = self._has_largefiles(target) + source_has_largefiles = self._has_largefiles(source) + merge_possible = True + message = u'' + + if target_has_largefiles != source_has_largefiles: + merge_possible = False + if source_has_largefiles: + message = _( + 'Target repository large files support is disabled.') + else: + message = _( + 'Source repository large files support is disabled.') + + return merge_possible, message + + def _has_largefiles(self, repo): + largefiles_ui = VcsSettingsModel(repo=repo).get_ui_settings( + 'extensions', 'largefiles') + return largefiles_ui and largefiles_ui[0].active + + def _try_merge(self, pull_request): + """ + Try to merge the pull request and return the merge status. + """ + target_vcs = pull_request.target_repo.scm_instance() + target_ref = self._refresh_reference( + pull_request.target_ref_parts, target_vcs) + + target_locked = pull_request.target_repo.locked + if target_locked and target_locked[0]: + merge_state = MergeResponse( + False, False, None, MergeFailureReason.TARGET_IS_LOCKED) + elif self._needs_merge_state_refresh(pull_request, target_ref): + merge_state = self._refresh_merge_state( + pull_request, target_vcs, target_ref) + else: + possible = pull_request.\ + _last_merge_status == MergeFailureReason.NONE + merge_state = MergeResponse( + possible, False, None, pull_request._last_merge_status) + return merge_state + + def _refresh_reference(self, reference, vcs_repository): + if reference.type in ('branch', 'book'): + name_or_id = reference.name + else: + name_or_id = reference.commit_id + refreshed_commit = vcs_repository.get_commit(name_or_id) + refreshed_reference = Reference( + reference.type, reference.name, refreshed_commit.raw_id) + return refreshed_reference + + def _needs_merge_state_refresh(self, pull_request, target_reference): + return not( + pull_request.revisions and + pull_request.revisions[0] == pull_request._last_merge_source_rev and + target_reference.commit_id == pull_request._last_merge_target_rev) + + def _refresh_merge_state(self, pull_request, target_vcs, target_reference): + workspace_id = self._workspace_id(pull_request) + source_vcs = pull_request.source_repo.scm_instance() + merge_state = target_vcs.merge( + target_reference, source_vcs, pull_request.source_ref_parts, + workspace_id, dry_run=True) + + # Do not store the response if there was an unknown error. + if merge_state.failure_reason != MergeFailureReason.UNKNOWN: + pull_request._last_merge_source_rev = pull_request.\ + source_ref_parts.commit_id + pull_request._last_merge_target_rev = target_reference.commit_id + pull_request._last_merge_status = ( + merge_state.failure_reason) + Session().add(pull_request) + Session().flush() + + return merge_state + + def _workspace_id(self, pull_request): + workspace_id = 'pr-%s' % pull_request.pull_request_id + return workspace_id + + def merge_status_message(self, status_code): + """ + Return a human friendly error message for the given merge status code. + """ + return self.MERGE_STATUS_MESSAGES[status_code] + + def generate_repo_data(self, repo, commit_id=None, branch=None, + bookmark=None): + all_refs, selected_ref = \ + self._get_repo_pullrequest_sources( + repo.scm_instance(), commit_id=commit_id, + branch=branch, bookmark=bookmark) + + refs_select2 = [] + for element in all_refs: + children = [{'id': x[0], 'text': x[1]} for x in element[0]] + refs_select2.append({'text': element[1], 'children': children}) + + return { + 'user': { + 'user_id': repo.user.user_id, + 'username': repo.user.username, + 'firstname': repo.user.firstname, + 'lastname': repo.user.lastname, + 'gravatar_link': h.gravatar_url(repo.user.email, 14), + }, + 'description': h.chop_at_smart(repo.description, '\n'), + 'refs': { + 'all_refs': all_refs, + 'selected_ref': selected_ref, + 'select2_refs': refs_select2 + } + } + + def generate_pullrequest_title(self, source, source_ref, target): + return '{source}#{at_ref} to {target}'.format( + source=source, + at_ref=source_ref, + target=target, + ) + + def _cleanup_merge_workspace(self, pull_request): + # Merging related cleanup + target_scm = pull_request.target_repo.scm_instance() + workspace_id = 'pr-%s' % pull_request.pull_request_id + + try: + target_scm.cleanup_merge_workspace(workspace_id) + except NotImplementedError: + pass + + def _get_repo_pullrequest_sources( + self, repo, commit_id=None, branch=None, bookmark=None): + """ + Return a structure with repo's interesting commits, suitable for + the selectors in pullrequest controller + + :param commit_id: a commit that must be in the list somehow + and selected by default + :param branch: a branch that must be in the list and selected + by default - even if closed + :param bookmark: a bookmark that must be in the list and selected + """ + + commit_id = safe_str(commit_id) if commit_id else None + branch = safe_str(branch) if branch else None + bookmark = safe_str(bookmark) if bookmark else None + + selected = None + + # order matters: first source that has commit_id in it will be selected + sources = [] + sources.append(('book', repo.bookmarks.items(), _('Bookmarks'), bookmark)) + sources.append(('branch', repo.branches.items(), _('Branches'), branch)) + + if commit_id: + ref_commit = (h.short_id(commit_id), commit_id) + sources.append(('rev', [ref_commit], _('Commit IDs'), commit_id)) + + sources.append( + ('branch', repo.branches_closed.items(), _('Closed Branches'), branch), + ) + + groups = [] + for group_key, ref_list, group_name, match in sources: + group_refs = [] + for ref_name, ref_id in ref_list: + ref_key = '%s:%s:%s' % (group_key, ref_name, ref_id) + group_refs.append((ref_key, ref_name)) + + if not selected and match in (ref_id, ref_name): + selected = ref_key + if group_refs: + groups.append((group_refs, group_name)) + + if not selected: + ref = commit_id or branch or bookmark + if ref: + raise CommitDoesNotExistError( + 'No commit refs could be found matching: %s' % ref) + elif repo.DEFAULT_BRANCH_NAME in repo.branches: + selected = 'branch:%s:%s' % ( + repo.DEFAULT_BRANCH_NAME, + repo.branches[repo.DEFAULT_BRANCH_NAME] + ) + elif repo.commit_ids: + rev = repo.commit_ids[0] + selected = 'rev:%s:%s' % (rev, rev) + else: + raise EmptyRepositoryError() + return groups, selected + + def get_diff(self, pull_request, context=DIFF_CONTEXT): + pull_request = self.__get_pull_request(pull_request) + return self._get_diff_from_pr_or_version(pull_request, context=context) + + def _get_diff_from_pr_or_version(self, pr_or_version, context): + source_repo = pr_or_version.source_repo + + # we swap org/other ref since we run a simple diff on one repo + target_ref_id = pr_or_version.target_ref_parts.commit_id + source_ref_id = pr_or_version.source_ref_parts.commit_id + target_commit = source_repo.get_commit( + commit_id=safe_str(target_ref_id)) + source_commit = source_repo.get_commit(commit_id=safe_str(source_ref_id)) + vcs_repo = source_repo.scm_instance() + + # TODO: johbo: In the context of an update, we cannot reach + # the old commit anymore with our normal mechanisms. It needs + # some sort of special support in the vcs layer to avoid this + # workaround. + if (source_commit.raw_id == vcs_repo.EMPTY_COMMIT_ID and + vcs_repo.alias == 'git'): + source_commit.raw_id = safe_str(source_ref_id) + + log.debug('calculating diff between ' + 'source_ref:%s and target_ref:%s for repo `%s`', + target_ref_id, source_ref_id, + safe_unicode(vcs_repo.path)) + + vcs_diff = vcs_repo.get_diff( + commit1=target_commit, commit2=source_commit, context=context) + return vcs_diff + + def _is_merge_enabled(self, pull_request): + settings_model = VcsSettingsModel(repo=pull_request.target_repo) + settings = settings_model.get_general_settings() + return settings.get('rhodecode_pr_merge_enabled', False) + + def _log_action(self, action, user, pull_request): + action_logger( + user, + '{action}:{pr_id}'.format( + action=action, pr_id=pull_request.pull_request_id), + pull_request.target_repo) + + +ChangeTuple = namedtuple('ChangeTuple', + ['added', 'common', 'removed']) + +FileChangeTuple = namedtuple('FileChangeTuple', + ['added', 'modified', 'removed']) diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/repo.py @@ -0,0 +1,918 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Repository model for rhodecode +""" + +import logging +import os +import re +import shutil +import time +import traceback +from datetime import datetime + +from sqlalchemy.sql import func +from sqlalchemy.sql.expression import true, or_ +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import HasUserGroupPermissionAny +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.exceptions import AttachedForksError +from rhodecode.lib.hooks_base import log_delete_repository +from rhodecode.lib.utils import make_db_config +from rhodecode.lib.utils2 import ( + safe_str, safe_unicode, remove_prefix, obfuscate_url_pw, + get_current_rhodecode_user, safe_int, datetime_to_time, action_logger_generic) +from rhodecode.lib.vcs.backends import get_backend +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + Repository, UserRepoToPerm, UserGroupRepoToPerm, UserRepoGroupToPerm, + UserGroupRepoGroupToPerm, User, Permission, Statistics, UserGroup, + RepoGroup, RepositoryField) +from rhodecode.model.scm import UserGroupList +from rhodecode.model.settings import VcsSettingsModel + + +log = logging.getLogger(__name__) + + +class RepoModel(BaseModel): + + cls = Repository + + def _get_user_group(self, users_group): + return self._get_instance(UserGroup, users_group, + callback=UserGroup.get_by_group_name) + + def _get_repo_group(self, repo_group): + return self._get_instance(RepoGroup, repo_group, + callback=RepoGroup.get_by_group_name) + + def _create_default_perms(self, repository, private): + # create default permission + default = 'repository.read' + def_user = User.get_default_user() + for p in def_user.user_perms: + if p.permission.permission_name.startswith('repository.'): + default = p.permission.permission_name + break + + default_perm = 'repository.none' if private else default + + repo_to_perm = UserRepoToPerm() + repo_to_perm.permission = Permission.get_by_key(default_perm) + + repo_to_perm.repository = repository + repo_to_perm.user_id = def_user.user_id + + return repo_to_perm + + @LazyProperty + def repos_path(self): + """ + Gets the repositories root path from database + """ + settings_model = VcsSettingsModel(sa=self.sa) + return settings_model.get_repos_location() + + def get(self, repo_id, cache=False): + repo = self.sa.query(Repository) \ + .filter(Repository.repo_id == repo_id) + + if cache: + repo = repo.options(FromCache("sql_cache_short", + "get_repo_%s" % repo_id)) + return repo.scalar() + + def get_repo(self, repository): + return self._get_repo(repository) + + def get_by_repo_name(self, repo_name, cache=False): + repo = self.sa.query(Repository) \ + .filter(Repository.repo_name == repo_name) + + if cache: + repo = repo.options(FromCache("sql_cache_short", + "get_repo_%s" % repo_name)) + return repo.scalar() + + def _extract_id_from_repo_name(self, repo_name): + if repo_name.startswith('/'): + repo_name = repo_name.lstrip('/') + by_id_match = re.match(r'^_(\d{1,})', repo_name) + if by_id_match: + return by_id_match.groups()[0] + + def get_repo_by_id(self, repo_name): + """ + Extracts repo_name by id from special urls. + Example url is _11/repo_name + + :param repo_name: + :return: repo object if matched else None + """ + try: + _repo_id = self._extract_id_from_repo_name(repo_name) + if _repo_id: + return self.get(_repo_id) + except Exception: + log.exception('Failed to extract repo_name from URL') + + return None + + def get_users(self, name_contains=None, limit=20): + # TODO: mikhail: move this method to the UserModel. + query = self.sa.query(User) + query = query.filter(User.active == true()) + if name_contains: + ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) + query = query.filter( + or_( + User.name.ilike(ilike_expression), + User.lastname.ilike(ilike_expression), + User.username.ilike(ilike_expression) + ) + ) + query = query.limit(limit) + users = query.all() + + _users = [ + { + 'id': user.user_id, + 'first_name': user.name, + 'last_name': user.lastname, + 'username': user.username, + 'icon_link': h.gravatar_url(user.email, 14), + 'value_display': h.person(user.email), + 'value': user.username, + 'value_type': 'user' + } + for user in users + ] + return _users + + def get_user_groups(self, name_contains=None, limit=20): + # TODO: mikhail: move this method to the UserGroupModel. + query = self.sa.query(UserGroup) + query = query.filter(UserGroup.users_group_active == true()) + if name_contains: + ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) + query = query.filter( + UserGroup.users_group_name.ilike(ilike_expression))\ + .order_by(func.length(UserGroup.users_group_name))\ + .order_by(UserGroup.users_group_name) + + query = query.limit(limit) + user_groups = query.all() + perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin'] + user_groups = UserGroupList(user_groups, perm_set=perm_set) + + _groups = [ + { + 'id': group.users_group_id, + # TODO: marcink figure out a way to generate the url for the + # icon + 'icon_link': '', + 'value_display': 'Group: %s (%d members)' % ( + group.users_group_name, len(group.members),), + 'value': group.users_group_name, + 'value_type': 'user_group' + } + for group in user_groups + ] + return _groups + + @classmethod + def update_repoinfo(cls, repositories=None): + if not repositories: + repositories = Repository.getAll() + for repo in repositories: + repo.update_commit_cache() + + def get_repos_as_dict(self, repo_list=None, admin=False, + super_user_actions=False): + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + c = _render.c + + def quick_menu(repo_name): + return _render('quick_menu', repo_name) + + def repo_lnk(name, rtype, rstate, private, fork_of): + return _render('repo_name', name, rtype, rstate, private, fork_of, + short_name=not admin, admin=False) + + def last_change(last_change): + return _render("last_change", last_change) + + def rss_lnk(repo_name): + return _render("rss", repo_name) + + def atom_lnk(repo_name): + return _render("atom", repo_name) + + def last_rev(repo_name, cs_cache): + return _render('revision', repo_name, cs_cache.get('revision'), + cs_cache.get('raw_id'), cs_cache.get('author'), + cs_cache.get('message')) + + def desc(desc): + if c.visual.stylify_metatags: + return h.urlify_text(h.escaped_stylize(h.truncate(desc, 60))) + else: + return h.urlify_text(h.html_escape(h.truncate(desc, 60))) + + def state(repo_state): + return _render("repo_state", repo_state) + + def repo_actions(repo_name): + return _render('repo_actions', repo_name, super_user_actions) + + def user_profile(username): + return _render('user_profile', username) + + repos_data = [] + for repo in repo_list: + cs_cache = repo.changeset_cache + row = { + "menu": quick_menu(repo.repo_name), + + "name": repo_lnk(repo.repo_name, repo.repo_type, + repo.repo_state, repo.private, repo.fork), + "name_raw": repo.repo_name.lower(), + + "last_change": last_change(repo.last_db_change), + "last_change_raw": datetime_to_time(repo.last_db_change), + + "last_changeset": last_rev(repo.repo_name, cs_cache), + "last_changeset_raw": cs_cache.get('revision'), + + "desc": desc(repo.description), + "owner": user_profile(repo.user.username), + + "state": state(repo.repo_state), + "rss": rss_lnk(repo.repo_name), + + "atom": atom_lnk(repo.repo_name), + } + if admin: + row.update({ + "action": repo_actions(repo.repo_name), + }) + repos_data.append(row) + + return repos_data + + def _get_defaults(self, repo_name): + """ + Gets information about repository, and returns a dict for + usage in forms + + :param repo_name: + """ + + repo_info = Repository.get_by_repo_name(repo_name) + + if repo_info is None: + return None + + defaults = repo_info.get_dict() + defaults['repo_name'] = repo_info.just_name + + groups = repo_info.groups_with_parents + parent_group = groups[-1] if groups else None + + # we use -1 as this is how in HTML, we mark an empty group + defaults['repo_group'] = getattr(parent_group, 'group_id', -1) + + keys_to_process = ( + {'k': 'repo_type', 'strip': False}, + {'k': 'repo_enable_downloads', 'strip': True}, + {'k': 'repo_description', 'strip': True}, + {'k': 'repo_enable_locking', 'strip': True}, + {'k': 'repo_landing_rev', 'strip': True}, + {'k': 'clone_uri', 'strip': False}, + {'k': 'repo_private', 'strip': True}, + {'k': 'repo_enable_statistics', 'strip': True} + ) + + for item in keys_to_process: + attr = item['k'] + if item['strip']: + attr = remove_prefix(item['k'], 'repo_') + + val = defaults[attr] + if item['k'] == 'repo_landing_rev': + val = ':'.join(defaults[attr]) + defaults[item['k']] = val + if item['k'] == 'clone_uri': + defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden + + # fill owner + if repo_info.user: + defaults.update({'user': repo_info.user.username}) + else: + replacement_user = User.get_first_admin().username + defaults.update({'user': replacement_user}) + + # fill repository users + for p in repo_info.repo_to_perm: + defaults.update({'u_perm_%s' % p.user.user_id: + p.permission.permission_name}) + + # fill repository groups + for p in repo_info.users_group_to_perm: + defaults.update({'g_perm_%s' % p.users_group.users_group_id: + p.permission.permission_name}) + + return defaults + + def update(self, repo, **kwargs): + try: + cur_repo = self._get_repo(repo) + source_repo_name = cur_repo.repo_name + if 'user' in kwargs: + cur_repo.user = User.get_by_username(kwargs['user']) + + if 'repo_group' in kwargs: + cur_repo.group = RepoGroup.get(kwargs['repo_group']) + log.debug('Updating repo %s with params:%s', cur_repo, kwargs) + + update_keys = [ + (1, 'repo_enable_downloads'), + (1, 'repo_description'), + (1, 'repo_enable_locking'), + (1, 'repo_landing_rev'), + (1, 'repo_private'), + (1, 'repo_enable_statistics'), + (0, 'clone_uri'), + (0, 'fork_id') + ] + for strip, k in update_keys: + if k in kwargs: + val = kwargs[k] + if strip: + k = remove_prefix(k, 'repo_') + if k == 'clone_uri': + from rhodecode.model.validators import Missing + _change = kwargs.get('clone_uri_change') + if _change in [Missing, 'OLD']: + # we don't change the value, so use original one + val = cur_repo.clone_uri + + setattr(cur_repo, k, val) + + new_name = cur_repo.get_new_name(kwargs['repo_name']) + cur_repo.repo_name = new_name + + # if private flag is set, reset default permission to NONE + if kwargs.get('repo_private'): + EMPTY_PERM = 'repository.none' + RepoModel().grant_user_permission( + repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM + ) + + # handle extra fields + for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), + kwargs): + k = RepositoryField.un_prefix_key(field) + ex_field = RepositoryField.get_by_key_name( + key=k, repo=cur_repo) + if ex_field: + ex_field.field_value = kwargs[field] + self.sa.add(ex_field) + self.sa.add(cur_repo) + + if source_repo_name != new_name: + # rename repository + self._rename_filesystem_repo( + old=source_repo_name, new=new_name) + + return cur_repo + except Exception: + log.error(traceback.format_exc()) + raise + + def _create_repo(self, repo_name, repo_type, description, owner, + private=False, clone_uri=None, repo_group=None, + landing_rev='rev:tip', fork_of=None, + copy_fork_permissions=False, enable_statistics=False, + enable_locking=False, enable_downloads=False, + copy_group_permissions=False, + state=Repository.STATE_PENDING): + """ + Create repository inside database with PENDING state, this should be + only executed by create() repo. With exception of importing existing + repos + """ + from rhodecode.model.scm import ScmModel + + owner = self._get_user(owner) + fork_of = self._get_repo(fork_of) + repo_group = self._get_repo_group(safe_int(repo_group)) + + try: + repo_name = safe_unicode(repo_name) + description = safe_unicode(description) + # repo name is just a name of repository + # while repo_name_full is a full qualified name that is combined + # with name and path of group + repo_name_full = repo_name + repo_name = repo_name.split(Repository.NAME_SEP)[-1] + + new_repo = Repository() + new_repo.repo_state = state + new_repo.enable_statistics = False + new_repo.repo_name = repo_name_full + new_repo.repo_type = repo_type + new_repo.user = owner + new_repo.group = repo_group + new_repo.description = description or repo_name + new_repo.private = private + new_repo.clone_uri = clone_uri + new_repo.landing_rev = landing_rev + + new_repo.enable_statistics = enable_statistics + new_repo.enable_locking = enable_locking + new_repo.enable_downloads = enable_downloads + + if repo_group: + new_repo.enable_locking = repo_group.enable_locking + + if fork_of: + parent_repo = fork_of + new_repo.fork = parent_repo + + self.sa.add(new_repo) + + EMPTY_PERM = 'repository.none' + if fork_of and copy_fork_permissions: + repo = fork_of + user_perms = UserRepoToPerm.query() \ + .filter(UserRepoToPerm.repository == repo).all() + group_perms = UserGroupRepoToPerm.query() \ + .filter(UserGroupRepoToPerm.repository == repo).all() + + for perm in user_perms: + UserRepoToPerm.create( + perm.user, new_repo, perm.permission) + + for perm in group_perms: + UserGroupRepoToPerm.create( + perm.users_group, new_repo, perm.permission) + # in case we copy permissions and also set this repo to private + # override the default user permission to make it a private + # repo + if private: + RepoModel(self.sa).grant_user_permission( + repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM) + + elif repo_group and copy_group_permissions: + user_perms = UserRepoGroupToPerm.query() \ + .filter(UserRepoGroupToPerm.group == repo_group).all() + + group_perms = UserGroupRepoGroupToPerm.query() \ + .filter(UserGroupRepoGroupToPerm.group == repo_group).all() + + for perm in user_perms: + perm_name = perm.permission.permission_name.replace( + 'group.', 'repository.') + perm_obj = Permission.get_by_key(perm_name) + UserRepoToPerm.create(perm.user, new_repo, perm_obj) + + for perm in group_perms: + perm_name = perm.permission.permission_name.replace( + 'group.', 'repository.') + perm_obj = Permission.get_by_key(perm_name) + UserGroupRepoToPerm.create( + perm.users_group, new_repo, perm_obj) + + if private: + RepoModel(self.sa).grant_user_permission( + repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM) + + else: + perm_obj = self._create_default_perms(new_repo, private) + self.sa.add(perm_obj) + + # now automatically start following this repository as owner + ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, + owner.user_id) + # we need to flush here, in order to check if database won't + # throw any exceptions, create filesystem dirs at the very end + self.sa.flush() + + return new_repo + except Exception: + log.error(traceback.format_exc()) + raise + + def create(self, form_data, cur_user): + """ + Create repository using celery tasks + + :param form_data: + :param cur_user: + """ + from rhodecode.lib.celerylib import tasks, run_task + return run_task(tasks.create_repo, form_data, cur_user) + + def update_permissions(self, repo, perm_additions=None, perm_updates=None, + perm_deletions=None, check_perms=True, + cur_user=None): + if not perm_additions: + perm_additions = [] + if not perm_updates: + perm_updates = [] + if not perm_deletions: + perm_deletions = [] + + req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') + + # update permissions + for member_id, perm, member_type in perm_updates: + member_id = int(member_id) + if member_type == 'user': + # this updates also current one if found + self.grant_user_permission( + repo=repo, user=member_id, perm=perm) + else: # set for user group + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): + self.grant_user_group_permission( + repo=repo, group_name=member_id, perm=perm) + + # set new permissions + for member_id, perm, member_type in perm_additions: + member_id = int(member_id) + if member_type == 'user': + self.grant_user_permission( + repo=repo, user=member_id, perm=perm) + else: # set for user group + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): + self.grant_user_group_permission( + repo=repo, group_name=member_id, perm=perm) + + # delete permissions + for member_id, perm, member_type in perm_deletions: + member_id = int(member_id) + if member_type == 'user': + self.revoke_user_permission(repo=repo, user=member_id) + else: # set for user group + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): + self.revoke_user_group_permission( + repo=repo, group_name=member_id) + + def create_fork(self, form_data, cur_user): + """ + Simple wrapper into executing celery task for fork creation + + :param form_data: + :param cur_user: + """ + from rhodecode.lib.celerylib import tasks, run_task + return run_task(tasks.create_repo_fork, form_data, cur_user) + + def delete(self, repo, forks=None, fs_remove=True, cur_user=None): + """ + Delete given repository, forks parameter defines what do do with + attached forks. Throws AttachedForksError if deleted repo has attached + forks + + :param repo: + :param forks: str 'delete' or 'detach' + :param fs_remove: remove(archive) repo from filesystem + """ + if not cur_user: + cur_user = getattr(get_current_rhodecode_user(), 'username', None) + repo = self._get_repo(repo) + if repo: + if forks == 'detach': + for r in repo.forks: + r.fork = None + self.sa.add(r) + elif forks == 'delete': + for r in repo.forks: + self.delete(r, forks='delete') + elif [f for f in repo.forks]: + raise AttachedForksError() + + old_repo_dict = repo.get_dict() + try: + self.sa.delete(repo) + if fs_remove: + self._delete_filesystem_repo(repo) + else: + log.debug('skipping removal from filesystem') + old_repo_dict.update({ + 'deleted_by': cur_user, + 'deleted_on': time.time(), + }) + log_delete_repository(**old_repo_dict) + except Exception: + log.error(traceback.format_exc()) + raise + + def grant_user_permission(self, repo, user, perm): + """ + Grant permission for user on given repository, or update existing one + if found + + :param repo: Instance of Repository, repository_id, or repository name + :param user: Instance of User, user_id or username + :param perm: Instance of Permission, or permission_name + """ + user = self._get_user(user) + repo = self._get_repo(repo) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserRepoToPerm) \ + .filter(UserRepoToPerm.user == user) \ + .filter(UserRepoToPerm.repository == repo) \ + .scalar() + if obj is None: + # create new ! + obj = UserRepoToPerm() + obj.repository = repo + obj.user = user + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s', perm, user, repo) + action_logger_generic( + 'granted permission: {} to user: {} on repo: {}'.format( + perm, user, repo), namespace='security.repo') + return obj + + def revoke_user_permission(self, repo, user): + """ + Revoke permission for user on given repository + + :param repo: Instance of Repository, repository_id, or repository name + :param user: Instance of User, user_id or username + """ + + user = self._get_user(user) + repo = self._get_repo(repo) + + obj = self.sa.query(UserRepoToPerm) \ + .filter(UserRepoToPerm.repository == repo) \ + .filter(UserRepoToPerm.user == user) \ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm on %s on %s', repo, user) + action_logger_generic( + 'revoked permission from user: {} on repo: {}'.format( + user, repo), namespace='security.repo') + + def grant_user_group_permission(self, repo, group_name, perm): + """ + Grant permission for user group on given repository, or update + existing one if found + + :param repo: Instance of Repository, repository_id, or repository name + :param group_name: Instance of UserGroup, users_group_id, + or user group name + :param perm: Instance of Permission, or permission_name + """ + repo = self._get_repo(repo) + group_name = self._get_user_group(group_name) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserGroupRepoToPerm) \ + .filter(UserGroupRepoToPerm.users_group == group_name) \ + .filter(UserGroupRepoToPerm.repository == repo) \ + .scalar() + + if obj is None: + # create new + obj = UserGroupRepoToPerm() + + obj.repository = repo + obj.users_group = group_name + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s', perm, group_name, repo) + action_logger_generic( + 'granted permission: {} to usergroup: {} on repo: {}'.format( + perm, group_name, repo), namespace='security.repo') + + return obj + + def revoke_user_group_permission(self, repo, group_name): + """ + Revoke permission for user group on given repository + + :param repo: Instance of Repository, repository_id, or repository name + :param group_name: Instance of UserGroup, users_group_id, + or user group name + """ + repo = self._get_repo(repo) + group_name = self._get_user_group(group_name) + + obj = self.sa.query(UserGroupRepoToPerm) \ + .filter(UserGroupRepoToPerm.repository == repo) \ + .filter(UserGroupRepoToPerm.users_group == group_name) \ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm to %s on %s', repo, group_name) + action_logger_generic( + 'revoked permission from usergroup: {} on repo: {}'.format( + group_name, repo), namespace='security.repo') + + def delete_stats(self, repo_name): + """ + removes stats for given repo + + :param repo_name: + """ + repo = self._get_repo(repo_name) + try: + obj = self.sa.query(Statistics) \ + .filter(Statistics.repository == repo).scalar() + if obj: + self.sa.delete(obj) + except Exception: + log.error(traceback.format_exc()) + raise + + def add_repo_field(self, repo_name, field_key, field_label, field_value='', + field_type='str', field_desc=''): + + repo = self._get_repo(repo_name) + + new_field = RepositoryField() + new_field.repository = repo + new_field.field_key = field_key + new_field.field_type = field_type # python type + new_field.field_value = field_value + new_field.field_desc = field_desc + new_field.field_label = field_label + self.sa.add(new_field) + return new_field + + def delete_repo_field(self, repo_name, field_key): + repo = self._get_repo(repo_name) + field = RepositoryField.get_by_key_name(field_key, repo) + if field: + self.sa.delete(field) + + def _create_filesystem_repo(self, repo_name, repo_type, repo_group, + clone_uri=None, repo_store_location=None, + use_global_config=False): + """ + makes repository on filesystem. It's group aware means it'll create + a repository within a group, and alter the paths accordingly of + group location + + :param repo_name: + :param alias: + :param parent: + :param clone_uri: + :param repo_store_location: + """ + from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group + from rhodecode.model.scm import ScmModel + + if Repository.NAME_SEP in repo_name: + raise ValueError( + 'repo_name must not contain groups got `%s`' % repo_name) + + if isinstance(repo_group, RepoGroup): + new_parent_path = os.sep.join(repo_group.full_path_splitted) + else: + new_parent_path = repo_group or '' + + if repo_store_location: + _paths = [repo_store_location] + else: + _paths = [self.repos_path, new_parent_path, repo_name] + # we need to make it str for mercurial + repo_path = os.path.join(*map(lambda x: safe_str(x), _paths)) + + # check if this path is not a repository + if is_valid_repo(repo_path, self.repos_path): + raise Exception('This path %s is a valid repository' % repo_path) + + # check if this path is a group + if is_valid_repo_group(repo_path, self.repos_path): + raise Exception('This path %s is a valid group' % repo_path) + + log.info('creating repo %s in %s from url: `%s`', + repo_name, safe_unicode(repo_path), + obfuscate_url_pw(clone_uri)) + + backend = get_backend(repo_type) + + config_repo = None if use_global_config else repo_name + if config_repo and new_parent_path: + config_repo = Repository.NAME_SEP.join( + (new_parent_path, config_repo)) + config = make_db_config(clear_session=False, repo=config_repo) + config.set('extensions', 'largefiles', '') + + # patch and reset hooks section of UI config to not run any + # hooks on creating remote repo + config.clear_section('hooks') + + # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice + if repo_type == 'git': + repo = backend( + repo_path, config=config, create=True, src_url=clone_uri, + bare=True) + else: + repo = backend( + repo_path, config=config, create=True, src_url=clone_uri) + + ScmModel().install_hooks(repo, repo_type=repo_type) + + log.debug('Created repo %s with %s backend', + safe_unicode(repo_name), safe_unicode(repo_type)) + return repo + + def _rename_filesystem_repo(self, old, new): + """ + renames repository on filesystem + + :param old: old name + :param new: new name + """ + log.info('renaming repo from %s to %s', old, new) + + old_path = os.path.join(self.repos_path, old) + new_path = os.path.join(self.repos_path, new) + if os.path.isdir(new_path): + raise Exception( + 'Was trying to rename to already existing dir %s' % new_path + ) + shutil.move(old_path, new_path) + + def _delete_filesystem_repo(self, repo): + """ + removes repo from filesystem, the removal is acctually made by + added rm__ prefix into dir, and rename internat .hg/.git dirs so this + repository is no longer valid for rhodecode, can be undeleted later on + by reverting the renames on this repository + + :param repo: repo object + """ + rm_path = os.path.join(self.repos_path, repo.repo_name) + repo_group = repo.group + log.info("Removing repository %s", rm_path) + # disable hg/git internal that it doesn't get detected as repo + alias = repo.repo_type + + config = make_db_config(clear_session=False) + config.set('extensions', 'largefiles', '') + bare = getattr(repo.scm_instance(config=config), 'bare', False) + + # skip this for bare git repos + if not bare: + # disable VCS repo + vcs_path = os.path.join(rm_path, '.%s' % alias) + if os.path.exists(vcs_path): + shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias)) + + _now = datetime.now() + _ms = str(_now.microsecond).rjust(6, '0') + _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms), + repo.just_name) + if repo_group: + # if repository is in group, prefix the removal path with the group + args = repo_group.full_path_splitted + [_d] + _d = os.path.join(*args) + + if os.path.isdir(rm_path): + shutil.move(rm_path, os.path.join(self.repos_path, _d)) diff --git a/rhodecode/model/repo_group.py b/rhodecode/model/repo_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/repo_group.py @@ -0,0 +1,646 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +repo group model for RhodeCode +""" + + +import datetime +import itertools +import logging +import os +import shutil +import traceback + +from zope.cachedescriptors.property import Lazy as LazyProperty + +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm, + UserGroup, Repository) +from rhodecode.model.settings import VcsSettingsModel +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.utils2 import action_logger_generic + +log = logging.getLogger(__name__) + + +class RepoGroupModel(BaseModel): + + cls = RepoGroup + PERSONAL_GROUP_DESC = '[personal] repo group: owner `%(username)s`' + + def _get_user_group(self, users_group): + return self._get_instance(UserGroup, users_group, + callback=UserGroup.get_by_group_name) + + def _get_repo_group(self, repo_group): + return self._get_instance(RepoGroup, repo_group, + callback=RepoGroup.get_by_group_name) + + @LazyProperty + def repos_path(self): + """ + Gets the repositories root path from database + """ + + settings_model = VcsSettingsModel(sa=self.sa) + return settings_model.get_repos_location() + + def get_by_group_name(self, repo_group_name, cache=None): + repo = self.sa.query(RepoGroup) \ + .filter(RepoGroup.group_name == repo_group_name) + + if cache: + repo = repo.options(FromCache( + "sql_cache_short", "get_repo_group_%s" % repo_group_name)) + return repo.scalar() + + def _create_default_perms(self, new_group): + # create default permission + default_perm = 'group.read' + def_user = User.get_default_user() + for p in def_user.user_perms: + if p.permission.permission_name.startswith('group.'): + default_perm = p.permission.permission_name + break + + repo_group_to_perm = UserRepoGroupToPerm() + repo_group_to_perm.permission = Permission.get_by_key(default_perm) + + repo_group_to_perm.group = new_group + repo_group_to_perm.user_id = def_user.user_id + return repo_group_to_perm + + def _get_group_name_and_parent(self, group_name_full, repo_in_path=False): + """ + Get's the group name and a parent group name from given group name. + If repo_in_path is set to truth, we asume the full path also includes + repo name, in such case we clean the last element. + + :param group_name_full: + """ + split_paths = 1 + if repo_in_path: + split_paths = 2 + _parts = group_name_full.rsplit(RepoGroup.url_sep(), split_paths) + + if repo_in_path and len(_parts) > 1: + # such case last element is the repo_name + _parts.pop(-1) + group_name_cleaned = _parts[-1] # just the group name + parent_repo_group_name = None + + if len(_parts) > 1: + parent_repo_group_name = _parts[0] + + if parent_repo_group_name: + parent_group = RepoGroup.get_by_group_name(parent_repo_group_name) + + return group_name_cleaned, parent_repo_group_name + + def check_exist_filesystem(self, group_name, exc_on_failure=True): + create_path = os.path.join(self.repos_path, group_name) + log.debug('creating new group in %s', create_path) + + if os.path.isdir(create_path): + if exc_on_failure: + raise Exception('That directory already exists !') + return False + return True + + def _create_group(self, group_name): + """ + makes repository group on filesystem + + :param repo_name: + :param parent_id: + """ + + self.check_exist_filesystem(group_name) + create_path = os.path.join(self.repos_path, group_name) + log.debug('creating new group in %s', create_path) + os.makedirs(create_path, mode=0755) + log.debug('created group in %s', create_path) + + def _rename_group(self, old, new): + """ + Renames a group on filesystem + + :param group_name: + """ + + if old == new: + log.debug('skipping group rename') + return + + log.debug('renaming repository group from %s to %s', old, new) + + old_path = os.path.join(self.repos_path, old) + new_path = os.path.join(self.repos_path, new) + + log.debug('renaming repos paths from %s to %s', old_path, new_path) + + if os.path.isdir(new_path): + raise Exception('Was trying to rename to already ' + 'existing dir %s' % new_path) + shutil.move(old_path, new_path) + + def _delete_filesystem_group(self, group, force_delete=False): + """ + Deletes a group from a filesystem + + :param group: instance of group from database + :param force_delete: use shutil rmtree to remove all objects + """ + paths = group.full_path.split(RepoGroup.url_sep()) + paths = os.sep.join(paths) + + rm_path = os.path.join(self.repos_path, paths) + log.info("Removing group %s", rm_path) + # delete only if that path really exists + if os.path.isdir(rm_path): + if force_delete: + shutil.rmtree(rm_path) + else: + # archive that group` + _now = datetime.datetime.now() + _ms = str(_now.microsecond).rjust(6, '0') + _d = 'rm__%s_GROUP_%s' % ( + _now.strftime('%Y%m%d_%H%M%S_' + _ms), group.name) + shutil.move(rm_path, os.path.join(self.repos_path, _d)) + + def create(self, group_name, group_description, owner, just_db=False, + copy_permissions=False, commit_early=True): + + (group_name_cleaned, + parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name) + + parent_group = None + if parent_group_name: + parent_group = self._get_repo_group(parent_group_name) + + # becase we are doing a cleanup, we need to check if such directory + # already exists. If we don't do that we can accidentally delete existing + # directory via cleanup that can cause data issues, since delete does a + # folder rename to special syntax later cleanup functions can delete this + cleanup_group = self.check_exist_filesystem(group_name, + exc_on_failure=False) + try: + user = self._get_user(owner) + new_repo_group = RepoGroup() + new_repo_group.user = user + new_repo_group.group_description = group_description or group_name + new_repo_group.parent_group = parent_group + new_repo_group.group_name = group_name + + self.sa.add(new_repo_group) + + # create an ADMIN permission for owner except if we're super admin, + # later owner should go into the owner field of groups + if not user.is_admin: + self.grant_user_permission(repo_group=new_repo_group, + user=owner, perm='group.admin') + + if parent_group and copy_permissions: + # copy permissions from parent + user_perms = UserRepoGroupToPerm.query() \ + .filter(UserRepoGroupToPerm.group == parent_group).all() + + group_perms = UserGroupRepoGroupToPerm.query() \ + .filter(UserGroupRepoGroupToPerm.group == parent_group).all() + + for perm in user_perms: + # don't copy over the permission for user who is creating + # this group, if he is not super admin he get's admin + # permission set above + if perm.user != user or user.is_admin: + UserRepoGroupToPerm.create( + perm.user, new_repo_group, perm.permission) + + for perm in group_perms: + UserGroupRepoGroupToPerm.create( + perm.users_group, new_repo_group, perm.permission) + else: + perm_obj = self._create_default_perms(new_repo_group) + self.sa.add(perm_obj) + + # now commit the changes, earlier so we are sure everything is in + # the database. + if commit_early: + self.sa.commit() + if not just_db: + self._create_group(new_repo_group.group_name) + + # trigger the post hook + from rhodecode.lib.hooks_base import log_create_repository_group + repo_group = RepoGroup.get_by_group_name(group_name) + log_create_repository_group( + created_by=user.username, **repo_group.get_dict()) + + return new_repo_group + except Exception: + self.sa.rollback() + log.exception('Exception occurred when creating repository group, ' + 'doing cleanup...') + # rollback things manually ! + repo_group = RepoGroup.get_by_group_name(group_name) + if repo_group: + RepoGroup.delete(repo_group.group_id) + self.sa.commit() + if cleanup_group: + RepoGroupModel()._delete_filesystem_group(repo_group) + raise + + def update_permissions( + self, repo_group, perm_additions=None, perm_updates=None, + perm_deletions=None, recursive=None, check_perms=True, + cur_user=None): + from rhodecode.model.repo import RepoModel + from rhodecode.lib.auth import HasUserGroupPermissionAny + + if not perm_additions: + perm_additions = [] + if not perm_updates: + perm_updates = [] + if not perm_deletions: + perm_deletions = [] + + req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') + + def _set_perm_user(obj, user, perm): + if isinstance(obj, RepoGroup): + self.grant_user_permission( + repo_group=obj, user=user, perm=perm) + elif isinstance(obj, Repository): + # private repos will not allow to change the default + # permissions using recursive mode + if obj.private and user == User.DEFAULT_USER: + return + + # we set group permission but we have to switch to repo + # permission + perm = perm.replace('group.', 'repository.') + RepoModel().grant_user_permission( + repo=obj, user=user, perm=perm) + + def _set_perm_group(obj, users_group, perm): + if isinstance(obj, RepoGroup): + self.grant_user_group_permission( + repo_group=obj, group_name=users_group, perm=perm) + elif isinstance(obj, Repository): + # we set group permission but we have to switch to repo + # permission + perm = perm.replace('group.', 'repository.') + RepoModel().grant_user_group_permission( + repo=obj, group_name=users_group, perm=perm) + + def _revoke_perm_user(obj, user): + if isinstance(obj, RepoGroup): + self.revoke_user_permission(repo_group=obj, user=user) + elif isinstance(obj, Repository): + RepoModel().revoke_user_permission(repo=obj, user=user) + + def _revoke_perm_group(obj, user_group): + if isinstance(obj, RepoGroup): + self.revoke_user_group_permission( + repo_group=obj, group_name=user_group) + elif isinstance(obj, Repository): + RepoModel().revoke_user_group_permission( + repo=obj, group_name=user_group) + + # start updates + updates = [] + log.debug('Now updating permissions for %s in recursive mode:%s', + repo_group, recursive) + + # initialize check function, we'll call that multiple times + has_group_perm = HasUserGroupPermissionAny(*req_perms) + + for obj in repo_group.recursive_groups_and_repos(): + # iterated obj is an instance of a repos group or repository in + # that group, recursive option can be: none, repos, groups, all + if recursive == 'all': + obj = obj + elif recursive == 'repos': + # skip groups, other than this one + if isinstance(obj, RepoGroup) and not obj == repo_group: + continue + elif recursive == 'groups': + # skip repos + if isinstance(obj, Repository): + continue + else: # recursive == 'none': + # DEFAULT option - don't apply to iterated objects + # also we do a break at the end of this loop. if we are not + # in recursive mode + obj = repo_group + + # update permissions + for member_id, perm, member_type in perm_updates: + member_id = int(member_id) + if member_type == 'user': + # this updates also current one if found + _set_perm_user(obj, user=member_id, perm=perm) + else: # set for user group + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or has_group_perm(member_name, + user=cur_user): + _set_perm_group(obj, users_group=member_id, perm=perm) + + # set new permissions + for member_id, perm, member_type in perm_additions: + member_id = int(member_id) + if member_type == 'user': + _set_perm_user(obj, user=member_id, perm=perm) + else: # set for user group + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or has_group_perm(member_name, + user=cur_user): + _set_perm_group(obj, users_group=member_id, perm=perm) + + # delete permissions + for member_id, perm, member_type in perm_deletions: + member_id = int(member_id) + if member_type == 'user': + _revoke_perm_user(obj, user=member_id) + else: # set for user group + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or has_group_perm(member_name, + user=cur_user): + _revoke_perm_group(obj, user_group=member_id) + + updates.append(obj) + # if it's not recursive call for all,repos,groups + # break the loop and don't proceed with other changes + if recursive not in ['all', 'repos', 'groups']: + break + + return updates + + def update(self, repo_group, form_data): + try: + repo_group = self._get_repo_group(repo_group) + old_path = repo_group.full_path + + # change properties + if 'group_description' in form_data: + repo_group.group_description = form_data['group_description'] + + if 'enable_locking' in form_data: + repo_group.enable_locking = form_data['enable_locking'] + + if 'group_parent_id' in form_data: + parent_group = ( + self._get_repo_group(form_data['group_parent_id'])) + repo_group.group_parent_id = ( + parent_group.group_id if parent_group else None) + repo_group.parent_group = parent_group + + # mikhail: to update the full_path, we have to explicitly + # update group_name + group_name = form_data.get('group_name', repo_group.name) + repo_group.group_name = repo_group.get_new_name(group_name) + + new_path = repo_group.full_path + + if 'user' in form_data: + repo_group.user = User.get_by_username(form_data['user']) + + self.sa.add(repo_group) + + # iterate over all members of this groups and do fixes + # set locking if given + # if obj is a repoGroup also fix the name of the group according + # to the parent + # if obj is a Repo fix it's name + # this can be potentially heavy operation + for obj in repo_group.recursive_groups_and_repos(): + # set the value from it's parent + obj.enable_locking = repo_group.enable_locking + if isinstance(obj, RepoGroup): + new_name = obj.get_new_name(obj.name) + log.debug('Fixing group %s to new name %s', + obj.group_name, new_name) + obj.group_name = new_name + elif isinstance(obj, Repository): + # we need to get all repositories from this new group and + # rename them accordingly to new group path + new_name = obj.get_new_name(obj.just_name) + log.debug('Fixing repo %s to new name %s', + obj.repo_name, new_name) + obj.repo_name = new_name + self.sa.add(obj) + + self._rename_group(old_path, new_path) + + return repo_group + except Exception: + log.error(traceback.format_exc()) + raise + + def delete(self, repo_group, force_delete=False, fs_remove=True): + repo_group = self._get_repo_group(repo_group) + try: + self.sa.delete(repo_group) + if fs_remove: + self._delete_filesystem_group(repo_group, force_delete) + else: + log.debug('skipping removal from filesystem') + + except Exception: + log.error('Error removing repo_group %s', repo_group) + raise + + def grant_user_permission(self, repo_group, user, perm): + """ + Grant permission for user on given repository group, or update + existing one if found + + :param repo_group: Instance of RepoGroup, repositories_group_id, + or repositories_group name + :param user: Instance of User, user_id or username + :param perm: Instance of Permission, or permission_name + """ + + repo_group = self._get_repo_group(repo_group) + user = self._get_user(user) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserRepoGroupToPerm)\ + .filter(UserRepoGroupToPerm.user == user)\ + .filter(UserRepoGroupToPerm.group == repo_group)\ + .scalar() + if obj is None: + # create new ! + obj = UserRepoGroupToPerm() + obj.group = repo_group + obj.user = user + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s', perm, user, repo_group) + action_logger_generic( + 'granted permission: {} to user: {} on repogroup: {}'.format( + perm, user, repo_group), namespace='security.repogroup') + return obj + + def revoke_user_permission(self, repo_group, user): + """ + Revoke permission for user on given repository group + + :param repo_group: Instance of RepoGroup, repositories_group_id, + or repositories_group name + :param user: Instance of User, user_id or username + """ + + repo_group = self._get_repo_group(repo_group) + user = self._get_user(user) + + obj = self.sa.query(UserRepoGroupToPerm)\ + .filter(UserRepoGroupToPerm.user == user)\ + .filter(UserRepoGroupToPerm.group == repo_group)\ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm on %s on %s', repo_group, user) + action_logger_generic( + 'revoked permission from user: {} on repogroup: {}'.format( + user, repo_group), namespace='security.repogroup') + + def grant_user_group_permission(self, repo_group, group_name, perm): + """ + Grant permission for user group on given repository group, or update + existing one if found + + :param repo_group: Instance of RepoGroup, repositories_group_id, + or repositories_group name + :param group_name: Instance of UserGroup, users_group_id, + or user group name + :param perm: Instance of Permission, or permission_name + """ + repo_group = self._get_repo_group(repo_group) + group_name = self._get_user_group(group_name) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserGroupRepoGroupToPerm)\ + .filter(UserGroupRepoGroupToPerm.group == repo_group)\ + .filter(UserGroupRepoGroupToPerm.users_group == group_name)\ + .scalar() + + if obj is None: + # create new + obj = UserGroupRepoGroupToPerm() + + obj.group = repo_group + obj.users_group = group_name + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group) + action_logger_generic( + 'granted permission: {} to usergroup: {} on repogroup: {}'.format( + perm, group_name, repo_group), namespace='security.repogroup') + return obj + + def revoke_user_group_permission(self, repo_group, group_name): + """ + Revoke permission for user group on given repository group + + :param repo_group: Instance of RepoGroup, repositories_group_id, + or repositories_group name + :param group_name: Instance of UserGroup, users_group_id, + or user group name + """ + repo_group = self._get_repo_group(repo_group) + group_name = self._get_user_group(group_name) + + obj = self.sa.query(UserGroupRepoGroupToPerm)\ + .filter(UserGroupRepoGroupToPerm.group == repo_group)\ + .filter(UserGroupRepoGroupToPerm.users_group == group_name)\ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm to %s on %s', repo_group, group_name) + action_logger_generic( + 'revoked permission from usergroup: {} on repogroup: {}'.format( + group_name, repo_group), namespace='security.repogroup') + + def get_repo_groups_as_dict(self, repo_group_list=None, admin=False, + super_user_actions=False): + + from rhodecode.lib.utils import PartialRenderer + _render = PartialRenderer('data_table/_dt_elements.html') + c = _render.c + h = _render.h + + def quick_menu(repo_group_name): + return _render('quick_repo_group_menu', repo_group_name) + + def repo_group_lnk(repo_group_name): + return _render('repo_group_name', repo_group_name) + + def desc(desc): + if c.visual.stylify_metatags: + return h.urlify_text(h.escaped_stylize(h.truncate(desc, 60))) + else: + return h.urlify_text(h.html_escape(h.truncate(desc, 60))) + + def repo_group_actions(repo_group_id, repo_group_name, gr_count): + return _render( + 'repo_group_actions', repo_group_id, repo_group_name, gr_count) + + def repo_group_name(repo_group_name, children_groups): + return _render("repo_group_name", repo_group_name, children_groups) + + def user_profile(username): + return _render('user_profile', username) + + repo_group_data = [] + for group in repo_group_list: + + row = { + "menu": quick_menu(group.group_name), + "name": repo_group_lnk(group.group_name), + "name_raw": group.group_name, + "desc": desc(group.group_description), + "top_level_repos": 0, + "owner": user_profile(group.user.username) + } + if admin: + repo_count = group.repositories.count() + children_groups = map( + h.safe_unicode, + itertools.chain((g.name for g in group.parents), + (x.name for x in [group]))) + row.update({ + "action": repo_group_actions( + group.group_id, group.group_name, repo_count), + "top_level_repos": repo_count, + "name": repo_group_name(group.group_name, children_groups), + + }) + repo_group_data.append(row) + + return repo_group_data diff --git a/rhodecode/model/repo_permission.py b/rhodecode/model/repo_permission.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/repo_permission.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +repository permission model for RhodeCode +""" + +import logging +from rhodecode.model import BaseModel +from rhodecode.model.db import UserRepoToPerm, UserGroupRepoToPerm, \ + Permission + +log = logging.getLogger(__name__) + + +class RepositoryPermissionModel(BaseModel): + + cls = UserRepoToPerm + + def get_user_permission(self, repository, user): + repository = self._get_repo(repository) + user = self._get_user(user) + + return UserRepoToPerm.query() \ + .filter(UserRepoToPerm.user == user) \ + .filter(UserRepoToPerm.repository == repository) \ + .scalar() + + def update_user_permission(self, repository, user, permission): + permission = Permission.get_by_key(permission) + current = self.get_user_permission(repository, user) + if current: + if not current.permission is permission: + current.permission = permission + else: + p = UserRepoToPerm() + p.user = user + p.repository = repository + p.permission = permission + self.sa.add(p) + + def delete_user_permission(self, repository, user): + current = self.get_user_permission(repository, user) + if current: + self.sa.delete(current) + + def get_users_group_permission(self, repository, users_group): + return UserGroupRepoToPerm.query() \ + .filter(UserGroupRepoToPerm.users_group == users_group) \ + .filter(UserGroupRepoToPerm.repository == repository) \ + .scalar() + + def update_users_group_permission(self, repository, users_group, + permission): + permission = Permission.get_by_key(permission) + current = self.get_users_group_permission(repository, users_group) + if current: + if not current.permission is permission: + current.permission = permission + else: + p = UserGroupRepoToPerm() + p.users_group = users_group + p.repository = repository + p.permission = permission + self.sa.add(p) + + def delete_users_group_permission(self, repository, users_group): + current = self.get_users_group_permission(repository, users_group) + if current: + self.sa.delete(current) + + def update_or_delete_user_permission(self, repository, user, permission): + if permission: + self.update_user_permission(repository, user, permission) + else: + self.delete_user_permission(repository, user) + + def update_or_delete_users_group_permission(self, repository, user_group, + permission): + if permission: + self.update_users_group_permission(repository, user_group, + permission) + else: + self.delete_users_group_permission(repository, user_group) diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/scm.py @@ -0,0 +1,1105 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Scm model for RhodeCode +""" + +import os.path +import re +import sys +import time +import traceback +import logging +import cStringIO +import pkg_resources + +import pylons +from pylons.i18n.translation import _ +from sqlalchemy import func +from zope.cachedescriptors.property import Lazy as LazyProperty + +import rhodecode +from rhodecode.lib.vcs import get_backend +from rhodecode.lib.vcs.exceptions import RepositoryError, NodeNotChangedError +from rhodecode.lib.vcs.nodes import FileNode +from rhodecode.lib.vcs.backends.base import EmptyCommit +from rhodecode.lib import helpers as h + +from rhodecode.lib.auth import ( + HasRepoPermissionAny, HasRepoGroupPermissionAny, + HasUserGroupPermissionAny) +from rhodecode.lib.exceptions import NonRelativePathError, IMCCommitError +from rhodecode.lib import hooks_utils, caches +from rhodecode.lib.utils import ( + get_filesystem_repos, action_logger, make_db_config) +from rhodecode.lib.utils2 import ( + safe_str, safe_unicode, get_server_url, md5) +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + Repository, CacheKey, UserFollowing, UserLog, User, RepoGroup, + PullRequest, DbMigrateVersion) +from rhodecode.model.settings import VcsSettingsModel + +log = logging.getLogger(__name__) + + +class UserTemp(object): + def __init__(self, user_id): + self.user_id = user_id + + def __repr__(self): + return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id) + + +class RepoTemp(object): + def __init__(self, repo_id): + self.repo_id = repo_id + + def __repr__(self): + return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id) + + +class SimpleCachedRepoList(object): + """ + Lighter version of of iteration of repos without the scm initialisation, + and with cache usage + """ + def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None): + self.db_repo_list = db_repo_list + self.repos_path = repos_path + self.order_by = order_by + self.reversed = (order_by or '').startswith('-') + if not perm_set: + perm_set = ['repository.read', 'repository.write', + 'repository.admin'] + self.perm_set = perm_set + + def __len__(self): + return len(self.db_repo_list) + + def __repr__(self): + return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) + + def __iter__(self): + for dbr in self.db_repo_list: + # check permission at this level + has_perm = HasRepoPermissionAny(*self.perm_set)( + dbr.repo_name, 'SimpleCachedRepoList check') + if not has_perm: + continue + + tmp_d = { + 'name': dbr.repo_name, + 'dbrepo': dbr.get_dict(), + 'dbrepo_fork': dbr.fork.get_dict() if dbr.fork else {} + } + yield tmp_d + + +class _PermCheckIterator(object): + + def __init__( + self, obj_list, obj_attr, perm_set, perm_checker, + extra_kwargs=None): + """ + Creates iterator from given list of objects, additionally + checking permission for them from perm_set var + + :param obj_list: list of db objects + :param obj_attr: attribute of object to pass into perm_checker + :param perm_set: list of permissions to check + :param perm_checker: callable to check permissions against + """ + self.obj_list = obj_list + self.obj_attr = obj_attr + self.perm_set = perm_set + self.perm_checker = perm_checker + self.extra_kwargs = extra_kwargs or {} + + def __len__(self): + return len(self.obj_list) + + def __repr__(self): + return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) + + def __iter__(self): + checker = self.perm_checker(*self.perm_set) + for db_obj in self.obj_list: + # check permission at this level + name = getattr(db_obj, self.obj_attr, None) + if not checker(name, self.__class__.__name__, **self.extra_kwargs): + continue + + yield db_obj + + +class RepoList(_PermCheckIterator): + + def __init__(self, db_repo_list, perm_set=None, extra_kwargs=None): + if not perm_set: + perm_set = [ + 'repository.read', 'repository.write', 'repository.admin'] + + super(RepoList, self).__init__( + obj_list=db_repo_list, + obj_attr='repo_name', perm_set=perm_set, + perm_checker=HasRepoPermissionAny, + extra_kwargs=extra_kwargs) + + +class RepoGroupList(_PermCheckIterator): + + def __init__(self, db_repo_group_list, perm_set=None, extra_kwargs=None): + if not perm_set: + perm_set = ['group.read', 'group.write', 'group.admin'] + + super(RepoGroupList, self).__init__( + obj_list=db_repo_group_list, + obj_attr='group_name', perm_set=perm_set, + perm_checker=HasRepoGroupPermissionAny, + extra_kwargs=extra_kwargs) + + +class UserGroupList(_PermCheckIterator): + + def __init__(self, db_user_group_list, perm_set=None, extra_kwargs=None): + if not perm_set: + perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin'] + + super(UserGroupList, self).__init__( + obj_list=db_user_group_list, + obj_attr='users_group_name', perm_set=perm_set, + perm_checker=HasUserGroupPermissionAny, + extra_kwargs=extra_kwargs) + + +class ScmModel(BaseModel): + """ + Generic Scm Model + """ + + @LazyProperty + def repos_path(self): + """ + Gets the repositories root path from database + """ + + settings_model = VcsSettingsModel(sa=self.sa) + return settings_model.get_repos_location() + + def repo_scan(self, repos_path=None): + """ + Listing of repositories in given path. This path should not be a + repository itself. Return a dictionary of repository objects + + :param repos_path: path to directory containing repositories + """ + + if repos_path is None: + repos_path = self.repos_path + + log.info('scanning for repositories in %s', repos_path) + + config = make_db_config() + config.set('extensions', 'largefiles', '') + repos = {} + + for name, path in get_filesystem_repos(repos_path, recursive=True): + # name need to be decomposed and put back together using the / + # since this is internal storage separator for rhodecode + name = Repository.normalize_repo_name(name) + + try: + if name in repos: + raise RepositoryError('Duplicate repository name %s ' + 'found in %s' % (name, path)) + elif path[0] in rhodecode.BACKENDS: + klass = get_backend(path[0]) + repos[name] = klass(path[1], config=config) + except OSError: + continue + log.debug('found %s paths with repositories', len(repos)) + return repos + + def get_repos(self, all_repos=None, sort_key=None): + """ + Get all repositories from db and for each repo create it's + backend instance and fill that backed with information from database + + :param all_repos: list of repository names as strings + give specific repositories list, good for filtering + + :param sort_key: initial sorting of repositories + """ + if all_repos is None: + all_repos = self.sa.query(Repository)\ + .filter(Repository.group_id == None)\ + .order_by(func.lower(Repository.repo_name)).all() + repo_iter = SimpleCachedRepoList( + all_repos, repos_path=self.repos_path, order_by=sort_key) + return repo_iter + + def get_repo_groups(self, all_groups=None): + if all_groups is None: + all_groups = RepoGroup.query()\ + .filter(RepoGroup.group_parent_id == None).all() + return [x for x in RepoGroupList(all_groups)] + + def mark_for_invalidation(self, repo_name, delete=False): + """ + Mark caches of this repo invalid in the database. `delete` flag + removes the cache entries + + :param repo_name: the repo_name for which caches should be marked + invalid, or deleted + :param delete: delete the entry keys instead of setting bool + flag on them + """ + CacheKey.set_invalidate(repo_name, delete=delete) + repo = Repository.get_by_repo_name(repo_name) + + if repo: + config = repo._config + config.set('extensions', 'largefiles', '') + cs_cache = None + if delete: + # if we do a hard clear, reset last-commit to Empty + cs_cache = EmptyCommit() + repo.update_commit_cache(config=config, cs_cache=cs_cache) + caches.clear_repo_caches(repo_name) + + def toggle_following_repo(self, follow_repo_id, user_id): + + f = self.sa.query(UserFollowing)\ + .filter(UserFollowing.follows_repo_id == follow_repo_id)\ + .filter(UserFollowing.user_id == user_id).scalar() + + if f is not None: + try: + self.sa.delete(f) + action_logger(UserTemp(user_id), + 'stopped_following_repo', + RepoTemp(follow_repo_id)) + return + except Exception: + log.error(traceback.format_exc()) + raise + + try: + f = UserFollowing() + f.user_id = user_id + f.follows_repo_id = follow_repo_id + self.sa.add(f) + + action_logger(UserTemp(user_id), + 'started_following_repo', + RepoTemp(follow_repo_id)) + except Exception: + log.error(traceback.format_exc()) + raise + + def toggle_following_user(self, follow_user_id, user_id): + f = self.sa.query(UserFollowing)\ + .filter(UserFollowing.follows_user_id == follow_user_id)\ + .filter(UserFollowing.user_id == user_id).scalar() + + if f is not None: + try: + self.sa.delete(f) + return + except Exception: + log.error(traceback.format_exc()) + raise + + try: + f = UserFollowing() + f.user_id = user_id + f.follows_user_id = follow_user_id + self.sa.add(f) + except Exception: + log.error(traceback.format_exc()) + raise + + def is_following_repo(self, repo_name, user_id, cache=False): + r = self.sa.query(Repository)\ + .filter(Repository.repo_name == repo_name).scalar() + + f = self.sa.query(UserFollowing)\ + .filter(UserFollowing.follows_repository == r)\ + .filter(UserFollowing.user_id == user_id).scalar() + + return f is not None + + def is_following_user(self, username, user_id, cache=False): + u = User.get_by_username(username) + + f = self.sa.query(UserFollowing)\ + .filter(UserFollowing.follows_user == u)\ + .filter(UserFollowing.user_id == user_id).scalar() + + return f is not None + + def get_followers(self, repo): + repo = self._get_repo(repo) + + return self.sa.query(UserFollowing)\ + .filter(UserFollowing.follows_repository == repo).count() + + def get_forks(self, repo): + repo = self._get_repo(repo) + return self.sa.query(Repository)\ + .filter(Repository.fork == repo).count() + + def get_pull_requests(self, repo): + repo = self._get_repo(repo) + return self.sa.query(PullRequest)\ + .filter(PullRequest.target_repo == repo)\ + .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count() + + def mark_as_fork(self, repo, fork, user): + repo = self._get_repo(repo) + fork = self._get_repo(fork) + if fork and repo.repo_id == fork.repo_id: + raise Exception("Cannot set repository as fork of itself") + + if fork and repo.repo_type != fork.repo_type: + raise RepositoryError( + "Cannot set repository as fork of repository with other type") + + repo.fork = fork + self.sa.add(repo) + return repo + + def pull_changes(self, repo, username): + dbrepo = self._get_repo(repo) + clone_uri = dbrepo.clone_uri + if not clone_uri: + raise Exception("This repository doesn't have a clone uri") + + repo = dbrepo.scm_instance(cache=False) + # TODO: marcink fix this an re-enable since we need common logic + # for hg/git remove hooks so we don't trigger them on fetching + # commits from remote + repo.config.clear_section('hooks') + + repo_name = dbrepo.repo_name + try: + # TODO: we need to make sure those operations call proper hooks ! + repo.pull(clone_uri) + + self.mark_for_invalidation(repo_name) + except Exception: + log.error(traceback.format_exc()) + raise + + def commit_change(self, repo, repo_name, commit, user, author, message, + content, f_path): + """ + Commits changes + + :param repo: SCM instance + + """ + user = self._get_user(user) + + # decoding here will force that we have proper encoded values + # in any other case this will throw exceptions and deny commit + content = safe_str(content) + path = safe_str(f_path) + # message and author needs to be unicode + # proper backend should then translate that into required type + message = safe_unicode(message) + author = safe_unicode(author) + imc = repo.in_memory_commit + imc.change(FileNode(path, content, mode=commit.get_file_mode(f_path))) + try: + # TODO: handle pre-push action ! + tip = imc.commit( + message=message, author=author, parents=[commit], + branch=commit.branch) + except Exception as e: + log.error(traceback.format_exc()) + raise IMCCommitError(str(e)) + finally: + # always clear caches, if commit fails we want fresh object also + self.mark_for_invalidation(repo_name) + + # We trigger the post-push action + hooks_utils.trigger_post_push_hook( + username=user.username, action='push_local', repo_name=repo_name, + repo_alias=repo.alias, commit_ids=[tip.raw_id]) + return tip + + def _sanitize_path(self, f_path): + if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path: + raise NonRelativePathError('%s is not an relative path' % f_path) + if f_path: + f_path = os.path.normpath(f_path) + return f_path + + def get_dirnode_metadata(self, commit, dir_node): + if not dir_node.is_dir(): + return [] + + data = [] + for node in dir_node: + if not node.is_file(): + # we skip file-nodes + continue + + last_commit = node.last_commit + last_commit_date = last_commit.date + data.append({ + 'name': node.name, + 'size': h.format_byte_size_binary(node.size), + 'modified_at': h.format_date(last_commit_date), + 'modified_ts': last_commit_date.isoformat(), + 'revision': last_commit.revision, + 'short_id': last_commit.short_id, + 'message': h.escape(last_commit.message), + 'author': h.escape(last_commit.author), + 'user_profile': h.gravatar_with_user(last_commit.author), + }) + + return data + + def get_nodes(self, repo_name, commit_id, root_path='/', flat=True, + extended_info=False, content=False): + """ + recursive walk in root dir and return a set of all path in that dir + based on repository walk function + + :param repo_name: name of repository + :param commit_id: commit id for which to list nodes + :param root_path: root path to list + :param flat: return as a list, if False returns a dict with decription + + """ + _files = list() + _dirs = list() + try: + _repo = self._get_repo(repo_name) + commit = _repo.scm_instance().get_commit(commit_id=commit_id) + root_path = root_path.lstrip('/') + for __, dirs, files in commit.walk(root_path): + for f in files: + _content = None + _data = f.unicode_path + if not flat: + _data = { + "name": f.unicode_path, + "type": "file", + } + if extended_info: + _content = safe_str(f.content) + _data.update({ + "md5": md5(_content), + "binary": f.is_binary, + "size": f.size, + "extension": f.extension, + + "mimetype": f.mimetype, + "lines": f.lines()[0] + }) + if content: + full_content = None + if not f.is_binary: + # in case we loaded the _content already + # re-use it, or load from f[ile] + full_content = _content or safe_str(f.content) + + _data.update({ + "content": full_content + }) + _files.append(_data) + for d in dirs: + _data = d.unicode_path + if not flat: + _data = { + "name": d.unicode_path, + "type": "dir", + } + if extended_info: + _data.update({ + "md5": None, + "binary": None, + "size": None, + "extension": None, + }) + if content: + _data.update({ + "content": None + }) + _dirs.append(_data) + except RepositoryError: + log.debug("Exception in get_nodes", exc_info=True) + raise + + return _dirs, _files + + def create_nodes(self, user, repo, message, nodes, parent_commit=None, + author=None, trigger_push_hook=True): + """ + Commits given multiple nodes into repo + + :param user: RhodeCode User object or user_id, the commiter + :param repo: RhodeCode Repository object + :param message: commit message + :param nodes: mapping {filename:{'content':content},...} + :param parent_commit: parent commit, can be empty than it's + initial commit + :param author: author of commit, cna be different that commiter + only for git + :param trigger_push_hook: trigger push hooks + + :returns: new commited commit + """ + + user = self._get_user(user) + scm_instance = repo.scm_instance(cache=False) + + processed_nodes = [] + for f_path in nodes: + f_path = self._sanitize_path(f_path) + content = nodes[f_path]['content'] + f_path = safe_str(f_path) + # decoding here will force that we have proper encoded values + # in any other case this will throw exceptions and deny commit + if isinstance(content, (basestring,)): + content = safe_str(content) + elif isinstance(content, (file, cStringIO.OutputType,)): + content = content.read() + else: + raise Exception('Content is of unrecognized type %s' % ( + type(content) + )) + processed_nodes.append((f_path, content)) + + message = safe_unicode(message) + commiter = user.full_contact + author = safe_unicode(author) if author else commiter + + imc = scm_instance.in_memory_commit + + if not parent_commit: + parent_commit = EmptyCommit(alias=scm_instance.alias) + + if isinstance(parent_commit, EmptyCommit): + # EmptyCommit means we we're editing empty repository + parents = None + else: + parents = [parent_commit] + # add multiple nodes + for path, content in processed_nodes: + imc.add(FileNode(path, content=content)) + # TODO: handle pre push scenario + tip = imc.commit(message=message, + author=author, + parents=parents, + branch=parent_commit.branch) + + self.mark_for_invalidation(repo.repo_name) + if trigger_push_hook: + hooks_utils.trigger_post_push_hook( + username=user.username, action='push_local', + repo_name=repo.repo_name, repo_alias=scm_instance.alias, + commit_ids=[tip.raw_id]) + return tip + + def update_nodes(self, user, repo, message, nodes, parent_commit=None, + author=None, trigger_push_hook=True): + user = self._get_user(user) + scm_instance = repo.scm_instance(cache=False) + + message = safe_unicode(message) + commiter = user.full_contact + author = safe_unicode(author) if author else commiter + + imc = scm_instance.in_memory_commit + + if not parent_commit: + parent_commit = EmptyCommit(alias=scm_instance.alias) + + if isinstance(parent_commit, EmptyCommit): + # EmptyCommit means we we're editing empty repository + parents = None + else: + parents = [parent_commit] + + # add multiple nodes + for _filename, data in nodes.items(): + # new filename, can be renamed from the old one, also sanitaze + # the path for any hack around relative paths like ../../ etc. + filename = self._sanitize_path(data['filename']) + old_filename = self._sanitize_path(_filename) + content = data['content'] + + filenode = FileNode(old_filename, content=content) + op = data['op'] + if op == 'add': + imc.add(filenode) + elif op == 'del': + imc.remove(filenode) + elif op == 'mod': + if filename != old_filename: + # TODO: handle renames more efficient, needs vcs lib + # changes + imc.remove(filenode) + imc.add(FileNode(filename, content=content)) + else: + imc.change(filenode) + + try: + # TODO: handle pre push scenario + # commit changes + tip = imc.commit(message=message, + author=author, + parents=parents, + branch=parent_commit.branch) + except NodeNotChangedError: + raise + except Exception as e: + log.exception("Unexpected exception during call to imc.commit") + raise IMCCommitError(str(e)) + finally: + # always clear caches, if commit fails we want fresh object also + self.mark_for_invalidation(repo.repo_name) + + if trigger_push_hook: + hooks_utils.trigger_post_push_hook( + username=user.username, action='push_local', + repo_name=repo.repo_name, repo_alias=scm_instance.alias, + commit_ids=[tip.raw_id]) + + def delete_nodes(self, user, repo, message, nodes, parent_commit=None, + author=None, trigger_push_hook=True): + """ + Deletes given multiple nodes into `repo` + + :param user: RhodeCode User object or user_id, the committer + :param repo: RhodeCode Repository object + :param message: commit message + :param nodes: mapping {filename:{'content':content},...} + :param parent_commit: parent commit, can be empty than it's initial + commit + :param author: author of commit, cna be different that commiter only + for git + :param trigger_push_hook: trigger push hooks + + :returns: new commit after deletion + """ + + user = self._get_user(user) + scm_instance = repo.scm_instance(cache=False) + + processed_nodes = [] + for f_path in nodes: + f_path = self._sanitize_path(f_path) + # content can be empty but for compatabilty it allows same dicts + # structure as add_nodes + content = nodes[f_path].get('content') + processed_nodes.append((f_path, content)) + + message = safe_unicode(message) + commiter = user.full_contact + author = safe_unicode(author) if author else commiter + + imc = scm_instance.in_memory_commit + + if not parent_commit: + parent_commit = EmptyCommit(alias=scm_instance.alias) + + if isinstance(parent_commit, EmptyCommit): + # EmptyCommit means we we're editing empty repository + parents = None + else: + parents = [parent_commit] + # add multiple nodes + for path, content in processed_nodes: + imc.remove(FileNode(path, content=content)) + + # TODO: handle pre push scenario + tip = imc.commit(message=message, + author=author, + parents=parents, + branch=parent_commit.branch) + + self.mark_for_invalidation(repo.repo_name) + if trigger_push_hook: + hooks_utils.trigger_post_push_hook( + username=user.username, action='push_local', + repo_name=repo.repo_name, repo_alias=scm_instance.alias, + commit_ids=[tip.raw_id]) + return tip + + def strip(self, repo, commit_id, branch): + scm_instance = repo.scm_instance(cache=False) + scm_instance.config.clear_section('hooks') + scm_instance.strip(commit_id, branch) + self.mark_for_invalidation(repo.repo_name) + + def get_unread_journal(self): + return self.sa.query(UserLog).count() + + def get_repo_landing_revs(self, repo=None): + """ + Generates select option with tags branches and bookmarks (for hg only) + grouped by type + + :param repo: + """ + + hist_l = [] + choices = [] + repo = self._get_repo(repo) + hist_l.append(['rev:tip', _('latest tip')]) + choices.append('rev:tip') + if not repo: + return choices, hist_l + + repo = repo.scm_instance() + + branches_group = ( + [(u'branch:%s' % safe_unicode(b), safe_unicode(b)) + for b in repo.branches], + _("Branches")) + hist_l.append(branches_group) + choices.extend([x[0] for x in branches_group[0]]) + + if repo.alias == 'hg': + bookmarks_group = ( + [(u'book:%s' % safe_unicode(b), safe_unicode(b)) + for b in repo.bookmarks], + _("Bookmarks")) + hist_l.append(bookmarks_group) + choices.extend([x[0] for x in bookmarks_group[0]]) + + tags_group = ( + [(u'tag:%s' % safe_unicode(t), safe_unicode(t)) + for t in repo.tags], + _("Tags")) + hist_l.append(tags_group) + choices.extend([x[0] for x in tags_group[0]]) + + return choices, hist_l + + def install_git_hook(self, repo, force_create=False): + """ + Creates a rhodecode hook inside a git repository + + :param repo: Instance of VCS repo + :param force_create: Create even if same name hook exists + """ + + loc = os.path.join(repo.path, 'hooks') + if not repo.bare: + loc = os.path.join(repo.path, '.git', 'hooks') + if not os.path.isdir(loc): + os.makedirs(loc, mode=0777) + + tmpl_post = pkg_resources.resource_string( + 'rhodecode', '/'.join( + ('config', 'hook_templates', 'git_post_receive.py.tmpl'))) + tmpl_pre = pkg_resources.resource_string( + 'rhodecode', '/'.join( + ('config', 'hook_templates', 'git_pre_receive.py.tmpl'))) + + for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]: + _hook_file = os.path.join(loc, '%s-receive' % h_type) + log.debug('Installing git hook in repo %s', repo) + _rhodecode_hook = _check_rhodecode_hook(_hook_file) + + if _rhodecode_hook or force_create: + log.debug('writing %s hook file !', h_type) + try: + with open(_hook_file, 'wb') as f: + tmpl = tmpl.replace('_TMPL_', rhodecode.__version__) + tmpl = tmpl.replace('_ENV_', sys.executable) + f.write(tmpl) + os.chmod(_hook_file, 0755) + except IOError: + log.exception('error writing hook file %s', _hook_file) + else: + log.debug('skipping writing hook file') + + def install_svn_hooks(self, repo, force_create=False): + """ + Creates rhodecode hooks inside a svn repository + + :param repo: Instance of VCS repo + :param force_create: Create even if same name hook exists + """ + hooks_path = os.path.join(repo.path, 'hooks') + if not os.path.isdir(hooks_path): + os.makedirs(hooks_path) + post_commit_tmpl = pkg_resources.resource_string( + 'rhodecode', '/'.join( + ('config', 'hook_templates', 'svn_post_commit_hook.py.tmpl'))) + pre_commit_template = pkg_resources.resource_string( + 'rhodecode', '/'.join( + ('config', 'hook_templates', 'svn_pre_commit_hook.py.tmpl'))) + templates = { + 'post-commit': post_commit_tmpl, + 'pre-commit': pre_commit_template + } + for filename in templates: + _hook_file = os.path.join(hooks_path, filename) + _rhodecode_hook = _check_rhodecode_hook(_hook_file) + if _rhodecode_hook or force_create: + log.debug('writing %s hook file !', filename) + template = templates[filename] + try: + with open(_hook_file, 'wb') as f: + template = template.replace( + '_TMPL_', rhodecode.__version__) + template = template.replace('_ENV_', sys.executable) + f.write(template) + os.chmod(_hook_file, 0755) + except IOError: + log.exception('error writing hook file %s', filename) + else: + log.debug('skipping writing hook file') + + def install_hooks(self, repo, repo_type): + if repo_type == 'git': + self.install_git_hook(repo) + elif repo_type == 'svn': + self.install_svn_hooks(repo) + + def get_server_info(self, environ=None): + import platform + import rhodecode + import pkg_resources + from rhodecode.model.meta import Base as sql_base, Session + from sqlalchemy.engine import url + from rhodecode.lib.base import get_server_ip_addr, get_server_port + from rhodecode.lib.vcs.backends.git import discover_git_version + from rhodecode.model.gist import GIST_STORE_LOC + + try: + # cygwin cannot have yet psutil support. + import psutil + except ImportError: + psutil = None + + environ = environ or {} + _NA = 'NOT AVAILABLE' + _memory = _NA + _uptime = _NA + _boot_time = _NA + _cpu = _NA + _disk = dict(percent=0, used=0, total=0, error='') + _load = {'1_min': _NA, '5_min': _NA, '15_min': _NA} + + model = VcsSettingsModel() + storage_path = model.get_repos_location() + gist_storage_path = os.path.join(storage_path, GIST_STORE_LOC) + archive_storage_path = rhodecode.CONFIG.get('archive_cache_dir', '') + search_index_storage_path = rhodecode.CONFIG.get('search.location', '') + + if psutil: + # disk storage + try: + _disk = dict(psutil.disk_usage(storage_path)._asdict()) + except Exception as e: + log.exception('Failed to fetch disk info') + _disk = {'percent': 0, 'used': 0, 'total': 0, 'error': str(e)} + + # memory + _memory = dict(psutil.virtual_memory()._asdict()) + _memory['percent2'] = psutil._common.usage_percent( + (_memory['total'] - _memory['free']), + _memory['total'], 1) + + # load averages + if hasattr(psutil.os, 'getloadavg'): + _load = dict(zip( + ['1_min', '5_min', '15_min'], psutil.os.getloadavg())) + _uptime = time.time() - psutil.boot_time() + _boot_time = psutil.boot_time() + _cpu = psutil.cpu_percent(0.5) + + mods = dict([(p.project_name, p.version) + for p in pkg_resources.working_set]) + + def get_storage_size(storage_path): + sizes = [] + for file_ in os.listdir(storage_path): + storage_file = os.path.join(storage_path, file_) + if os.path.isfile(storage_file): + try: + sizes.append(os.path.getsize(storage_file)) + except OSError: + log.exception('Failed to get size of storage file %s', + storage_file) + pass + + return sum(sizes) + + # archive cache storage + _disk_archive = {'percent': 0, 'used': 0, 'total': 0} + try: + archive_storage_path_exists = os.path.isdir( + archive_storage_path) + if archive_storage_path and archive_storage_path_exists: + used = get_storage_size(archive_storage_path) + _disk_archive.update({ + 'used': used, + 'total': used, + }) + except Exception as e: + log.exception('failed to fetch archive cache storage') + _disk_archive['error'] = str(e) + + # search index storage + _disk_index = {'percent': 0, 'used': 0, 'total': 0} + try: + search_index_storage_path_exists = os.path.isdir( + search_index_storage_path) + if search_index_storage_path_exists: + used = get_storage_size(search_index_storage_path) + _disk_index.update({ + 'percent': 100, + 'used': used, + 'total': used, + }) + except Exception as e: + log.exception('failed to fetch search index storage') + _disk_index['error'] = str(e) + + # gist storage + _disk_gist = {'percent': 0, 'used': 0, 'total': 0, 'items': 0} + try: + items_count = 0 + used = 0 + for root, dirs, files in os.walk(safe_str(gist_storage_path)): + if root == gist_storage_path: + items_count = len(dirs) + + for f in files: + try: + used += os.path.getsize(os.path.join(root, f)) + except OSError: + pass + _disk_gist.update({ + 'percent': 100, + 'used': used, + 'total': used, + 'items': items_count + }) + except Exception as e: + log.exception('failed to fetch gist storage items') + _disk_gist['error'] = str(e) + + # GIT info + git_ver = discover_git_version() + + # SVN info + # TODO: johbo: Add discover_svn_version to replace this code. + try: + import svn.core + svn_ver = svn.core.SVN_VERSION + except ImportError: + svn_ver = None + + # DB stuff + db_info = url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url']) + db_type = db_info.__to_string__() + try: + engine = sql_base.metadata.bind + db_server_info = engine.dialect._get_server_version_info( + Session.connection(bind=engine)) + db_version = '%s %s' % (db_info.drivername, + '.'.join(map(str, db_server_info))) + except Exception: + log.exception('failed to fetch db version') + db_version = '%s %s' % (db_info.drivername, '?') + + db_migrate = DbMigrateVersion.query().filter( + DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one() + db_migrate_version = db_migrate.version + + info = { + 'py_version': ' '.join(platform._sys_version()), + 'py_path': sys.executable, + 'py_modules': sorted(mods.items(), key=lambda k: k[0].lower()), + + 'platform': safe_unicode(platform.platform()), + 'storage': storage_path, + 'archive_storage': archive_storage_path, + 'index_storage': search_index_storage_path, + 'gist_storage': gist_storage_path, + + + 'db_type': db_type, + 'db_version': db_version, + 'db_migrate_version': db_migrate_version, + + 'rhodecode_version': rhodecode.__version__, + 'rhodecode_config_ini': rhodecode.CONFIG.get('__file__'), + 'server_ip': '%s:%s' % ( + get_server_ip_addr(environ, log_errors=False), + get_server_port(environ) + ), + 'server_id': rhodecode.CONFIG.get('instance_id'), + + 'git_version': safe_unicode(git_ver), + 'hg_version': mods.get('mercurial'), + 'svn_version': svn_ver, + + 'uptime': _uptime, + 'boot_time': _boot_time, + 'load': _load, + 'cpu': _cpu, + 'memory': _memory, + 'disk': _disk, + 'disk_archive': _disk_archive, + 'disk_gist': _disk_gist, + 'disk_index': _disk_index, + } + return info + + +def _check_rhodecode_hook(hook_path): + """ + Check if the hook was created by RhodeCode + """ + if not os.path.exists(hook_path): + return True + + log.debug('hook exists, checking if it is from rhodecode') + hook_content = _read_hook(hook_path) + matches = re.search(r'(?:RC_HOOK_VER)\s*=\s*(.*)', hook_content) + if matches: + try: + version = matches.groups()[0] + log.debug('got %s, it is rhodecode', version) + return True + except Exception: + log.exception("Exception while reading the hook version.") + + return False + + +def _read_hook(hook_path): + with open(hook_path, 'rb') as f: + content = f.read() + return content diff --git a/rhodecode/model/settings.py b/rhodecode/model/settings.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/settings.py @@ -0,0 +1,681 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import hashlib +import logging +from collections import namedtuple +from functools import wraps + +from rhodecode.lib.caching_query import FromCache +from rhodecode.lib.utils2 import ( + Optional, AttributeDict, safe_str, remove_prefix, str2bool) +from rhodecode.model import BaseModel +from rhodecode.model.db import ( + RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting) +from rhodecode.model.meta import Session + + +log = logging.getLogger(__name__) + + +UiSetting = namedtuple( + 'UiSetting', ['section', 'key', 'value', 'active']) + +SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google'] + + +class SettingNotFound(Exception): + def __init__(self): + super(SettingNotFound, self).__init__('Setting is not found') + + +class SettingsModel(BaseModel): + BUILTIN_HOOKS = ( + RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH, + RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PULL, + RhodeCodeUi.HOOK_PRE_PULL) + HOOKS_SECTION = 'hooks' + + def __init__(self, sa=None, repo=None): + self.repo = repo + self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi + self.SettingsDbModel = ( + RepoRhodeCodeSetting if repo else RhodeCodeSetting) + super(SettingsModel, self).__init__(sa) + + def get_ui_by_key(self, key): + q = self.UiDbModel.query() + q = q.filter(self.UiDbModel.ui_key == key) + q = self._filter_by_repo(RepoRhodeCodeUi, q) + return q.scalar() + + def get_ui_by_section(self, section): + q = self.UiDbModel.query() + q = q.filter(self.UiDbModel.ui_section == section) + q = self._filter_by_repo(RepoRhodeCodeUi, q) + return q.all() + + def get_ui_by_section_and_key(self, section, key): + q = self.UiDbModel.query() + q = q.filter(self.UiDbModel.ui_section == section) + q = q.filter(self.UiDbModel.ui_key == key) + q = self._filter_by_repo(RepoRhodeCodeUi, q) + return q.scalar() + + def get_ui(self, section=None, key=None): + q = self.UiDbModel.query() + q = self._filter_by_repo(RepoRhodeCodeUi, q) + + if section: + q = q.filter(self.UiDbModel.ui_section == section) + if key: + q = q.filter(self.UiDbModel.ui_key == key) + + # TODO: mikhail: add caching + result = [ + UiSetting( + section=safe_str(r.ui_section), key=safe_str(r.ui_key), + value=safe_str(r.ui_value), active=r.ui_active + ) + for r in q.all() + ] + return result + + def get_builtin_hooks(self): + q = self.UiDbModel.query() + q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS)) + return self._get_hooks(q) + + def get_custom_hooks(self): + q = self.UiDbModel.query() + q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS)) + return self._get_hooks(q) + + def create_ui_section_value(self, section, val, key=None, active=True): + new_ui = self.UiDbModel() + new_ui.ui_section = section + new_ui.ui_value = val + new_ui.ui_active = active + + if self.repo: + repo = self._get_repo(self.repo) + repository_id = repo.repo_id + new_ui.repository_id = repository_id + + if not key: + # keys are unique so they need appended info + if self.repo: + key = hashlib.sha1( + '{}{}{}'.format(section, val, repository_id)).hexdigest() + else: + key = hashlib.sha1('{}{}'.format(section, val)).hexdigest() + + new_ui.ui_key = key + + Session().add(new_ui) + return new_ui + + def create_or_update_hook(self, key, value): + ui = ( + self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or + self.UiDbModel()) + ui.ui_section = self.HOOKS_SECTION + ui.ui_active = True + ui.ui_key = key + ui.ui_value = value + + if self.repo: + repo = self._get_repo(self.repo) + repository_id = repo.repo_id + ui.repository_id = repository_id + + Session().add(ui) + return ui + + def delete_ui(self, id_): + ui = self.UiDbModel.get(id_) + if not ui: + raise SettingNotFound() + Session().delete(ui) + + def get_setting_by_name(self, name): + q = self._get_settings_query() + q = q.filter(self.SettingsDbModel.app_settings_name == name) + return q.scalar() + + def create_or_update_setting( + self, name, val=Optional(''), type_=Optional('unicode')): + """ + Creates or updates RhodeCode setting. If updates is triggered it will + only update parameters that are explicityl set Optional instance will + be skipped + + :param name: + :param val: + :param type_: + :return: + """ + + res = self.get_setting_by_name(name) + repo = self._get_repo(self.repo) if self.repo else None + + if not res: + val = Optional.extract(val) + type_ = Optional.extract(type_) + + args = ( + (repo.repo_id, name, val, type_) + if repo else (name, val, type_)) + res = self.SettingsDbModel(*args) + + else: + if self.repo: + res.repository_id = repo.repo_id + + res.app_settings_name = name + if not isinstance(type_, Optional): + # update if set + res.app_settings_type = type_ + if not isinstance(val, Optional): + # update if set + res.app_settings_value = val + + Session.add(res) + return res + + def get_all_settings(self, cache=False): + q = self._get_settings_query() + if cache: + repo = self._get_repo(self.repo) if self.repo else None + cache_key = ( + "get_repo_{}_settings".format(repo.repo_id) + if repo else "get_hg_settings") + q = q.options(FromCache("sql_cache_short", cache_key)) + + if not q: + raise Exception('Could not get application settings !') + + settings = { + 'rhodecode_' + result.app_settings_name: result.app_settings_value + for result in q + } + return settings + + def get_auth_settings(self): + q = self._get_settings_query() + q = q.filter( + self.SettingsDbModel.app_settings_name.startswith('auth_')) + rows = q.all() + auth_settings = { + row.app_settings_name: row.app_settings_value for row in rows} + return auth_settings + + def get_auth_plugins(self): + auth_plugins = self.get_setting_by_name("auth_plugins") + return auth_plugins.app_settings_value + + def get_default_repo_settings(self, strip_prefix=False): + q = self._get_settings_query() + q = q.filter( + self.SettingsDbModel.app_settings_name.startswith('default_')) + rows = q.all() + + result = {} + for row in rows: + key = row.app_settings_name + if strip_prefix: + key = remove_prefix(key, prefix='default_') + result.update({key: row.app_settings_value}) + return result + + def get_repo(self): + repo = self._get_repo(self.repo) + if not repo: + raise Exception( + 'Repository {} cannot be found'.format(self.repo)) + return repo + + def _filter_by_repo(self, model, query): + if self.repo: + repo = self.get_repo() + query = query.filter(model.repository_id == repo.repo_id) + return query + + def _get_hooks(self, query): + query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION) + query = self._filter_by_repo(RepoRhodeCodeUi, query) + return query.all() + + def _get_settings_query(self): + q = self.SettingsDbModel.query() + return self._filter_by_repo(RepoRhodeCodeSetting, q) + + def list_enabled_social_plugins(self, settings): + enabled = [] + for plug in SOCIAL_PLUGINS_LIST: + if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug) + )): + enabled.append(plug) + return enabled + + +def assert_repo_settings(func): + @wraps(func) + def _wrapper(self, *args, **kwargs): + if not self.repo_settings: + raise Exception('Repository is not specified') + return func(self, *args, **kwargs) + return _wrapper + + +class IssueTrackerSettingsModel(object): + INHERIT_SETTINGS = 'inherit_issue_tracker_settings' + SETTINGS_PREFIX = 'issuetracker_' + + def __init__(self, sa=None, repo=None): + self.global_settings = SettingsModel(sa=sa) + self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None + + @property + def inherit_global_settings(self): + if not self.repo_settings: + return True + setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS) + return setting.app_settings_value if setting else True + + @inherit_global_settings.setter + def inherit_global_settings(self, value): + if self.repo_settings: + settings = self.repo_settings.create_or_update_setting( + self.INHERIT_SETTINGS, value, type_='bool') + Session().add(settings) + + def _get_keyname(self, key, uid, prefix=''): + return '{0}{1}{2}_{3}'.format( + prefix, self.SETTINGS_PREFIX, key, uid) + + def _make_dict_for_settings(self, qs): + prefix_match = self._get_keyname('pat', '', 'rhodecode_') + + issuetracker_entries = {} + # create keys + for k, v in qs.items(): + if k.startswith(prefix_match): + uid = k[len(prefix_match):] + issuetracker_entries[uid] = None + + # populate + for uid in issuetracker_entries: + issuetracker_entries[uid] = AttributeDict({ + 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')), + 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')), + 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')), + 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')), + }) + return issuetracker_entries + + def get_global_settings(self, cache=False): + """ + Returns list of global issue tracker settings + """ + defaults = self.global_settings.get_all_settings(cache=cache) + settings = self._make_dict_for_settings(defaults) + return settings + + def get_repo_settings(self, cache=False): + """ + Returns list of issue tracker settings per repository + """ + if not self.repo_settings: + raise Exception('Repository is not specified') + all_settings = self.repo_settings.get_all_settings(cache=cache) + settings = self._make_dict_for_settings(all_settings) + return settings + + def get_settings(self, cache=False): + if self.inherit_global_settings: + return self.get_global_settings(cache=cache) + else: + return self.get_repo_settings(cache=cache) + + def delete_entries(self, uid): + if self.repo_settings: + all_patterns = self.get_repo_settings() + settings_model = self.repo_settings + else: + all_patterns = self.get_global_settings() + settings_model = self.global_settings + entries = all_patterns.get(uid) + + for del_key in entries: + setting_name = self._get_keyname(del_key, uid) + entry = settings_model.get_setting_by_name(setting_name) + if entry: + Session().delete(entry) + + Session().commit() + + def create_or_update_setting( + self, name, val=Optional(''), type_=Optional('unicode')): + if self.repo_settings: + setting = self.repo_settings.create_or_update_setting( + name, val, type_) + else: + setting = self.global_settings.create_or_update_setting( + name, val, type_) + return setting + + +class VcsSettingsModel(object): + + INHERIT_SETTINGS = 'inherit_vcs_settings' + GENERAL_SETTINGS = ('use_outdated_comments', 'pr_merge_enabled') + HOOKS_SETTINGS = ( + ('hooks', 'changegroup.repo_size'), + ('hooks', 'changegroup.push_logger'), + ('hooks', 'outgoing.pull_logger')) + HG_SETTINGS = ( + ('extensions', 'largefiles'), ('phases', 'publish')) + GLOBAL_HG_SETTINGS = HG_SETTINGS + (('extensions', 'hgsubversion'), ) + SVN_BRANCH_SECTION = 'vcs_svn_branch' + SVN_TAG_SECTION = 'vcs_svn_tag' + SSL_SETTING = ('web', 'push_ssl') + PATH_SETTING = ('paths', '/') + + def __init__(self, sa=None, repo=None): + self.global_settings = SettingsModel(sa=sa) + self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None + self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS + self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION) + + @property + @assert_repo_settings + def inherit_global_settings(self): + setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS) + return setting.app_settings_value if setting else True + + @inherit_global_settings.setter + @assert_repo_settings + def inherit_global_settings(self, value): + self.repo_settings.create_or_update_setting( + self.INHERIT_SETTINGS, value, type_='bool') + + def get_global_svn_branch_patterns(self): + return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION) + + @assert_repo_settings + def get_repo_svn_branch_patterns(self): + return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION) + + def get_global_svn_tag_patterns(self): + return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION) + + @assert_repo_settings + def get_repo_svn_tag_patterns(self): + return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION) + + def get_global_settings(self): + return self._collect_all_settings(global_=True) + + @assert_repo_settings + def get_repo_settings(self): + return self._collect_all_settings(global_=False) + + @assert_repo_settings + def create_or_update_repo_settings( + self, data, inherit_global_settings=False): + from rhodecode.model.scm import ScmModel + + self.inherit_global_settings = inherit_global_settings + + repo = self.repo_settings.get_repo() + if not inherit_global_settings: + if repo.repo_type == 'svn': + self.create_repo_svn_settings(data) + else: + self.create_or_update_repo_hook_settings(data) + self.create_or_update_repo_pr_settings(data) + + if repo.repo_type == 'hg': + self.create_or_update_repo_hg_settings(data) + + ScmModel().mark_for_invalidation(repo.repo_name, delete=True) + + @assert_repo_settings + def create_or_update_repo_hook_settings(self, data): + for section, key in self.HOOKS_SETTINGS: + data_key = self._get_form_ui_key(section, key) + if data_key not in data: + raise ValueError( + 'The given data does not contain {} key'.format(data_key)) + + active = data.get(data_key) + repo_setting = self.repo_settings.get_ui_by_section_and_key( + section, key) + if not repo_setting: + global_setting = self.global_settings.\ + get_ui_by_section_and_key(section, key) + self.repo_settings.create_ui_section_value( + section, global_setting.ui_value, key=key, active=active) + else: + repo_setting.ui_active = active + Session().add(repo_setting) + + def update_global_hook_settings(self, data): + for section, key in self.HOOKS_SETTINGS: + data_key = self._get_form_ui_key(section, key) + if data_key not in data: + raise ValueError( + 'The given data does not contain {} key'.format(data_key)) + active = data.get(data_key) + repo_setting = self.global_settings.get_ui_by_section_and_key( + section, key) + repo_setting.ui_active = active + Session().add(repo_setting) + + @assert_repo_settings + def create_or_update_repo_pr_settings(self, data): + return self._create_or_update_general_settings( + self.repo_settings, data) + + def create_or_update_global_pr_settings(self, data): + return self._create_or_update_general_settings( + self.global_settings, data) + + @assert_repo_settings + def create_repo_svn_settings(self, data): + return self._create_svn_settings(self.repo_settings, data) + + def create_global_svn_settings(self, data): + return self._create_svn_settings(self.global_settings, data) + + @assert_repo_settings + def create_or_update_repo_hg_settings(self, data): + largefiles, phases = self.HG_SETTINGS + largefiles_key, phases_key = self._get_hg_settings( + self.HG_SETTINGS, data) + self._create_or_update_ui( + self.repo_settings, *largefiles, value='', + active=data[largefiles_key]) + self._create_or_update_ui( + self.repo_settings, *phases, value=safe_str(data[phases_key])) + + def create_or_update_global_hg_settings(self, data): + largefiles, phases, subversion = self.GLOBAL_HG_SETTINGS + largefiles_key, phases_key, subversion_key = self._get_hg_settings( + self.GLOBAL_HG_SETTINGS, data) + self._create_or_update_ui( + self.global_settings, *largefiles, value='', + active=data[largefiles_key]) + self._create_or_update_ui( + self.global_settings, *phases, value=safe_str(data[phases_key])) + self._create_or_update_ui( + self.global_settings, *subversion, active=data[subversion_key]) + + def update_global_ssl_setting(self, value): + self._create_or_update_ui( + self.global_settings, *self.SSL_SETTING, value=value) + + def update_global_path_setting(self, value): + self._create_or_update_ui( + self.global_settings, *self.PATH_SETTING, value=value) + + @assert_repo_settings + def delete_repo_svn_pattern(self, id_): + self.repo_settings.delete_ui(id_) + + def delete_global_svn_pattern(self, id_): + self.global_settings.delete_ui(id_) + + @assert_repo_settings + def get_repo_ui_settings(self, section=None, key=None): + global_uis = self.global_settings.get_ui(section, key) + repo_uis = self.repo_settings.get_ui(section, key) + filtered_repo_uis = self._filter_ui_settings(repo_uis) + filtered_repo_uis_keys = [ + (s.section, s.key) for s in filtered_repo_uis] + + def _is_global_ui_filtered(ui): + return ( + (ui.section, ui.key) in filtered_repo_uis_keys + or ui.section in self._svn_sections) + + filtered_global_uis = [ + ui for ui in global_uis if not _is_global_ui_filtered(ui)] + + return filtered_global_uis + filtered_repo_uis + + def get_global_ui_settings(self, section=None, key=None): + return self.global_settings.get_ui(section, key) + + def get_ui_settings(self, section=None, key=None): + if not self.repo_settings or self.inherit_global_settings: + return self.get_global_ui_settings(section, key) + else: + return self.get_repo_ui_settings(section, key) + + def get_svn_patterns(self, section=None): + if not self.repo_settings: + return self.get_global_ui_settings(section) + else: + return self.get_repo_ui_settings(section) + + @assert_repo_settings + def get_repo_general_settings(self): + global_settings = self.global_settings.get_all_settings() + repo_settings = self.repo_settings.get_all_settings() + filtered_repo_settings = self._filter_general_settings(repo_settings) + global_settings.update(filtered_repo_settings) + return global_settings + + def get_global_general_settings(self): + return self.global_settings.get_all_settings() + + def get_general_settings(self): + if not self.repo_settings or self.inherit_global_settings: + return self.get_global_general_settings() + else: + return self.get_repo_general_settings() + + def get_repos_location(self): + return self.global_settings.get_ui_by_key('/').ui_value + + def _filter_ui_settings(self, settings): + filtered_settings = [ + s for s in settings if self._should_keep_setting(s)] + return filtered_settings + + def _should_keep_setting(self, setting): + keep = ( + (setting.section, setting.key) in self._ui_settings or + setting.section in self._svn_sections) + return keep + + def _filter_general_settings(self, settings): + keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS] + return { + k: settings[k] + for k in settings if k in keys} + + def _collect_all_settings(self, global_=False): + settings = self.global_settings if global_ else self.repo_settings + result = {} + + for section, key in self._ui_settings: + ui = settings.get_ui_by_section_and_key(section, key) + result_key = self._get_form_ui_key(section, key) + if ui: + if section in ('hooks', 'extensions'): + result[result_key] = ui.ui_active + else: + result[result_key] = ui.ui_value + + for name in self.GENERAL_SETTINGS: + setting = settings.get_setting_by_name(name) + if setting: + result_key = 'rhodecode_{}'.format(name) + result[result_key] = setting.app_settings_value + + return result + + def _get_form_ui_key(self, section, key): + return '{section}_{key}'.format( + section=section, key=key.replace('.', '_')) + + def _create_or_update_ui( + self, settings, section, key, value=None, active=None): + ui = settings.get_ui_by_section_and_key(section, key) + if not ui: + active = True if active is None else active + settings.create_ui_section_value( + section, value, key=key, active=active) + else: + if active is not None: + ui.ui_active = active + if value is not None: + ui.ui_value = value + Session().add(ui) + + def _create_svn_settings(self, settings, data): + svn_settings = { + 'new_svn_branch': self.SVN_BRANCH_SECTION, + 'new_svn_tag': self.SVN_TAG_SECTION + } + for key in svn_settings: + if data.get(key): + settings.create_ui_section_value(svn_settings[key], data[key]) + + def _create_or_update_general_settings(self, settings, data): + for name in self.GENERAL_SETTINGS: + data_key = 'rhodecode_{}'.format(name) + if data_key not in data: + raise ValueError( + 'The given data does not contain {} key'.format(data_key)) + setting = settings.create_or_update_setting( + name, data[data_key], 'bool') + Session().add(setting) + + def _get_hg_settings(self, settings, data): + data_keys = [self._get_form_ui_key(*s) for s in settings] + for data_key in data_keys: + if data_key not in data: + raise ValueError( + 'The given data does not contain {} key'.format(data_key)) + return data_keys diff --git a/rhodecode/model/supervisor.py b/rhodecode/model/supervisor.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/supervisor.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2014-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +Model for supervisor process manager +""" + +import xmlrpclib +import logging +import traceback + +import rhodecode +from rhodecode.model import BaseModel + +log = logging.getLogger(__name__) + + +SUPERVISOR_MASTER = 'MASTER' # special name for supervisor master process + + +class SupervisorModel(BaseModel): + + cls = None + + def __init__(self, sa=None): + super(SupervisorModel, self).__init__(sa=sa) + + def _verify_connection(self, connection): + if not isinstance(connection, xmlrpclib.ServerProxy): + raise Exception('Invalid connection given, got %s, expected %s' + % (type(connection), xmlrpclib.ServerProxy)) + + def get_connection(self, supervisor_uri): + uri = supervisor_uri or 'http://' + try: + server_connection = xmlrpclib.ServerProxy(uri) + return server_connection + except Exception as e: + log.error(traceback.format_exc()) + raise + + def get_master_log(self, connection, offset, length): + self._verify_connection(connection) + return connection.supervisor.readLog(offset, length) + + def get_master_state(self, connection): + self._verify_connection(connection) + _data = connection.supervisor.getState() + _data.update({'pid': connection.supervisor.getPID()}) + _data.update({'id': connection.supervisor.getIdentification()}) + _data.update({'ver': connection.supervisor.getSupervisorVersion()}) + return _data + + def get_group_processes(self, connection, groupid): + self._verify_connection(connection) + res = [] + for data in connection.supervisor.getAllProcessInfo(): + if data['group'] == groupid: + res.append(data) + return res + + def get_process_info(self, connection, procid): + self._verify_connection(connection) + + return connection.supervisor.getProcessInfo(procid) + + def read_process_log(self, connection, procid, offset, length): + self._verify_connection(connection) + if procid == SUPERVISOR_MASTER: + log = self.get_master_log(connection, offset, length) + else: + log = connection.supervisor.readProcessLog(procid, offset, length) + # make sure we just return whole lines not to confuse people + return ''.join(log.splitlines(1)[1:]) diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/user.py @@ -0,0 +1,840 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +users model for RhodeCode +""" + +import logging +import traceback + +import datetime +from pylons import url +from pylons.i18n.translation import _ + +import ipaddress +from sqlalchemy.exc import DatabaseError +from sqlalchemy.sql.expression import true, false + +from rhodecode.lib.utils2 import ( + safe_unicode, get_current_rhodecode_user, action_logger_generic, + AttributeDict) +from rhodecode.lib.caching_query import FromCache +from rhodecode.model import BaseModel +from rhodecode.model.auth_token import AuthTokenModel +from rhodecode.model.db import ( + User, UserToPerm, UserEmailMap, UserIpMap) +from rhodecode.lib.exceptions import ( + DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException, + UserOwnsUserGroupsException, NotAllowedToCreateUserError) +from rhodecode.model.meta import Session +from rhodecode.model.repo_group import RepoGroupModel + + +log = logging.getLogger(__name__) + + +class UserModel(BaseModel): + cls = User + + def get(self, user_id, cache=False): + user = self.sa.query(User) + if cache: + user = user.options(FromCache("sql_cache_short", + "get_user_%s" % user_id)) + return user.get(user_id) + + def get_user(self, user): + return self._get_user(user) + + def get_by_username(self, username, cache=False, case_insensitive=False): + + if case_insensitive: + user = self.sa.query(User).filter(User.username.ilike(username)) + else: + user = self.sa.query(User)\ + .filter(User.username == username) + if cache: + user = user.options(FromCache("sql_cache_short", + "get_user_%s" % username)) + return user.scalar() + + def get_by_email(self, email, cache=False, case_insensitive=False): + return User.get_by_email(email, case_insensitive, cache) + + def get_by_auth_token(self, auth_token, cache=False): + return User.get_by_auth_token(auth_token, cache) + + def get_active_user_count(self, cache=False): + return User.query().filter( + User.active == True).filter( + User.username != User.DEFAULT_USER).count() + + def create(self, form_data, cur_user=None): + if not cur_user: + cur_user = getattr(get_current_rhodecode_user(), 'username', None) + + user_data = { + 'username': form_data['username'], + 'password': form_data['password'], + 'email': form_data['email'], + 'firstname': form_data['firstname'], + 'lastname': form_data['lastname'], + 'active': form_data['active'], + 'extern_type': form_data['extern_type'], + 'extern_name': form_data['extern_name'], + 'admin': False, + 'cur_user': cur_user + } + + try: + if form_data.get('create_repo_group'): + user_data['create_repo_group'] = True + if form_data.get('password_change'): + user_data['force_password_change'] = True + + return UserModel().create_or_update(**user_data) + except Exception: + log.error(traceback.format_exc()) + raise + + def update_user(self, user, skip_attrs=None, **kwargs): + from rhodecode.lib.auth import get_crypt_password + + user = self._get_user(user) + if user.username == User.DEFAULT_USER: + raise DefaultUserException( + _("You can't Edit this user since it's" + " crucial for entire application")) + + # first store only defaults + user_attrs = { + 'updating_user_id': user.user_id, + 'username': user.username, + 'password': user.password, + 'email': user.email, + 'firstname': user.name, + 'lastname': user.lastname, + 'active': user.active, + 'admin': user.admin, + 'extern_name': user.extern_name, + 'extern_type': user.extern_type, + 'language': user.user_data.get('language') + } + + # in case there's new_password, that comes from form, use it to + # store password + if kwargs.get('new_password'): + kwargs['password'] = kwargs['new_password'] + + # cleanups, my_account password change form + kwargs.pop('current_password', None) + kwargs.pop('new_password', None) + kwargs.pop('new_password_confirmation', None) + + # cleanups, user edit password change form + kwargs.pop('password_confirmation', None) + kwargs.pop('password_change', None) + + # create repo group on user creation + kwargs.pop('create_repo_group', None) + + # legacy forms send name, which is the firstname + firstname = kwargs.pop('name', None) + if firstname: + kwargs['firstname'] = firstname + + for k, v in kwargs.items(): + # skip if we don't want to update this + if skip_attrs and k in skip_attrs: + continue + + user_attrs[k] = v + + try: + return self.create_or_update(**user_attrs) + except Exception: + log.error(traceback.format_exc()) + raise + + def create_or_update( + self, username, password, email, firstname='', lastname='', + active=True, admin=False, extern_type=None, extern_name=None, + cur_user=None, plugin=None, force_password_change=False, + allow_to_create_user=True, create_repo_group=False, + updating_user_id=None, language=None, strict_creation_check=True): + """ + Creates a new instance if not found, or updates current one + + :param username: + :param password: + :param email: + :param firstname: + :param lastname: + :param active: + :param admin: + :param extern_type: + :param extern_name: + :param cur_user: + :param plugin: optional plugin this method was called from + :param force_password_change: toggles new or existing user flag + for password change + :param allow_to_create_user: Defines if the method can actually create + new users + :param create_repo_group: Defines if the method should also + create an repo group with user name, and owner + :param updating_user_id: if we set it up this is the user we want to + update this allows to editing username. + :param language: language of user from interface. + + :returns: new User object with injected `is_new_user` attribute. + """ + if not cur_user: + cur_user = getattr(get_current_rhodecode_user(), 'username', None) + + from rhodecode.lib.auth import ( + get_crypt_password, check_password, generate_auth_token) + from rhodecode.lib.hooks_base import ( + log_create_user, check_allowed_create_user) + + def _password_change(new_user, password): + # empty password + if not new_user.password: + return False + + # password check is only needed for RhodeCode internal auth calls + # in case it's a plugin we don't care + if not plugin: + + # first check if we gave crypted password back, and if it matches + # it's not password change + if new_user.password == password: + return False + + password_match = check_password(password, new_user.password) + if not password_match: + return True + + return False + + user_data = { + 'username': username, + 'password': password, + 'email': email, + 'firstname': firstname, + 'lastname': lastname, + 'active': active, + 'admin': admin + } + + if updating_user_id: + log.debug('Checking for existing account in RhodeCode ' + 'database with user_id `%s` ' % (updating_user_id,)) + user = User.get(updating_user_id) + else: + log.debug('Checking for existing account in RhodeCode ' + 'database with username `%s` ' % (username,)) + user = User.get_by_username(username, case_insensitive=True) + + if user is None: + # we check internal flag if this method is actually allowed to + # create new user + if not allow_to_create_user: + msg = ('Method wants to create new user, but it is not ' + 'allowed to do so') + log.warning(msg) + raise NotAllowedToCreateUserError(msg) + + log.debug('Creating new user %s', username) + + # only if we create user that is active + new_active_user = active + if new_active_user and strict_creation_check: + # raises UserCreationError if it's not allowed for any reason to + # create new active user, this also executes pre-create hooks + check_allowed_create_user(user_data, cur_user, strict_check=True) + new_user = User() + edit = False + else: + log.debug('updating user %s', username) + new_user = user + edit = True + + # we're not allowed to edit default user + if user.username == User.DEFAULT_USER: + raise DefaultUserException( + _("You can't edit this user (`%(username)s`) since it's " + "crucial for entire application") % {'username': user.username}) + + # inject special attribute that will tell us if User is new or old + new_user.is_new_user = not edit + # for users that didn's specify auth type, we use RhodeCode built in + from rhodecode.authentication.plugins import auth_rhodecode + extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.name + extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.name + + try: + new_user.username = username + new_user.admin = admin + new_user.email = email + new_user.active = active + new_user.extern_name = safe_unicode(extern_name) + new_user.extern_type = safe_unicode(extern_type) + new_user.name = firstname + new_user.lastname = lastname + + if not edit: + new_user.api_key = generate_auth_token(username) + + # set password only if creating an user or password is changed + if not edit or _password_change(new_user, password): + reason = 'new password' if edit else 'new user' + log.debug('Updating password reason=>%s', reason) + new_user.password = get_crypt_password(password) if password else None + + if force_password_change: + new_user.update_userdata(force_password_change=True) + if language: + new_user.update_userdata(language=language) + + self.sa.add(new_user) + + if not edit and create_repo_group: + # create new group same as username, and make this user an owner + desc = RepoGroupModel.PERSONAL_GROUP_DESC % {'username': username} + RepoGroupModel().create(group_name=username, + group_description=desc, + owner=username, commit_early=False) + if not edit: + # add the RSS token + AuthTokenModel().create(username, + description='Generated feed token', + role=AuthTokenModel.cls.ROLE_FEED) + log_create_user(created_by=cur_user, **new_user.get_dict()) + return new_user + except (DatabaseError,): + log.error(traceback.format_exc()) + raise + + def create_registration(self, form_data): + from rhodecode.model.notification import NotificationModel + from rhodecode.model.notification import EmailNotificationModel + + try: + form_data['admin'] = False + form_data['extern_name'] = 'rhodecode' + form_data['extern_type'] = 'rhodecode' + new_user = self.create(form_data) + + self.sa.add(new_user) + self.sa.flush() + + user_data = new_user.get_dict() + kwargs = { + # use SQLALCHEMY safe dump of user data + 'user': AttributeDict(user_data), + 'date': datetime.datetime.now() + } + notification_type = EmailNotificationModel.TYPE_REGISTRATION + # pre-generate the subject for notification itself + (subject, + _h, _e, # we don't care about those + body_plaintext) = EmailNotificationModel().render_email( + notification_type, **kwargs) + + # create notification objects, and emails + NotificationModel().create( + created_by=new_user, + notification_subject=subject, + notification_body=body_plaintext, + notification_type=notification_type, + recipients=None, # all admins + email_kwargs=kwargs, + ) + + return new_user + except Exception: + log.error(traceback.format_exc()) + raise + + def _handle_user_repos(self, username, repositories, handle_mode=None): + _superadmin = self.cls.get_first_admin() + left_overs = True + + from rhodecode.model.repo import RepoModel + + if handle_mode == 'detach': + for obj in repositories: + obj.user = _superadmin + # set description we know why we super admin now owns + # additional repositories that were orphaned ! + obj.description += ' \n::detached repository from deleted user: %s' % (username,) + self.sa.add(obj) + left_overs = False + elif handle_mode == 'delete': + for obj in repositories: + RepoModel().delete(obj, forks='detach') + left_overs = False + + # if nothing is done we have left overs left + return left_overs + + def _handle_user_repo_groups(self, username, repository_groups, + handle_mode=None): + _superadmin = self.cls.get_first_admin() + left_overs = True + + from rhodecode.model.repo_group import RepoGroupModel + + if handle_mode == 'detach': + for r in repository_groups: + r.user = _superadmin + # set description we know why we super admin now owns + # additional repositories that were orphaned ! + r.group_description += ' \n::detached repository group from deleted user: %s' % (username,) + self.sa.add(r) + left_overs = False + elif handle_mode == 'delete': + for r in repository_groups: + RepoGroupModel().delete(r) + left_overs = False + + # if nothing is done we have left overs left + return left_overs + + def _handle_user_user_groups(self, username, user_groups, handle_mode=None): + _superadmin = self.cls.get_first_admin() + left_overs = True + + from rhodecode.model.user_group import UserGroupModel + + if handle_mode == 'detach': + for r in user_groups: + for user_user_group_to_perm in r.user_user_group_to_perm: + if user_user_group_to_perm.user.username == username: + user_user_group_to_perm.user = _superadmin + r.user = _superadmin + # set description we know why we super admin now owns + # additional repositories that were orphaned ! + r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,) + self.sa.add(r) + left_overs = False + elif handle_mode == 'delete': + for r in user_groups: + UserGroupModel().delete(r) + left_overs = False + + # if nothing is done we have left overs left + return left_overs + + def delete(self, user, cur_user=None, handle_repos=None, + handle_repo_groups=None, handle_user_groups=None): + if not cur_user: + cur_user = getattr(get_current_rhodecode_user(), 'username', None) + user = self._get_user(user) + + try: + if user.username == User.DEFAULT_USER: + raise DefaultUserException( + _(u"You can't remove this user since it's" + u" crucial for entire application")) + + left_overs = self._handle_user_repos( + user.username, user.repositories, handle_repos) + if left_overs and user.repositories: + repos = [x.repo_name for x in user.repositories] + raise UserOwnsReposException( + _(u'user "%s" still owns %s repositories and cannot be ' + u'removed. Switch owners or remove those repositories:%s') + % (user.username, len(repos), ', '.join(repos))) + + left_overs = self._handle_user_repo_groups( + user.username, user.repository_groups, handle_repo_groups) + if left_overs and user.repository_groups: + repo_groups = [x.group_name for x in user.repository_groups] + raise UserOwnsRepoGroupsException( + _(u'user "%s" still owns %s repository groups and cannot be ' + u'removed. Switch owners or remove those repository groups:%s') + % (user.username, len(repo_groups), ', '.join(repo_groups))) + + left_overs = self._handle_user_user_groups( + user.username, user.user_groups, handle_user_groups) + if left_overs and user.user_groups: + user_groups = [x.users_group_name for x in user.user_groups] + raise UserOwnsUserGroupsException( + _(u'user "%s" still owns %s user groups and cannot be ' + u'removed. Switch owners or remove those user groups:%s') + % (user.username, len(user_groups), ', '.join(user_groups))) + + # we might change the user data with detach/delete, make sure + # the object is marked as expired before actually deleting ! + self.sa.expire(user) + self.sa.delete(user) + from rhodecode.lib.hooks_base import log_delete_user + log_delete_user(deleted_by=cur_user, **user.get_dict()) + except Exception: + log.error(traceback.format_exc()) + raise + + def reset_password_link(self, data): + from rhodecode.lib.celerylib import tasks, run_task + from rhodecode.model.notification import EmailNotificationModel + user_email = data['email'] + try: + user = User.get_by_email(user_email) + if user: + log.debug('password reset user found %s', user) + + password_reset_url = url( + 'reset_password_confirmation', key=user.api_key, + qualified=True) + + email_kwargs = { + 'password_reset_url': password_reset_url, + 'user': user, + 'email': user_email, + 'date': datetime.datetime.now() + } + + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs) + + recipients = [user_email] + + action_logger_generic( + 'sending password reset email to user: {}'.format( + user), namespace='security.password_reset') + + run_task(tasks.send_email, recipients, subject, + email_body_plaintext, email_body) + + else: + log.debug("password reset email %s not found", user_email) + except Exception: + log.error(traceback.format_exc()) + return False + + return True + + def reset_password(self, data): + from rhodecode.lib.celerylib import tasks, run_task + from rhodecode.model.notification import EmailNotificationModel + from rhodecode.lib import auth + user_email = data['email'] + pre_db = True + try: + user = User.get_by_email(user_email) + new_passwd = auth.PasswordGenerator().gen_password( + 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) + if user: + user.password = auth.get_crypt_password(new_passwd) + # also force this user to reset his password ! + user.update_userdata(force_password_change=True) + + Session().add(user) + Session().commit() + log.info('change password for %s', user_email) + if new_passwd is None: + raise Exception('unable to generate new password') + + pre_db = False + + email_kwargs = { + 'new_password': new_passwd, + 'user': user, + 'email': user_email, + 'date': datetime.datetime.now() + } + + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION, **email_kwargs) + + recipients = [user_email] + + action_logger_generic( + 'sent new password to user: {} with email: {}'.format( + user, user_email), namespace='security.password_reset') + + run_task(tasks.send_email, recipients, subject, + email_body_plaintext, email_body) + + except Exception: + log.error('Failed to update user password') + log.error(traceback.format_exc()) + if pre_db: + # we rollback only if local db stuff fails. If it goes into + # run_task, we're pass rollback state this wouldn't work then + Session().rollback() + + return True + + def fill_data(self, auth_user, user_id=None, api_key=None, username=None): + """ + Fetches auth_user by user_id,or api_key if present. + Fills auth_user attributes with those taken from database. + Additionally set's is_authenitated if lookup fails + present in database + + :param auth_user: instance of user to set attributes + :param user_id: user id to fetch by + :param api_key: api key to fetch by + :param username: username to fetch by + """ + if user_id is None and api_key is None and username is None: + raise Exception('You need to pass user_id, api_key or username') + + log.debug( + 'doing fill data based on: user_id:%s api_key:%s username:%s', + user_id, api_key, username) + try: + dbuser = None + if user_id: + dbuser = self.get(user_id) + elif api_key: + dbuser = self.get_by_auth_token(api_key) + elif username: + dbuser = self.get_by_username(username) + + if not dbuser: + log.warning( + 'Unable to lookup user by id:%s api_key:%s username:%s', + user_id, api_key, username) + return False + if not dbuser.active: + log.debug('User `%s` is inactive, skipping fill data', username) + return False + + log.debug('filling user:%s data', dbuser) + + # TODO: johbo: Think about this and find a clean solution + user_data = dbuser.get_dict() + user_data.update(dbuser.get_api_data(include_secrets=True)) + + for k, v in user_data.iteritems(): + # properties of auth user we dont update + if k not in ['auth_tokens', 'permissions']: + setattr(auth_user, k, v) + + # few extras + setattr(auth_user, 'feed_token', dbuser.feed_token) + except Exception: + log.error(traceback.format_exc()) + auth_user.is_authenticated = False + return False + + return True + + def has_perm(self, user, perm): + perm = self._get_perm(perm) + user = self._get_user(user) + + return UserToPerm.query().filter(UserToPerm.user == user)\ + .filter(UserToPerm.permission == perm).scalar() is not None + + def grant_perm(self, user, perm): + """ + Grant user global permissions + + :param user: + :param perm: + """ + user = self._get_user(user) + perm = self._get_perm(perm) + # if this permission is already granted skip it + _perm = UserToPerm.query()\ + .filter(UserToPerm.user == user)\ + .filter(UserToPerm.permission == perm)\ + .scalar() + if _perm: + return + new = UserToPerm() + new.user = user + new.permission = perm + self.sa.add(new) + return new + + def revoke_perm(self, user, perm): + """ + Revoke users global permissions + + :param user: + :param perm: + """ + user = self._get_user(user) + perm = self._get_perm(perm) + + obj = UserToPerm.query()\ + .filter(UserToPerm.user == user)\ + .filter(UserToPerm.permission == perm)\ + .scalar() + if obj: + self.sa.delete(obj) + + def add_extra_email(self, user, email): + """ + Adds email address to UserEmailMap + + :param user: + :param email: + """ + from rhodecode.model import forms + form = forms.UserExtraEmailForm()() + data = form.to_python({'email': email}) + user = self._get_user(user) + + obj = UserEmailMap() + obj.user = user + obj.email = data['email'] + self.sa.add(obj) + return obj + + def delete_extra_email(self, user, email_id): + """ + Removes email address from UserEmailMap + + :param user: + :param email_id: + """ + user = self._get_user(user) + obj = UserEmailMap.query().get(email_id) + if obj: + self.sa.delete(obj) + + def parse_ip_range(self, ip_range): + ip_list = [] + def make_unique(value): + seen = [] + return [c for c in value if not (c in seen or seen.append(c))] + + # firsts split by commas + for ip_range in ip_range.split(','): + if not ip_range: + continue + ip_range = ip_range.strip() + if '-' in ip_range: + start_ip, end_ip = ip_range.split('-', 1) + start_ip = ipaddress.ip_address(start_ip.strip()) + end_ip = ipaddress.ip_address(end_ip.strip()) + parsed_ip_range = [] + + for index in xrange(int(start_ip), int(end_ip) + 1): + new_ip = ipaddress.ip_address(index) + parsed_ip_range.append(str(new_ip)) + ip_list.extend(parsed_ip_range) + else: + ip_list.append(ip_range) + + return make_unique(ip_list) + + def add_extra_ip(self, user, ip, description=None): + """ + Adds ip address to UserIpMap + + :param user: + :param ip: + """ + from rhodecode.model import forms + form = forms.UserExtraIpForm()() + data = form.to_python({'ip': ip}) + user = self._get_user(user) + + obj = UserIpMap() + obj.user = user + obj.ip_addr = data['ip'] + obj.description = description + self.sa.add(obj) + return obj + + def delete_extra_ip(self, user, ip_id): + """ + Removes ip address from UserIpMap + + :param user: + :param ip_id: + """ + user = self._get_user(user) + obj = UserIpMap.query().get(ip_id) + if obj: + self.sa.delete(obj) + + def get_accounts_in_creation_order(self, current_user=None): + """ + Get accounts in order of creation for deactivation for license limits + + pick currently logged in user, and append to the list in position 0 + pick all super-admins in order of creation date and add it to the list + pick all other accounts in order of creation and add it to the list. + + Based on that list, the last accounts can be disabled as they are + created at the end and don't include any of the super admins as well + as the current user. + + :param current_user: optionally current user running this operation + """ + + if not current_user: + current_user = get_current_rhodecode_user() + active_super_admins = [ + x.user_id for x in User.query() + .filter(User.user_id != current_user.user_id) + .filter(User.active == true()) + .filter(User.admin == true()) + .order_by(User.created_on.asc())] + + active_regular_users = [ + x.user_id for x in User.query() + .filter(User.user_id != current_user.user_id) + .filter(User.active == true()) + .filter(User.admin == false()) + .order_by(User.created_on.asc())] + + list_of_accounts = [current_user.user_id] + list_of_accounts += active_super_admins + list_of_accounts += active_regular_users + + return list_of_accounts + + def deactivate_last_users(self, expected_users): + """ + Deactivate accounts that are over the license limits. + Algorithm of which accounts to disabled is based on the formula: + + Get current user, then super admins in creation order, then regular + active users in creation order. + + Using that list we mark all accounts from the end of it as inactive. + This way we block only latest created accounts. + + :param expected_users: list of users in special order, we deactivate + the end N ammoun of users from that list + """ + + list_of_accounts = self.get_accounts_in_creation_order() + + for acc_id in list_of_accounts[expected_users + 1:]: + user = User.get(acc_id) + log.info('Deactivating account %s for license unlock', user) + user.active = False + Session().add(user) + Session().commit() + + return diff --git a/rhodecode/model/user_group.py b/rhodecode/model/user_group.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/user_group.py @@ -0,0 +1,511 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +""" +user group model for RhodeCode +""" + + +import logging +import traceback + +from rhodecode.lib.utils2 import safe_str +from rhodecode.model import BaseModel +from rhodecode.model.db import UserGroupMember, UserGroup,\ + UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm,\ + UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm +from rhodecode.lib.exceptions import UserGroupAssignedException,\ + RepoGroupAssignmentError +from rhodecode.lib.utils2 import get_current_rhodecode_user, action_logger_generic + +log = logging.getLogger(__name__) + + +class UserGroupModel(BaseModel): + + cls = UserGroup + + def _get_user_group(self, user_group): + return self._get_instance(UserGroup, user_group, + callback=UserGroup.get_by_group_name) + + def _create_default_perms(self, user_group): + # create default permission + default_perm = 'usergroup.read' + def_user = User.get_default_user() + for p in def_user.user_perms: + if p.permission.permission_name.startswith('usergroup.'): + default_perm = p.permission.permission_name + break + + user_group_to_perm = UserUserGroupToPerm() + user_group_to_perm.permission = Permission.get_by_key(default_perm) + + user_group_to_perm.user_group = user_group + user_group_to_perm.user_id = def_user.user_id + return user_group_to_perm + + def update_permissions(self, user_group, perm_additions=None, perm_updates=None, + perm_deletions=None, check_perms=True, cur_user=None): + from rhodecode.lib.auth import HasUserGroupPermissionAny + if not perm_additions: + perm_additions = [] + if not perm_updates: + perm_updates = [] + if not perm_deletions: + perm_deletions = [] + + req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') + + # update permissions + for member_id, perm, member_type in perm_updates: + member_id = int(member_id) + if member_type == 'user': + # this updates existing one + self.grant_user_permission( + user_group=user_group, user=member_id, perm=perm + ) + else: + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + self.grant_user_group_permission( + target_user_group=user_group, user_group=member_id, perm=perm + ) + + # set new permissions + for member_id, perm, member_type in perm_additions: + member_id = int(member_id) + if member_type == 'user': + self.grant_user_permission( + user_group=user_group, user=member_id, perm=perm + ) + else: + # check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + self.grant_user_group_permission( + target_user_group=user_group, user_group=member_id, perm=perm + ) + + # delete permissions + for member_id, perm, member_type in perm_deletions: + member_id = int(member_id) + if member_type == 'user': + self.revoke_user_permission(user_group=user_group, user=member_id) + else: + #check if we have permissions to alter this usergroup + member_name = UserGroup.get(member_id).users_group_name + if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + self.revoke_user_group_permission( + target_user_group=user_group, user_group=member_id + ) + + def get(self, user_group_id, cache=False): + return UserGroup.get(user_group_id) + + def get_group(self, user_group): + return self._get_user_group(user_group) + + def get_by_name(self, name, cache=False, case_insensitive=False): + return UserGroup.get_by_group_name(name, cache, case_insensitive) + + def create(self, name, description, owner, active=True, group_data=None): + try: + new_user_group = UserGroup() + new_user_group.user = self._get_user(owner) + new_user_group.users_group_name = name + new_user_group.user_group_description = description + new_user_group.users_group_active = active + if group_data: + new_user_group.group_data = group_data + self.sa.add(new_user_group) + perm_obj = self._create_default_perms(new_user_group) + self.sa.add(perm_obj) + + self.grant_user_permission(user_group=new_user_group, + user=owner, perm='usergroup.admin') + + return new_user_group + except Exception: + log.error(traceback.format_exc()) + raise + + def _get_memberships_for_user_ids(self, user_group, user_id_list): + members = [] + for user_id in user_id_list: + member = self._get_membership(user_group.users_group_id, user_id) + members.append(member) + return members + + def _get_added_and_removed_user_ids(self, user_group, user_id_list): + current_members = user_group.members or [] + current_members_ids = [m.user.user_id for m in current_members] + + added_members = [ + user_id for user_id in user_id_list + if user_id not in current_members_ids] + if user_id_list == []: + # all members were deleted + deleted_members = current_members_ids + else: + deleted_members = [ + user_id for user_id in current_members_ids + if user_id not in user_id_list] + + return (added_members, deleted_members) + + def _set_users_as_members(self, user_group, user_ids): + user_group.members = [] + self.sa.flush() + members = self._get_memberships_for_user_ids( + user_group, user_ids) + user_group.members = members + self.sa.add(user_group) + + def _update_members_from_user_ids(self, user_group, user_ids): + added, removed = self._get_added_and_removed_user_ids( + user_group, user_ids) + self._set_users_as_members(user_group, user_ids) + self._log_user_changes('added to', user_group, added) + self._log_user_changes('removed from', user_group, removed) + + def _clean_members_data(self, members_data): + # TODO: anderson: this should be in the form validation but I couldn't + # make it work there as it conflicts with the other validator + if not members_data: + members_data = [] + + if isinstance(members_data, basestring): + new_members = [members_data] + else: + new_members = members_data + + new_members = [int(uid) for uid in new_members] + return new_members + + def update(self, user_group, form_data): + user_group = self._get_user_group(user_group) + if 'users_group_name' in form_data: + user_group.users_group_name = form_data['users_group_name'] + if 'users_group_active' in form_data: + user_group.users_group_active = form_data['users_group_active'] + if 'user_group_description' in form_data: + user_group.user_group_description = form_data[ + 'user_group_description'] + + # handle owner change + if 'user' in form_data: + owner = form_data['user'] + if isinstance(owner, basestring): + user_group.user = User.get_by_username(form_data['user']) + + if 'users_group_members' in form_data: + members_id_list = self._clean_members_data( + form_data['users_group_members']) + self._update_members_from_user_ids(user_group, members_id_list) + + self.sa.add(user_group) + + def delete(self, user_group, force=False): + """ + Deletes repository group, unless force flag is used + raises exception if there are members in that group, else deletes + group and users + + :param user_group: + :param force: + """ + user_group = self._get_user_group(user_group) + try: + # check if this group is not assigned to repo + assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\ + .filter(UserGroupRepoToPerm.users_group == user_group).all()] + # check if this group is not assigned to repo + assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\ + .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()] + + if (assigned_to_repo or assigned_to_repo_group) and not force: + assigned = ','.join(map(safe_str, + assigned_to_repo+assigned_to_repo_group)) + + raise UserGroupAssignedException( + 'UserGroup assigned to %s' % (assigned,)) + self.sa.delete(user_group) + except Exception: + log.error(traceback.format_exc()) + raise + + def _log_user_changes(self, action, user_group, user_or_users): + users = user_or_users + if not isinstance(users, (list, tuple)): + users = [users] + rhodecode_user = get_current_rhodecode_user() + ipaddr = getattr(rhodecode_user, 'ip_addr', '') + group_name = user_group.users_group_name + + for user_or_user_id in users: + user = self._get_user(user_or_user_id) + log_text = 'User {user} {action} {group}'.format( + action=action, user=user.username, group=group_name) + log.info('Logging action: {0} by {1} ip:{2}'.format( + log_text, rhodecode_user, ipaddr)) + + def _find_user_in_group(self, user, user_group): + user_group_member = None + for m in user_group.members: + if m.user_id == user.user_id: + # Found this user's membership row + user_group_member = m + break + + return user_group_member + + def _get_membership(self, user_group_id, user_id): + user_group_member = UserGroupMember(user_group_id, user_id) + return user_group_member + + def add_user_to_group(self, user_group, user): + user_group = self._get_user_group(user_group) + user = self._get_user(user) + user_member = self._find_user_in_group(user, user_group) + if user_member: + # user already in the group, skip + return True + + member = self._get_membership( + user_group.users_group_id, user.user_id) + user_group.members.append(member) + + try: + self.sa.add(member) + except Exception: + # what could go wrong here? + log.error(traceback.format_exc()) + raise + + self._log_user_changes('added to', user_group, user) + return member + + def remove_user_from_group(self, user_group, user): + user_group = self._get_user_group(user_group) + user = self._get_user(user) + user_group_member = self._find_user_in_group(user, user_group) + + if not user_group_member: + # User isn't in that group + return False + + try: + self.sa.delete(user_group_member) + except Exception: + log.error(traceback.format_exc()) + raise + + self._log_user_changes('removed from', user_group, user) + return True + + def has_perm(self, user_group, perm): + user_group = self._get_user_group(user_group) + perm = self._get_perm(perm) + + return UserGroupToPerm.query()\ + .filter(UserGroupToPerm.users_group == user_group)\ + .filter(UserGroupToPerm.permission == perm).scalar() is not None + + def grant_perm(self, user_group, perm): + user_group = self._get_user_group(user_group) + perm = self._get_perm(perm) + + # if this permission is already granted skip it + _perm = UserGroupToPerm.query()\ + .filter(UserGroupToPerm.users_group == user_group)\ + .filter(UserGroupToPerm.permission == perm)\ + .scalar() + if _perm: + return + + new = UserGroupToPerm() + new.users_group = user_group + new.permission = perm + self.sa.add(new) + return new + + def revoke_perm(self, user_group, perm): + user_group = self._get_user_group(user_group) + perm = self._get_perm(perm) + + obj = UserGroupToPerm.query()\ + .filter(UserGroupToPerm.users_group == user_group)\ + .filter(UserGroupToPerm.permission == perm).scalar() + if obj: + self.sa.delete(obj) + + def grant_user_permission(self, user_group, user, perm): + """ + Grant permission for user on given user group, or update + existing one if found + + :param user_group: Instance of UserGroup, users_group_id, + or users_group_name + :param user: Instance of User, user_id or username + :param perm: Instance of Permission, or permission_name + """ + + user_group = self._get_user_group(user_group) + user = self._get_user(user) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserUserGroupToPerm)\ + .filter(UserUserGroupToPerm.user == user)\ + .filter(UserUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj is None: + # create new ! + obj = UserUserGroupToPerm() + obj.user_group = user_group + obj.user = user + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s', perm, user, user_group) + action_logger_generic( + 'granted permission: {} to user: {} on usergroup: {}'.format( + perm, user, user_group), namespace='security.usergroup') + + return obj + + def revoke_user_permission(self, user_group, user): + """ + Revoke permission for user on given user group + + :param user_group: Instance of UserGroup, users_group_id, + or users_group name + :param user: Instance of User, user_id or username + """ + + user_group = self._get_user_group(user_group) + user = self._get_user(user) + + obj = self.sa.query(UserUserGroupToPerm)\ + .filter(UserUserGroupToPerm.user == user)\ + .filter(UserUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm on %s on %s', user_group, user) + action_logger_generic( + 'revoked permission from user: {} on usergroup: {}'.format( + user, user_group), namespace='security.usergroup') + + def grant_user_group_permission(self, target_user_group, user_group, perm): + """ + Grant user group permission for given target_user_group + + :param target_user_group: + :param user_group: + :param perm: + """ + target_user_group = self._get_user_group(target_user_group) + user_group = self._get_user_group(user_group) + permission = self._get_perm(perm) + # forbid assigning same user group to itself + if target_user_group == user_group: + raise RepoGroupAssignmentError('target repo:%s cannot be ' + 'assigned to itself' % target_user_group) + + # check if we have that permission already + obj = self.sa.query(UserGroupUserGroupToPerm)\ + .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\ + .filter(UserGroupUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj is None: + # create new ! + obj = UserGroupUserGroupToPerm() + obj.user_group = user_group + obj.target_user_group = target_user_group + obj.permission = permission + self.sa.add(obj) + log.debug( + 'Granted perm %s to %s on %s', perm, target_user_group, user_group) + action_logger_generic( + 'granted permission: {} to usergroup: {} on usergroup: {}'.format( + perm, user_group, target_user_group), + namespace='security.usergroup') + + return obj + + def revoke_user_group_permission(self, target_user_group, user_group): + """ + Revoke user group permission for given target_user_group + + :param target_user_group: + :param user_group: + """ + target_user_group = self._get_user_group(target_user_group) + user_group = self._get_user_group(user_group) + + obj = self.sa.query(UserGroupUserGroupToPerm)\ + .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\ + .filter(UserGroupUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj: + self.sa.delete(obj) + log.debug( + 'Revoked perm on %s on %s', target_user_group, user_group) + action_logger_generic( + 'revoked permission from usergroup: {} on usergroup: {}'.format( + user_group, target_user_group), + namespace='security.repogroup') + + def enforce_groups(self, user, groups, extern_type=None): + user = self._get_user(user) + log.debug('Enforcing groups %s on user %s', groups, user) + current_groups = user.group_member + # find the external created groups + externals = [x.users_group for x in current_groups + if 'extern_type' in x.users_group.group_data] + + # calculate from what groups user should be removed + # externals that are not in groups + for gr in externals: + if gr.users_group_name not in groups: + log.debug('Removing user %s from user group %s', user, gr) + self.remove_user_from_group(gr, user) + + # now we calculate in which groups user should be == groups params + owner = User.get_first_admin().username + for gr in set(groups): + existing_group = UserGroup.get_by_group_name(gr) + if not existing_group: + desc = 'Automatically created from plugin:%s' % extern_type + # we use first admin account to set the owner of the group + existing_group = UserGroupModel().create(gr, desc, owner, + group_data={'extern_type': extern_type}) + + # we can only add users to special groups created via plugins + managed = 'extern_type' in existing_group.group_data + if managed: + log.debug('Adding user %s to user group %s', user, gr) + UserGroupModel().add_user_to_group(existing_group, user) + else: + log.debug('Skipping addition to group %s since it is ' + 'not managed by auth plugins' % gr) diff --git a/rhodecode/model/validation_schema.py b/rhodecode/model/validation_schema.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/validation_schema.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import colander +from colander import Invalid # noqa + + +class GroupNameType(colander.String): + SEPARATOR = '/' + + def deserialize(self, node, cstruct): + result = super(GroupNameType, self).deserialize(node, cstruct) + return self._replace_extra_slashes(result) + + def _replace_extra_slashes(self, path): + path = path.split(self.SEPARATOR) + path = [item for item in path if item] + return self.SEPARATOR.join(path) + + +class RepoGroupSchema(colander.Schema): + group_name = colander.SchemaNode(GroupNameType()) + + +class RepoSchema(colander.Schema): + repo_name = colander.SchemaNode(GroupNameType()) + + +class SearchParamsSchema(colander.MappingSchema): + search_query = colander.SchemaNode( + colander.String(), + missing='') + search_type = colander.SchemaNode( + colander.String(), + missing='content', + validator=colander.OneOf(['content', 'path', 'commit', 'repository'])) + page_limit = colander.SchemaNode( + colander.Integer(), + missing=10, + validator=colander.Range(1, 500)) + requested_page = colander.SchemaNode( + colander.Integer(), + missing=1) + diff --git a/rhodecode/model/validators.py b/rhodecode/model/validators.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/validators.py @@ -0,0 +1,1076 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Set of generic validators +""" + +import logging +import os +import re +from collections import defaultdict + +import formencode +import ipaddress +from formencode.validators import ( + UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, + NotEmpty, IPAddress, CIDR, String, FancyValidator +) +from pylons.i18n.translation import _ +from sqlalchemy.sql.expression import true +from sqlalchemy.util import OrderedSet +from webhelpers.pylonslib.secure_form import authentication_token + +from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.lib.auth import HasRepoGroupPermissionAny, HasPermissionAny +from rhodecode.lib.exceptions import LdapImportError +from rhodecode.lib.utils import repo_name_slug, make_db_config +from rhodecode.lib.utils2 import safe_int, str2bool, aslist, md5 +from rhodecode.lib.vcs.backends.git.repository import GitRepository +from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository +from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository +from rhodecode.model.db import ( + RepoGroup, Repository, UserGroup, User, ChangesetStatus, Gist) +from rhodecode.model.settings import VcsSettingsModel + +# silence warnings and pylint +UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ + NotEmpty, IPAddress, CIDR, String, FancyValidator + +log = logging.getLogger(__name__) + + +class _Missing(object): + pass + +Missing = _Missing() + + +class StateObj(object): + """ + this is needed to translate the messages using _() in validators + """ + _ = staticmethod(_) + + +def M(self, key, state=None, **kwargs): + """ + returns string from self.message based on given key, + passed kw params are used to substitute %(named)s params inside + translated strings + + :param msg: + :param state: + """ + if state is None: + state = StateObj() + else: + state._ = staticmethod(_) + # inject validator into state object + return self.message(key, state, **kwargs) + + +def UniqueList(convert=None): + class _UniqueList(formencode.FancyValidator): + """ + Unique List ! + """ + messages = { + 'empty': _(u'Value cannot be an empty list'), + 'missing_value': _(u'Value cannot be an empty list'), + } + + def _to_python(self, value, state): + ret_val = [] + + def make_unique(value): + seen = [] + return [c for c in value if not (c in seen or seen.append(c))] + + if isinstance(value, list): + ret_val = make_unique(value) + elif isinstance(value, set): + ret_val = make_unique(list(value)) + elif isinstance(value, tuple): + ret_val = make_unique(list(value)) + elif value is None: + ret_val = [] + else: + ret_val = [value] + + if convert: + ret_val = map(convert, ret_val) + return ret_val + + def empty_value(self, value): + return [] + + return _UniqueList + + +def UniqueListFromString(): + class _UniqueListFromString(UniqueList()): + def _to_python(self, value, state): + if isinstance(value, basestring): + value = aslist(value, ',') + return super(_UniqueListFromString, self)._to_python(value, state) + return _UniqueListFromString + + +def ValidSvnPattern(section, repo_name=None): + class _validator(formencode.validators.FancyValidator): + messages = { + 'pattern_exists': _(u'Pattern already exists'), + } + + def validate_python(self, value, state): + if not value: + return + model = VcsSettingsModel(repo=repo_name) + ui_settings = model.get_svn_patterns(section=section) + for entry in ui_settings: + if value == entry.value: + msg = M(self, 'pattern_exists', state) + raise formencode.Invalid(msg, value, state) + return _validator + + +def ValidUsername(edit=False, old_data={}): + class _validator(formencode.validators.FancyValidator): + messages = { + 'username_exists': _(u'Username "%(username)s" already exists'), + 'system_invalid_username': + _(u'Username "%(username)s" is forbidden'), + 'invalid_username': + _(u'Username may only contain alphanumeric characters ' + u'underscores, periods or dashes and must begin with ' + u'alphanumeric character or underscore') + } + + def validate_python(self, value, state): + if value in ['default', 'new_user']: + msg = M(self, 'system_invalid_username', state, username=value) + raise formencode.Invalid(msg, value, state) + # check if user is unique + old_un = None + if edit: + old_un = User.get(old_data.get('user_id')).username + + if old_un != value or not edit: + if User.get_by_username(value, case_insensitive=True): + msg = M(self, 'username_exists', state, username=value) + raise formencode.Invalid(msg, value, state) + + if (re.match(r'^[\w]{1}[\w\-\.]{0,254}$', value) + is None): + msg = M(self, 'invalid_username', state) + raise formencode.Invalid(msg, value, state) + return _validator + + +def ValidRegex(msg=None): + class _validator(formencode.validators.Regex): + messages = {'invalid': msg or _(u'The input is not valid')} + return _validator + + +def ValidRepoUser(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_username': _(u'Username %(username)s is not valid') + } + + def validate_python(self, value, state): + try: + User.query().filter(User.active == true())\ + .filter(User.username == value).one() + except Exception: + msg = M(self, 'invalid_username', state, username=value) + raise formencode.Invalid( + msg, value, state, error_dict={'username': msg} + ) + + return _validator + + +def ValidUserGroup(edit=False, old_data={}): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_group': _(u'Invalid user group name'), + 'group_exist': _(u'User group "%(usergroup)s" already exists'), + 'invalid_usergroup_name': + _(u'user group name may only contain alphanumeric ' + u'characters underscores, periods or dashes and must begin ' + u'with alphanumeric character') + } + + def validate_python(self, value, state): + if value in ['default']: + msg = M(self, 'invalid_group', state) + raise formencode.Invalid( + msg, value, state, error_dict={'users_group_name': msg} + ) + # check if group is unique + old_ugname = None + if edit: + old_id = old_data.get('users_group_id') + old_ugname = UserGroup.get(old_id).users_group_name + + if old_ugname != value or not edit: + is_existing_group = UserGroup.get_by_group_name( + value, case_insensitive=True) + if is_existing_group: + msg = M(self, 'group_exist', state, usergroup=value) + raise formencode.Invalid( + msg, value, state, error_dict={'users_group_name': msg} + ) + + if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None: + msg = M(self, 'invalid_usergroup_name', state) + raise formencode.Invalid( + msg, value, state, error_dict={'users_group_name': msg} + ) + + return _validator + + +def ValidRepoGroup(edit=False, old_data={}, can_create_in_root=False): + class _validator(formencode.validators.FancyValidator): + messages = { + 'group_parent_id': _(u'Cannot assign this group as parent'), + 'group_exists': _(u'Group "%(group_name)s" already exists'), + 'repo_exists': _(u'Repository with name "%(group_name)s" ' + u'already exists'), + 'permission_denied': _(u"no permission to store repository group" + u"in this location"), + 'permission_denied_root': _( + u"no permission to store repository group " + u"in root location") + } + + def _to_python(self, value, state): + group_name = repo_name_slug(value.get('group_name', '')) + group_parent_id = safe_int(value.get('group_parent_id')) + gr = RepoGroup.get(group_parent_id) + if gr: + parent_group_path = gr.full_path + # value needs to be aware of group name in order to check + # db key This is an actual just the name to store in the + # database + group_name_full = ( + parent_group_path + RepoGroup.url_sep() + group_name) + else: + group_name_full = group_name + + value['group_name'] = group_name + value['group_name_full'] = group_name_full + value['group_parent_id'] = group_parent_id + return value + + def validate_python(self, value, state): + + old_group_name = None + group_name = value.get('group_name') + group_name_full = value.get('group_name_full') + group_parent_id = safe_int(value.get('group_parent_id')) + if group_parent_id == -1: + group_parent_id = None + + group_obj = RepoGroup.get(old_data.get('group_id')) + parent_group_changed = False + if edit: + old_group_name = group_obj.group_name + old_group_parent_id = group_obj.group_parent_id + + if group_parent_id != old_group_parent_id: + parent_group_changed = True + + # TODO: mikhail: the following if statement is not reached + # since group_parent_id's OneOf validation fails before. + # Can be removed. + + # check against setting a parent of self + parent_of_self = ( + old_data['group_id'] == group_parent_id + if group_parent_id else False + ) + if parent_of_self: + msg = M(self, 'group_parent_id', state) + raise formencode.Invalid( + msg, value, state, error_dict={'group_parent_id': msg} + ) + + # group we're moving current group inside + child_group = None + if group_parent_id: + child_group = RepoGroup.query().filter( + RepoGroup.group_id == group_parent_id).scalar() + + # do a special check that we cannot move a group to one of + # it's children + if edit and child_group: + parents = [x.group_id for x in child_group.parents] + move_to_children = old_data['group_id'] in parents + if move_to_children: + msg = M(self, 'group_parent_id', state) + raise formencode.Invalid( + msg, value, state, error_dict={'group_parent_id': msg}) + + # Check if we have permission to store in the parent. + # Only check if the parent group changed. + if parent_group_changed: + if child_group is None: + if not can_create_in_root: + msg = M(self, 'permission_denied_root', state) + raise formencode.Invalid( + msg, value, state, + error_dict={'group_parent_id': msg}) + else: + valid = HasRepoGroupPermissionAny('group.admin') + forbidden = not valid( + child_group.group_name, 'can create group validator') + if forbidden: + msg = M(self, 'permission_denied', state) + raise formencode.Invalid( + msg, value, state, + error_dict={'group_parent_id': msg}) + + # if we change the name or it's new group, check for existing names + # or repositories with the same name + if old_group_name != group_name_full or not edit: + # check group + gr = RepoGroup.get_by_group_name(group_name_full) + if gr: + msg = M(self, 'group_exists', state, group_name=group_name) + raise formencode.Invalid( + msg, value, state, error_dict={'group_name': msg}) + + # check for same repo + repo = Repository.get_by_repo_name(group_name_full) + if repo: + msg = M(self, 'repo_exists', state, group_name=group_name) + raise formencode.Invalid( + msg, value, state, error_dict={'group_name': msg}) + + return _validator + + +def ValidPassword(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_password': + _(u'Invalid characters (non-ascii) in password') + } + + def validate_python(self, value, state): + try: + (value or '').decode('ascii') + except UnicodeError: + msg = M(self, 'invalid_password', state) + raise formencode.Invalid(msg, value, state,) + return _validator + + +def ValidOldPassword(username): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_password': _(u'Invalid old password') + } + + def validate_python(self, value, state): + from rhodecode.authentication.base import authenticate, HTTP_TYPE + if not authenticate(username, value, '', HTTP_TYPE): + msg = M(self, 'invalid_password', state) + raise formencode.Invalid( + msg, value, state, error_dict={'current_password': msg} + ) + return _validator + + +def ValidPasswordsMatch( + passwd='new_password', passwd_confirmation='password_confirmation'): + class _validator(formencode.validators.FancyValidator): + messages = { + 'password_mismatch': _(u'Passwords do not match'), + } + + def validate_python(self, value, state): + + pass_val = value.get('password') or value.get(passwd) + if pass_val != value[passwd_confirmation]: + msg = M(self, 'password_mismatch', state) + raise formencode.Invalid( + msg, value, state, + error_dict={passwd: msg, passwd_confirmation: msg} + ) + return _validator + + +def ValidAuth(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_password': _(u'invalid password'), + 'invalid_username': _(u'invalid user name'), + 'disabled_account': _(u'Your account is disabled') + } + + def validate_python(self, value, state): + from rhodecode.authentication.base import authenticate, HTTP_TYPE + + password = value['password'] + username = value['username'] + + if not authenticate(username, password, '', + HTTP_TYPE, + skip_missing=True): + user = User.get_by_username(username) + if user and not user.active: + log.warning('user %s is disabled', username) + msg = M(self, 'disabled_account', state) + raise formencode.Invalid( + msg, value, state, error_dict={'username': msg} + ) + else: + log.warning('user %s failed to authenticate', username) + msg = M(self, 'invalid_username', state) + msg2 = M(self, 'invalid_password', state) + raise formencode.Invalid( + msg, value, state, + error_dict={'username': msg, 'password': msg2} + ) + return _validator + + +def ValidAuthToken(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_token': _(u'Token mismatch') + } + + def validate_python(self, value, state): + if value != authentication_token(): + msg = M(self, 'invalid_token', state) + raise formencode.Invalid(msg, value, state) + return _validator + + +def ValidRepoName(edit=False, old_data={}): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_repo_name': + _(u'Repository name %(repo)s is disallowed'), + # top level + 'repository_exists': _(u'Repository with name %(repo)s ' + u'already exists'), + 'group_exists': _(u'Repository group with name "%(repo)s" ' + u'already exists'), + # inside a group + 'repository_in_group_exists': _(u'Repository with name %(repo)s ' + u'exists in group "%(group)s"'), + 'group_in_group_exists': _( + u'Repository group with name "%(repo)s" ' + u'exists in group "%(group)s"'), + } + + def _to_python(self, value, state): + repo_name = repo_name_slug(value.get('repo_name', '')) + repo_group = value.get('repo_group') + if repo_group: + gr = RepoGroup.get(repo_group) + group_path = gr.full_path + group_name = gr.group_name + # value needs to be aware of group name in order to check + # db key This is an actual just the name to store in the + # database + repo_name_full = group_path + RepoGroup.url_sep() + repo_name + else: + group_name = group_path = '' + repo_name_full = repo_name + + value['repo_name'] = repo_name + value['repo_name_full'] = repo_name_full + value['group_path'] = group_path + value['group_name'] = group_name + return value + + def validate_python(self, value, state): + + repo_name = value.get('repo_name') + repo_name_full = value.get('repo_name_full') + group_path = value.get('group_path') + group_name = value.get('group_name') + + if repo_name in [ADMIN_PREFIX, '']: + msg = M(self, 'invalid_repo_name', state, repo=repo_name) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_name': msg}) + + rename = old_data.get('repo_name') != repo_name_full + create = not edit + if rename or create: + + if group_path: + if Repository.get_by_repo_name(repo_name_full): + msg = M(self, 'repository_in_group_exists', state, + repo=repo_name, group=group_name) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_name': msg}) + if RepoGroup.get_by_group_name(repo_name_full): + msg = M(self, 'group_in_group_exists', state, + repo=repo_name, group=group_name) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_name': msg}) + else: + if RepoGroup.get_by_group_name(repo_name_full): + msg = M(self, 'group_exists', state, repo=repo_name) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_name': msg}) + + if Repository.get_by_repo_name(repo_name_full): + msg = M( + self, 'repository_exists', state, repo=repo_name) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_name': msg}) + return value + return _validator + + +def ValidForkName(*args, **kwargs): + return ValidRepoName(*args, **kwargs) + + +def SlugifyName(): + class _validator(formencode.validators.FancyValidator): + + def _to_python(self, value, state): + return repo_name_slug(value) + + def validate_python(self, value, state): + pass + + return _validator + + +def ValidCloneUri(): + class InvalidCloneUrl(Exception): + allowed_prefixes = () + + def url_handler(repo_type, url): + config = make_db_config(clear_session=False) + if repo_type == 'hg': + allowed_prefixes = ('http', 'svn+http', 'git+http') + + if 'http' in url[:4]: + # initially check if it's at least the proper URL + # or does it pass basic auth + MercurialRepository.check_url(url, config) + elif 'svn+http' in url[:8]: # svn->hg import + SubversionRepository.check_url(url, config) + elif 'git+http' in url[:8]: # git->hg import + raise NotImplementedError() + else: + exc = InvalidCloneUrl('Clone from URI %s not allowed. ' + 'Allowed url must start with one of %s' + % (url, ','.join(allowed_prefixes))) + exc.allowed_prefixes = allowed_prefixes + raise exc + + elif repo_type == 'git': + allowed_prefixes = ('http', 'svn+http', 'hg+http') + if 'http' in url[:4]: + # initially check if it's at least the proper URL + # or does it pass basic auth + GitRepository.check_url(url, config) + elif 'svn+http' in url[:8]: # svn->git import + raise NotImplementedError() + elif 'hg+http' in url[:8]: # hg->git import + raise NotImplementedError() + else: + exc = InvalidCloneUrl('Clone from URI %s not allowed. ' + 'Allowed url must start with one of %s' + % (url, ','.join(allowed_prefixes))) + exc.allowed_prefixes = allowed_prefixes + raise exc + + class _validator(formencode.validators.FancyValidator): + messages = { + 'clone_uri': _(u'invalid clone url for %(rtype)s repository'), + 'invalid_clone_uri': _( + u'Invalid clone url, provide a valid clone ' + u'url starting with one of %(allowed_prefixes)s') + } + + def validate_python(self, value, state): + repo_type = value.get('repo_type') + url = value.get('clone_uri') + + if url: + try: + url_handler(repo_type, url) + except InvalidCloneUrl as e: + log.warning(e) + msg = M(self, 'invalid_clone_uri', rtype=repo_type, + allowed_prefixes=','.join(e.allowed_prefixes)) + raise formencode.Invalid(msg, value, state, + error_dict={'clone_uri': msg}) + except Exception: + log.exception('Url validation failed') + msg = M(self, 'clone_uri', rtype=repo_type) + raise formencode.Invalid(msg, value, state, + error_dict={'clone_uri': msg}) + return _validator + + +def ValidForkType(old_data={}): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_fork_type': _(u'Fork have to be the same type as parent') + } + + def validate_python(self, value, state): + if old_data['repo_type'] != value: + msg = M(self, 'invalid_fork_type', state) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_type': msg} + ) + return _validator + + +def CanWriteGroup(old_data=None): + class _validator(formencode.validators.FancyValidator): + messages = { + 'permission_denied': _( + u"You do not have the permission " + u"to create repositories in this group."), + 'permission_denied_root': _( + u"You do not have the permission to store repositories in " + u"the root location.") + } + + def _to_python(self, value, state): + # root location + if value in [-1, "-1"]: + return None + return value + + def validate_python(self, value, state): + gr = RepoGroup.get(value) + gr_name = gr.group_name if gr else None # None means ROOT location + # create repositories with write permission on group is set to true + create_on_write = HasPermissionAny( + 'hg.create.write_on_repogroup.true')() + group_admin = HasRepoGroupPermissionAny('group.admin')( + gr_name, 'can write into group validator') + group_write = HasRepoGroupPermissionAny('group.write')( + gr_name, 'can write into group validator') + forbidden = not (group_admin or (group_write and create_on_write)) + can_create_repos = HasPermissionAny( + 'hg.admin', 'hg.create.repository') + gid = (old_data['repo_group'].get('group_id') + if (old_data and 'repo_group' in old_data) else None) + value_changed = gid != safe_int(value) + new = not old_data + # do check if we changed the value, there's a case that someone got + # revoked write permissions to a repository, he still created, we + # don't need to check permission if he didn't change the value of + # groups in form box + if value_changed or new: + # parent group need to be existing + if gr and forbidden: + msg = M(self, 'permission_denied', state) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_type': msg} + ) + # check if we can write to root location ! + elif gr is None and not can_create_repos(): + msg = M(self, 'permission_denied_root', state) + raise formencode.Invalid( + msg, value, state, error_dict={'repo_type': msg} + ) + + return _validator + + +def ValidPerms(type_='repo'): + if type_ == 'repo_group': + EMPTY_PERM = 'group.none' + elif type_ == 'repo': + EMPTY_PERM = 'repository.none' + elif type_ == 'user_group': + EMPTY_PERM = 'usergroup.none' + + class _validator(formencode.validators.FancyValidator): + messages = { + 'perm_new_member_name': + _(u'This username or user group name is not valid') + } + + def _to_python(self, value, state): + perm_updates = OrderedSet() + perm_additions = OrderedSet() + perm_deletions = OrderedSet() + # build a list of permission to update/delete and new permission + + # Read the perm_new_member/perm_del_member attributes and group + # them by they IDs + new_perms_group = defaultdict(dict) + del_perms_group = defaultdict(dict) + for k, v in value.copy().iteritems(): + if k.startswith('perm_del_member'): + # delete from org storage so we don't process that later + del value[k] + # part is `id`, `type` + _type, part = k.split('perm_del_member_') + args = part.split('_') + if len(args) == 2: + _key, pos = args + del_perms_group[pos][_key] = v + if k.startswith('perm_new_member'): + # delete from org storage so we don't process that later + del value[k] + # part is `id`, `type`, `perm` + _type, part = k.split('perm_new_member_') + args = part.split('_') + if len(args) == 2: + _key, pos = args + new_perms_group[pos][_key] = v + + # store the deletes + for k in sorted(del_perms_group.keys()): + perm_dict = del_perms_group[k] + del_member = perm_dict.get('id') + del_type = perm_dict.get('type') + if del_member and del_type: + perm_deletions.add((del_member, None, del_type)) + + # store additions in order of how they were added in web form + for k in sorted(new_perms_group.keys()): + perm_dict = new_perms_group[k] + new_member = perm_dict.get('id') + new_type = perm_dict.get('type') + new_perm = perm_dict.get('perm') + if new_member and new_perm and new_type: + perm_additions.add((new_member, new_perm, new_type)) + + # get updates of permissions + # (read the existing radio button states) + for k, update_value in value.iteritems(): + if k.startswith('u_perm_') or k.startswith('g_perm_'): + member = k[7:] + update_type = {'u': 'user', + 'g': 'users_group'}[k[0]] + if member == User.DEFAULT_USER: + if str2bool(value.get('repo_private')): + # set none for default when updating to + # private repo protects agains form manipulation + update_value = EMPTY_PERM + perm_updates.add((member, update_value, update_type)) + # check the deletes + + value['perm_additions'] = list(perm_additions) + value['perm_updates'] = list(perm_updates) + value['perm_deletions'] = list(perm_deletions) + + # validate users they exist and they are active ! + for member_id, _perm, member_type in perm_additions: + try: + if member_type == 'user': + self.user_db = User.query()\ + .filter(User.active == true())\ + .filter(User.user_id == member_id).one() + if member_type == 'users_group': + self.user_db = UserGroup.query()\ + .filter(UserGroup.users_group_active == true())\ + .filter(UserGroup.users_group_id == member_id)\ + .one() + + except Exception: + log.exception('Updated permission failed: org_exc:') + msg = M(self, 'perm_new_member_type', state) + raise formencode.Invalid( + msg, value, state, error_dict={ + 'perm_new_member_name': msg} + ) + return value + return _validator + + +def ValidSettings(): + class _validator(formencode.validators.FancyValidator): + def _to_python(self, value, state): + # settings form for users that are not admin + # can't edit certain parameters, it's extra backup if they mangle + # with forms + + forbidden_params = [ + 'user', 'repo_type', 'repo_enable_locking', + 'repo_enable_downloads', 'repo_enable_statistics' + ] + + for param in forbidden_params: + if param in value: + del value[param] + return value + + def validate_python(self, value, state): + pass + return _validator + + +def ValidPath(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'invalid_path': _(u'This is not a valid path') + } + + def validate_python(self, value, state): + if not os.path.isdir(value): + msg = M(self, 'invalid_path', state) + raise formencode.Invalid( + msg, value, state, error_dict={'paths_root_path': msg} + ) + return _validator + + +def UniqSystemEmail(old_data={}): + class _validator(formencode.validators.FancyValidator): + messages = { + 'email_taken': _(u'This e-mail address is already taken') + } + + def _to_python(self, value, state): + return value.lower() + + def validate_python(self, value, state): + if (old_data.get('email') or '').lower() != value: + user = User.get_by_email(value, case_insensitive=True) + if user: + msg = M(self, 'email_taken', state) + raise formencode.Invalid( + msg, value, state, error_dict={'email': msg} + ) + return _validator + + +def ValidSystemEmail(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'non_existing_email': _(u'e-mail "%(email)s" does not exist.') + } + + def _to_python(self, value, state): + return value.lower() + + def validate_python(self, value, state): + user = User.get_by_email(value, case_insensitive=True) + if user is None: + msg = M(self, 'non_existing_email', state, email=value) + raise formencode.Invalid( + msg, value, state, error_dict={'email': msg} + ) + + return _validator + + +def NotReviewedRevisions(repo_id): + class _validator(formencode.validators.FancyValidator): + messages = { + 'rev_already_reviewed': + _(u'Revisions %(revs)s are already part of pull request ' + u'or have set status'), + } + + def validate_python(self, value, state): + # check revisions if they are not reviewed, or a part of another + # pull request + statuses = ChangesetStatus.query()\ + .filter(ChangesetStatus.revision.in_(value))\ + .filter(ChangesetStatus.repo_id == repo_id)\ + .all() + + errors = [] + for status in statuses: + if status.pull_request_id: + errors.append(['pull_req', status.revision[:12]]) + elif status.status: + errors.append(['status', status.revision[:12]]) + + if errors: + revs = ','.join([x[1] for x in errors]) + msg = M(self, 'rev_already_reviewed', state, revs=revs) + raise formencode.Invalid( + msg, value, state, error_dict={'revisions': revs}) + + return _validator + + +def ValidIp(): + class _validator(CIDR): + messages = { + 'badFormat': _(u'Please enter a valid IPv4 or IpV6 address'), + 'illegalBits': _( + u'The network size (bits) must be within the range ' + u'of 0-32 (not %(bits)r)'), + } + + # we ovveride the default to_python() call + def to_python(self, value, state): + v = super(_validator, self).to_python(value, state) + v = v.strip() + net = ipaddress.ip_network(address=v, strict=False) + return str(net) + + def validate_python(self, value, state): + try: + addr = value.strip() + # this raises an ValueError if address is not IpV4 or IpV6 + ipaddress.ip_network(addr, strict=False) + except ValueError: + raise formencode.Invalid(self.message('badFormat', state), + value, state) + + return _validator + + +def FieldKey(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'badFormat': _( + u'Key name can only consist of letters, ' + u'underscore, dash or numbers'), + } + + def validate_python(self, value, state): + if not re.match('[a-zA-Z0-9_-]+$', value): + raise formencode.Invalid(self.message('badFormat', state), + value, state) + return _validator + + +def BasePath(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'badPath': _(u'Filename cannot be inside a directory'), + } + + def _to_python(self, value, state): + return value + + def validate_python(self, value, state): + if value != os.path.basename(value): + raise formencode.Invalid(self.message('badPath', state), + value, state) + return _validator + + +def ValidAuthPlugins(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'import_duplicate': _( + u'Plugins %(loaded)s and %(next_to_load)s ' + u'both export the same name'), + } + + def _to_python(self, value, state): + # filter empty values + return filter(lambda s: s not in [None, ''], value) + + def validate_python(self, value, state): + from rhodecode.authentication.base import loadplugin + module_list = value + unique_names = {} + try: + for module in module_list: + plugin = loadplugin(module) + plugin_name = plugin.name + if plugin_name in unique_names: + msg = M(self, 'import_duplicate', state, + loaded=unique_names[plugin_name], + next_to_load=plugin_name) + raise formencode.Invalid(msg, value, state) + unique_names[plugin_name] = plugin + except (KeyError, AttributeError, TypeError) as e: + raise formencode.Invalid(str(e), value, state) + + return _validator + + +def UniqGistId(): + class _validator(formencode.validators.FancyValidator): + messages = { + 'gistid_taken': _(u'This gistid is already in use') + } + + def _to_python(self, value, state): + return repo_name_slug(value.lower()) + + def validate_python(self, value, state): + existing = Gist.get_by_access_id(value) + if existing: + msg = M(self, 'gistid_taken', state) + raise formencode.Invalid( + msg, value, state, error_dict={'gistid': msg} + ) + + return _validator + + +def ValidPattern(): + + class _Validator(formencode.validators.FancyValidator): + + def _to_python(self, value, state): + patterns = [] + + prefix = 'new_pattern' + for name, v in value.iteritems(): + pattern_name = '_'.join((prefix, 'pattern')) + if name.startswith(pattern_name): + new_item_id = name[len(pattern_name)+1:] + + def _field(name): + return '%s_%s_%s' % (prefix, name, new_item_id) + + values = { + 'issuetracker_pat': value.get(_field('pattern')), + 'issuetracker_pat': value.get(_field('pattern')), + 'issuetracker_url': value.get(_field('url')), + 'issuetracker_pref': value.get(_field('prefix')), + 'issuetracker_desc': value.get(_field('description')) + } + new_uid = md5(values['issuetracker_pat']) + + has_required_fields = ( + values['issuetracker_pat'] + and values['issuetracker_url']) + + if has_required_fields: + settings = [ + ('_'.join((key, new_uid)), values[key], 'unicode') + for key in values] + patterns.append(settings) + + value['patterns'] = patterns + delete_patterns = value.get('uid') or [] + if not isinstance(delete_patterns, (list, tuple)): + delete_patterns = [delete_patterns] + value['delete_patterns'] = delete_patterns + return value + return _Validator diff --git a/rhodecode/public/css/alerts.less b/rhodecode/public/css/alerts.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/alerts.less @@ -0,0 +1,58 @@ +.alert1 { .border ( @border-thickness-tags, @alert1 ); color:@alert1; } +.alert2 { .border ( @border-thickness-tags, @alert2 ); color:@alert2; } +.alert3 { .border ( @border-thickness-tags, @alert3 ); color:@alert3; } +.alert4 { .border ( @border-thickness-tags, @alert4 ); color:@alert4; } + +.alert { + clear: both; + margin: @space auto 0 auto; + padding: @padding; + border: @border-thickness solid; + border-radius: @border-radius; + + // overwritter css from specific alerts + color: @grey3; + border-color: @alert4; + background-color: @alert4-inner; + + a { + text-decoration: underline; + } + .close { + color: @grey3; + } +} + +.infoform .alert { + width: 100%; + margin-top: 0; +} + +.alert-success { + border-color: @alert1; + background-color: @alert1-inner; +} + +.alert-error { + border-color: @alert2; + background-color: @alert2-inner; +} + +.alert-warning { + border-color: @alert3; + background-color: @alert3-inner; +} + +.alert-dismissable { + padding-right: 10px; + + .close { + margin-top: -5px; + } +} + +.loginbox { + .alert { + margin: 0 auto 35px auto; + } +} diff --git a/rhodecode/public/css/bootstrap-variables.less b/rhodecode/public/css/bootstrap-variables.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/bootstrap-variables.less @@ -0,0 +1,856 @@ +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +@gray-base: #000; +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 20%); // #333 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +@brand-primary: darken(#428bca, 6.5%); +@brand-success: #5cb85c; +@brand-info: #5bc0de; +@brand-warning: #f0ad4e; +@brand-danger: #d9534f; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for `<body>`. +@body-bg: #fff; +//** Global text color on `<body>`. +@text-color: @gray-dark; + +//** Global textual link color. +@link-color: @brand-primary; +//** Link hover color set via `darken()` function. +@link-hover-color: darken(@link-color, 15%); +//** Link hover decoration. +@link-hover-decoration: underline; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`. +@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; +@font-family-base: @font-family-sans-serif; + +@font-size-base: 14px; +@font-size-large: ceil((@font-size-base * 1.25)); // ~18px +@font-size-small: ceil((@font-size-base * 0.85)); // ~12px + +@font-size-h1: floor((@font-size-base * 2.6)); // ~36px +@font-size-h2: floor((@font-size-base * 2.15)); // ~30px +@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px +@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px +@font-size-h5: @font-size-base; +@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px + +//** Unit-less `line-height` for use in components like buttons. +@line-height-base: 1.428571429; // 20/14 +//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc. +@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px + +//** By default, this inherits from the `<body>`. +@headings-font-family: inherit; +@headings-font-weight: 500; +@headings-line-height: 1.1; +@headings-color: inherit; + + +//== Iconography +// +//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower. + +//** Load fonts from this directory. +@icon-font-path: "../fonts/"; +//** File name for all font files. +@icon-font-name: "glyphicons-halflings-regular"; +//** Element ID within SVG icon file. +@icon-font-svg-id: "glyphicons_halflingsregular"; + + +//== Components +// +//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). + +@padding-base-vertical: 6px; +@padding-base-horizontal: 12px; + +@padding-large-vertical: 10px; +@padding-large-horizontal: 16px; + +@padding-small-vertical: 5px; +@padding-small-horizontal: 10px; + +@padding-xs-vertical: 1px; +@padding-xs-horizontal: 5px; + +@line-height-large: 1.33; +@line-height-small: 1.5; + +@border-radius-base: @border-radius; +@border-radius-large: 6px; +@border-radius-small: 3px; + +//** Global color for active items (e.g., navs or dropdowns). +@component-active-color: #fff; +//** Global background color for active items (e.g., navs or dropdowns). +@component-active-bg: @brand-primary; + +//** Width of the `border` for generating carets that indicator dropdowns. +@caret-width-base: 4px; +//** Carets increase slightly in size for larger components. +@caret-width-large: 5px; + + +//== Tables +// +//## Customizes the `.table` component with basic values, each used across all table variations. + +//** Padding for `<th>`s and `<td>`s. +@table-cell-padding: 8px; +//** Padding for cells in `.table-condensed`. +@table-condensed-cell-padding: 5px; + +//** Default background color used for all tables. +@table-bg: transparent; +//** Background color used for `.table-striped`. +@table-bg-accent: #f9f9f9; +//** Background color used for `.table-hover`. +@table-bg-hover: #f5f5f5; +@table-bg-active: @table-bg-hover; + +//** Border color for table and cell borders. +@table-border-color: #ddd; + + +//== Buttons +// +//## For each of Bootstrap's buttons, define text, background and border color. + +@btn-font-weight: normal; + +@btn-default-color: #333; +@btn-default-bg: #fff; +@btn-default-border: #ccc; + +@btn-primary-color: #fff; +@btn-primary-bg: @brand-primary; +@btn-primary-border: darken(@btn-primary-bg, 5%); + +@btn-success-color: #fff; +@btn-success-bg: @brand-success; +@btn-success-border: darken(@btn-success-bg, 5%); + +@btn-info-color: #fff; +@btn-info-bg: @brand-info; +@btn-info-border: darken(@btn-info-bg, 5%); + +@btn-warning-color: #fff; +@btn-warning-bg: @brand-warning; +@btn-warning-border: darken(@btn-warning-bg, 5%); + +@btn-danger-color: #fff; +@btn-danger-bg: @brand-danger; +@btn-danger-border: darken(@btn-danger-bg, 5%); + +@btn-link-disabled-color: @gray-light; + + +//== Forms +// +//## + +//** `<input>` background color +@input-bg: #fff; +//** `<input disabled>` background color +@input-bg-disabled: @gray-lighter; + +//** Text color for `<input>`s +@input-color: @gray; +//** `<input>` border color +@input-border: #ccc; + +// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4 +//** Default `.form-control` border radius +@input-border-radius: @border-radius-base; +//** Large `.form-control` border radius +@input-border-radius-large: @border-radius-large; +//** Small `.form-control` border radius +@input-border-radius-small: @border-radius-small; + +//** Border color for inputs on focus +@input-border-focus: #66afe9; + +//** Placeholder text color +@input-color-placeholder: #999; + +//** Default `.form-control` height +@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2); +//** Large `.form-control` height +@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2); +//** Small `.form-control` height +@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2); + +@legend-color: @gray-dark; +@legend-border-color: #e5e5e5; + +//** Background color for textual input addons +@input-group-addon-bg: @gray-lighter; +//** Border color for textual input addons +@input-group-addon-border-color: @input-border; + +//** Disabled cursor for form controls and buttons. +@cursor-disabled: not-allowed; + + +//== Dropdowns +// +//## Dropdown menu container and contents. + +//** Background for the dropdown menu. +@dropdown-bg: #fff; +//** Dropdown menu `border-color`. +@dropdown-border: rgba(0,0,0,.15); +//** Dropdown menu `border-color` **for IE8**. +@dropdown-fallback-border: #ccc; +//** Divider color for between dropdown items. +@dropdown-divider-bg: #e5e5e5; + +//** Dropdown link text color. +@dropdown-link-color: @gray-dark; +//** Hover color for dropdown links. +@dropdown-link-hover-color: darken(@gray-dark, 5%); +//** Hover background for dropdown links. +@dropdown-link-hover-bg: #f5f5f5; + +//** Active dropdown menu item text color. +@dropdown-link-active-color: @component-active-color; +//** Active dropdown menu item background color. +@dropdown-link-active-bg: @component-active-bg; + +//** Disabled dropdown menu item background color. +@dropdown-link-disabled-color: @gray-light; + +//** Text color for headers within dropdown menus. +@dropdown-header-color: @gray-light; + +//** Deprecated `@dropdown-caret-color` as of v3.1.0 +@dropdown-caret-color: #000; + + +//-- Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. +// +// Note: These variables are not generated into the Customizer. + +@zindex-navbar: 1000; +@zindex-dropdown: 1000; +@zindex-popover: 1060; +@zindex-tooltip: 1070; +@zindex-navbar-fixed: 1030; +@zindex-modal: 1040; + + +//== Media queries breakpoints +// +//## Define the breakpoints at which your layout will change, adapting to different screen sizes. + +// Extra small screen / phone +//** Deprecated `@screen-xs` as of v3.0.1 +@screen-xs: 480px; +//** Deprecated `@screen-xs-min` as of v3.2.0 +@screen-xs-min: @screen-xs; +//** Deprecated `@screen-phone` as of v3.0.1 +@screen-phone: @screen-xs-min; + +// Small screen / tablet +//** Deprecated `@screen-sm` as of v3.0.1 +@screen-sm: 768px; +@screen-sm-min: @screen-sm; +//** Deprecated `@screen-tablet` as of v3.0.1 +@screen-tablet: @screen-sm-min; + +// Medium screen / desktop +//** Deprecated `@screen-md` as of v3.0.1 +@screen-md: 992px; +@screen-md-min: @screen-md; +//** Deprecated `@screen-desktop` as of v3.0.1 +@screen-desktop: @screen-md-min; + +// Large screen / wide desktop +//** Deprecated `@screen-lg` as of v3.0.1 +@screen-lg: 1200px; +@screen-lg-min: @screen-lg; +//** Deprecated `@screen-lg-desktop` as of v3.0.1 +@screen-lg-desktop: @screen-lg-min; + +// So media queries don't overlap when required, provide a maximum +@screen-xs-max: (@screen-sm-min - 1); +@screen-sm-max: (@screen-md-min - 1); +@screen-md-max: (@screen-lg-min - 1); + + +//== Grid system +// +//## Define your custom responsive grid. + +//** Number of columns in the grid. +@grid-columns: 12; +//** Padding between columns. Gets divided in half for the left and right. +@grid-gutter-width: 30px; +// Navbar collapse +//** Point at which the navbar becomes uncollapsed. +@grid-float-breakpoint: @screen-sm-min; +//** Point at which the navbar begins collapsing. +@grid-float-breakpoint-max: (@grid-float-breakpoint - 1); + + +//== Container sizes +// +//## Define the maximum width of `.container` for different screen sizes. + +// Small screen / tablet +@container-tablet: (720px + @grid-gutter-width); +//** For `@screen-sm-min` and up. +@container-sm: @container-tablet; + +// Medium screen / desktop +@container-desktop: (940px + @grid-gutter-width); +//** For `@screen-md-min` and up. +@container-md: @container-desktop; + +// Large screen / wide desktop +@container-large-desktop: (1140px + @grid-gutter-width); +//** For `@screen-lg-min` and up. +@container-lg: @container-large-desktop; + + +//== Navbar +// +//## + +// Basics of a navbar +@navbar-height: 50px; +@navbar-margin-bottom: @line-height-computed; +@navbar-border-radius: @border-radius-base; +@navbar-padding-horizontal: floor((@grid-gutter-width / 2)); +@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2); +@navbar-collapse-max-height: 340px; + +@navbar-default-color: #777; +@navbar-default-bg: #f8f8f8; +@navbar-default-border: darken(@navbar-default-bg, 6.5%); + +// Navbar links +@navbar-default-link-color: #777; +@navbar-default-link-hover-color: #333; +@navbar-default-link-hover-bg: transparent; +@navbar-default-link-active-color: #555; +@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%); +@navbar-default-link-disabled-color: #ccc; +@navbar-default-link-disabled-bg: transparent; + +// Navbar brand label +@navbar-default-brand-color: @navbar-default-link-color; +@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%); +@navbar-default-brand-hover-bg: transparent; + +// Navbar toggle +@navbar-default-toggle-hover-bg: #ddd; +@navbar-default-toggle-icon-bar-bg: #888; +@navbar-default-toggle-border-color: #ddd; + + +// Inverted navbar +// Reset inverted navbar basics +@navbar-inverse-color: lighten(@gray-light, 15%); +@navbar-inverse-bg: #222; +@navbar-inverse-border: darken(@navbar-inverse-bg, 10%); + +// Inverted navbar links +@navbar-inverse-link-color: lighten(@gray-light, 15%); +@navbar-inverse-link-hover-color: #fff; +@navbar-inverse-link-hover-bg: transparent; +@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color; +@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%); +@navbar-inverse-link-disabled-color: #444; +@navbar-inverse-link-disabled-bg: transparent; + +// Inverted navbar brand label +@navbar-inverse-brand-color: @navbar-inverse-link-color; +@navbar-inverse-brand-hover-color: #fff; +@navbar-inverse-brand-hover-bg: transparent; + +// Inverted navbar toggle +@navbar-inverse-toggle-hover-bg: #333; +@navbar-inverse-toggle-icon-bar-bg: #fff; +@navbar-inverse-toggle-border-color: #333; + + +//== Navs +// +//## + +//=== Shared nav styles +@nav-link-padding: 10px 15px; +@nav-link-hover-bg: @gray-lighter; + +@nav-disabled-link-color: @gray-light; +@nav-disabled-link-hover-color: @gray-light; + +//== Tabs +@nav-tabs-border-color: #ddd; + +@nav-tabs-link-hover-border-color: @gray-lighter; + +@nav-tabs-active-link-hover-bg: @body-bg; +@nav-tabs-active-link-hover-color: @gray; +@nav-tabs-active-link-hover-border-color: #ddd; + +@nav-tabs-justified-link-border-color: #ddd; +@nav-tabs-justified-active-link-border-color: @body-bg; + +//== Pills +@nav-pills-border-radius: @border-radius-base; +@nav-pills-active-link-hover-bg: @component-active-bg; +@nav-pills-active-link-hover-color: @component-active-color; + + +//== Pagination +// +//## + +@pagination-color: @link-color; +@pagination-bg: #fff; +@pagination-border: #ddd; + +@pagination-hover-color: @link-hover-color; +@pagination-hover-bg: @gray-lighter; +@pagination-hover-border: #ddd; + +@pagination-active-color: #fff; +@pagination-active-bg: @brand-primary; +@pagination-active-border: @brand-primary; + +@pagination-disabled-color: @gray-light; +@pagination-disabled-bg: #fff; +@pagination-disabled-border: #ddd; + + +//== Pager +// +//## + +@pager-bg: @pagination-bg; +@pager-border: @pagination-border; +@pager-border-radius: 15px; + +@pager-hover-bg: @pagination-hover-bg; + +@pager-active-bg: @pagination-active-bg; +@pager-active-color: @pagination-active-color; + +@pager-disabled-color: @pagination-disabled-color; + + +//== Jumbotron +// +//## + +@jumbotron-padding: 30px; +@jumbotron-color: inherit; +@jumbotron-bg: @gray-lighter; +@jumbotron-heading-color: inherit; +@jumbotron-font-size: ceil((@font-size-base * 1.5)); + + +//== Form states and alerts +// +//## Define colors for form feedback states and, by default, alerts. + +@state-success-text: #3c763d; +@state-success-bg: #dff0d8; +@state-success-border: darken(spin(@state-success-bg, -10), 5%); + +@state-info-text: #31708f; +@state-info-bg: #d9edf7; +@state-info-border: darken(spin(@state-info-bg, -10), 7%); + +@state-warning-text: #8a6d3b; +@state-warning-bg: #fcf8e3; +@state-warning-border: darken(spin(@state-warning-bg, -10), 5%); + +@state-danger-text: #a94442; +@state-danger-bg: #f2dede; +@state-danger-border: darken(spin(@state-danger-bg, -10), 5%); + + +//== Tooltips +// +//## + +//** Tooltip max width +@tooltip-max-width: 200px; +//** Tooltip text color +@tooltip-color: #fff; +//** Tooltip background color +@tooltip-bg: #000; +@tooltip-opacity: .9; + +//** Tooltip arrow width +@tooltip-arrow-width: 5px; +//** Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + + +//== Popovers +// +//## + +//** Popover body background color +@popover-bg: #fff; +//** Popover maximum width +@popover-max-width: 276px; +//** Popover border color +@popover-border-color: rgba(0,0,0,.2); +//** Popover fallback border color +@popover-fallback-border-color: #ccc; + +//** Popover title background color +@popover-title-bg: darken(@popover-bg, 3%); + +//** Popover arrow width +@popover-arrow-width: 10px; +//** Popover arrow color +@popover-arrow-color: @popover-bg; + +//** Popover outer arrow width +@popover-arrow-outer-width: (@popover-arrow-width + 1); +//** Popover outer arrow color +@popover-arrow-outer-color: fadein(@popover-border-color, 5%); +//** Popover outer arrow fallback color +@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%); + + +//== Labels +// +//## + +//** Default label background color +@label-default-bg: @gray-light; +//** Primary label background color +@label-primary-bg: @brand-primary; +//** Success label background color +@label-success-bg: @brand-success; +//** Info label background color +@label-info-bg: @brand-info; +//** Warning label background color +@label-warning-bg: @brand-warning; +//** Danger label background color +@label-danger-bg: @brand-danger; + +//** Default label text color +@label-color: #fff; +//** Default text color of a linked label +@label-link-hover-color: #fff; + + +//== Modals +// +//## + +//** Padding applied to the modal body +@modal-inner-padding: 15px; + +//** Padding applied to the modal title +@modal-title-padding: 15px; +//** Modal title line-height +@modal-title-line-height: @line-height-base; + +//** Background color of modal content area +@modal-content-bg: #fff; +//** Modal content border color +@modal-content-border-color: rgba(0,0,0,.2); +//** Modal content border color **for IE8** +@modal-content-fallback-border-color: #999; + +//** Modal backdrop background color +@modal-backdrop-bg: #000; +//** Modal backdrop opacity +@modal-backdrop-opacity: .5; +//** Modal header border color +@modal-header-border-color: #e5e5e5; +//** Modal footer border color +@modal-footer-border-color: @modal-header-border-color; + +@modal-lg: 900px; +@modal-md: 600px; +@modal-sm: 300px; + + +//== Alerts +// +//## Define alert colors, border radius, and padding. + +@alert-padding: 15px; +@alert-border-radius: @border-radius-base; +@alert-link-font-weight: bold; + +@alert-success-bg: @state-success-bg; +@alert-success-text: @state-success-text; +@alert-success-border: @state-success-border; + +@alert-info-bg: @state-info-bg; +@alert-info-text: @state-info-text; +@alert-info-border: @state-info-border; + +@alert-warning-bg: @state-warning-bg; +@alert-warning-text: @state-warning-text; +@alert-warning-border: @state-warning-border; + +@alert-danger-bg: @state-danger-bg; +@alert-danger-text: @state-danger-text; +@alert-danger-border: @state-danger-border; + + +//== Progress bars +// +//## + +//** Background color of the whole progress component +@progress-bg: #f5f5f5; +//** Progress bar text color +@progress-bar-color: #fff; +//** Variable for setting rounded corners on progress bar. +@progress-border-radius: @border-radius-base; + +//** Default progress bar color +@progress-bar-bg: @brand-primary; +//** Success progress bar color +@progress-bar-success-bg: @brand-success; +//** Warning progress bar color +@progress-bar-warning-bg: @brand-warning; +//** Danger progress bar color +@progress-bar-danger-bg: @brand-danger; +//** Info progress bar color +@progress-bar-info-bg: @brand-info; + + +//== List group +// +//## + +//** Background color on `.list-group-item` +@list-group-bg: #fff; +//** `.list-group-item` border color +@list-group-border: #ddd; +//** List group border radius +@list-group-border-radius: @border-radius-base; + +//** Background color of single list items on hover +@list-group-hover-bg: #f5f5f5; +//** Text color of active list items +@list-group-active-color: @component-active-color; +//** Background color of active list items +@list-group-active-bg: @component-active-bg; +//** Border color of active list elements +@list-group-active-border: @list-group-active-bg; +//** Text color for content within active list items +@list-group-active-text-color: lighten(@list-group-active-bg, 40%); + +//** Text color of disabled list items +@list-group-disabled-color: @gray-light; +//** Background color of disabled list items +@list-group-disabled-bg: @gray-lighter; +//** Text color for content within disabled list items +@list-group-disabled-text-color: @list-group-disabled-color; + +@list-group-link-color: #555; +@list-group-link-hover-color: @list-group-link-color; +@list-group-link-heading-color: #333; + + +//== Panels +// +//## + +@panel-bg: #fff; +@panel-body-padding: @padding; +@panel-heading-padding: 10px 15px; +@panel-footer-padding: @panel-heading-padding; +@panel-border-radius: @border-radius-base; + +//** Border color for elements within panels +@panel-inner-border: #ddd; +@panel-footer-bg: #fff; + +@panel-default-text: @text-color; +@panel-default-border: @grey5; +@panel-default-heading-bg: @grey6; + +@panel-primary-text: #fff; +@panel-primary-border: @brand-primary; +@panel-primary-heading-bg: @brand-primary; + +@panel-success-text: @state-success-text; +@panel-success-border: @state-success-border; +@panel-success-heading-bg: @state-success-bg; + +@panel-info-text: @state-info-text; +@panel-info-border: @state-info-border; +@panel-info-heading-bg: @state-info-bg; + +@panel-warning-text: @state-warning-text; +@panel-warning-border: @state-warning-border; +@panel-warning-heading-bg: @state-warning-bg; + +@panel-danger-text: @state-danger-text; +@panel-danger-border: @state-danger-border; +@panel-danger-heading-bg: @state-danger-bg; + + +//== Thumbnails +// +//## + +//** Padding around the thumbnail image +@thumbnail-padding: 4px; +//** Thumbnail background color +@thumbnail-bg: @body-bg; +//** Thumbnail border color +@thumbnail-border: #ddd; +//** Thumbnail border radius +@thumbnail-border-radius: @border-radius-base; + +//** Custom text color for thumbnail captions +@thumbnail-caption-color: @text-color; +//** Padding around the thumbnail caption +@thumbnail-caption-padding: 9px; + + +//== Wells +// +//## + +@well-bg: #f5f5f5; +@well-border: darken(@well-bg, 7%); + + +//== Badges +// +//## + +@badge-color: #fff; +//** Linked badge text color on hover +@badge-link-hover-color: #fff; +@badge-bg: @gray-light; + +//** Badge text color in active nav link +@badge-active-color: @link-color; +//** Badge background color in active nav link +@badge-active-bg: #fff; + +@badge-font-weight: bold; +@badge-line-height: 1; +@badge-border-radius: 10px; + + +//== Breadcrumbs +// +//## + +@breadcrumb-padding-vertical: 8px; +@breadcrumb-padding-horizontal: 15px; +//** Breadcrumb background color +@breadcrumb-bg: #f5f5f5; +//** Breadcrumb text color +@breadcrumb-color: #ccc; +//** Text color of current page in the breadcrumb +@breadcrumb-active-color: @gray-light; +//** Textual separator for between breadcrumb elements +@breadcrumb-separator: "/"; + + +//== Carousel +// +//## + +@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6); + +@carousel-control-color: #fff; +@carousel-control-width: 15%; +@carousel-control-opacity: .5; +@carousel-control-font-size: 20px; + +@carousel-indicator-active-bg: #fff; +@carousel-indicator-border-color: #fff; + +@carousel-caption-color: #fff; + + +//== Close +// +//## + +@close-font-weight: bold; +@close-color: #000; +@close-text-shadow: 0 1px 0 #fff; + + +//== Code +// +//## + +@code-color: #c7254e; +@code-bg: #f9f2f4; + +@kbd-color: #fff; +@kbd-bg: #333; + +@pre-bg: #f5f5f5; +@pre-color: @gray-dark; +@pre-border-color: #ccc; +@pre-scrollable-max-height: 340px; + + +//== Type +// +//## + +//** Horizontal offset for forms and lists. +@component-offset-horizontal: 180px; +//** Text muted color +@text-muted: @grey4; +//** Abbreviations and acronyms border color +@abbr-border-color: @gray-light; +//** Headings small color +@headings-small-color: @gray-light; +//** Blockquote small color +@blockquote-small-color: @gray-light; +//** Blockquote font size +@blockquote-font-size: (@font-size-base * 1.25); +//** Blockquote border color +@blockquote-border-color: @gray-lighter; +//** Page header border color +@page-header-border-color: @gray-lighter; +//** Width of horizontal description list titles +@dl-horizontal-offset: @component-offset-horizontal; +//** Horizontal line color. +@hr-border: @gray-lighter; diff --git a/rhodecode/public/css/buttons.less b/rhodecode/public/css/buttons.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/buttons.less @@ -0,0 +1,381 @@ + + +//BUTTONS +button, +.btn, +input[type="button"] { + -webkit-appearance: none; + display: inline-block; + margin: 0 @padding/3 0 0; + padding: @button-padding; + text-align: center; + font-size: @basefontsize; + line-height: 1em; + font-family: @text-light; + text-decoration: none; + text-shadow: none; + color: @grey4; + background-color: white; + background-image: none; + border: none; + .border ( @border-thickness-buttons, @grey4 ); + .border-radius (@border-radius); + cursor: pointer; + white-space: nowrap; + -webkit-transition: background .3s,color .3s; + -moz-transition: background .3s,color .3s; + -o-transition: background .3s,color .3s; + transition: background .3s,color .3s; + + a { + display: block; + margin: 0; + padding: 0; + color: inherit; + text-decoration: none; + + &:hover { + text-decoration: none; + } + } + + &:focus, + &:active { + outline:none; + } + &:hover { + color: white; + background-color: @grey4; + } + + .icon-remove-sign { + display: none; + } + + //disabled buttons + //last; overrides any other styles + &:disabled { + opacity: .7; + cursor: auto; + background-color: white; + color: @grey4; + text-shadow: none; + } + +} + + +.btn-default { + .border ( @border-thickness-buttons, @rcblue ); + background-image: none; + color: @rcblue; + + a { + color: @rcblue; + } + + &:hover, + &.active { + color: white; + background-color: @rcdarkblue; + .border ( @border-thickness, @rcdarkblue ); + + a { + color: white; + } + } + &:disabled { + .border ( @border-thickness-buttons, @grey4 ); + background-color: none; + } +} + +.btn-primary, +.btn-small, /* TODO: anderson: remove .btn-small to not mix with the new btn-sm */ +.btn-success { + .border ( @border-thickness, @rcblue ); + background-color: @rcblue; + color: white; + + a { + color: white; + } + + &:hover, + &.active { + .border ( @border-thickness, @rcdarkblue ); + color: white; + background-color: @rcdarkblue; + + a { + color: white; + } + } + &:disabled { + background-color: @rcblue; + } +} + +.btn-secondary { + &:extend(.btn-default); + + background-color: white; + + &:focus { + outline: 0; + } + + &:hover { + &:extend(.btn-default:hover); + } + + &.btn-link { + &:extend(.btn-link); + color: @rcblue; + } + + &:disabled { + color: @rcblue; + background-color: white; + } +} + +.btn-warning, +.btn-danger, +.revoke_perm, +.btn-x, +.form .action_button.btn-x { + .border ( @border-thickness, @alert2 ); + background-color: white; + color: @alert2; + + a { + color: @alert2; + } + + &:hover, + &.active { + .border ( @border-thickness, @alert2 ); + color: white; + background-color: @alert2; + + a { + color: white; + } + } + + i { + display:none; + } + + &:disabled { + background-color: white; + color: @alert2; + } +} + +.btn-sm, +.btn-mini, +.field-sm .btn { + padding: @padding/3; +} + +.btn-xs { + padding: @padding/4; +} + +.btn-lg { + padding: @padding * 1.2; +} + +.btn-link { + background: transparent; + border: none; + padding: 0; + color: @rcblue; + + &:hover { + background: transparent; + border: none; + color: @rcdarkblue; + } + + &:disabled { + color: @grey4; + } + + // TODO: johbo: Check if we can avoid this, indicates that the structure + // is not yet good. + // lisa: The button CSS reflects the button HTML; both need a cleanup. + &.btn-danger { + color: @alert2; + + &:hover { + color: darken(@alert2,30%); + } + + &:disabled { + color: @alert2; + } + } +} + +.btn-social { + &:extend(.btn-default); + margin: 5px 5px 5px 0px; + min-width: 150px; +} + +// TODO: johbo: check these exceptions + +.links { + + .btn + .btn { + margin-top: @padding; + } +} + + +.action_button { + display:inline; + margin: 0; + padding: 0 1em 0 0; + font-size: inherit; + color: @rcblue; + border: none; + .border-radius (0); + background-color: transparent; + + &:last-child { + border: none; + } + + &:hover { + color: @rcdarkblue; + background-color: transparent; + border: none; + } +} +.grid_delete { + .action_button { + border: none; + } +} + + +// TODO: johbo: Form button tweaks, check if we can use the classes instead +input[type="submit"] { + &:extend(.btn-primary); + + &:focus { + outline: 0; + } + + &:hover { + &:extend(.btn-primary:hover); + } + + &.btn-link { + &:extend(.btn-link); + color: @rcblue; + + &:disabled { + color: @rcblue; + background-color: transparent; + } + } + + &:disabled { + .border ( @border-thickness-buttons, @rcblue ); + background-color: @rcblue; + color: white; + } +} + +input[type="reset"] { + &:extend(.btn-default); + + // TODO: johbo: Check if this tweak can be avoided. + background: transparent; + + &:focus { + outline: 0; + } + + &:hover { + &:extend(.btn-default:hover); + } + + &.btn-link { + &:extend(.btn-link); + color: @rcblue; + + &:disabled { + border: none; + } + } + + &:disabled { + .border ( @border-thickness-buttons, @rcblue ); + background-color: white; + color: @rcblue; + } +} + +input[type="submit"], +input[type="reset"] { + &.btn-danger { + &:extend(.btn-danger); + + &:focus { + outline: 0; + } + + &:hover { + &:extend(.btn-danger:hover); + } + + &.btn-link { + &:extend(.btn-link); + color: @alert2; + + &:hover { + color: darken(@alert2,30%); + } + } + + &:disabled { + color: @alert2; + background-color: white; + } + } + &.btn-danger-action { + .border ( @border-thickness, @alert2 ); + background-color: @alert2; + color: white; + + a { + color: white; + } + + &:hover { + background-color: darken(@alert2,20%); + } + + &.active { + .border ( @border-thickness, @alert2 ); + color: white; + background-color: @alert2; + + a { + color: white; + } + } + + &:disabled { + background-color: white; + color: @alert2; + } + } +} + diff --git a/rhodecode/public/css/code-block.less b/rhodecode/public/css/code-block.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/code-block.less @@ -0,0 +1,600 @@ +// Default styles + +.diff-collapse { + margin: @padding 0; + text-align: right; +} + +.diff-container { + margin-bottom: @space; + + .diffblock { + margin-bottom: @space; + } + + &.hidden { + display: none; + overflow: hidden; + } +} + +.compare_view_files { + + .diff-container { + + .diffblock { + margin-bottom: 0; + } + } +} + +div.diffblock .sidebyside { + background: #ffffff; +} + +div.diffblock { + overflow-x: auto; + overflow-y: hidden; + clear: both; + padding: 0px; + background: @grey6; + border: @border-thickness solid @grey5; + -webkit-border-radius: @border-radius @border-radius 0px 0px; + border-radius: @border-radius @border-radius 0px 0px; + + + .comments-number { + float: right; + } + + // BEGIN CODE-HEADER STYLES + + .code-header { + background: @grey6; + padding: 10px 0 10px 0; + height: auto; + width: 100%; + + .hash { + float: left; + padding: 2px 0 0 2px; + } + + .date { + float: left; + text-transform: uppercase; + padding: 4px 0px 0px 2px; + } + + div { + margin-left: 4px; + } + + div.compare_header { + min-height: 40px; + margin: 0; + padding: 0 @padding; + + .drop-menu { + float:left; + display: block; + margin:0 0 @padding 0; + } + + .compare-label { + float: left; + clear: both; + display: inline-block; + min-width: 5em; + margin: 0; + padding: @button-padding @button-padding @button-padding 0; + font-family: @text-semibold; + } + + .compare-buttons { + float: left; + margin: 0; + padding: 0 0 @padding; + + .btn { + margin: 0 @padding 0 0; + } + } + } + + } + + .parents { + float: left; + width: 100px; + font-weight: 400; + vertical-align: middle; + padding: 0px 2px 0px 2px; + background-color: @grey6; + + #parent_link { + margin: 00px 2px; + + &.double { + margin: 0px 2px; + } + + &.disabled{ + margin-right: @padding; + } + } + } + + .children { + float: right; + width: 100px; + font-weight: 400; + vertical-align: middle; + text-align: right; + padding: 0px 2px 0px 2px; + background-color: @grey6; + + #child_link { + margin: 0px 2px; + + &.double { + margin: 0px 2px; + } + + &.disabled{ + margin-right: @padding; + } + } + } + + .changeset_header { + height: 16px; + + & > div{ + margin-right: @padding; + } + } + + .changeset_file { + text-align: left; + float: left; + padding: 0; + + a{ + display: inline-block; + margin-right: 0.5em; + } + + #selected_mode{ + margin-left: 0; + } + } + + .diff-menu-wrapper { + float: left; + } + + .diff-menu { + position: absolute; + background: none repeat scroll 0 0 #FFFFFF; + border-color: #003367 @grey3 @grey3; + border-right: 1px solid @grey3; + border-style: solid solid solid; + border-width: @border-thickness; + box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2); + margin-top: 5px; + margin-left: 1px; + } + + .diff-actions, .editor-actions { + float: left; + + input{ + margin: 0 0.5em 0 0; + } + } + + // END CODE-HEADER STYLES + + // BEGIN CODE-BODY STYLES + + .code-body { + background: white; + padding: 0; + background-color: #ffffff; + position: relative; + max-width: none; + box-sizing: border-box; + // TODO: johbo: Parent has overflow: auto, this forces the child here + // to have the intended size and to scroll. Should be simplified. + width: 100%; + overflow-x: auto; + } + + pre.raw { + background: white; + color: @grey1; + } + // END CODE-BODY STYLES + +} + + +table.code-difftable { + border-collapse: collapse; + width: 99%; + border-radius: 0px !important; + + td { + padding: 0 !important; + background: none !important; + border: 0 !important; + } + + .context { + background: none repeat scroll 0 0 #DDE7EF; + } + + .add { + background: none repeat scroll 0 0 #DDFFDD; + + ins { + background: none repeat scroll 0 0 #AAFFAA; + text-decoration: none; + } + } + + .del { + background: none repeat scroll 0 0 #FFDDDD; + + del { + background: none repeat scroll 0 0 #FFAAAA; + text-decoration: none; + } + } + + /** LINE NUMBERS **/ + .lineno { + padding-left: 2px; + padding-right: 2px; + text-align: right; + width: 32px; + -moz-user-select: none; + -webkit-user-select: none; + border-right: @border-thickness solid @grey5 !important; + border-left: 0px solid #CCC !important; + border-top: 0px solid #CCC !important; + border-bottom: none !important; + + a { + &:extend(pre); + text-align: right; + padding-right: 2px; + cursor: pointer; + display: block; + width: 32px; + } + } + + .context { + cursor: auto; + &:extend(pre); + } + + .lineno-inline { + background: none repeat scroll 0 0 #FFF !important; + padding-left: 2px; + padding-right: 2px; + text-align: right; + width: 30px; + -moz-user-select: none; + -webkit-user-select: none; + } + + /** CODE **/ + .code { + display: block; + width: 100%; + + td { + margin: 0; + padding: 0; + } + + pre { + margin: 0; + padding: 0; + margin-left: .5em; + } + } +} + + +// Comments + +div.comment:target { + border-left: 6px solid @comment-highlight-color; + padding-left: 3px; + margin-left: -9px; +} + +//TODO: anderson: can't get an absolute number out of anything, so had to put the +//current values that might change. But to make it clear I put as a calculation +@comment-max-width: 1065px; +@pr-extra-margin: 34px; +@pr-border-spacing: 4px; +@pr-comment-width: @comment-max-width - @pr-extra-margin - @pr-border-spacing; + +// Pull Request +.cs_files .code-difftable { + border: @border-thickness solid @grey5; //borders only on PRs + + .comment-inline-form, + div.comment { + width: @pr-comment-width; + } +} + +// Changeset +.code-difftable { + .comment-inline-form, + div.comment { + width: @comment-max-width; + } +} + +//Style page +@style-extra-margin: @sidebar-width + (@sidebarpadding * 3) + @padding; +#style-page .code-difftable{ + .comment-inline-form, + div.comment { + width: @comment-max-width - @style-extra-margin; + } +} + +#context-bar > h2 { + font-size: 20px; +} + +#context-bar > h2> a { + font-size: 20px; +} +// end of defaults + +.file_diff_buttons { + padding: 0 0 @padding; + + .drop-menu { + float: left; + margin: 0 @padding 0 0; + } + .btn { + margin: 0 @padding 0 0; + } +} + +.code-body.textarea.editor { + max-width: none; + padding: 15px; +} + +td.injected_diff{ + max-width: 1178px; + overflow-x: auto; + overflow-y: hidden; + + div.diff-container, + div.diffblock{ + max-width: 100%; + } + + div.code-body { + max-width: 1124px; + overflow-x: auto; + padding: 0; + } + div.diffblock { + border: none; + } + + &.inline-form { + width: 99% + } + } + + +table.code-difftable { + width: 100%; +} + +/** PYGMENTS COLORING **/ +div.codeblock { + + // TODO: johbo: Added interim to get rid of the margin around + // Select2 widgets. This needs further cleanup. + margin-top: @padding; + + overflow: auto; + padding: 0px; + border: @border-thickness solid @grey5; + background: @grey6; + .border-radius(@border-radius); + + #remove_gist { + float: right; + } + + .author { + clear: both; + vertical-align: middle; + font-family: @text-bold; + } + + .btn-mini { + float: left; + margin: 0 5px 0 0; + } + + .code-header { + padding: @padding; + border-bottom: @border-thickness solid @grey5; + + .stats { + clear: both; + margin: 0 0 @padding 0; + padding: 0; + .left { + float: left; + clear: left; + max-width: 75%; + margin: 0 0 @padding 0; + + &.item { + margin-right: @padding; + &.last { border-right: none; } + } + } + .buttons { float: right; } + .author { + height: 25px; margin-left: 15px; font-weight: bold; + } + } + + .commit { + margin: 5px 0 0 26px; + font-weight: normal; + white-space: pre-wrap; + } + } + + .message { + position: relative; + margin: @padding; + + .codeblock-label { + margin: 0 0 1em 0; + } + } + + .code-body { + padding: @padding; + background-color: #ffffff; + min-width: 100%; + box-sizing: border-box; + // TODO: johbo: Parent has overflow: auto, this forces the child here + // to have the intended size and to scroll. Should be simplified. + width: 100%; + overflow-x: auto; + } +} + +.code-highlighttable, +div.codeblock .code-body table { + width: 0 !important; + border: 0px !important; + margin: 0; + letter-spacing: normal; + + + td { + border: 0px !important; + vertical-align: top; + } +} + +div.codeblock .code-header .search-path { padding: 0 0 0 10px; } +div.search-code-body { + background-color: #ffffff; padding: 5px 0 5px 10px; + pre { + .match { background-color: #faffa6;} + .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; } + } +} + +div.annotatediv { margin-left: 2px; margin-right: 4px; } +.code-highlight { + margin: 0; padding: 0; border-left: @border-thickness solid @grey5; + pre, .linenodiv pre { padding: 0 5px; margin: 0; } + pre div:target {background-color: @comment-highlight-color !important;} +} + +.linenos a { text-decoration: none; } + +.CodeMirror-selected { background: @rchighlightblue; } +.CodeMirror-focused .CodeMirror-selected { background: @rchighlightblue; } +.CodeMirror ::selection { background: @rchighlightblue; } +.CodeMirror ::-moz-selection { background: @rchighlightblue; } + +.code { display: block; border:0px !important; } +.code-highlight, +.codehilite { + .hll { background-color: #ffffcc } + .c { color: #408080; font-style: italic } /* Comment */ + .err, .codehilite .err { border: @border-thickness solid #FF0000 } /* Error */ + .k { color: #008000; font-weight: bold } /* Keyword */ + .o { color: #666666 } /* Operator */ + .cm { color: #408080; font-style: italic } /* Comment.Multiline */ + .cp { color: #BC7A00 } /* Comment.Preproc */ + .c1 { color: #408080; font-style: italic } /* Comment.Single */ + .cs { color: #408080; font-style: italic } /* Comment.Special */ + .gd { color: #A00000 } /* Generic.Deleted */ + .ge { font-style: italic } /* Generic.Emph */ + .gr { color: #FF0000 } /* Generic.Error */ + .gh { color: #000080; font-weight: bold } /* Generic.Heading */ + .gi { color: #00A000 } /* Generic.Inserted */ + .go { color: #808080 } /* Generic.Output */ + .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ + .gs { font-weight: bold } /* Generic.Strong */ + .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ + .gt { color: #0040D0 } /* Generic.Traceback */ + .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ + .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ + .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ + .kp { color: #008000 } /* Keyword.Pseudo */ + .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ + .kt { color: #B00040 } /* Keyword.Type */ + .m { color: #666666 } /* Literal.Number */ + .s { color: #BA2121 } /* Literal.String */ + .na { color: #7D9029 } /* Name.Attribute */ + .nb { color: #008000 } /* Name.Builtin */ + .nc { color: #0000FF; font-weight: bold } /* Name.Class */ + .no { color: #880000 } /* Name.Constant */ + .nd { color: #AA22FF } /* Name.Decorator */ + .ni { color: #999999; font-weight: bold } /* Name.Entity */ + .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ + .nf { color: #0000FF } /* Name.Function */ + .nl { color: #A0A000 } /* Name.Label */ + .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ + .nt { color: #008000; font-weight: bold } /* Name.Tag */ + .nv { color: #19177C } /* Name.Variable */ + .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ + .w { color: #bbbbbb } /* Text.Whitespace */ + .mf { color: #666666 } /* Literal.Number.Float */ + .mh { color: #666666 } /* Literal.Number.Hex */ + .mi { color: #666666 } /* Literal.Number.Integer */ + .mo { color: #666666 } /* Literal.Number.Oct */ + .sb { color: #BA2121 } /* Literal.String.Backtick */ + .sc { color: #BA2121 } /* Literal.String.Char */ + .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ + .s2 { color: #BA2121 } /* Literal.String.Double */ + .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ + .sh { color: #BA2121 } /* Literal.String.Heredoc */ + .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ + .sx { color: #008000 } /* Literal.String.Other */ + .sr { color: #BB6688 } /* Literal.String.Regex */ + .s1 { color: #BA2121 } /* Literal.String.Single */ + .ss { color: #19177C } /* Literal.String.Symbol */ + .bp { color: #008000 } /* Name.Builtin.Pseudo */ + .vc { color: #19177C } /* Name.Variable.Class */ + .vg { color: #19177C } /* Name.Variable.Global */ + .vi { color: #19177C } /* Name.Variable.Instance */ + .il { color: #666666 } /* Literal.Number.Integer.Long */ +} + +/* customized pre blocks for markdown/rst */ +pre.literal-block, .codehilite pre{ + padding: @padding; + border: 1px solid @grey6; + .border-radius(@border-radius); + background-color: @grey7; +} diff --git a/rhodecode/public/css/codemirror.less b/rhodecode/public/css/codemirror.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/codemirror.less @@ -0,0 +1,405 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + border-radius: @border-radius; + border: @border-thickness solid @grey6; + margin: 0 0 @padding; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: @grey6; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: @grey4; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: @grey6; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +@-moz-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@-webkit-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + margin-bottom: -30px; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + height: 100%; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + border-right: none; + width: 0; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror ::selection { background: #d7d4f0; } +.CodeMirror ::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } + +/* codemirror autocomplete widget */ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 0; + + border-radius: @border-radius; + border: @border-thickness solid @rcblue; + + color: @rcblue; + background-color: white; + font-size: 95%; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 4px 8px; + max-width: 40em; + white-space: pre; + color: @rcblue; + cursor: pointer; +} + +.CodeMirror-hint-active { + background: @rclightblue; + color: @rcblue; +} + +.CodeMirror-hint-entry { + width: 38em; + color: @rcblue; +} + +.CodeMirror-hint-entry .gravatar { + margin-right: 4px; +} + +.CodeMirror-empty { + border: @border-thickness solid @grey5; +} + +.CodeMirror-focused { + border: @border-thickness solid @grey5; +} + +.CodeMirror-empty.CodeMirror-focused { + border: @border-thickness solid @grey5; +} + +.CodeMirror pre.CodeMirror-placeholder { + color: @grey4; +} + +/** RhodeCode Customizations **/ + +.CodeMirror.cm-s-rc-input { + border: @border-thickness solid @grey4; +} + +.CodeMirror-code pre { + border-right: 30px solid transparent; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; +} +.CodeMirror-wrap .CodeMirror-code pre { + border-right: none; + width: auto; +} diff --git a/rhodecode/public/css/comments.less b/rhodecode/public/css/comments.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/comments.less @@ -0,0 +1,356 @@ +// comments.less +// For use in RhodeCode applications; +// see style guide documentation for guidelines. + + +// Comments +.comments { + width: 100%; +} + +tr.inline-comments div { + max-width: 100%; + + p { + white-space: normal; + } + + code, pre, .code, dd { + overflow-x: auto; + width: 1062px; + } + + dd { + width: auto; + } +} + +#injected_page_comments { + .comment-previous-link, + .comment-next-link, + .comment-links-divider { + display: none; + } +} + +.add-comment { + margin-bottom: 10px; +} +.hide-comment-button .add-comment { + display: none; +} + +.comment-bubble { + color: @grey4; + margin-top: 4px; + margin-right: 30px; + visibility: hidden; +} + +.comment { + margin: @padding 0; + padding: 4px 0 0 0; + line-height: 1em; + + .meta { + position: relative; + width: 100%; + margin: 0 0 .5em 0; + + &:hover .permalink { + visibility: visible; + color: @rcblue; + } + } + + .author, + .date { + display: inline; + margin: 0 .5 0 0; + padding: 0 .5 0 0; + + &:after { + content: ' | '; + color: @grey5; + } + } + + .status-change, + .permalink, + .changeset-status-lbl { + display: inline; + } + + .permalink { + visibility: hidden; + } + + .comment-links-divider { + display: inline; + } + + .comment-links-block { + float:right; + text-align: right; + min-width: 85px; + + [class^="icon-"]:before, + [class*=" icon-"]:before { + margin-left: 0; + margin-right: 0; + } + } + + .comment-previous-link { + display: inline-block; + + .arrow_comment_link{ + cursor: pointer; + i { + font-size:10px; + } + } + .arrow_comment_link.disabled { + cursor: default; + color: @grey5; + } + } + + .comment-next-link { + display: inline-block; + + .arrow_comment_link{ + cursor: pointer; + i { + font-size:10px; + } + } + .arrow_comment_link.disabled { + cursor: default; + color: @grey5; + } + } + + .flag_status { + display: inline-block; + margin: -2px .5em 0 .25em + } + + .delete-comment { + display: inline-block; + color: @rcblue; + + &:hover { + cursor: pointer; + } + } + + + .text { + clear: both; + border: @border-thickness solid @grey5; + .border-radius(@border-radius); + .box-sizing(border-box); + + .markdown-block p, + .rst-block p { + margin: .5em 0 !important; + // TODO: lisa: This is needed because of other rst !important rules :[ + } + } +} + +.show-outdated-comments { + display: inline; + color: @rcblue; +} + +.outdated { + display: none; + opacity: 0.6; + + .comment { + margin: 0 0 @padding; + + .date:after { + content: none; + } + } + .outdated_comment_block { + padding: 0 0 @space 0; + } +} + +// Comment Form +div.comment-form { + margin-top: 20px; +} + +.comment-form strong { + display: block; + margin-bottom: 15px; +} + +.comment-form textarea { + width: 100%; + height: 100px; + font-family: 'Monaco', 'Courier', 'Courier New', monospace; +} + +form.comment-form { + margin-top: 10px; + margin-left: 10px; +} + +.comment-inline-form .comment-block-ta, +.comment-form .comment-block-ta, +.comment-form .preview-box { + border: @border-thickness solid @grey5; + .border-radius(@border-radius); + .box-sizing(border-box); + background-color: white; +} + +.comment-form-submit { + margin-top: 5px; + margin-left: 525px; +} + +.file-comments { + display: none; +} + +.comment-form .preview-box.unloaded, +.comment-inline-form .preview-box.unloaded { + height: 50px; + text-align: center; + padding: 20px; + background-color: white; +} + +.comment-footer { + position: relative; + width: 100%; + min-height: 42px; + + .status_box, + .cancel-button { + float: left; + display: inline-block; + } + + .action-buttons { + float: right; + display: inline-block; + } +} + +.comment-form { + + .comment { + margin-left: 10px; + } + + .comment-help { + color: @grey4; + padding: 5px 0 5px 0; + } + + .comment-title { + padding: 5px 0 5px 0; + } + + .comment-button { + display: inline-block; + } + + .comment-button .comment-button-input { + margin-right: 0; + } + + .comment-footer { + margin-bottom: 110px; + } +} + + +.comment-form-login { + .comment-help { + padding: 0.9em; //same as the button + } + + div.clearfix { + clear: both; + width: 100%; + display: block; + } +} + +.preview-box { + padding: 10px; + min-height: 100px; + margin-bottom: 15px; + background-color: white; + border: @border-thickness solid #ccc; + .border-radius(@border-radius); + .box-sizing(border-box); +} + +.add-another-button { + margin-left: 10px; + margin-top: 10px; + margin-bottom: 10px; +} + +.comment .buttons { + float: right; + margin: -1px 0px 0px 0px; +} + +// Inline Comment Form +.injected_diff .comment-inline-form, +.comment-inline-form { + background-color: @grey6; + margin-top: 10px; + margin-bottom: 20px; +} + +.inline-form { + padding: 10px 7px; +} + +.inline-form div { + max-width: 100%; +} + +.overlay { + display: none; + position: absolute; + width: 100%; + text-align: center; + vertical-align: middle; + font-size: 16px; + background: none repeat scroll 0 0 white; + + &.submitting { + display: block; + opacity: 0.5; + z-index: 100; + } +} +.comment-inline-form .overlay.submitting .overlay-text { + margin-top: 5%; +} + +.comment-inline-form .clearfix, +.comment-form .clearfix { + .border-radius(@border-radius); + margin: 0px; +} + +.hide-inline-form-button { + margin-left: 5px; +} +.comment-button .hide-inline-form { + background: white; +} diff --git a/rhodecode/public/css/diff.less b/rhodecode/public/css/diff.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/diff.less @@ -0,0 +1,78 @@ +div.diffblock .code-header .changeset_header > div { + margin: 0 @padding; +} + + +// Line select and comment +div.diffblock.margined.comm tr { + td { + position: relative; + } + + .add-comment-line { + // Force td width for Firefox + width: 20px; + + // TODO: anderson: fixing mouse-over bug. + // why was it vertical-align baseline in first place?? + vertical-align: top !important; + // Force width and display for IE 9 + .add-comment-content { + display: inline-block; + width: 20px; + + a { + display: none; + position: absolute; + top: 2px; + left: 2px; + color: @grey3; + } + } + } + + &.line { + &:hover, &.hover{ + .add-comment-line a{ + display: inline; + } + } + + &.hover, &.selected { + &, del, ins { + background-color: lighten(@alert3, 10%) !important; + } + } + + &.commenting { + &, del, ins { + background-image: none !important; + background-color: lighten(@alert4, 10%) !important; + } + } + } +} + +.compare-header { + overflow-x: auto; + overflow-y: hidden; + clear: both; + padding: @padding; + background: @grey6; + border: @border-thickness solid @border-default-color; + .border-radius(@border-radius); + + .compare-value, + .compare-label { + float: left; + display: inline-block; + min-width: 5em; + margin: 0; + padding: 0.9em 0.9em 0.9em 0; + } + + .compare-label { + clear: both; + font-family: @text-semibold; + } +} \ No newline at end of file diff --git a/rhodecode/public/css/examples.less b/rhodecode/public/css/examples.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/examples.less @@ -0,0 +1,73 @@ +// Utilities for showing examples in our style guide + +.bs-example { + + // TODO: johbo: mainly copy paste here, find better integration + border-color: #e5e5e5 #eee #eee; + border-style: solid; + border-width: 1px 0; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05) inset; + margin: 0 -15px 15px; + padding: 45px 15px 15px; + position: relative; + + background-color: #fff; + border-color: #ddd; + border-radius: 4px 4px 0 0; + border-width: 1px; + box-shadow: none; + margin-left: 0; + margin-right: 0; + + table { + width: 100%; + } +} + +.sidebar li.divider { + padding-top: 30px; + border-top:1px solid #eee; +} + +.bs-example:after { + color: #959595; + content: "Example"; + font-size: 12px; + font-weight: 700; + left: 15px; + letter-spacing: 1px; + position: absolute; + text-transform: uppercase; + top: 15px; +} + +.template-example { + xmp { + display: inline; + } +} + +#icons-list{ + span{ + margin-right: @textmargin/2; + } +} + +.rctable.examples { + margin: 0; + + td:first-child { width: 135px; } + td:nth-child(2) { width: 400px; } + + &.end { margin-bottom: 40px; } +} + + +// For use in Style Guide to mark out code examples +.highlight-html { + margin-bottom: 30px; + border: 1px solid #dbd9da; + border-radius: 2px; + color: #979797; + background-color: #f3f3f3; +} diff --git a/rhodecode/public/css/fonts.less b/rhodecode/public/css/fonts.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/fonts.less @@ -0,0 +1,51 @@ + +@font-face { + font-family: 'proximanovaregular'; + src: url('../fonts/ProximaNova/ProximaNova-Regular.eot'); /* IE9 Compat Modes */ + src: url('../fonts/ProximaNova/ProximaNova-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ProximaNova/ProximaNova-Regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ProximaNova/ProximaNova-Regular.ttf') format('truetype'); + font-style: normal; + font-weight: normal; + text-rendering: optimizeLegibility; +} +@font-face { + font-family: 'proximanovaitalic'; + src: url('../fonts/ProximaNova/ProximaNova-Italic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/ProximaNova/ProximaNova-Italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ProximaNova/ProximaNova-Italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ProximaNova/ProximaNova-Italic.ttf') format('truetype'); + font-style: italic; + font-weight: normal; + text-rendering: optimizeLegibility; +} +@font-face { + font-family: 'proximanovasemibold'; + src: url('../fonts/ProximaNova/ProximaNova-Semibold.eot'); /* IE9 Compat Modes */ + src: url('../fonts/ProximaNova/ProximaNova-Semibold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ProximaNova/ProximaNova-Semibold.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ProximaNova/ProximaNova-Semibold.ttf') format('truetype'); + font-style: normal; + font-weight: bold; + text-rendering: optimizeLegibility; +} +@font-face { + font-family: 'proximanovabold'; + src: url('../fonts/ProximaNova/ProximaNova-Bold.eot'); /* IE9 Compat Modes */ + src: url('../fonts/ProximaNova/ProximaNova-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ProximaNova/ProximaNova-Bold.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ProximaNova/ProximaNova-Bold.ttf') format('truetype'); + font-style: normal; + font-weight: bold; + text-rendering: optimizeLegibility; +} +@font-face { + font-family: 'proximanovabolditalic'; + src: url('../fonts/ProximaNova/ProximaNova-BoldItalic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/ProximaNova/ProximaNova-BoldItalic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ProximaNova/ProximaNova-BoldItalic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ProximaNova/ProximaNova-BoldItalic.ttf') format('truetype'); + font-style: italic; + font-weight: bold; + text-rendering: optimizeLegibility; +} \ No newline at end of file diff --git a/rhodecode/public/css/form-bootstrap.less b/rhodecode/public/css/form-bootstrap.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/form-bootstrap.less @@ -0,0 +1,264 @@ +// +// Forms +// -------------------------------------------------- + +// Form validation states +// +// Used to generate the form validation CSS for warnings, errors, and successes. + +.form-control-validation(@text-color: @grey3; @border-color: @grey4; @background-color: @grey6) { + // Color the label and help text + .help-block, + .control-label, + .radio, + .checkbox, + .radio-inline, + .checkbox-inline, + &.radio label, + &.checkbox label, + &.radio-inline label, + &.checkbox-inline label { + color: @text-color; + } +} + + +// Form control focus state +// +// Generate a customized focus state and for any input with the specified color, +// which defaults to the `@input-border-focus` variable. +// +// We highly encourage you to not customize the default value, but instead use +// this to tweak colors on an as-needed basis. This aesthetic change is based on +// WebKit's default styles, but applicable to a wider range of browsers. Its +// usability and accessibility should be taken into account with any change. +// +// Example usage: change the default blue border and shadow to white for better +// contrast against a dark gray background. +.form-control-focus(@color: @input-border-focus) { + @color-rgba: rgba(red(@color), green(@color), blue(@color), .6); + &:focus { + border-color: @color; + outline: 0; + .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}"); + } +} + +// Form control sizing +// +// Relative text size, padding, and border-radii changes for form controls. For +// horizontal sizing, wrap controls in the predefined grid classes. `<select>` +// element gets special love because it's special, and that's a fact! +.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { + height: @input-height; + padding: @padding-vertical @padding-horizontal; + font-size: @font-size; + line-height: @line-height; + border-radius: @border-radius; + + select& { + height: @input-height; + line-height: @input-height; + } + + textarea&, + select[multiple]& { + height: auto; + } +} + + + +// Normalize non-controls +// +// Restyle and baseline non-control form elements. + +fieldset { + padding: 0; + margin: 0; + border: 0; + // Chrome and Firefox set a `min-width: min-content;` on fieldsets, + // so we reset that to ensure it behaves more like a standard block element. + // See https://github.com/twbs/bootstrap/issues/12359. + min-width: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; +} + +label { + display: inline-block; + max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141) + margin-bottom: 5px; + //TODO: lisa: this should probably be @text-bold instead + font-weight: bold; +} + + +// Normalize form controls +// +// While most of our form styles require extra classes, some basic normalization +// is required to ensure optimum display with or without those classes to better +// address browser inconsistencies. + +// Override content-box in Normalize (* isn't specific enough) +input[type="search"] { + .box-sizing(border-box); +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; // IE8-9 + line-height: normal; +} + +// Set the height of file controls to match text inputs +input[type="file"] { + display: block; +} + +// Make range inputs behave like textual form controls +input[type="range"] { + display: block; + width: 100%; +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Focus for file, radio, and checkbox +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + +// Adjust output element +output { + display: block; + padding-top: (@padding-base-vertical + 1); + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; +} + + +// Search inputs in iOS +// +// This overrides the extra rounded corners on search inputs in iOS so that our +// `.form-control` class can properly style them. Note that this cannot simply +// be added to `.form-control` as it's not specific enough. For details, see +// https://github.com/twbs/bootstrap/issues/11586. + +input[type="search"] { + -webkit-appearance: none; +} + + +// Special styles for iOS temporal inputs +// +// In Mobile Safari, setting `display: block` on temporal inputs causes the +// text within the input to become vertically misaligned. As a workaround, we +// set a pixel line-height that matches the given height of the input, but only +// for Safari. + +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"], + input[type="time"], + input[type="datetime-local"], + input[type="month"] { + line-height: @input-height-base; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm { + line-height: @input-height-small; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg { + line-height: @input-height-large; + } +} + + +// Checkboxes and radios +// +// Indent the labels to position radios/checkboxes as hanging controls. + +.radio, +.checkbox { + position: relative; + display: inline-block; + margin-bottom: 10px; + + label { + min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; + } +} + +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing +} + +// Radios and checkboxes on same line +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; // space out consecutive inline controls +} + +// Apply same disabled cursor tweak as for inputs +// Some special care is needed because <label>s don't inherit their parent's `cursor`. +// +// Note: Neither radios nor checkboxes can be readonly. +input[type="radio"], +input[type="checkbox"] { + &[disabled], + &.disabled, + fieldset[disabled] & { + cursor: @cursor-disabled; + } +} +// These classes are used directly on <label>s +.radio-inline, +.checkbox-inline { + &.disabled, + fieldset[disabled] & { + cursor: @cursor-disabled; + } +} +// These classes are used on elements with <label> descendants +.radio, +.checkbox { + &.disabled, + fieldset[disabled] & { + label { + cursor: @cursor-disabled; + } + } +} diff --git a/rhodecode/public/css/forms.less b/rhodecode/public/css/forms.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/forms.less @@ -0,0 +1,293 @@ +// forms.less +// For use in RhodeCode applications; +// see style guide documentation for guidelines. + +form.rcform { + + // reset for ie + // using :not(#ie) prevents older browsers from applying these rules + input[type="radio"], + input[type="checkbox"] { + padding: 0; + border: none; + } + label { display: inline; border:none; padding:none; } + .label { display: none; } + + max-width: 940px; + line-height: normal; + white-space: normal; + font-size: @basefontsize; + font-family: @text-light; + color: @form-textcolor; + + fieldset, + .buttons { + clear: both; + position: relative; + display:block; + width: 100%; + min-height: 3em; + margin-bottom: @form-vertical-margin; + line-height: 1.2em; + + &:after { //clearfix + content: ""; + clear: both; + width: 100%; + height: 1em; + } + + .label:not(#ie) { + display: inline; + margin: 0 1em 0 .5em; + line-height: 1em; + } + } + + legend { + float: left; + display: block; + width: @legend-width; + margin: 0; + padding: 0 @padding 0 0; + } + + .fields { + float: left; + display: block; + width: 100%; + max-width: 500px; + margin: 0 0 @padding -@legend-width; + padding: 0 0 0 @legend-width; + + .btn { + display: inline-block; + margin: 0 1em @padding 0; + } + } + + input, + textarea { + float: left; + .box-sizing(content-box); + padding: @input-padding; + border: @border-thickness-inputs solid @grey4; + } + + input { + float: left; + margin: 0 @input-padding 0 0; + line-height: 1em; + } + + input[type="text"], + input[type="password"], + textarea { + float: left; + min-width: 200px; + margin: 0 1em @padding 0; + color: @form-textcolor; + } + + input[type="text"], + input[type="password"] { + height: 1em; + } + + textarea { + width: 100%; + margin-top: -1em; //so it lines up with legend + overflow: auto; + } + + label:not(#ie) { + cursor: pointer; + display: inline-block; + position: relative; + background: white; + border-radius: 4px; + box-shadow: none; + + &:hover::after { + opacity: 0.5; + } + } + + input[type="radio"]:not(#ie), + input[type="checkbox"]:not(#ie) { + // Hide the input, but have it still be clickable + opacity: 0; + float: left; + height: 0; + width: 0; + margin: 0; + padding: 0; + } + input[type='radio'] + label:not(#ie), + input[type='checkbox'] + label:not(#ie) { + margin: 0; + clear: none; + } + + input[type='radio'] + label:not(#ie) { + .circle (@form-radio-width,white); + float: left; + display: inline-block; + height: @form-radio-width; + width: @form-radio-width; + margin: 2px 6px 2px 0; + border: 1px solid @grey4; + background-color: white; + box-shadow: none; + text-indent: -9999px; + transition: none; + + & + .label { + float: left; + margin-top: 7px + } + } + + input[type='radio']:checked + label:not(#ie) { + margin: 0 4px 0 -2px; + padding: 3px; + border-style: double; + border-color: white; + border-width: thick; + background-color: @rcblue; + box-shadow: none; + } + + input[type='checkbox'] + label:not(#ie) { + float: left; + width: @form-check-width; + height: @form-check-width; + margin: 0 5px 1em 0; + border: 1px solid @grey3; + .border-radius(@border-radius); + background-color: white; + box-shadow: none; + text-indent: -9999px; + transition: none; + + &:after { + content: ''; + width: 9px; + height: 5px; + position: absolute; + top: 4px; + left: 4px; + border: 3px solid @grey3; + border-top: none; + border-right: none; + background: transparent; + opacity: 0; + transform: rotate(-45deg); + filter: progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476); /* IE6,IE7 */ + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"; /* IE8 */ } + + & + .label { + float: left; + margin-top: 5px + } + } + + input[type=checkbox]:not(#ie) { + visibility: hidden; + &:checked + label:after { + opacity: 1; + } + } + + // center checkbox and label on a drop-down + .drop-menu + select + input[type='checkbox'] + label:not(#ie) { + margin-top:10px; + + & + .label { + margin-top: 15px; + } + } + + .formlist { + position: relative; + float: left; + margin: 0; + padding: 0; + + li { + list-style-type: none; + + &:before { content:none; } + &:after { + content: ""; + float: left; + display: block; + height: @padding; + width: 100%; + } + } + } + + .drop-menu { + float: left; + margin: 0 @input-padding 0 0; + } + + .help-block, + .error-message { + display: block; + clear: both; + margin: @textmargin 0; + } + + .error-message { + margin-top: 5px; + } + + input[type=submit] { + &:extend(.btn-primary); + + &:hover { + &:extend(.btn-primary:hover); + } + } + + input[type=reset] { + &:extend(.btn-default); + + &:hover { + &:extend(.btn-default:hover); + } + } + + select, + option:checked { + background-color: @rclightblue; + } + +} + + +// for situations where we wish to display the form value but not the form input +input.input-valuedisplay { + border: none; +} + +// for forms which only display information +.infoform { + .fields { + .field { + label, + .label, + input, + .input { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + } + } + } +} diff --git a/rhodecode/public/css/helpers.less b/rhodecode/public/css/helpers.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/helpers.less @@ -0,0 +1,78 @@ +//--- RESETS ---// +:focus { outline: none; } +a { cursor: pointer; } + +//--- clearfix --// +.clearfix { + &:before, + &:after { + content:""; + width: 100%; + clear: both; + float: left; + } +} + +.linebreak { + display: block; +} + +.pull-right { + float: right !important; +} + +.pull-left { + float: left !important; +} + +.block-left { + float: left; +} + +.block-right { + float: right; + clear: right; + + li:before { content:none; } +} + +//--- DEVICE-SPECIFIC CLASSES ---------------// +//regular tablet and up +@media (min-width:768px) { + .no-mobile { + display: block; + } + .mobile-only { + display: none; + } +} +//small tablet and phone +@media (max-width:767px) { + .mobile-only { + display: block; + } + .no-mobile { + display: none; + } +} + +//--- STICKY FOOTER ---// +html, body { + height: 100%; + margin: 0; +} +.outerwrapper { + height: 100%; + min-height: 100%; + margin: 0; + padding-bottom: 3em; /* must be equal to footer height */ +} +.outerwrapper:after{ + content:" "; +} +#footer { + clear: both; + position: relative; + height: 3em; /* footer height */ + margin: -3em 0 0; /* must be equal to footer height */ +} diff --git a/rhodecode/public/css/legacy_code_styles.less b/rhodecode/public/css/legacy_code_styles.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/legacy_code_styles.less @@ -0,0 +1,365 @@ + +/** MODAL **/ +.modal-open { + overflow:hidden; +} +body.modal-open, .modal-open .navbar-fixed-top, .modal-open .navbar-fixed-bottom { + margin-right:15px; +} +.modal { + position:fixed; + top:0; + right:0; + bottom:0; + left:0; + z-index:1040; + display:none; + overflow-y:scroll; + &.fade .modal-dialog { + -webkit-transform:translate(0,-25%); + -ms-transform:translate(0,-25%); + transform:translate(0,-25%); + -webkit-transition:-webkit-transform 0.3s ease-out; + -moz-transition:-moz-transform 0.3s ease-out; + -o-transition:-o-transform 0.3s ease-out; + transition:transform 0.3s ease-out; + } + &.in .modal-dialog { + -webkit-transform:translate(0,0); + -ms-transform:translate(0,0); + transform:translate(0,0); + } +} +.modal-dialog { + z-index:1050; + width:auto; + padding:10px; + margin-right:auto; + margin-left:auto; +} +.modal-content { + position:relative; + background-color:#ffffff; + border: @border-thickness solid rgba(0,0,0,0.2); + .border-radius(@border-radius); + outline:none; + -webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5); + box-shadow:0 3px 9px rgba(0,0,0,0.5); + background-clip:padding-box; +} +.modal-backdrop { + position:fixed; + top:0; + right:0; + bottom:0; + left:0; + z-index:1030; + background-color:#000000; + + &.modal-backdrop.fade { + opacity:0; + filter:alpha(opacity=0); + } + &.in { + opacity:0.5; + filter:alpha(opacity=50); + } +} +.modal-header { + min-height:16.428571429px; + padding:15px; + border-bottom: @border-thickness solid @grey6; + .close { + margin-top:-2px; + } +} +.modal-title { + margin:0; + line-height:1.428571429; +} +.modal-body { + position:relative; + padding:20px; +} +.modal-footer { + padding:19px 20px 20px; + margin-top:15px; + text-align:right; + border-top:1px solid #e5e5e5; + .btn + .btn { + margin-bottom:0; + margin-left:5px; + } + .btn-group .btn + .btn { + margin-left:-1px; + } + .btn-block + .btn-block { + margin-left:0; + } + &:before { + display:table; + content:" "; + } + &:after { + display:table; + content:" "; + clear:both; + } +} + +/** MARKDOWN styling **/ +div.markdown-block { + clear: both; + overflow: hidden; + margin: 0; + padding: 3px 15px 3px; +} + +div.markdown-block h1, +div.markdown-block h2, +div.markdown-block h3, +div.markdown-block h4, +div.markdown-block h5, +div.markdown-block h6 { + border-bottom: none !important; + padding: 0 !important; + overflow: visible !important; +} + +div.markdown-block h1 { + font-size: 32px; + margin: 15px 0 15px 0 !important; + padding-bottom: 5px !important; +} + +div.markdown-block h2 { + font-size: 24px !important; + margin: 34px 0 10px 0 !important; + border-top: 3px #e6e5e5 solid !important; + padding-top: 15px !important; + padding-bottom: 8px !important; +} + +div.markdown-block h3 { + font-size: 18px !important; + margin: 30px 0 8px 0 !important; + padding-bottom: 2px !important; +} + +div.markdown-block h4 { + font-size: 13px !important; + margin: 18px 0 3px 0 !important; +} + +div.markdown-block h5 { + font-size: 12px !important; + margin: 15px 0 3px 0 !important; +} + +div.markdown-block h6 { + font-size: 12px; + color: #777777; + margin: 15px 0 3px 0 !important; +} + +div.markdown-block hr { + height: 1px; + border: 0; + color: #CCCCCC; + color: #e6e5e5; + height: 3px; + margin-bottom: 13px; +} + +div.markdown-block ol, +div.markdown-block ul, +div.markdown-block p, +div.markdown-block blockquote, +div.markdown-block dl, +div.markdown-block li, +div.markdown-block table, +div.markdown-block pre { + margin: 15px 0 !important; + margin: 3px 0px 13px 0px !important; + color: #424242 !important; + font-size: 13px !important; + font-family: "Helvetica" !important; + font-weight: normal !important; + overflow: visible !important; + line-height: 140% !important; +} + +div.markdown-block img { + padding: 4px; + border: @border-thickness solid @grey5; + border: @border-thickness solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + margin: 5px 0 0 0 !important; +} + +div.markdown-block ul, +div.markdown-block ol { + padding-left: 30px !important; + margin-top: 0px !important; + margin-bottom: 18px !important; +} + +div.markdown-block ul li, +div.markdown-block ol li { + list-style: disc !important; + margin: 13px !important; + padding: 0 !important; +} + +div.markdown-block ol li { + list-style: decimal !important; +} + +/* +div.markdown-block a, +div.markdown-block a:visited { + color: #4183C4 !important; + background-color: inherit; + text-decoration: none; +} +*/ + +div.markdown-block #message { + .border-radius(@border-radius); + border: @border-thickness solid @grey5; + display: block; + width: 100%; + height: 60px; + margin: 6px 0px; +} + +div.markdown-block button, +div.markdown-block #ws { + font-size: @basefontsize; + padding: 4px 6px; + .border-radius(@border-radius); + border: @border-thickness solid @grey5; + background-color: @grey6; +} + +div.markdown-block code, +div.markdown-block pre, +div.markdown-block #ws, +div.markdown-block #message { + font-family: Monaco; + font-size: 11px; + .border-radius(@border-radius); + background-color: white; + color: @grey3; +} + + +div.markdown-block code { + border: @border-thickness solid @grey6; + margin: 0 2px; + padding: 0 5px; +} + +div.markdown-block pre { + border: @border-thickness solid @grey5; + overflow: auto; + padding: 4px 8px; +} + +div.markdown-block pre > code { + border: 0; + margin: 0; + padding: 0; +} + +/** RST STYLE **/ +div.rst-block { + clear: both; + overflow: hidden; + margin: 0; + padding: 3px 15px 3px; +} + +div.rst-block h2 { + font-weight: normal; +} + +div.rst-block h1, +div.rst-block h2, +div.rst-block h3, +div.rst-block h4, +div.rst-block h5, +div.rst-block h6 { + border-bottom: 0 !important; + margin: 0 !important; + padding: 0 !important; + line-height: 1.5em !important; +} + + +div.rst-block h1:first-child { + padding-top: .25em !important; +} + +div.rst-block h2, +div.rst-block h3 { + margin: 1em 0 !important; +} + +div.rst-block h2 { + margin-top: 1.5em !important; + border-top: 4px solid #e0e0e0 !important; + padding-top: .5em !important; +} + +div.rst-block p { + color: black !important; + margin: 1em 0 !important; + line-height: 1.5em !important; +} + +div.rst-block ul { + list-style: disc !important; + margin: 1em 0 1em 2em !important; + clear: both; +} + +div.rst-block ol { + list-style: decimal; + margin: 1em 0 1em 2em !important; +} + +div.rst-block pre, +div.rst-block code { + font: 12px "Bitstream Vera Sans Mono","Courier",monospace; +} + +div.rst-block code { + font-size: 12px !important; + background-color: ghostWhite !important; + color: #444 !important; + padding: 0 .2em !important; + border: 1px solid #dedede !important; +} + +div.rst-block pre code { + padding: 0 !important; + font-size: 12px !important; + background-color: #eee !important; + border: none !important; +} + +div.rst-block pre { + margin: 1em 0; + padding: @padding; + border: 1px solid @grey6; + .border-radius(@border-radius); + overflow: auto; + font-size: 12px; + color: #444; + background-color: @grey7; +} + + diff --git a/rhodecode/public/css/login.less b/rhodecode/public/css/login.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/login.less @@ -0,0 +1,297 @@ +//LOGIN + + +.loginbox { + max-width: 65%; + margin: @pagepadding auto; + font-family: @text-light; + border: @border-thickness solid @grey5; + box-sizing: border-box; + + @media (max-width:1200px) { + max-width: 85%; + } + + @media (max-width:768px) { + max-width: 100%; + width: 100%; + margin: 0; + } + + .title { + float: none; + } + + .header { + width: 100%; + padding: 0 35px; + box-sizing: border-box; + + .title { + padding: 0; + } + } + + .loginwrapper { + float: left; + height: 100%; + width: 100%; + padding: 35px 55px 35px 0; + background-color: white; + box-sizing: border-box; + + @media (max-width:414px) { + padding: 35px; + } + } + + .left-column { + float: left; + position: relative; + width: 50%; + height: 100%; + + @media (max-width:414px) { + display:none; + } + } + + .right-column { + float: right; + position: relative; + width: 50%; + + @media (max-width:414px) { + width: 100%; + } + } + + .sign-in-image { + display: block; + width: 65%; + margin: 5% auto; + } + + .sign-in-title { + h1 { + margin: 0; + } + + h4 { + margin: @padding*2 0; + } + } + + .form { + label { + display: block; + } + + input { + width: 100%; + margin: 0 10% @padding 0; + .box-sizing(border-box) ; + + &[type="checkbox"] { + clear: both; + width: auto; + margin: 0 1em @padding 0; + } + } + + .checkbox { + display: inline; + width: auto; + } + + .sign-in { + clear: both; + width: 100%; + margin: @padding 0; + } + } + .register_message, + .activation_msg { + padding: 0 0 @padding; + } + + .buttons, + .links { + padding: 0; + } + + .buttons { + input { + margin-right: 0; + .box-sizing(border-box); + } + + #sign_up, #send { + width: 100%; + } + } + + .fields { + .field.field-compact { + margin-bottom: 0px; + } + + .buttons { + margin: 0; + } + + .field { + margin-bottom: 15px; + + input { + width: 100%; + .box-sizing(border-box); + } + + .input { + margin-left: 0; + } + + .label { + padding-top: 0; + } + } + } + + .checkbox { + margin: 0 0 @textmargin 0; + + input[type="checkbox"] { + width: auto; + } + + label { + padding: 0; + min-height: 0; + } + } + + .activation_msg { + padding: @padding 0 0; + color: @grey4; + } + + .links { + float: right; + margin: 0; + padding: 0; + line-height: 1; + + p { + float: right; + margin: 0; + line-height: 1.5em; + } + } +} + +.user-menu.submenu { + right: 0; + left: auto; +} +#quick_login { + left: auto; + right: 0; + padding: @menupadding; + z-index: 999; + overflow: hidden; + background-color: @grey6; + color: @grey2; + + h4 { + margin-bottom: 12px; + } + + .form { + width: auto; + } + + label, .field { + margin-bottom: 0; + } + + .label { + padding-top: 0; + } + + input { + min-width: 215px; + margin: 8px 0 @padding; + } + + input[type="submit"] { + &:extend(.btn-primary); + width:100%; + min-width: 0; + } + + .forgot_password, + .buttons .register { + a { + color: @rcblue; + + &:hover { + color: @rcdarkblue; + } + } + } + + .buttons { + margin: 0; + } + + .buttons a { + padding: 8px 0; + line-height: 1.4em; + color: @grey4; + + &:hover { + color: @grey2; + } + } + + #sign_in { + margin-bottom: 0 + } + + .big_gravatar { + float: left; + display: block; + margin-top: .5em; + } + + .full_name, + .email { + margin: 0 0 0 65px; + } + + .email { + font-family: @text-light; + } + + ol.links { + clear:both; + margin: 0; + padding: @padding 0 0 0; + + li { + border-top: @border-thickness solid @grey5; + + input { + margin: @padding 0 0 0; + } + } + } +} +.submenu #quick_login li:hover { + background-color: transparent; +} + +#quick_login_link:hover + #quick_login { + display: block; +} diff --git a/rhodecode/public/css/main-content.less b/rhodecode/public/css/main-content.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/main-content.less @@ -0,0 +1,373 @@ + +// Contains the style definitions used for .main-content +// elements which are mainly around the admin settings. + + +// TODO: johbo: Integrate in a better way, this is for "main content" which +// should not have a limit on the width. +.main-content-full { + clear: both; +} + + +.main-content { + max-width: @maincontent-maxwidth; + + h3, + // TODO: johbo: Change templates to use h3 instead of h4 here + h4 { + line-height: 1em; + } + + // TODO: johbo: Check if we can do that on a global level + table { + th { + padding: 0; + } + td.field{ + .help-block{ + margin-left: 0; + } + } + } + + // TODO: johbo: Tweak this into the general styling, for a full width + // textarea + .textarea-full { + // 2x 10px padding and 2x 1px border + margin-right: 22px; + } + +} + + +// TODO: johbo: duplicated, think about a mixins.less +.block-left{ + float: left; +} + +.form { + .checkboxes { + // TODO: johbo: Should be changed in .checkboxes already + width: auto; + } + + // TODO: johbo: some settings pages are broken and don't have the .buttons + // inside the .fields, tweak those templates and remove this. + .buttons { + margin-top: @textmargin; + } + + .help-block { + display: block; + margin-left: @label-width; + } + + .action_button { + color: @grey4; + } +} + +.main-content-full-width { + .main-content; + width: 100%; + min-width: 100%; +} + +.field { + clear: left; + margin-bottom: @padding; + +} + +.fields { + label { + color: @grey2; + } + + .field { + clear: right; + margin-bottom: @textmargin; + width: 100%; + + .label { + float: left; + margin-right: @form-vertical-margin; + margin-top: 0; + padding-top: @input-padding-px + @border-thickness-inputs; + width: @label-width - @form-vertical-margin; + } + // used in forms for fields that show just text + .label-text { + .label; + padding-top: 5px; + } + // Used to position content on the right side of a .label + .content, + .side-by-side-selector { + padding-top: @input-padding-px + @input-border-thickness; + } + + .checkboxes, + .input, + .select, + .textarea, + .content { + float: none; + margin-left: @label-width; + + .help-block{ + margin-left: 0; + } + } + + .checkboxes, + .input, + .select { + .help-block { + display: block; + } + } + + .checkboxes, + .radios { + // TODO: johbo: We get a 4px margin from the from-bootstrap, + // compensating here to align well with labels on the left. + padding-top: @input-padding-px + @input-border-thickness - 3px; + } + + .checkbox, + .radio { + display: block; + width: auto; + } + + .checkbox + .checkbox { + display: block; + } + + .input, + .select { + .help-block, + .info-block { + margin-top: @form-vertical-margin / 2; + } + } + + .input { + .medium { + width: @fields-input-m; + } + .large { + width: @fields-input-l; + } + + .text-as-placeholder { + padding-top: @input-padding-px + @border-thickness-inputs; + } + } + + // TODO: johbo: Try to find a better integration of this bit. + // When using a select2 inside of a field, it should not have the + // top margin. + .select .drop-menu { + margin-top: 0; + } + + .textarea { + float: none; + + textarea { + // TODO: johbo: From somewhere we get a clear which does + // more harm than good here. + clear: none; + } + + .CodeMirror { + // TODO: johbo: Tweak to position the .help-block nicer, + // figure out how to apply for .text-block instead. + margin-bottom: 10px; + } + + // TODO: johbo: Check if we can remove the grey background on + // the global level and remove this if possible. + .help-block { + background: transparent; + padding: 0; + } + } + + &.tag_patterns, + &.branch_patterns { + + input { + max-width: 430px; + } + } + } + + .field-sm { + .label { + padding-top: @input-padding-px / 2 + @input-border-thickness; + } + .checkboxes, + .radios { + // TODO: johbo: We get a 4px margin from the from-bootstrap, + // compensating here to align well with labels on the left. + padding-top: @input-padding-px / 2 + @input-border-thickness - 3px; + } + } + + .field.customhooks { + .label { + padding-top: 0; + } + .input-wrapper { + padding-right: 25px; + + input { + width: 100%; + } + } + .input { + padding-right: 25px; + } + } + + .buttons { + // TODO: johbo: define variable for this value. + // Note that this should be 40px but since most elements add some + // space in the bottom, we are with 20 closer to 40. + margin-top: 20px; + clear: both; + margin-bottom: @padding; + } + + .desc{ + margin-right: @textmargin; + } + + input, + .drop-menu { + margin-right: @padding/3; + } + +} + +.form-vertical .fields .field { + + .label { + float: none; + width: auto; + } + + .checkboxes, + .input, + .select, + .textarea { + margin-left: 0; + } + + // TODO: johbo: had to tweak the width here to make it big enough for + // the license. + .textarea.editor { + max-width: none; + } + + .textarea.large textarea { + min-height: 200px; + } + + .help-block { + margin-left: 0; + } +} + + + + +.main-content { + .block-left; + + .section { + margin-bottom: @space; + } + + + // Table aligning same way as forms in admin section, e.g. + // python packages table + table.formalign { + float: left; + width: auto; + + .label { + width: @label-width; + } + + } + + + table.issuetracker { + + color: @text-color; + + .issue-tracker-example { + color: @grey4; + } + } + + .side-by-side-selector{ + .left-group, + .middle-group, + .right-group{ + float: left; + } + + .left-group, + .right-group{ + width: 45%; + text-align: center; + + label{ + width: 100%; + text-align: left; + } + + select{ + width: 100%; + background: none; + border-color: @border-highlight-color; + color: @text-color; + font-family: @text-light; + font-size: @basefontsize; + color: @grey1; + padding: @textmargin/2; + } + + select:after{ + content: ""; + } + + } + + .middle-group{ + width: 10%; + text-align: center; + padding-top: 6em; + } + + } + + .permissions_boxes{ + label, .label{ + margin-right: @textmargin/2; + } + } + + .radios{ + label{ + margin-right: @textmargin; + } + } +} + diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/main.less @@ -0,0 +1,2076 @@ +//Primary CSS + +//--- IMPORTS ------------------// + +@import 'helpers'; +@import 'mixins'; +@import 'rcicons'; +@import 'fonts'; +@import 'variables'; +@import 'bootstrap-variables'; +@import 'form-bootstrap'; +@import 'codemirror'; +@import 'legacy_code_styles'; +@import 'progress-bar'; + +@import 'type'; +@import 'alerts'; +@import 'buttons'; +@import 'tags'; +@import 'code-block'; +@import 'examples'; +@import 'login'; +@import 'main-content'; +@import 'select2'; +@import 'comments'; +@import 'panels-bootstrap'; +@import 'panels'; + + +//--- BASE ------------------// +.noscript-error { + top: 0; + left: 0; + width: 100%; + z-index: 101; + text-align: center; + font-family: @text-semibold; + font-size: 120%; + color: white; + background-color: @alert2; + padding: 5px 0 5px 0; +} + +html { + display: table; + height: 100%; + width: 100%; +} + +body { + display: table-cell; + width: 100%; +} + +//--- LAYOUT ------------------// + +.hidden{ + display: none !important; +} + +.box{ + float: left; + width: 100%; +} + +.browser-header { + clear: both; +} +.main { + clear: both; + padding:0 0 @pagepadding; + height: auto; + + &:after { //clearfix + content:""; + clear:both; + width:100%; + display:block; + } +} + +.action-link{ + margin-left: @padding; + padding-left: @padding; + border-left: @border-thickness solid @border-default-color; +} + +input + .action-link, .action-link.first{ + border-left: none; +} + +.action-link.last{ + margin-right: @padding; + padding-right: @padding; +} + +.action-link.active, +.action-link.active a{ + color: @grey4; +} + +ul.simple-list{ + list-style: none; + margin: 0; + padding: 0; +} + +.main-content { + padding-bottom: @pagepadding; +} + +.wrapper { + position: relative; + max-width: @wrapper-maxwidth; + margin: 0 auto; +} + +#content { + clear: both; + padding: 0 @contentpadding; +} + +.advanced-settings-fields{ + input{ + margin-left: @textmargin; + margin-right: @padding/2; + } +} + +.cs_files_title { + margin: @pagepadding 0 0; +} + +input.inline[type="file"] { + display: inline; +} + +.error_page { + margin: 10% auto; + + h1 { + color: @grey2; + } + + .error-branding { + font-family: @text-semibold; + color: @grey4; + } + + .error_message { + font-family: @text-regular; + } + + .sidebar { + min-height: 275px; + margin: 0; + padding: 0 0 @sidebarpadding @sidebarpadding; + border: none; + } + + .main-content { + position: relative; + margin: 0 @sidebarpadding @sidebarpadding; + padding: 0 0 0 @sidebarpadding; + border-left: @border-thickness solid @grey5; + + @media (max-width:767px) { + clear: both; + width: 100%; + margin: 0; + border: none; + } + } + + .inner-column { + float: left; + width: 29.75%; + min-height: 150px; + margin: @sidebarpadding 2% 0 0; + padding: 0 2% 0 0; + border-right: @border-thickness solid @grey5; + + @media (max-width:767px) { + clear: both; + width: 100%; + border: none; + } + + ul { + padding-left: 1.25em; + } + + &:last-child { + margin: @sidebarpadding 0 0; + border: none; + } + + h4 { + margin: 0 0 @padding; + font-family: @text-semibold; + } + } +} +.error-page-logo { + width: 130px; + height: 160px; +} + +// HEADER +.header { + + // TODO: johbo: Fix login pages, so that they work without a min-height + // for the header and then remove the min-height. I chose a smaller value + // intentionally here to avoid rendering issues in the main navigation. + min-height: 49px; + + position: relative; + vertical-align: bottom; + padding: 0 @header-padding; + background-color: @grey2; + color: @grey5; + + .title { + overflow: visible; + } + + &:before, + &:after { + content: ""; + clear: both; + width: 100%; + } + + // TODO: johbo: Avoids breaking "Repositories" chooser + .select2-container .select2-choice .select2-arrow { + display: none; + } +} + +#header-inner { + &.title { + margin: 0; + } + &:before, + &:after { + content: ""; + clear: both; + } +} + +// Gists +#files_data { + clear: both; //for firefox +} +#gistid { + margin-right: @padding; +} + +// Global Settings Editor +.textarea.editor { + float: left; + position: relative; + max-width: @texteditor-width; + + select { + position: absolute; + top:10px; + right:0; + } + + .CodeMirror { + margin: 0; + } + + .help-block { + margin: 0 0 @padding; + padding:.5em; + background-color: @grey6; + } +} + +ul.auth_plugins { + margin: @padding 0 @padding @legend-width; + padding: 0; + + li { + margin-bottom: @padding; + line-height: 1em; + list-style-type: none; + + .auth_buttons .btn { + margin-right: @padding; + } + + &:before { content: none; } + } +} + +// Pull Requests + +.pullrequestlist { + max-width: @pullrequest-width; + margin-bottom: @space; + + // Tweaks for "My Account" / "Pull requests" + .prwrapper { + clear: left; + + .pr { + margin: 0; + padding: 0; + border-bottom: none; + } + + // TODO: johbo: Replace with something that makes up an inline form or + // similar. + .repolist_actions { + display: inline-block; + } + } + +} + +.pullrequests_section_head { + display: block; + clear: both; + margin: @padding 0; + font-family: @text-bold; +} + +.pr-origininfo, .pr-targetinfo { + position: relative; + + .tag { + display: inline-block; + margin: 0 1em .5em 0; + } + + .clone-url { + display: inline-block; + margin: 0 0 .5em 0; + padding: 0; + line-height: 1.2em; + } +} + +.pr-pullinfo { + clear: both; + margin: .5em 0; +} + +#pr-title-input { + width: 72%; + font-size: 1em; + font-family: @text-bold; + margin: 0; + padding: 0 0 0 @padding/4; + line-height: 1.7em; + color: @text-color; + letter-spacing: .02em; +} + +#pullrequest_title { + width: 100%; + box-sizing: border-box; +} + +#pr_open_message { + border: @border-thickness solid #fff; + border-radius: @border-radius; + padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0; + text-align: right; + overflow: hidden; +} + +.pr-submit-button { + float: right; + margin: 0 0 0 5px; +} + +.pr-spacing-container { + padding: 20px; + clear: both +} + +#pr-description-input { + margin-bottom: 0; +} + +.pr-description-label { + vertical-align: top; +} + +.perms_section_head { + min-width: 625px; + + h2 { + margin-bottom: 0; + } + + .label-checkbox { + float: left; + } + + &.field { + margin: @space 0 @padding; + } + + &:first-child.field { + margin-top: 0; + + .label { + margin-top: 0; + padding-top: 0; + } + + .radios { + padding-top: 0; + } + } + + .radios { + float: right; + position: relative; + width: 405px; + } +} + +//--- MODULES ------------------// + + +// Fixed Sidebar Column +.sidebar-col-wrapper { + padding-left: @sidebar-all-width; + + .sidebar { + width: @sidebar-width; + margin-left: -@sidebar-all-width; + } +} + +.sidebar-col-wrapper.scw-small { + padding-left: @sidebar-small-all-width; + + .sidebar { + width: @sidebar-small-width; + margin-left: -@sidebar-small-all-width; + } +} + + +// FOOTER +#footer { + padding: 0; + text-align: center; + vertical-align: middle; + color: @grey2; + background-color: @grey6; + + p { + margin: 0; + padding: 1em; + line-height: 1em; + } + + .server-instance { //server instance + display: none; + } + + .title { + float: none; + margin: 0 auto; + } +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + .box-shadow(none); + -webkit-appearance: none; +} + +.close { + float: right; + font-size: 21px; + font-family: @text-bootstrap; + line-height: 1em; + font-weight: bold; + color: @grey2; + + &:hover, + &:focus { + color: @grey1; + text-decoration: none; + cursor: pointer; + } +} + +// GRID +.sorting, +.sorting_desc, +.sorting_asc { + cursor: pointer; +} +.sorting_desc:after { + content: "\00A0\25B2"; + font-size: .75em; +} +.sorting_asc:after { + content: "\00A0\25BC"; + font-size: .68em; +} + + +.user_auth_tokens { + + &.truncate { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .fields .field .input { + margin: 0; + } + + input#description { + width: 100px; + margin: 0; + } + + .drop-menu { + // TODO: johbo: Remove this, should work out of the box when + // having multiple inputs inline + margin: 0 0 0 5px; + } +} +#user_list_table { + .closed { + background-color: @grey6; + } +} + + +input { + &.disabled { + opacity: .5; + } +} + +// remove extra padding in firefox +input::-moz-focus-inner { border:0; padding:0 } + +.adjacent input { + margin-bottom: @padding; +} + +.permissions_boxes { + display: block; +} + +//TODO: lisa: this should be in tables +.show_more_col { + width: 20px; +} + +//FORMS + +.medium-inline, +input#description.medium-inline { + display: inline; + width: @medium-inline-input-width; + min-width: 100px; +} + +select { + //reset + -webkit-appearance: none; + -moz-appearance: none; + + display: inline-block; + height: 28px; + width: auto; + margin: 0 @padding @padding 0; + padding: 0 18px 0 8px; + line-height:1em; + font-size: @basefontsize; + border: @border-thickness solid @rcblue; + background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%; + color: @rcblue; + + &:after { + content: "\00A0\25BE"; + } + + &:focus { + outline: none; + } +} + +option { + &:focus { + outline: none; + } +} + +input, +textarea { + padding: @input-padding; + border: @input-border-thickness solid @border-highlight-color; + .border-radius (@border-radius); + font-family: @text-light; + font-size: @basefontsize; + + &.input-sm { + padding: 5px; + } + + &#description { + min-width: @input-description-minwidth; + min-height: 1em; + padding: 10px; + } +} + +.field-sm { + input, + textarea { + padding: 5px; + } +} + +textarea { + display: block; + clear: both; + width: 100%; + min-height: 100px; + margin-bottom: @padding; + .box-sizing(border-box); + overflow: auto; +} + +label { + font-family: @text-light; +} + +// GRAVATARS +// centers gravatar on username to the right + +.gravatar { + display: inline; + min-width: 16px; + min-height: 16px; + margin: -5px 0; + padding: 0; + line-height: 1em; + border: 1px solid @grey4; + + &.gravatar-large { + margin: -0.5em .25em -0.5em 0; + } + + & + .user { + display: inline; + margin: 0; + padding: 0 0 0 .17em; + line-height: 1em; + } +} + +.rc-user { // gravatar + user wrapper + position: relative; + min-width: 100px; + max-width: 200px; + min-height: (@gravatar-size + @border-thickness * 2); // account for border + display: block; + padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2); + + + .gravatar { + display: block; + position: absolute; + top: 0; + left: 0; + min-width: @gravatar-size; + min-height: @gravatar-size; + margin: 0; + } + + .user { + display: block; + max-width: 175px; + padding-top: 2px; + overflow: hidden; + text-overflow: ellipsis; + } +} + +.gist-gravatar, +.journal_container { + .gravatar-large { + margin: 0 .5em -10px 0; + } +} + + +// ADMIN SETTINGS + +// Tag Patterns +.tag_patterns { + .tag_input { + margin-bottom: @padding; + } +} + +.locked_input { + position: relative; + + input { + display: inline; + margin-top: 3px; + } + + br { + display: none; + } + + .error-message { + float: left; + width: 100%; + } + + .lock_input_button { + display: inline; + } + + .help-block { + clear: both; + } +} + +// Notifications + +.notifications_buttons { + margin: 0 0 @space 0; + padding: 0; + + .btn { + display: inline-block; + } +} + +.notification-list { + + div { + display: inline-block; + vertical-align: middle; + } + + .container { + display: block; + margin: 0 0 @padding 0; + } + + .delete-notifications { + margin-left: @padding; + text-align: right; + cursor: pointer; + } + + .read-notifications { + margin-left: @padding/2; + text-align: right; + width: 35px; + cursor: pointer; + } + + .icon-minus-sign { + color: @alert2; + } + + .icon-ok-sign { + color: @alert1; + } +} + +.user_settings { + float: left; + clear: both; + display: block; + width: 100%; + + .gravatar_box { + margin-bottom: @padding; + + &:after { + content: " "; + clear: both; + width: 100%; + } + } + + .fields .field { + clear: both; + } +} + +.advanced_settings { + margin-bottom: @space; + + .help-block { + margin-left: 0; + } + + button + .help-block { + margin-top: @padding; + } +} + +// admin settings radio buttons and labels +.label-2 { + float: left; + width: @label2-width; + + label { + color: @grey1; + } +} +.checkboxes { + float: left; + width: @checkboxes-width; + margin-bottom: @padding; + + .checkbox { + width: 100%; + + label { + margin: 0; + padding: 0; + } + } + + .checkbox + .checkbox { + display: inline-block; + } + + label { + margin-right: 1em; + } +} + +// CHANGELOG +.container_header { + float: left; + display: block; + width: 100%; + margin: @padding 0 @padding; + + #filter_changelog { + float: left; + margin-right: @padding; + } + + .breadcrumbs_light { + display: inline-block; + } +} + +.info_box { + float: right; +} + + +#graph_nodes { + padding-top: 43px; +} + +#graph_content{ + + // adjust for table headers so that graph renders properly + // #graph_nodes padding - table cell padding + padding-top: (@space - (@basefontsize * 2.4)); + + &.graph_full_width { + width: 100%; + max-width: 100%; + } +} + +#graph { + .flag_status { + margin: 0; + } + + .pagination-left { + float: left; + clear: both; + } + + .log-container { + max-width: 345px; + + .message{ + max-width: 340px; + } + } + + .graph-col-wrapper { + padding-left: 110px; + + #graph_nodes { + width: 100px; + margin-left: -110px; + float: left; + clear: left; + } + } +} + +#filter_changelog { + float: left; +} + + +//--- THEME ------------------// + +#logo { + float: left; + margin: 9px 0 0 0; + + .header { + background-color: transparent; + } + + a { + display: inline-block; + } + + img { + height:30px; + } +} + +.logo-wrapper { + float:left; +} + +.branding{ + float: left; + padding: 9px 2px; + line-height: 1em; + font-size: @navigation-fontsize; +} + +img { + border: none; + outline: none; +} + user-profile-header +label { + + input[type="checkbox"] { + margin-right: 1em; + } + input[type="radio"] { + margin-right: 1em; + } +} + +.flag_status { + margin: 2px 8px 6px 2px; + &.under_review { + .circle(5px, @alert3); + } + &.approved { + .circle(5px, @alert1); + } + &.rejected, + &.forced_closed{ + .circle(5px, @alert2); + } + &.not_reviewed { + .circle(5px, @grey5); + } +} + +.flag_status_comment_box { + margin: 5px 6px 0px 2px; +} +.test_pattern_preview { + margin: @space 0; + + p { + margin-bottom: 0; + border-bottom: @border-thickness solid @border-default-color; + color: @grey3; + } + + .btn { + margin-bottom: @padding; + } +} +#test_pattern_result { + display: none; + &:extend(pre); + padding: .9em; + color: @grey3; + background-color: @grey7; + border-right: @border-thickness solid @border-default-color; + border-bottom: @border-thickness solid @border-default-color; + border-left: @border-thickness solid @border-default-color; +} + +#repo_vcs_settings { + #inherit_overlay_vcs_default { + display: none; + } + #inherit_overlay_vcs_custom { + display: custom; + } + &.inherited { + #inherit_overlay_vcs_default { + display: block; + } + #inherit_overlay_vcs_custom { + display: none; + } + } +} + +.issue-tracker-link { + color: @rcblue; +} + +// Issue Tracker Table Show/Hide +#repo_issue_tracker { + #inherit_overlay { + display: none; + } + #custom_overlay { + display: custom; + } + &.inherited { + #inherit_overlay { + display: block; + } + #custom_overlay { + display: none; + } + } +} +table.issuetracker { + &.readonly { + tr, td { + color: @grey3; + } + } + .edit { + display: none; + } + .editopen { + .edit { + display: inline; + } + .entry { + display: none; + } + } + tr td.td-action { + min-width: 117px; + } + td input { + max-width: none; + min-width: 30px; + width: 80%; + } + .issuetracker_pref input { + width: 40%; + } + input.edit_issuetracker_update { + margin-right: 0; + width: auto; + } +} + +//Permissions Settings +#add_perm { + margin: 0 0 @padding; + cursor: pointer; +} + +.perm_ac { + input { + width: 95%; + } +} + +.autocomplete-suggestions { + width: auto !important; // overrides autocomplete.js + margin: 0; + border: @border-thickness solid @rcblue; + border-radius: @border-radius; + color: @rcblue; + background-color: white; +} +.autocomplete-selected { + background: #F0F0F0; +} +.ac-container-wrap { + margin: 0; + padding: 8px; + border-bottom: @border-thickness solid @rclightblue; + list-style-type: none; + cursor: pointer; + + &:hover { + background-color: @rclightblue; + } + + img { + margin-right: 1em; + } + + strong { + font-weight: normal; + } +} + +// Settings Dropdown +.user-menu .container { + padding: 0 4px; + margin: 0; +} + +.user-menu .gravatar { + cursor: pointer; +} + +.codeblock { + margin-bottom: @padding; + clear: both; + + .stats{ + overflow: hidden; + } + + .message{ + textarea{ + margin: 0; + } + } + + .code-header { + .stats { + line-height: 2em; + + .revision_id { + margin-left: 0; + } + .buttons { + padding-right: 0; + } + } + + .item{ + margin-right: 0.5em; + } + } + + #editor_container{ + position: relative; + margin: @padding; + } +} + +#file_history_container { + display: none; +} + +.file-history-inner { + margin-bottom: 10px; +} + +// Pull Requests +.summary-details { + width: 72%; +} +.pr-summary { + border-bottom: @border-thickness solid @grey5; + margin-bottom: @space; +} +.reviewers-title { + width: 25%; + min-width: 200px; +} +.reviewers { + width: 25%; + min-width: 200px; +} +.reviewers ul li { + position: relative; + width: 100%; + margin-bottom: 8px; +} +.reviewers_member { + width: 100%; + overflow: auto; +} +.reviewer_status { + display: inline-block; + vertical-align: top; + width: 7%; + min-width: 20px; + height: 1.2em; + margin-top: 3px; + line-height: 1em; +} + +.reviewer_name { + display: inline-block; + max-width: 83%; + padding-right: 20px; + vertical-align: middle; +} + +.reviewer_member_remove { + position: absolute; + right: 0; + top: 0; + width: 16px; + margin-bottom: 10px; + padding: 0; + color: black; +} +.reviewer_member_status { + margin-top: 5px; +} +.pr-summary #summary{ + width: 100%; +} +.pr-summary .action_button:hover { + border: 0; + cursor: pointer; +} +.pr-details-title { + padding-bottom: 8px; + border-bottom: @border-thickness solid @grey5; + .action_button { + color: @rcblue; + } +} +.pr-details-content { + margin-top: @textmargin; + margin-bottom: @textmargin/2; +} +.pr-description { + white-space:pre-wrap; +} +.group_members { + margin-top: 0; + padding: 0; + list-style: outside none none; +} +.reviewer_ac .ac-input { + width: 92%; + margin-bottom: 1em; +} +#update_commits { + float: right; +} +.compare_view_commits tr{ + height: 20px; +} +.compare_view_commits td { + vertical-align: top; + padding-top: 10px; +} +.compare_view_commits .author { + margin-left: 5px; +} + +.compare_view_files { + width: 100%; + + td { + vertical-align: middle; + } +} + +.compare_view_filepath { + color: @grey1; +} + +.show_more { + display: inline-block; + position: relative; + vertical-align: middle; + width: 4px; + height: @basefontsize; + + &:after { + content: "\00A0\25BE"; + display: inline-block; + width:10px; + line-height: 5px; + font-size: 12px; + cursor: pointer; + } +} + +.journal_more .show_more { + display: inline; + + &:after { + content: none; + } +} + +.open .show_more:after, +.select2-dropdown-open .show_more:after { + .rotate(180deg); + margin-left: 4px; +} + + +.compare_view_commits .collapse_commit:after { + cursor: pointer; + content: "\00A0\25B4"; + margin-left: -3px; + font-size: 17px; + color: @grey4; +} + +.diff_links { + margin-left: 8px; +} + +p.ancestor { + margin: @padding 0; +} + +.cs_icon_td input[type="checkbox"] { + display: none; +} + +.cs_icon_td .expand_file_icon:after { + cursor: pointer; + content: "\00A0\25B6"; + font-size: 12px; + color: @grey4; +} + +.cs_icon_td .collapse_file_icon:after { + cursor: pointer; + content: "\00A0\25BC"; + font-size: 12px; + color: @grey4; +} + +/*new binary +NEW_FILENODE = 1 +DEL_FILENODE = 2 +MOD_FILENODE = 3 +RENAMED_FILENODE = 4 +COPIED_FILENODE = 5 +CHMOD_FILENODE = 6 +BIN_FILENODE = 7 +*/ +.cs_files_expand { + font-size: @basefontsize + 5px; + line-height: 1.8em; + float: right; +} + +.cs_files_expand span{ + color: @rcblue; + cursor: pointer; +} +.cs_files { + clear: both; + padding-bottom: @padding; + + .cur_cs { + margin: 10px 2px; + font-weight: bold; + } + + .node { + float: left; + } + + .changes { + float: right; + color: white; + font-size: @basefontsize - 4px; + margin-top: 4px; + opacity: 0.6; + filter: Alpha(opacity=60); /* IE8 and earlier */ + + .added { + background-color: @alert1; + float: left; + text-align: center; + } + + .deleted { + background-color: @alert2; + float: left; + text-align: center; + } + + .bin { + background-color: @alert1; + text-align: center; + } + + /*new binary*/ + .bin.bin1 { + background-color: @alert1; + text-align: center; + } + + /*deleted binary*/ + .bin.bin2 { + background-color: @alert2; + text-align: center; + } + + /*mod binary*/ + .bin.bin3 { + background-color: @grey2; + text-align: center; + } + + /*rename file*/ + .bin.bin4 { + background-color: @alert4; + text-align: center; + } + + /*copied file*/ + .bin.bin5 { + background-color: @alert4; + text-align: center; + } + + /*chmod file*/ + .bin.bin6 { + background-color: @grey2; + text-align: center; + } + } +} + +.cs_files .cs_added, .cs_files .cs_A, +.cs_files .cs_added, .cs_files .cs_M, +.cs_files .cs_added, .cs_files .cs_D { + height: 16px; + padding-right: 10px; + margin-top: 7px; + text-align: left; +} + +.cs_icon_td { + min-width: 16px; + width: 16px; +} + +.pull-request-merge { + padding: 10px 0; + margin-top: 10px; + margin-bottom: 20px; +} + +.pull-request-merge .pull-request-wrap { + height: 25px; + padding: 5px 0; +} + +.pull-request-merge span { + margin-right: 10px; +} +#close_pull_request { + margin-right: 0px; +} + +.empty_data { + color: @grey4; +} + +#changeset_compare_view_content { + margin-bottom: @space; + clear: both; + width: 100%; + box-sizing: border-box; + .border-radius(@border-radius); + + .help-block { + margin: @padding 0; + color: @text-color; + } + + .empty_data { + margin: @padding 0; + } + + .alert { + margin-bottom: @space; + } +} + +.table_disp { + .status { + width: auto; + + .flag_status { + float: left; + } + } +} + +.status_box_menu { + margin: 0; +} + +.notification-table{ + margin-bottom: @space; + display: table; + width: 100%; + + .container{ + display: table-row; + + .notification-header{ + border-bottom: @border-thickness solid @border-default-color; + } + + .notification-subject{ + display: table-cell; + } + } +} + +// Notifications +.notification-header{ + display: table; + width: 100%; + padding: floor(@basefontsize/2) 0; + line-height: 1em; + + .desc, .delete-notifications, .read-notifications{ + display: table-cell; + text-align: left; + } + + .desc{ + width: 1163px; + } + + .delete-notifications, .read-notifications{ + width: 35px; + min-width: 35px; //fixes when only one button is displayed + } +} + +.notification-body { + .markdown-block, + .rst-block { + padding: @padding 0; + } + + .notification-subject { + padding: @textmargin 0; + border-bottom: @border-thickness solid @border-default-color; + } +} + + +.notifications_buttons{ + float: right; +} + +// Repositories + +#summary.fields{ + display: table; + + .field{ + display: table-row; + + .label-summary{ + display: table-cell; + min-width: @label-summary-minwidth; + padding-top: @padding/2; + padding-bottom: @padding/2; + padding-right: @padding/2; + } + + .input{ + display: table-cell; + padding: @padding/2; + + input{ + min-width: 29em; + padding: @padding/4; + } + } + .statistics, .downloads{ + .disabled{ + color: @grey4; + } + } + } +} + +#summary{ + width: 70%; +} + + +// Journal +.journal.title { + h5 { + float: left; + margin: 0; + width: 70%; + } + + ul { + float: right; + display: inline-block; + margin: 0; + width: 30%; + text-align: right; + + li { + display: inline; + font-size: @journal-fontsize; + line-height: 1em; + + &:before { content: none; } + } + } +} + +.filterexample { + position: absolute; + top: 95px; + left: @contentpadding; + color: @rcblue; + font-size: 11px; + font-family: @text-regular; + cursor: help; + + &:hover { + color: @rcdarkblue; + } + + @media (max-width:768px) { + position: relative; + top: auto; + left: auto; + display: block; + } +} + + +#journal{ + margin-bottom: @space; + + .journal_day{ + margin-bottom: @textmargin/2; + padding-bottom: @textmargin/2; + font-size: @journal-fontsize; + border-bottom: @border-thickness solid @border-default-color; + } + + .journal_container{ + margin-bottom: @space; + + .journal_user{ + display: inline-block; + } + .journal_action_container{ + display: block; + margin-top: @textmargin; + + div{ + display: inline; + } + + div.journal_action_params{ + display: block; + } + + div.journal_repo:after{ + content: "\A"; + white-space: pre; + } + + div.date{ + display: block; + margin-bottom: @textmargin; + } + } + } +} + +// Files +.edit-file-title { + border-bottom: @border-thickness solid @border-default-color; + + .breadcrumbs { + margin-bottom: 0; + } +} + +.edit-file-fieldset { + margin-top: @sidebarpadding; + + .fieldset { + .left-label { + width: 13%; + } + .right-content { + width: 87%; + max-width: 100%; + } + .filename-label { + margin-top: 13px; + } + .commit-message-label { + margin-top: 4px; + } + .file-upload-input { + input { + display: none; + } + } + p { + margin-top: 5px; + } + + } + .custom-path-link { + margin-left: 5px; + } + #commit { + resize: vertical; + } +} + +.delete-file-preview { + max-height: 250px; +} + +.new-file, +#filter_activate, +#filter_deactivate { + float: left; + margin: 0 0 0 15px; +} + +h3.files_location{ + line-height: 2.4em; +} + +.browser-nav { + display: table; + margin-bottom: @space; + + + .info_box { + display: inline-table; + height: 2.5em; + + .browser-cur-rev, .info_box_elem { + display: table-cell; + vertical-align: middle; + } + + .info_box_elem { + border-top: @border-thickness solid @rcblue; + border-bottom: @border-thickness solid @rcblue; + + #at_rev, a { + padding: 0.6em 0.9em; + margin: 0; + .box-shadow(none); + border: 0; + height: 12px; + } + + input#at_rev { + max-width: 50px; + text-align: right; + } + + &.previous { + border: @border-thickness solid @rcblue; + .disabled { + color: @grey4; + cursor: not-allowed; + } + } + + &.next { + border: @border-thickness solid @rcblue; + .disabled { + color: @grey4; + cursor: not-allowed; + } + } + } + + .browser-cur-rev { + + span{ + margin: 0; + color: @rcblue; + height: 12px; + display: inline-block; + padding: 0.7em 1em ; + border: @border-thickness solid @rcblue; + margin-right: @padding; + } + } + } + + .search_activate { + display: table-cell; + vertical-align: middle; + + input, label{ + margin: 0; + padding: 0; + } + + input{ + margin-left: @textmargin; + } + + } +} + +.file_author{ + margin-bottom: @padding; + + div{ + display: inline-block; + margin-right: 0.5em; + } +} + +.browser-cur-rev{ + margin-bottom: @textmargin; +} + +#node_filter_box_loading{ + .info_text; +} + +.browser-search { + margin: -25px 0px 5px 0px; +} + +.node-filter { + font-size: @repo-title-fontsize; + padding: 4px 0px 0px 0px; + + .node-filter-path { + float: left; + color: @grey4; + } + .node-filter-input { + float: left; + margin: -2px 0px 0px 2px; + input { + padding: 2px; + border: none; + font-size: @repo-title-fontsize; + } + } +} + + +.browser-result{ + td a{ + margin-left: 0.5em; + display: inline-block; + + em{ + font-family: @text-bold; + } + } +} + +.browser-highlight{ + background-color: @grey5-alpha; +} + + +// Search + +.search-form{ + #q { + width: @search-form-width; + } + .fields{ + margin: 0 0 @space; + } + + label{ + display: inline-block; + margin-right: @textmargin; + padding-top: 0.25em; + } + + + .results{ + clear: both; + margin: 0 0 @padding; + } +} + +div.search-feedback-items { + display: inline-block; + padding:0px 0px 0px 96px; +} + +div.search-code-body { + background-color: #ffffff; padding: 5px 0 5px 10px; + pre { + .match { background-color: #faffa6;} + .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; } + } +} + +.expand_commit.search { + .show_more.open { + height: auto; + max-height: none; + } +} + +.search-results { + + h2 { + margin-bottom: 0; + } + .codeblock { + border: none; + background: transparent; + } + + .codeblock-header { + border: none; + background: transparent; + } + + .code-body { + border: @border-thickness solid @border-default-color; + .border-radius(@border-radius); + } + + .td-commit { + &:extend(pre); + border-bottom: @border-thickness solid @border-default-color; + } + + .message { + height: auto; + max-width: 350px; + white-space: normal; + text-overflow: initial; + overflow: visible; + + .match { background-color: #faffa6;} + .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; } + } + +} + +table.rctable td.td-search-results div { + max-width: 100%; +} + +#tip-box, .tip-box{ + padding: @menupadding/2; + display: block; + border: @border-thickness solid @border-highlight-color; + .border-radius(@border-radius); + background-color: white; + z-index: 99; + white-space: pre-wrap; +} + +#linktt { + width: 79px; +} + +#help_kb .modal-content{ + max-width: 750px; + margin: 10% auto; + + table{ + td,th{ + border-bottom: none; + line-height: 2.5em; + } + th{ + padding-bottom: @textmargin/2; + } + td.keys{ + text-align: center; + } + } + + .block-left{ + width: 45%; + margin-right: 5%; + } + .modal-footer{ + clear: both; + } + .key.tag{ + padding: 0.5em; + background-color: @rcblue; + color: white; + border-color: @rcblue; + .box-shadow(none); + } +} + + + +//--- IMPORTS FOR REFACTORED STYLES ------------------// + +@import 'statistics-graph'; +@import 'tables'; +@import 'forms'; +@import 'diff'; +@import 'summary'; +@import 'navigation'; + +//--- SHOW/HIDE SECTIONS --// + +.btn-collapse { + float: right; + text-align: right; + font-family: @text-light; + font-size: @basefontsize; + cursor: pointer; + border: none; + color: @rcblue; +} + +table.rctable, +table.dataTable { + .btn-collapse { + float: right; + text-align: right; + } +} + + +// TODO: johbo: Fix for IE10, this avoids that we see a border +// and padding around checkboxes and radio boxes. Move to the right place, +// or better: Remove this once we did the form refactoring. +input[type=checkbox], +input[type=radio] { + padding: 0; + border: none; +} diff --git a/rhodecode/public/css/mergerly.css b/rhodecode/public/css/mergerly.css new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/mergerly.css @@ -0,0 +1,41 @@ + +/* required */ +.mergely-column textarea { width: 80px; height: 200px; } +.mergely-column { float: left; } +.mergely-margin { float: left; } +.mergely-canvas { float: left; width: 28px; } + +/* resizeable */ +.mergely-resizer { width: 100%; height: 100%; } + +/* style configuration */ +.mergely-column { border: 1px solid #ccc; } +.mergely-active { border: 1px solid #a3d1ff; } + +.mergely.a.rhs.start { border-top: 1px solid #ddffdd; } +.mergely.a.lhs.start.end, +.mergely.a.rhs.end { border-bottom: 1px solid #ddffdd; } +.mergely.a.rhs { background-color: #ddffdd; } +.mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #ddffdd; } + +.mergely.d.lhs { background-color: #edc0c0; } +.mergely.d.lhs.end, +.mergely.d.rhs.start.end { border-bottom: 1px solid #ffdddd; } +.mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ffdddd; } +.mergely.d.lhs.start { border-top: 1px solid #ffdddd; } + +.mergely.c.lhs, +.mergely.c.rhs { background-color: #fafafa; } +.mergely.c.lhs.start, +.mergely.c.rhs.start { border-top: 1px solid #a3a3a3; } +.mergely.c.lhs.end, +.mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; } + +.mergely.ch.a.rhs { background-color: #ddffdd; } +.mergely.ch.d.lhs { background-color: #ffdddd; } + + +.mergely-margin #compare-lhs-margin, +.mergely-margin #compare-rhs-margin { + cursor: pointer +} diff --git a/rhodecode/public/css/mixins.less b/rhodecode/public/css/mixins.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/mixins.less @@ -0,0 +1,255 @@ + + +/* inset border for buttons - does not work in ie */ +.inner-border(@size:1px,@border-color:#000) { + -webkit-box-shadow: inset 0 0 0 @size @border-color; + -moz-box-shadow: inset 0 0 0 @size @border-color; + box-shadow: inset 0 0 0 @size @border-color; + -ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=@size,MakeShadow=true,ShadowOpacity=1); + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=@size,MakeShadow=true,ShadowOpacity=1); + zoom: 1; +} + +.border(@size:1px,@border-color:#000) { + border: @size solid @border-color; +} + +.inner-border-bottom(@size:1px,@border-color:#000) { + -webkit-box-shadow: inset 0 (-@size*2) 0 -@size @border-color; + -moz-box-shadow: inset 0 (-@size*2) 0 -@size @border-color; + box-shadow: inset 0 (-@size*2) 0 -@size @border-color; +} + +/* rounded borders */ +.border-radius(@radius: 2px) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +/* rounded borders - bottom only */ +.border-radius-bottom(@radius: 2px) { + -webkit-border-bottom-right-radius: @radius; + -webkit-border-bottom-left-radius: @radius; + -moz-border-radius-bottomright: @radius; + -moz-border-radius-bottomleft: @radius; + border-bottom-right-radius: @radius; + border-bottom-left-radius: @radius; +} + +/* rounded borders - top only */ +.border-radius-top(@radius: 2px) { + -webkit-border-top-right-radius: @radius; + -webkit-border-top-left-radius: @radius; + -moz-border-radius-topright: @radius; + -moz-border-radius-topleft: @radius; + border-top-right-radius: @radius; + border-top-left-radius: @radius; +} + +/* text shadow */ +.text-shadow(@width:1px) { + text-shadow: 0 @width 0 rgba(0,0,0,.75); +} + +/* centers text in a circle - input diameter of circle and color */ +.circle (@radius:20,@color:#000) { + height: @radius; + width: @radius; + padding: round(@radius/2); + font-size: @radius; + line-height:1em; + .border-radius(50%); + text-align: center; + vertical-align: middle; + background-color: @color; + color: white; +} + +/* pill version of the circle */ +.pill (@radius:20,@color:#000) { + height: @radius; + width: @radius; + padding: 1px round(@radius*1.2); + font-size: @radius; + line-height:1em; + .border-radius(round(@radius*1.2)); + text-align: center; + vertical-align: middle; + background-color: @color; + color: white; +} + +.absolute-center { + margin: auto; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +// rotates +.rotate(@degrees:180deg) { + -ms-transform: rotate(@degrees); + -webkit-transform: rotate(@degrees); + transform: rotate(@degrees); +} + + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// WebKit-style focus +.tab-focus() { + // Default + outline: thin dotted; + // WebKit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +//box-shadow +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; + -moz-box-shadow: @shadow; + box-shadow: @shadow; // iOS <4.3 & Android <4.1 +} + + +// Transitions + +.transition(@transition) { + -webkit-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-property(@transition-property) { + -webkit-transition-property: @transition-property; + transition-property: @transition-property; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} +.transition-duration(@transition-duration) { + -webkit-transition-duration: @transition-duration; + transition-duration: @transition-duration; +} +.transition-timing-function(@timing-function) { + -webkit-transition-timing-function: @timing-function; + transition-timing-function: @timing-function; +} +.transition-transform(@transition) { + -webkit-transition: -webkit-transform @transition; + -moz-transition: -moz-transform @transition; + -o-transition: -o-transform @transition; + transition: transform @transition; +} + + +// Placeholder text +.placeholder(@color: @input-color-placeholder) { + // Firefox + &::-moz-placeholder { + color: @color; + opacity: 1; // See https://github.com/twbs/bootstrap/pull/11526 + } + &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+ + &::-webkit-input-placeholder { color: @color; } // Safari and Chrome +} + +// Rounded Corners +// these are used to generate graphics in code-block.html + +.top-left-rounded-corner { + -webkit-border-top-left-radius: @border-radius; + -khtml-border-radius-topleft: @border-radius; + border-top-left-radius: @border-radius; +} + +.top-right-rounded-corner { + -webkit-border-top-right-radius: @border-radius; + -khtml-border-radius-topright: @border-radius; + border-top-right-radius: @border-radius; +} + +.bottom-left-rounded-corner { + -webkit-border-bottom-left-radius: @border-radius; + -khtml-border-radius-bottomleft: @border-radius; + border-bottom-left-radius: @border-radius; +} + +.bottom-right-rounded-corner { + -webkit-border-bottom-right-radius: @border-radius; + -khtml-border-radius-bottomright: @border-radius; + border-bottom-right-radius: @border-radius; +} + +.top-left-rounded-corner-mid { + -webkit-border-top-left-radius: @border-radius; + -khtml-border-radius-topleft: @border-radius; + border-top-left-radius: @border-radius; +} + +.top-right-rounded-corner-mid { + -webkit-border-top-right-radius: @border-radius; + -khtml-border-radius-topright: @border-radius; + border-top-right-radius: @border-radius; +} + +.bottom-left-rounded-corner-mid { + -webkit-border-bottom-left-radius: @border-radius; + -khtml-border-radius-bottomleft: @border-radius; + border-bottom-left-radius: @border-radius; +} + +.bottom-right-rounded-corner-mid { + -webkit-border-bottom-right-radius: @border-radius; + -khtml-border-radius-bottomright: @border-radius; + border-bottom-right-radius: @border-radius; +} + +// For Bootstrap +.border-top-radius(@radius) { + border-top-right-radius: @radius; + border-top-left-radius: @radius; +} +.border-right-radius(@radius) { + border-bottom-right-radius: @radius; + border-top-right-radius: @radius; +} +.border-bottom-radius(@radius) { + border-bottom-right-radius: @radius; + border-bottom-left-radius: @radius; +} +.border-left-radius(@radius) { + border-bottom-left-radius: @radius; + border-top-left-radius: @radius; +} +.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { + border-color: @border; + + & > .panel-heading { + color: @heading-text-color; + background-color: @heading-bg-color; + border-color: @heading-border; + + + .panel-collapse > .panel-body { + border-top-color: @border; + } + .badge { + color: @heading-bg-color; + background-color: @heading-text-color; + } + } + & > .panel-footer { + + .panel-collapse > .panel-body { + border-bottom-color: @border; + } + } +} \ No newline at end of file diff --git a/rhodecode/public/css/navigation.less b/rhodecode/public/css/navigation.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/navigation.less @@ -0,0 +1,623 @@ +// navigation.less +// For use in RhodeCode applications; +// see style guide documentation for guidelines. + +// HEADER NAVIGATION + +.horizontal-list { + float: right; + display: block; + margin: 0; + padding: 0; + -webkit-padding-start: 0; + text-align: left; + font-size: @navigation-fontsize; + color: @grey6; + z-index:10; + + li { + line-height: 1em; + list-style-type: none; + + a { + padding: 0 .5em; + + &.menu_link_notifications { + .pill(7px,@rcblue); + display: inline; + margin: 0 7px 0 .7em; + font-size: @basefontsize; + color: white; + + &.empty { + background-color: @grey4; + } + + &:hover { + background-color: @rcdarkblue; + } + } + } + .pill_container { + margin: 1.25em 0px 0px 0px; + float: right; + } + + &#quick_login_li { + &:hover { + color: @grey5; + } + + a.menu_link_notifications { + color: white; + } + + .user { + padding-bottom: 10px; + } + + &.open { + .user { + border-bottom: 5px solid @rcblue; + } + } + } + + &:before { content: none; } + + &:last-child { + .menulabel { + padding-right: 0; + border-right: none; + + .show_more { + padding-right: 0; + } + } + + &> a { + border-bottom: none; + } + } + + &.active { + border-bottom: 5px solid @rcblue; + } + + &.open { + + a { + color: white; + } + } + + &:focus { + outline: none; + } + + ul li { + display: block; + + &:last-child> a { + border-bottom: none; + } + + ul li:last-child a { + /* we don't expect more then 3 levels of submenu and the third + level can have different html structure */ + border-bottom: none; + } + } + } + + > li { + float: left; + display: block; + padding: 0; + + > a, + &.has_select2 a { + display: block; + padding: 10px 0 2px; + + .show_more { + margin-top: -4px; + padding-right: .5em; + } + } + + .menulabel { + padding: 0 .5em; + line-height: 1em; + // for this specifically we do not use a variable + border-right: 1px solid @grey4; + } + + .pr_notifications { + padding-left: .5em; + } + + .pr_notifications + .menulabel { + display:inline; + padding-left: 0; + } + + &:hover, + &.open, + &.active { + a { + color: @grey1; + } + } + } + + pre { + margin: 0; + padding: 0; + } + + .select2-container, + .menulink.childs { + position: relative; + } + + #quick_login { + + li a { + padding: .5em 0; + border-bottom: none; + color: @grey2; + + &:hover { color: @grey1; } + } + + .show_more { + padding-left: .5em; + } + } + + #quick_login_link { + display: inline-block; + + .gravatar { + border: 1px solid @grey2; + } + + .gravatar-login { + height: 20px; + width: 20px; + margin: -8px 0; + padding: 0; + } + + &:hover .user { + color: @grey6; + } + } +} +.header .horizontal-list { + + li { + + &#quick_login_li { + padding-left: .5em; + + &:hover #quick_login_link { + color: inherit; + } + } + + &:before { content: none; } + } + + > li { + + a { + padding: 18px 0 12px 0; + color: @nav-grey; + + &.menu_link_notifications { + padding: 1px 8px; + } + } + + &:hover, + &.open, + &.active { + .pill_container a { + // don't select text for the pill container, it has it' own + // hover behaviour + color: @nav-grey; + } + } + + &:hover, + &.open, + &.active { + a { + color: @grey6; + } + } + + .select2-dropdown-open a { + color: @grey6; + } + + .repo-switcher { + padding-left: 0; + + .menulabel { + padding-left: 0; + } + } + } + + li ul li { + background-color:@grey2; + + a { + padding: .5em 0; + border-bottom: @border-thickness solid @border-default-color; + color: @grey6; + } + + &:last-child a, &.last a{ + border-bottom: none; + } + + &:hover { + background-color: @grey3; + } + } + + .submenu { + margin-top: 5px; + } +} + +// SUBMENUS +.navigation .submenu { + display: none; +} + +.navigation li.open { + + .submenu, + .repo_switcher { + display: block; + } +} + +.submenu { + position: absolute; + top: 100%; + left: 0; + min-width: 150px; + margin: 6px 0 0; + padding: 0; + text-align: left; + font-family: @text-light; + border-radius: @border-radius; + z-index: 20; + + li { + display: block; + margin: 0; + padding: 0 .5em; + line-height: 1em; + color: @grey3; + background-color: @grey6; + + &:before { content: none; } + + a { + display: block; + width: 100%; + padding: .5em 0; + border-right: none; + border-bottom: @border-thickness solid white; + color: @grey3; + } + + ul { + display: none; + position: absolute; + top: 0; + right: 100%; + padding: 0; + z-index: 30; + } + &:hover { + background-color: @grey5; + -webkit-transition: background .3s; + -moz-transition: background .3s; + -o-transition: background .3s; + transition: background .3s; + + ul { + display: block; + } + } + } +} + + + + +// repo dropdown +.quick_repo_menu { + width: 15px; + text-align: center; + position: relative; + cursor: pointer; + + div { + overflow: visible !important; + } + + &.sorting { + cursor: auto; + } + + &:hover { + .menu_items_container { + position: absolute; + display: block; + } + .menu_items { + display: block; + } + } + + i { + margin: 0; + color: @grey4; + } + + .menu_items_container { + position: absolute; + top: 0; + left: 100%; + margin: 0; + padding: 0; + list-style: none; + background-color: @grey6; + z-index: 999; + text-align: left; + + a { + color: @grey2; + } + + ul.menu_items { + margin: 0; + padding: 0; + } + + li { + margin: 0; + padding: 0; + line-height: 1em; + list-style-type: none; + + &:before { content: none; } + + a { + display: block; + height: 16px; + padding: 8px; //must add up to td height (28px) + + &:hover { + background-color: @grey5; + -webkit-transition: background .3s; + -moz-transition: background .3s; + -o-transition: background .3s; + transition: background .3s; + } + } + } + } +} + +// Header Repository Switcher +// Select2 Dropdown +#select2-drop.select2-drop.repo-switcher-dropdown { + width: auto !important; + margin-top: 5px; + padding: 1em 0; + text-align: left; + .border-radius-bottom(@border-radius); + border-color: transparent; + color: @grey6; + background-color: @grey2; + + input { + min-width: 90%; + } + + ul.select2-result-sub { + + li { + line-height: 1em; + + &:hover, + &.select2-highlighted { + background-color: @grey3; + } + } + + &:before { content: none; } + } + + ul.select2-results { + min-width: 200px; + margin: 0; + padding: 0; + list-style-type: none; + overflow-x: visible; + overflow-y: scroll; + + li { + padding: 0 8px; + line-height: 1em; + color: @grey6; + + &:before { content: none; } + + &>.select2-result-label { + padding: 8px 0; + border-bottom: @border-thickness solid @grey3; + white-space: nowrap; + color: @grey5; + cursor: pointer; + } + + &.select2-result-with-children { + margin: 0; + padding: 0; + } + + &.select2-result-unselectable > .select2-result-label { + margin: 0 8px; + } + + } + } + + ul.select2-result-sub { + margin: 0; + padding: 0; + + li { + display: block; + margin: 0; + border-right: none; + line-height: 1em; + font-family: @text-light; + color: @grey2; + + &:before { content: none; } + + &:hover { + background-color: @grey3; + } + } + } +} + + +#context-bar { + display: block; + margin: 0 auto; + padding: 0 @header-padding; + background-color: @grey6; + border-bottom: @border-thickness solid @grey5; + + .clear { + clear: both; + } +} + +ul#context-pages { + li { + line-height: 1em; + + &:before { content: none; } + + a { + color: @grey3; + } + + &.active { + // special case, non-variable color + border-bottom: 4px solid @nav-grey; + + a { + color: @grey1; + } + } + } +} + +// PAGINATION + +.pagination { + border: @border-thickness solid @rcblue; + color: @rcblue; + + .current { + color: @grey4; + } +} + +.dataTables_paginate, .pagination-wh { + text-align: left; + display: inline-block; + border-left: 1px solid @rcblue; + float: none; + overflow: hidden; + + .paginate_button, .pager_curpage, + .pager_link, .pg-previous, .pg-next, .pager_dotdot { + display: inline-block; + padding: @menupadding/4 @menupadding; + border: 1px solid @rcblue; + border-left: 0; + color: @rcblue; + cursor: pointer; + float: left; + } + + .pager_curpage, .pager_dotdot, + .paginate_button.current, .paginate_button.disabled, + .disabled { + color: @grey3; + cursor: default; + } +} + +// SIDEBAR + +.sidebar { + .block-left; + clear: left; + max-width: @sidebar-width; + margin-right: @sidebarpadding; + padding-right: @sidebarpadding; + font-family: @text-regular; + color: @grey1; + + &#graph_nodes { + clear:both; + width: auto; + margin-left: -100px; + padding: 0; + border: none; + } + + .nav-pills { + margin: 0; + } + + .nav { + list-style: none; + padding: 0; + + li { + padding-bottom: @menupadding; + line-height: 1em; + color: @grey4; + + &.active a { + color: @grey2; + } + + a { + color: @grey4; + } + + &:before { content: none; } + } + + } +} diff --git a/rhodecode/public/css/panels-bootstrap.less b/rhodecode/public/css/panels-bootstrap.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/panels-bootstrap.less @@ -0,0 +1,271 @@ +// +// Panels +// -------------------------------------------------- + + +// Base class +.panel { + margin-bottom: @line-height-computed; + background-color: @panel-bg; + border: 1px solid transparent; + border-radius: @panel-border-radius; + .box-shadow(0 1px 1px rgba(0,0,0,.05)); +} + +// Panel contents +.panel-body { + padding: @panel-body-padding; + &:extend(.clearfix all); +} + +// Optional heading +.panel-heading { + padding: @panel-heading-padding; + border-bottom: 1px solid transparent; + .border-top-radius((@panel-border-radius - 1)); + + > .dropdown .dropdown-toggle { + color: inherit; + } +} + +// Within heading, strip any `h*` tag of its default margins for spacing. +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: ceil((@font-size-base * 1.125)); + color: inherit; + + > a, + > small, + > .small, + > small > a, + > .small > a { + color: inherit; + } +} + +// Optional footer (stays gray in every modifier class) +.panel-footer { + padding: @panel-footer-padding; + background-color: @panel-footer-bg; + border-top: 1px solid @panel-inner-border; + .border-bottom-radius((@panel-border-radius - 1)); +} + + +// List groups in panels +// +// By default, space out list group content from panel headings to account for +// any kind of custom content between the two. + +.panel { + > .list-group, + > .panel-collapse > .list-group { + margin-bottom: 0; + + .list-group-item { + border-width: 1px 0; + border-radius: 0; + } + + // Add border top radius for first one + &:first-child { + .list-group-item:first-child { + border-top: 0; + .border-top-radius((@panel-border-radius - 1)); + } + } + + // Add border bottom radius for last one + &:last-child { + .list-group-item:last-child { + border-bottom: 0; + .border-bottom-radius((@panel-border-radius - 1)); + } + } + } + > .panel-heading + .panel-collapse > .list-group { + .list-group-item:first-child { + .border-top-radius(0); + } + } +} +// Collapse space between when there's no additional content. +.panel-heading + .list-group { + .list-group-item:first-child { + border-top-width: 0; + } +} +.list-group + .panel-footer { + border-top-width: 0; +} + +// Tables in panels +// +// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and +// watch it go full width. + +.panel { + > .table, + > .table-responsive > .table, + > .panel-collapse > .table { + margin-bottom: 0; + + caption { + padding-left: @panel-body-padding; + padding-right: @panel-body-padding; + } + } + // Add border top radius for first one + > .table:first-child, + > .table-responsive:first-child > .table:first-child { + .border-top-radius((@panel-border-radius - 1)); + + > thead:first-child, + > tbody:first-child { + > tr:first-child { + border-top-left-radius: (@panel-border-radius - 1); + border-top-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-top-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-top-right-radius: (@panel-border-radius - 1); + } + } + } + } + // Add border bottom radius for last one + > .table:last-child, + > .table-responsive:last-child > .table:last-child { + .border-bottom-radius((@panel-border-radius - 1)); + + > tbody:last-child, + > tfoot:last-child { + > tr:last-child { + border-bottom-left-radius: (@panel-border-radius - 1); + border-bottom-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-bottom-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-bottom-right-radius: (@panel-border-radius - 1); + } + } + } + } + > .panel-body + .table, + > .panel-body + .table-responsive, + > .table + .panel-body, + > .table-responsive + .panel-body { + border-top: 1px solid @table-border-color; + } + > .table > tbody:first-child > tr:first-child th, + > .table > tbody:first-child > tr:first-child td { + border-top: 0; + } + > .table-bordered, + > .table-responsive > .table-bordered { + border: 0; + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-left: 0; + } + > th:last-child, + > td:last-child { + border-right: 0; + } + } + } + > thead, + > tbody { + > tr:first-child { + > td, + > th { + border-bottom: 0; + } + } + } + > tbody, + > tfoot { + > tr:last-child { + > td, + > th { + border-bottom: 0; + } + } + } + } + > .table-responsive { + border: 0; + margin-bottom: 0; + } +} + + +// Collapsable panels (aka, accordion) +// +// Wrap a series of panels in `.panel-group` to turn them into an accordion with +// the help of our collapse JavaScript plugin. + +.panel-group { + margin-bottom: @line-height-computed; + + // Tighten up margin so it's only between panels + .panel { + margin-bottom: 0; + border-radius: @panel-border-radius; + + + .panel { + margin-top: 5px; + } + } + + .panel-heading { + border-bottom: 0; + + + .panel-collapse > .panel-body, + + .panel-collapse > .list-group { + border-top: 1px solid @panel-inner-border; + } + } + + .panel-footer { + border-top: 0; + + .panel-collapse .panel-body { + border-bottom: 1px solid @panel-inner-border; + } + } +} + + +// Contextual variations +.panel-default { + .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border); +} +.panel-primary { + .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border); +} +.panel-success { + .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border); +} +.panel-info { + .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border); +} +.panel-warning { + .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border); +} +.panel-danger { + .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border); +} diff --git a/rhodecode/public/css/panels.less b/rhodecode/public/css/panels.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/panels.less @@ -0,0 +1,87 @@ +// See panels-bootstrap.less +// These provide overrides for custom styling of Bootstrap panels + +.panel { + &:extend(.clearfix); + + width: 100%; + margin: 0 0 25px 0; + border-color: @grey5; + .border-radius(@border-radius); + .box-shadow(none); + + .permalink { + visibility: hidden; + } + + &:hover .permalink { + visibility: visible; + color: @rcblue; + } + + .panel-heading { + position: relative; + min-height: 1em; + padding: @padding @panel-padding; + background-color: @grey6; + border-bottom: none; + + .panel-title, + h3.panel-title { + float: left; + padding: 0 @padding 0 0; + line-height: 1; + font-size: @panel-title; + color: @grey1; + } + + .panel-edit { + float: right; + line-height: 1; + font-size: @panel-title; + } + } + + .panel-body { + padding: @panel-padding; + } + + .panel-footer { + background-color: white; + padding: .65em @panel-padding .5em; + font-size: @panel-footer; + color: @text-muted; + } + + .q_filter_box { + min-width: 40%; + } + + // special cases + &.user-profile { + float: left; + + .panel-heading { + margin-bottom: @padding; + } + + .panel-body { + &:extend(.clearfix); + } + } +} + +.main-content h3.panel-title { + font-size: @panel-title; + color: @grey1; +} + +.panel-body-title-text { + margin: 0 0 20px 0; +} + +// play nice with the current form and field css +.field.panel-default, +.form.panel-default { + width: auto; +} \ No newline at end of file diff --git a/rhodecode/public/css/progress-bar.less b/rhodecode/public/css/progress-bar.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/progress-bar.less @@ -0,0 +1,142 @@ +#progress-message { + display:table; + padding: 10px 0; + font-size: @basefontsize; + font-weight: bold; + margin-right: auto; + margin-left: auto; +} +#progress { + width: 500px; + margin-left: auto; + margin-right: auto; +} +#progress_error { + display: none; +} +#progress_error_message { + font-weight: bold; + color:#aa1111; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + // TODO: lisa: should this be a color from the style guide? + // maybe @grey6: #eeeeee; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress-bar { + float: left; + width: 0; + height: 100%; + width: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .progress-bar { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} + +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-bar-success { + background-color: #5cb85c; +} + +.progress-striped .progress-bar-success { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-info { + background-color: #5bc0de; +} + +.progress-striped .progress-bar-info { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-warning { + background-color: #f0ad4e; +} + +.progress-striped .progress-bar-warning { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-danger { + background-color: #d9534f; +} + +.progress-striped .progress-bar-danger { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} diff --git a/rhodecode/public/css/rcicons.less b/rhodecode/public/css/rcicons.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/rcicons.less @@ -0,0 +1,116 @@ +@font-face { + font-family: 'rcicons'; + src: url('../fonts/RCIcons/rcicons.eot?18742416'); + src: url('../fonts/RCIcons/rcicons.eot?18742416#iefix') format('embedded-opentype'), + url('../fonts/RCIcons/rcicons.woff?18742416') format('woff'), + url('../fonts/RCIcons/rcicons.ttf?18742416') format('truetype'), + url('../fonts/RCIcons/rcicons.svg?18742416#rcicons') format('svg'); + font-weight: normal; + font-style: normal; +} +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ +/* +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: 'rcicons'; + src: url('../font/rcicons.svg?18742415#rcicons') format('svg'); + } +} +*/ + + [class^="icon-"]:before, [class*=" icon-"]:before { + font-family: "rcicons"; + font-style: normal; + font-weight: normal; + speak: none; + + display: inline-block; + text-decoration: inherit; + width: 1em; + margin-right: .2em; + text-align: center; + /* opacity: .8; */ + + /* For safety - reset parent styles, that can break glyph codes*/ + font-variant: normal; + text-transform: none; + + /* fix buttons height, for twitter bootstrap */ + line-height: 1em; + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: .2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ +} + +.icon-svn-transparent:before { content: '\e800'; } /* '' */ +.icon-hg-transparent:before { content: '\e801'; } /* '' */ +.icon-git-transparent:before { content: '\e802'; } /* '' */ +.icon-svn:before { content: '\e803'; } /* '' */ +.icon-hg:before { content: '\e804'; } /* '' */ +.icon-git:before { content: '\e805'; } /* '' */ +.icon-plus:before { content: '\e806'; } /* '' */ +.icon-minus:before { content: '\e807'; } /* '' */ +.icon-remove:before { content: '\e808'; } /* '' */ +.icon-bookmark:before { content: '\e809'; } /* '' */ +.icon-branch:before { content: '\e80a'; } /* '' */ +.icon-tag:before { content: '\e80b'; } /* '' */ +.icon-lock:before { content: '\e80c'; } /* '' */ +.icon-unlock:before { content: '\e80d'; } /* '' */ +.icon-delete:before, +.icon-false:before { content: '\e80e'; } /* '' */ +.icon-ok:before, +.icon-true:before { content: '\e80f'; } /* '' */ +.icon-comment:before { content: '\e810'; } /* '' */ +.icon-feed:before { content: '\e811'; } /* '' */ +.icon-right:before { content: '\e812'; } /* '' */ +.icon-left:before { content: '\e813'; } /* '' */ +.icon-arrow_down:before { content: '\e814'; } /* '' */ +.icon-group:before { content: '\e815'; } /* '' */ +.icon-folder:before { content: '\e816'; } /* '' */ +.icon-fork:before { content: '\e817'; } /* '' */ +.icon-more:before { content: '\e818'; } /* '' */ +.icon-comment-add:before { content: '\e819'; } /* '' */ + + +.icon-remove-sign:before { &:extend(.icon-remove:before); } +.icon-repo-private:before, +.icon-repo-lock:before { &:extend(.icon-lock:before); } +.icon-unlock-alt:before, +.icon-repo-unlock:before, +.icon-repo-public:before { &:extend(.icon-unlock:before); } +.icon-rss-sign:before { &:extend(.icon-feed:before); } +.icon-chevron-right:before { &:extend(.icon-right:before); } +.icon-chevron-left:before { &:extend(.icon-left:before); } +.icon-caret-down:before { &:extend(.icon-arrow_down:before); } +.icon-folder-close:before { &:extend(.icon-folder:before); } +.icon-code-fork:before { &:extend(.icon-fork:before); } + + +//--- ICONS STYLING ------------------// + +.icon-git { color: @color4 !important; } +.icon-hg { color: @color8 !important; } +.icon-svn { color: @color1 !important; } +.icon-repo-lock { color: #FF0000; } +.icon-repo-unlock { color: #FF0000; } + +.repo-switcher-dropdown .select2-result-label { + .icon-git:before { + &:extend(.icon-git-transparent:before); + } + .icon-hg:before { + &:extend(.icon-hg-transparent:before); + color: @alert4; + } + .icon-svn:before { + &:extend(.icon-svn-transparent:before); + } +} diff --git a/rhodecode/public/css/select2.less b/rhodecode/public/css/select2.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/select2.less @@ -0,0 +1,222 @@ +// select2.less +// For use in RhodeCode application drop down select boxes; +// see style guide documentation for guidelines. + + +// SELECT2 DROPDOWN MENUS + +//Select2 Dropdown +.select2-results{ + .box-sizing(border-box); + overflow-y: scroll; +} + +.select2-container{margin: 0; position: relative; display: inline-block; zoom: 1;} +.select2-container, +.select2-drop, +.select2-search, +.select2-search input {.box-sizing(border-box);} +.select2-container .select2-choice{display:block; line-height:1em; -webkit-touch-callout:none;-moz-user-select:none;-ms-user-select:none;user-select:none; } +.main .select2-container .select2-choice { background-color: white; } +.select2-container .select2-choice abbr { display: none; width: 12px; height: 12px; position: absolute; right: 24px; top: 8px; font-size: 1px; text-decoration: none; border: 0; background: url('../images/select2.png') right top no-repeat; cursor: pointer; outline: 0; } +.select2-container.select2-allowclear .select2-choice abbr {display: inline-block;} +.select2-container .select2-choice abbr:hover { background-position: right -11px; cursor: pointer; } +.select2-drop-mask { border: 0; margin: 0; padding: 0; position: fixed; left: 0; top: 0; min-height: 100%; min-width: 100%; height: auto; width: auto; opacity: 0; z-index: 998; background-color: #fff; filter: alpha(opacity=0); } +.select2-drop { width: 100%; margin-top: -1px; position: absolute; z-index: 999; top: 100%; background: #fff; color: #000; border: @border-thickness solid @rcblue; border-top: 0; border-radius: 0 0 @border-radius @border-radius; } + .select2-drop.select2-drop-above { margin-top: 1px; border-top: @border-thickness solid @rclightblue; border-bottom: 0; border-radius: @border-radius @border-radius 0 0; } +.select2-drop-active { border: @border-thickness solid #5897fb; border-top: none; } +.select2-drop.select2-drop-above.select2-drop-active {border-top: @border-thickness solid #5897fb;} +.select2-drop-auto-width { border-top: @border-thickness solid #aaa; width: auto; } + .select2-drop-auto-width .select2-search {padding-top: 4px;} +html[dir="rtl"] .select2-container .select2-choice .select2-arrow { left: 0; right: auto; border-left: none; border-right: @border-thickness solid @grey5; border-radius: @border-radius 0 0 @border-radius; } +html[dir="rtl"] .select2-container .select2-choice .select2-arrow b {background-position: 2px 1px;} +.select2-search { display: inline-block; width: 100%; min-height: 26px; margin: 0; padding-left: 4px; padding-right: 4px; position: relative; z-index: 1000; white-space: nowrap; } + .select2-search input { width: 100%; height: auto !important; min-height: 26px; padding: 4px 20px 4px 5px; margin: 0; outline: 0; } +html[dir="rtl"] .select2-search input { padding: 4px 5px 4px 20px; background: #fff url('../images/select2.png') no-repeat -37px -22px; } +.select2-drop.select2-drop-above .select2-search input {margin-top: 4px;} +.select2-dropdown-open .select2-choice .select2-arrow { background: transparent; border-left: none; filter: none; } +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow {border-right: none;} +.select2-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } +/* results */ +.select2-results { max-height: 200px; padding: 0 0 0 4px; margin: 4px 4px 4px 0; position: relative; overflow-x: hidden; overflow-y: auto; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } +html[dir="rtl"] .select2-results { padding: 0 4px 0 0; margin: 4px 0 4px 4px; } +.select2-results .select2-disabled{background:@grey6;display:list-item;cursor:default} +.select2-results .select2-selected{display:none} +.select2-more-results.select2-active{background:#f4f4f4 url('../images/select2-spinner.gif') no-repeat 100%} +.select2-container.select2-container-disabled .select2-choice abbr{display:none} +.select2-container.select2-container-disabled {background:@grey6;cursor:default} +.select2-container.select2-container-disabled .select2-choice {background:@grey6;cursor:default} +.select2-container-multi .select2-choices li{float:left;list-style:none} +.select2-container-multi .select2-choices .select2-search-field{margin:0;padding:0;white-space:nowrap} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen{cursor:default} +.select2-search-choice-close{display:block;width:12px;height:13px;position:absolute;right:3px;top:4px;font-size:1px;outline:none;background:url('../images/select2.png') right top no-repeat} +.select2-container-multi .select2-search-choice-close{left:3px} +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover{background-position:right -11px} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close{background-position:right -11px} +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close{display:none;background:none} +.select2-offscreen,.select2-offscreen:focus{clip:rect(0 0 0 0) !important;width:1px !important;height:1px !important; + border:0 !important;margin:0 !important;padding:0 !important;overflow:hidden !important; + position: absolute !important;outline:0 !important;left:0 !important;top:0 !important} +.select2-display-none, +.select2-search-hidden {display:none} +.select2-search input { border-color: @rclightblue; } + +.select2-measure-scrollbar{position:absolute;top:-10000px;left:-10000px;width:100px;height:100px;overflow:scroll} +@media only screen and (-webkit-min-device-pixel-ratio:1.5), + only screen and (min-resolution:144dpi){ + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b{background-image:url('../images/select2x2.png');background-repeat:no-repeat;background-size:60px 40px;} + .select2-search input{background-position:100% -21px} +} +[class^="input-"] [class^="select2-choice"]>div{display:none} +[class^="input-"] .select2-offscreen{position:absolute} +select.select2{height:28px;visibility:hidden} +.autocomplete-suggestions{overflow:auto} +.autocomplete-suggestion{white-space:nowrap;overflow:hidden} + +/* Retina-ize icons */ +@media only screen and (-webkit-min-device-pixel-ratio:1.5), + only screen and (min-resolution:144dpi){ + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b{background-image:url('../images/select2x2.png');background-repeat:no-repeat;background-size:60px 40px;} + .select2-search input{background-position:100% -21px} +} + +//Internal Select2 Dropdown Menus + +.drop-menu-core { + min-width: 160px; + margin: 0 @padding 0 0; + padding: 0; + border: @border-thickness solid @rcblue; + border-radius: @border-radius; + color: @rcblue; + background-color: white; +} + +.drop-menu-dropdown { + .drop-menu-core; + + .flag_status { + margin-top: 0; + } +} + +.drop-menu-base { + .drop-menu-core; + position: relative; + display: inline-block; + line-height: 1em; + z-index: 2; + cursor: pointer; + + .flag_status { + margin-top: 0; + } + + a { + display:block; + padding: .9em; + padding-right: 2em; + position: relative; + + &:after { + position: absolute; + content: "\00A0\25BE"; + right: .6em; + line-height: 1em; + top: 0.9em; + width: 1em; + font-size: 1em; + } + } +} + +.drop-menu { + .drop-menu-base; + width: auto !important; +} + +.drop-menu-no-width { + .drop-menu-base; + width: auto; +} + +.field-sm .drop-menu { + padding: 1px 0 0 0; + a { + padding: 6px; + }; +} + +.select2-search input { + width: auto !important; + margin: .5em; + padding: .5em; +} + +.select2-no-results { + padding: .5em; +} + +.drop-menu-dropdown ul { + width: auto; + margin: 0; + padding: 0; + z-index: 50; + + li { + margin: 0; + line-height: 1em; + list-style-type: none; + + &:before { content: none; } + + &:hover, + &.select2-highlighted { + background-color: @rclightblue; + } + + &.select2-result-with-children { + &:hover { + background-color: white; + } + } + + .select2-result-label { + display:block; + padding: 8px; + font-family: @text-regular; + border-bottom: @border-thickness solid @rclightblue; + color: @rcblue; + cursor: pointer; + } + &.select2-result-with-children { + + .select2-result-label { + font-family: @text-semibold; + color: @rcdarkblue; + cursor: default; + } + + ul.select2-result-sub li .select2-result-label { + padding-left: 16px; + font-family: @text-regular; + color: @rcblue; + cursor: pointer; + } + } + } +} + +.side-by-side-selector { + .left-group, + .middle-group, + .right-group { + margin-bottom: @padding; + } +} diff --git a/rhodecode/public/css/statistics-graph.less b/rhodecode/public/css/statistics-graph.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/statistics-graph.less @@ -0,0 +1,55 @@ +/* + * statistics-graph + * + * Style definitions for the statistics component. This component is available + * for each repository which has statistics enabled. + */ + +.statistics-graph { + .data-info { + padding: 0 10px 10px 17px; + } + + #graph-main { + width: 450px; + height: 300px; + float: left; + } + + .graph-divider { + clear: both; + height: 10px; + } + + #graph-overview { + width: 450px; + height: 100px; + float: left; + } + + #legend_data { + clear: both; + margin-top: 10px; + width: 100%; + float: left; + + #legend_container { + table { + width: auto; + margin: 0; + } + } + } + + #legend_choices_tables { + border: 0; + font-size: smaller; + color: @grey3 + } + + .legendLabel { + label { + margin-left: @input-padding; + } + } +} diff --git a/rhodecode/public/css/summary.less b/rhodecode/public/css/summary.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/summary.less @@ -0,0 +1,268 @@ +// summary.less +// For use in RhodeCode applications; +// Used for headers and file detail summary screens. + +.summary { + float: left; + position: relative; + width: 100%; + margin: 0; + padding: 0; + + .summary-detail-header { + float: left; + display: block; + width: 100%; + margin-bottom: @textmargin; + padding: 0 0 .5em 0; + border-bottom: @border-thickness solid @border-default-color; + + .breadcrumbs { + float: left; + display: inline; + margin: 0; + padding: 0; + } + h4 { + float: left; + margin: 0 1em 0 0; + padding: 0; + line-height: 1.2em; + font-size: @basefontsize; + } + + .action_link { + float: right; + } + + .new-file { + float: right; + margin-top: -1.5em; + } + } + + .summary-detail { + float: left; + position: relative; + width: 73%; + margin: 0 3% @space 0; + padding: 0; + + .file_diff_buttons { + margin-top: @space; + } + + // commit message + .commit { + white-space: pre-wrap; + } + + #clone_url, + #clone_url_id { + min-width: 29em; + padding: @padding/4; + } + + &.directory { + margin-bottom: 0; + } + + .desc { + white-space: pre-wrap; + } + .disabled { + opacity: .5; + } + .help-block { + color: inherit; + margin: 0; + } + } + + .sidebar-right { + float: left; + width: 24%; + margin: 0; + padding: 0; + + ul { + margin-left: 0; + padding-left: 0; + + li { + + &:before { + content: none; + width: 0; + } + } + } + } + + #clone_by_name, #clone_by_id{ + display: inline-block; + margin-left: @padding; + } + + .codeblock { + border: none; + background-color: transparent; + } + + .code-body { + border: @border-thickness solid @border-default-color; + .border-radius(@border-radius); + } +} + +// this is used outside of just the summary +.fieldset, // similar to form fieldset +.summary .sidebar-right-content { // these have to match + clear: both; + float: left; + position: relative; + display:block; + width: 100%; + min-height: 1em; + margin-bottom: @textmargin; + padding: 0; + line-height: 1.2em; + + &:after { // clearfix + content: ""; + clear: both; + width: 100%; + height: 1em; + } +} + +.summary .sidebar-right-content { + margin-bottom: @space; +} + +.fieldset { + + .left-label { // similar to form legend + float: left; + display: block; + width: 25%; + margin: 0; + padding: 0; + font-family: @text-semibold; + } + + .right-content { // similar to form fields + float: left; + display: block; + width: 75%; + margin: 0 0 0 -15%; + padding: 0 0 0 15%; + + .truncate-wrap, + .truncate { + max-width: 100%; + width: 100%; + } + + .commit-long { + overflow-x: auto; + } + } +} + +// expand commit message +#message_expand { + clear: both; + display: block; + color: @rcblue; + cursor: pointer; +} + +#trimmed_message_box { + max-height: floor(2 * @basefontsize * 1.2); // 2 lines * line-height + overflow: hidden; +} + +// show/hide comments button +.show-inline-comments { + display: inline; + cursor: pointer; + + .comments-show { display: inline; } + .comments-hide { display: none; } + + &.comments-visible { + .comments-show { display: none; } + .comments-hide { display: inline; } + } +} + +// Quick Start section +.quick_start { + float: left; + display: block; + position: relative; + + // adds some space to make copy and paste easier + .left-label, + .right-content { + line-height: 1.6em; + } +} + +.submodule { + .summary-detail { + width: 100%; + + .btn-collapse { + display: none; + } + } +} + +.codeblock-header { + float: left; + display: block; + width: 100%; + margin: 0; + padding: @space 0 @padding 0; + border-top: @border-thickness solid @border-default-color; + + .stats { + float: left; + width: 50%; + } + + .buttons { + float: right; + width: 50%; + text-align: right; + color: @grey4; + } +} + +#summary-menu-stats { + + .stats-bullet { + color: @grey3; + min-width: 3em; + } + + .repo-size { + margin-bottom: .5em; + } + +} + +#readme { + width: 100%; + + .readme { + overflow-x: auto; + border: @border-thickness solid @border-default-color; + .border-radius(@border-radius); + } + .readme_box { + margin: 15px; + } +} diff --git a/rhodecode/public/css/tables.less b/rhodecode/public/css/tables.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/tables.less @@ -0,0 +1,526 @@ + +// tables.less +// For use in RhodeCode application tables; +// see style guide documentation for guidelines. + +// TABLES + +.rctable, +table.rctable, +table.dataTable { + clear:both; + width: 100%; + margin: 0 auto @padding; + padding: 0; + vertical-align: baseline; + line-height:1.5em; + border: none; + outline: none; + border-collapse: collapse; + border-spacing: 0; + color: @grey2; + + b { + font-weight: normal; + } + + em { + font-weight: bold; + font-style: normal; + } + + th, + td { + height: auto; + max-width: 20%; + padding: .65em 1em .65em 0; + vertical-align: middle; + border-bottom: @border-thickness solid @grey5; + white-space: normal; + + &.td-radio, + &.td-checkbox { + padding-right: 0; + text-align: center; + + input { + margin: 0 1em; + } + } + + &.truncate-wrap { + white-space: nowrap !important; + } + + pre { + margin: 0; + } + + .show_more { + height: inherit; + } + } + + .expired td { + background-color: @grey7; + } + + .td-radio + .td-owner { + padding-left: 1em; + } + + + th { + text-align: left; + font-family: @text-semibold; + } + + .hl { + td { + background-color: lighten(@alert4,25%); + } + } + +// Special Data Cell Types +// See style guide for desciptions and examples. + + td { + + &.user { + padding-left: 1em; + } + + &.td-rss { + width: 20px; + min-width: 0; + margin: 0; + } + + &.quick_repo_menu { + width: 15px; + text-align: center; + + &:hover { + background-color: @grey5; + } + } + + &.td-hash { + min-width: 80px; + width: 200px; + } + + &.td-time { + width: 160px; + white-space: nowrap; + } + + &.annotate{ + padding-right: 0; + + div.annotatediv{ + margin: 0 0.7em; + } + } + + &.td-gravatar { + width: 16px; + padding: 0 5px; + } + + &.tags-col { + padding-right: 0; + } + + &.td-description { + min-width: 350px; + } + + &.td-componentname { + white-space: nowrap; + } + + &.td-journalaction { + min-width: 300px; + + .journal_action_params { + // waiting for feedback + } + } + + &.td-active { + padding-left: .65em; + } + + &.td-url { + white-space: nowrap; + } + + &.td-comments { + min-width: 3em; + } + + &.td-buttons { + padding: .3em 0; + } + + &.td-action { + // this is for the remove/delete/edit buttons + padding-right: 0; + min-width: 95px; + text-transform: capitalize; + + i { + display: none; + } + } + + // TODO: lisa: this needs to be cleaned up with the buttons + .grid_edit, + .grid_delete { + display: inline-block; + margin: 0 @padding/3 0 0; + font-family: @text-light; + + i { + display: none; + } + } + + .grid_edit + .grid_delete { + border-left: @border-thickness solid @grey5; + padding-left: @padding/2; + } + + &.td-compare { + + input { + margin-right: 1em; + } + + .compare-radio-button { + margin: 0 1em 0 0; + } + + + } + + &.td-tags { + padding: .5em 1em .5em 0; + + .tag { + margin: 1px; + } + } + + .icon-svn, .icon-hg, .icon-git { + font-size: 1.4em; + } + + &.collapse_commit, + &.expand_commit { + padding-right: 0; + padding-left: 1em; + } + } + + .perm_admin_row { + color: @grey4; + background-color: @grey6; + } + + .noborder { + border: none; + + td { + border: none; + } + } +} + +// TRUNCATING +// TODO: lisaq: should this possibly be moved out of tables.less? +// for truncated text +// used inside of table cells and in code block headers +.truncate-wrap { + white-space: nowrap !important; + + //truncated text + .truncate { + max-width: 450px; + width: 300px; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + + &.autoexpand { + width: 120px; + margin-right: 200px; + } + } + &:hover .truncate.autoexpand { + overflow: visible; + } + + .tags-truncate { + width: 150px; + height: 22px; + overflow: hidden; + + .tag { + display: inline-block; + } + + &.truncate { + height: 22px; + max-height:2em; + width: 140px; + } + } +} + +.apikeys_wrap { + margin-bottom: @padding; + + table.rctable td:first-child { + width: 340px; + } +} + + + +// SPECIAL CASES + +// Repository Followers +table.rctable.followers_data { + width: 75%; + margin: 0; +} + +// Repository List +// Group Members List +table.rctable.group_members, +table#repo_list_table { + min-width: 600px; +} + +// Keyboard mappings +table.keyboard-mappings { + th { + text-align: left; + font-family: @text-semibold; + } +} + +// Branches, Tags, and Bookmarks +#obj_list_table.dataTable { + td.td-time { + padding-right: 1em; + } +} + +// User Admin +.rctable.useremails, +.rctable.account_emails { + .tag, + .btn { + float: right; + } + .btn { //to line up with tags + margin-right: 1.65em; + } +} + +// User List +#user_list_table { + + td.td-user { + min-width: 100px; + } +} + +// Pull Request List Table +#pull_request_list_table.dataTable { + + //TODO: lisa: This needs to be removed once the description is adjusted + // for using an expand_commit button (see issue 765) + td { + vertical-align: middle; + } +} + +// Settings (no border) +table.rctable.dl-settings { + td { + border: none; + } +} + + +// Statistics +table.trending_language_tbl { + width: 100%; + line-height: 1em; + + td div { + overflow: visible; + } +} + +.trending_language_tbl, .trending_language_tbl td { + border: 0; + margin: 0; + padding: 0; + background: transparent; +} + +.trending_language_tbl, .trending_language_tbl tr { + border-spacing: 0 3px; +} + +.trending_language { + position: relative; + width: 100%; + height: 19px; + overflow: hidden; + background-color: @grey6; + + span, b{ + position: absolute; + display: block; + height: 12px; + margin-bottom: 0px; + white-space: pre; + padding: floor(@basefontsize/4); + top: 0; + left: 0; + } + + span{ + color: @text-color; + z-index: 0; + min-width: 20px; + } + + b { + z-index: 1; + overflow: hidden; + background-color: @rcblue; + color: #FFF; + text-decoration: none; + } + +} + +// Changesets +#changesets.rctable { + + // td must be fixed height for graph + td { + height: 32px; + padding: 0 1em 0 0; + vertical-align: middle; + white-space: nowrap; + + &.td-description { + white-space: normal; + } + + &.expand_commit { + padding-right: 0; + } + } +} + +// Compare +table.compare_view_commits { + margin-top: @space; + + td.td-time { + padding-left: .5em; + } + + tr:hover { + cursor: pointer; + + td { + background-color: lighten(@alert4,25%); + } + } +} + +.file_history { + td.td-actions { + text-align: right; + } +} + +.compare_view_files { + + td.td-actions { + text-align: right; + } + + .flag_status { + margin: 0 0 0 5px; + } + + td.injected_diff { + + .code-difftable { + border:none; + } + + .diff-container { + border: @border-thickness solid @border-default-color; + .border-radius(@border-radius); + } + + div.diffblock { + border:none; + } + + div.code-body { + max-width: 1152px; + } + } + + .rctable { + + td { + padding-top: @space; + } + + &:first-child td { + padding-top: 0; + } + } + + .comment-bubble, + .show_comments { + float: right; + visibility: hidden; + padding: 0 1em 0 0; + } + + .injected_diff { + padding-bottom: @padding; + } +} + +// Gist List +#gist_list_table { + td { + vertical-align: middle; + + div{ + display: inline-block; + vertical-align: middle; + } + + img{ + vertical-align: middle; + } + } +} diff --git a/rhodecode/public/css/tags.less b/rhodecode/public/css/tags.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/tags.less @@ -0,0 +1,96 @@ +// tags.less +// For use in RhodeCode applications; +// see style guide documentation for guidelines. + +// TAGS +.tag, +.tagtag { + display: inline-block; + min-height: 0; + margin: 0 auto; + padding: .25em; + text-align: center; + font-size: (-1 + @basefontsize); //fit in tables + line-height: .9em; + border: none; + .border-radius(@border-radius); + font-family: @text-regular; + background-image: none; + color: @grey4; + .border ( @border-thickness-tags, @grey4 ); + white-space: nowrap; + a { + color: inherit; + text-decoration: underline; + + i, + [class^="icon-"]:before, + [class*=" icon-"]:before { + text-decoration: none; + } + } +} + +.tag0 { .border ( @border-thickness-tags, @grey4 ); color:@grey4; } +.tag1 { .border ( @border-thickness-tags, @color1 ); color:@color1; } +.tag2 { .border ( @border-thickness-tags, @color2 ); color:@color2; } +.tag3 { .border ( @border-thickness-tags, @color3 ); color:@color3; } +.tag4 { .border ( @border-thickness-tags, @color4 ); color:@color4; } +.tag5 { .border ( @border-thickness-tags, @color5 ); color:@color5; } +.tag6 { .border ( @border-thickness-tags, @color6 ); color:@color6; } +.tag7 { .border ( @border-thickness-tags, @color7 ); color:@color7; } +.tag8 { .border ( @border-thickness-tags, @color8 ); color:@color8; } + +.metatag-list { + margin: 0; + padding: 0; + + li { + margin: 0 0 @padding; + line-height: 1em; + list-style-type: none; + + &:before { content: none; } + } +} + +.branchtag, .booktag { + &:extend(.tag); + + + a { + color:inherit; + } +} + +.metatag { + &:extend(.tag); + a { + color:inherit; + text-decoration: underline; + } +} + +[tag="featured"] { &:extend(.tag1); } +[tag="stale"] { &:extend(.tag2); } +[tag="dead"] { &:extend(.tag3); } +[tag="lang"] { &:extend(.tag4); } +[tag="license"] { &:extend(.tag5); } +[tag="requires"] { &:extend(.tag6); } +[tag="recommends"] { &:extend(.tag7); } +[tag="see"] { &:extend(.tag8); } + +.perm_tag { + &:extend(.tag); + + &.read { + &:extend(.tag1); + } + + &.write { + &:extend(.tag4); + } + &.admin { + &:extend(.tag5); + } +} \ No newline at end of file diff --git a/rhodecode/public/css/type.less b/rhodecode/public/css/type.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/type.less @@ -0,0 +1,542 @@ +// +// Typography +// modified from Bootstrap +// -------------------------------------------------- + +// Base +body { + font-size: @basefontsize; + font-family: @text-light; + letter-spacing: .02em; + color: @grey2; +} + +#content, label{ + font-size: @basefontsize; +} + +label { + color: @grey2; +} + +::selection { background: @rchighlightblue; } + +// Headings +// ------------------------- + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + margin: 0 0 @textmargin 0; + padding: 0; + line-height: 1.8em; + color: @text-color; + a { + color: @rcblue; + } +} + +h1, .h1 { font-size: 1.54em; font-family: @text-bold; } +h2, .h2 { font-size: 1.23em; font-family: @text-semibold; } +h3, .h3 { font-size: 1.23em; font-family: @text-regular; } +h4, .h4 { font-size: 1em; font-family: @text-bold; } +h5, .h5 { font-size: 1em; font-family: @text-bold-italic; } +h6, .h6 { font-size: 1em; font-family: @text-bold-italic; } + +// Breadcrumbs +.breadcrumbs { + &:extend(h1); + margin: 0; +} + +.breadcrumbs_light { + float:left; + margin: @padding 0; +} + +// Body text +// ------------------------- + +p { + margin: 0 0 @textmargin 0; + padding: 0; + line-height: 2em; +} + +.lead { + margin-bottom: @textmargin; + font-weight: 300; + line-height: 1.4; + + @media (min-width: @screen-sm-min) { + font-size: (@basefontsize * 1.5); + } +} + +a, +.link { + color: @rcblue; + text-decoration: none; + outline: none; + cursor: pointer; + + &:focus { + outline: none; + } + + &:hover { + color: @rcdarkblue; + } +} + +img { + border: none; + outline: none; +} + +strong { + font-family: @text-bold; +} + +em { + font-family: @text-italic; +} + +strong em, +em strong { + font-family: @text-bold-italic; +} + +//TODO: lisa: b and i are depreciated, but we are still using them in places. +// Should probably make some decision whether to keep or lose these. +b { + +} + +i { + font-style: normal; +} + +label { + color: @text-color; + + input[type="checkbox"] { + margin-right: 1em; + } + input[type="radio"] { + margin-right: 1em; + } +} + +code, +.code { + font-size: .95em; + font-family: "Lucida Console", Monaco, monospace; + color: @grey3; + + a { + color: lighten(@rcblue,10%) + } +} + +pre { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: @basefontsize*.95; + line-height: 1.4em; + font-family: "Lucida Console", Monaco, monospace; + color: @grey3; +} + +// Emphasis & misc +// ------------------------- + +small, +.small { + font-size: 75%; + font-weight: normal; + line-height: 1em; +} + +mark, +.mark { + background-color: @rclightblue; + padding: .2em; +} + +// Alignment +.text-left { text-align: left; } +.text-right { text-align: right; } +.text-center { text-align: center; } +.text-justify { text-align: justify; } +.text-nowrap { white-space: nowrap; } + +// Transformation +.text-lowercase { text-transform: lowercase; } +.text-uppercase { text-transform: uppercase; } +.text-capitalize { text-transform: capitalize; } + +// Contextual colors +.text-muted { + color: @grey4; +} +.text-primary { + color: @rcblue; +} +.text-success { + color: @alert1; +} +.text-info { + color: @alert4; +} +.text-warning { + color: @alert3; +} +.text-danger { + color: @alert2; +} + +// Contextual backgrounds +.bg-primary { + background-color: white; +} +.bg-success { + background-color: @alert1; +} +.bg-info { + background-color: @alert4; +} +.bg-warning { + background-color: @alert3; +} +.bg-danger { + background-color: @alert2; +} + + +// Page header +// ------------------------- + +.page-header { + margin: @pagepadding 0 @textmargin; + border-bottom: @border-thickness solid @grey5; +} + +.title { + clear: both; + float: left; + width: 100%; + margin: @pagepadding 0 @pagepadding; + + .breadcrumbs{ + float: left; + clear: both; + width: 700px; + margin: 0; + + .q_filter_box { + margin-right: @padding; + } + } + + h1 a { + color: @rcblue; + } + + input{ + margin-right: @padding; + } + + h5, .h5 { + color: @grey1; + margin-bottom: @space; + + span { + display: inline-block; + } + } + + p { + margin-bottom: 0; + } + + .links{ + float: right; + display: inline; + margin: 0; + padding-left: 0; + list-style: none; + text-align: right; + + li:before { content: none; } + + a { + display: inline-block; + margin-left: @textmargin/2; + } + } + + .title-content { + float: left; + margin: 0; + padding: 0; + + & + .breadcrumbs { + margin-top: @padding; + } + + & + .links { + margin-top: -@button-padding; + + & + .breadcrumbs { + margin-top: @padding; + } + } + } + + .title-main { + font-size: @repo-title-fontsize; + } + + .title-description { + margin-top: .5em; + } + + .q_filter_box { + width: 200px; + } + +} + +#readme .title { + text-transform: none; +} + +// Lists +// ------------------------- + +// Unordered and Ordered lists +ul, +ol { + margin-top: 0; + margin-bottom: @textmargin; + ul, + ol { + margin-bottom: 0; + } +} + +li { + line-height: 2em; +} + +ul li { + position: relative; + display: block; + list-style-type: none; + + &:before { + content: "\2014\00A0"; + position: absolute; + top: 0; + left: -1.25em; + } + + p:first-child { + display:inline; + } +} + +// List options + +// Unstyled keeps list items block level, just removes default browser padding and list-style +.list-unstyled { + padding-left: 0; + list-style: none; + li:before { content: none; } +} + +// Inline turns list items into inline-block +.list-inline { + .list-unstyled(); + margin-left: -5px; + + > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; + } +} + +// Description Lists + +dl { + margin-top: 0; // Remove browser default + margin-bottom: @textmargin; +} + +dt, +dd { + line-height: 1.4em; +} + +dt { + margin: @textmargin 0 0 0; + font-family: @text-bold; +} + +dd { + margin-left: 0; // Undo browser default +} + +// Horizontal description lists +// Defaults to being stacked without any of the below styles applied, until the +// grid breakpoint is reached (default of ~768px). +// These are used in forms as well; see style guide. +// TODO: lisa: These should really not be used in forms. + +.dl-horizontal { + + overflow: hidden; + margin-top: -5px; + margin-bottom: @space; + + dt, dd { + float: left; + margin: 5px 0 5px 0; + } + + dt { + clear: left; + width: @label-width - @form-vertical-margin; + } + + dd { + &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present + margin-left: @form-vertical-margin; + max-width: @form-max-width - (@label-width - @form-vertical-margin) - @form-vertical-margin; + } + + pre { + margin: 0; + } + + &.settings { + dt { + text-align: left; + } + } + + @media (min-width: 768px) { + dt { + float: left; + width: 180px; + clear: left; + text-align: right; + } + dd { + margin-left: 20px; + } + } +} + + +// Misc +// ------------------------- + +// Abbreviations and acronyms +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: @border-thickness dotted @grey4; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +// Blockquotes +blockquote { + padding: 1em 2em; + margin: 0 0 2em; + font-size: @basefontsize; + border-left: 2px solid @grey6; + + p, + ul, + ol { + &:last-child { + margin-bottom: 0; + } + } + + footer, + small, + .small { + display: block; + font-size: 80%; + + &:before { + content: '\2014 \00A0'; // em dash, nbsp + } + } +} + +// Opposite alignment of blockquote +// +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid @grey6; + border-left: 0; + text-align: right; + + // Account for citation + footer, + small, + .small { + &:before { content: ''; } + &:after { + content: '\00A0 \2014'; // nbsp, em dash + } + } +} + +// Addresses +address { + margin-bottom: 2em; + font-style: normal; + line-height: 1.8em; +} + +.error-message { + display: block; + margin: @padding/3 0; + color: @alert2; +} + +.issue-tracker-link { + color: @rcblue; +} + +.info_text{ + font-size: @basefontsize; + color: @grey4; + font-family: @text-regular; +} + +// help block text +.help-block { + display: block; + margin: 0 0 @padding; + color: @grey4; + font-family: @text-light; +} + +.error-message { + display: block; + margin: @padding/3 0; + color: @alert2; +} diff --git a/rhodecode/public/css/variables.less b/rhodecode/public/css/variables.less new file mode 100644 --- /dev/null +++ b/rhodecode/public/css/variables.less @@ -0,0 +1,137 @@ +// variables for use in all RhodeCode products + +// FONTS +//Primary Colors (brand) +@rcblue: #427cc9; //RhodeCode blue +@rcdarkblue: #305b91; //RhodeCode dark blue +@rclightblue: lighten(@rcblue, 30%); +@rchighlightblue: lighten(@rcblue, 35%); + +// Secondary Colors (greyscale) +@grey1: #202020; //midnight +@grey2: #323232; //charcoal +@grey3: #666666; //tungsten +@grey4: #979797; //light grey +@grey5: #dbd9da; //greyish +@grey6: #eeeeee; //silver +@grey7: #f9f9f9; //light silver + +// special for navigation +@nav-grey: #CDCCCD; + +@grey5-alpha: rgba(219, 217, 218, 0.3); + +// Tertiary Colors +@color1: #879938; //olive green +@color2: #fcc93a; //bright yellow +@color3: #ff9e07; //orange-yellow +@color4: #fc663a; //bright orange +@color5: #d63d44; //signal red +@color6: #99287c; //violet +@color7: #682668; //dark purple +@color8: #194f8e; //dark blue + +// Alert Colors (bright) +@alert1: #0ac878; //bright green +@alert2: #e85e4d; //soft red +@alert3: #ffc854; //corn yellow +@alert4: #84a5d2; //light blue + +// Alert Inner Colors +@alert1-inner: #daf7eb; //bright green +@alert2-inner: #fbdfdb; //soft red +@alert3-inner: #fff4dd; //corn yellow +@alert4-inner: #e6edf6; //light blue + +// Highlight color for lines and colors +@comment-highlight-color: #ffd887; + +// FONTS +@basefontsize: 13px; +@navigation-fontsize: 14px; +@journal-fontsize: @basefontsize+7px; +@text-color: @grey2; +@repo-title-fontsize: 18px; + +@text-regular: "proximanovaregular","Proxima Nova Regular", "Proxima Nova", sans-serif; +@text-italic: "proximanovaitalic","Proxima Nova Italic", "Proxima Nova", sans-serif; +@text-bold: "proximanovabold","Proxima Nova Bold", "Proxima Nova", sans-serif; +@text-semibold: "proximanovasemibold","Proxima Nova Semibold", "Proxima Nova", sans-serif; +@text-bold-italic: "proximanovabolditalic","Proxima Nova Bold Italic", "Proxima Nova", sans-serif; +@text-light: @text-regular; +@text-light-italic: @text-italic; +// Used for .close buttons +@text-bootstrap: "Helvetica Neue", Helvetica, Arial, sans-serif; + +@panel-title: @basefontsize; +@panel-footer: @basefontsize; + +// BORDERS +@border-thickness: 1px; +@border-thickness-buttons: 1px; +@border-thickness-tags: 1px; +@border-radius: 2px; +@border-default-color: @grey5; +@border-highlight-color: @grey4; + +// SPACING +@contentpadding: 15px; //padding on left and right of pages +@pagepadding: 40px; //padding on top and bottom of pages +@menupadding: 12px; //padding for sidebar and content +@sidebarpadding: 15px; //spacing between sections +@space: 40px; //spacing between sections +@padding: 15px; //padding inside modules +@textmargin: 20px; //spacing below headers +@header-padding: 20px; +@panel-padding: @padding; +@gravatar-size: 16px; // height/width of gravatar w/o border + +// ADMIN +@form-max-width: 750px; + +// FORMS (new) +@border-thickness-inputs: 1px; +@input-padding: @button-padding; //needs to match button padding +// TODO: johbo: Needed for working computation of paddings around labels etc. +// Expected to be replaced once we are done with the form refactoring. +@input-padding-px: 12px; +@legend-width: 220px; +@form-vertical-margin: 20px; +@form-check-width: 20px; +@form-radio-width: 10px; +@form-textcolor: @grey3; + +// FORMS +@label-width: 220px; +//TODO: lisa: Eventually we don't need both of these; remove +// label-width when legend-width is no longer used + +@input-border-thickness: @border-thickness; +@medium-inline-input-width: 115px; +@input-description-minwidth: 300px; +@label2-width: 200px; +@checkboxes-width: 420px; +@label-summary-minwidth: 80px; +@search-form-width: 400px; +@fields-input-m: 400px; +@fields-input-l: 800px; + +// BUTTONS +@button-padding: .9em; + +// DEFAULT WIDTHS +@wrapper-maxwidth: 1200px; +@sidebar-width: 145px; +@sidebar-all-width: @sidebar-width + 2 * @sidebarpadding; +@sidebar-small-width: 100px; +@sidebar-small-all-width: @sidebar-small-width + 2 * @sidebarpadding; +@texteditor-width: 660px; +@maincontent-maxwidth: 940px; +@pullrequest-width: 1025px; +@summary-menu-stats-width: 200px; + +// SCREEN WIDTHS +@screen-sm-min: 320px; + +// For Bootstrap +@panel-border-radius: @border-radius; diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.eot new file mode 100755 index 0000000000000000000000000000000000000000..59ced842ce4973c035fb5dd1f24e029ca63d16b9 GIT binary patch literal 20335 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..704fab58795a1239191b784117b9cba522bf8c1c GIT binary patch literal 49212 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 C)o6+U diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-Bold.woff new file mode 100755 index 0000000000000000000000000000000000000000..3bfa4ecac332a3bd60742b3d6d1c73fb491f0dfd GIT binary patch literal 22864 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 H@`(Td-{thp diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.eot new file mode 100755 index 0000000000000000000000000000000000000000..466862b251820afda95e25bd49ec2625d6e61afe GIT binary patch literal 20914 zc$|cmRa6{I(57bw_rcxW-EDApcXxMp8{7#V++70!g1fsrgkT|P5+wWmyLY=6TXpeP zKmAsnzUotL8UVn!IsgFrFJS@yqj2yr|0A$KU>^wZA5&KU2?CV79s>Sz{h#;@1W^2s z8o7131OA^N`_JeJa0B=Q8~`o=i~p>u|DAmQcclri`_F+6ko=E01FZie3IOl_2oXRR zVDn#>*MB{30N4LG7k~}G@n3TPcgyzwnMm>f%mV-<wdB<Q@0Y;<av=Z#V}Nu3K#T%w z?nlC;zoFigy^)7vm_L<OuP2Kgi_8n%3!GHsF43rO!t>)>7GgUjxg-Y}46i#*o5y!g zLKLLgx@XaeCgjQ{WXa_UJoG4mtQ!*Ezn*>ndvaf4h^joFV{RR5tKenFEd<B%KBYI$ z{*|Pj0i7_{(Fmeuv`rts!dTZRZ2(8G#>iu&;tN?o*5(?lWmzk+aL}-sL?*!c-Ocd4 zE?Hx9>0Na1a$8AR7j>zHc)PPBso>>zqe(aA8Z425|Kv3cUNzHWqW77ere;8}A!7O} zlo%Nu-{Tbce)pYcz-5lUOZxL#_<n;4RMCzQVcKex)`0*DfV;SyV?lt89|coamAry4 z0#|Zp9P{|ddeVjOg@9aQ{;mOr0h-`6-SJ#XgE7I$-ZzE?f<Z1~UMf705H{F$Tr$8! zda~Q<JScoJzM@dA)vR8SosXtZ2Xt6vb}(O@A+hnm=38EbKXioE9eE8!$KWDB?;A?6 zn?}b&v`ie%qNN!njHaSYQ(%qemnAySdme|dp>d+JDBp)=J!DHy$chOf`ts98BNYau z-D8^;v4q?4c??md&;cptK<jq|Z`|y(QGIB>uA&Whwx24S%9MCQ({V6N8fM+8bfb^; z8KI8g?N*-K-POwgPCrd|O<(+sJ=jh%t5PS2X!xU-AeLyw_gO~lHk!3g=xzgeZ=LpU z6=b2BS0xSZHs;IREIg)M>JsIQmA-k}r9PGoQ+;3`+9`oL)+b*2F(MR_*c4XLJw0pF z!m#^X-LC<@wE=Pj>4-A2sr9*vcBRQNb1TZf@zItiW(bOHEyGHHRuUSLQr*ng#M0Ik zwL*1m+Kk`)#HOMq<#ViEoGQWb8lCPWjsp||$(YJGn%kG~HbQIbMWyDyK&r9WLsNJd zzN!=(QXFVy)8=t`w)F`FB-x#j-+_{$pJ}8_z9)&yn@huk0>J4pdK&P};k<v48_6lZ zWzX^J&@D<zuXyU6m+||oC-t=`<9lJ)e7DGyGTI4PW1m)c{aj2{{mGK44O8g{NwhSf z)Nx@GMKg*t_|;Z-q+;R8R8$u+O)h;64<G|Ij0KRgX+%sHI+$KqvPE#TPPiR#ad@W3 zKjsIrR2WRsQQ;0fqCEsjqDmA;(W%S1!%VXM%x_v&cd6D$Oq#-4#X-Jzj{J)@kN6oN zj^nZdI}*8+?@knatpzvX{Fu>EIFAYhueSR7Alx^+Wi@dU&P)5dAv7U?(W+glvQH4n z3Epx}vZPJXfQI3t$~R+0Drzf{Mw+!1Gi`qmtY`;bYec3wif$MCi~0|}TWoT?O_n0# z9j)Mp_fRxp7kyiuF#U%po~h5JkB6ldarYv^$wxYKr{4TO0Vg@+xL`3@C{dWSurM}Z zMf=|=^NpD(;jl(f!}U@ZC}%A>4zp4O`uk^3V4Pnp3|s1vM_1_jIeEh`Xwk6N`EDI= zD5nbC2a$o*qZG?dn}8MLSGc(XRQEK%IMk;FAi{Y2mG~wJPLQ_DSF8_%imU2al2rqD ziPf4&6Ic2`1M{nVIOD#bWK=@-5RT{<#vg-p*ylc@;XHZje@mVt{3yC|KGV$jpgsdD zuPi-tah+N%T0pAwHCVNjV)8`|Of}@eFh#GWRXwM&<EGI2ml7Hwe1^-xfr#KycGn#u zW8AM$U)l=muM{U1YXLSFe#O+%U*{8udMM?R)W(p8jMB*ADLZhqnPhHKnnlBX{wBb! zOeRvfIAcW}H0QgwqN>BroTlR>5)nHrk)|A6&5L%urzgjMt^p$VuF<U#sZdpLYN~iZ z?XJHjv*I9Dx2XJU6r_8DPju2vQ!uh2C_@&~9Q_psm>vFs$Se`B+oJs`RyA1<M}f$S zi_hVr!lxn`v5&%Z6|o56@=|#5OAXxRs*;mY2TV3Or8yPY&Sju@a`mB|7A4ZCL4Gt% z|8l=4+Vf|*@=!|;Kl67TG4&s9TXr_Oc3dKuskIW7X_>UvIQY{k7Xz>0R_~!W7#3ED zQo6z;OQ-VD^r)F$CxJnRMT%UG61?i>#Q3FZ-$-b=EWxc&UDZ5@cerfDW@Ek7F$b}1 z*v^bJ$MR$_ZHcwAmv+TWpyDVf#mXuQ(}~`^DV^x?o{#0RltqhHfJr_R_AAJ)uG;Zl z1)0wS+!1+b`HQ9Vj2%rLa7QPz)y8)bMUDPWX!Eg{bCcvJuJx%O=>j$_I-5}weM&Yq z06NIUc0<#msABa4`$K3zw9LFJ9_PD<*PcOQE!qz*JseM((G;RYRyb&|ne6Ghua5@E z>Pe~(eOL$6#=mke<J`=sPZ4gj#lkTofY|4uTTnbfO?4<m=^v6_Kn)3DeGlA;(1uI< zB$~d>SVCP*Rvm?eb$KEZwC%>;Q6iT)Z-dRj`v+_L;DSb2jn@#Y@p`+-zvHZg7N9(o zzPYQ#y2+%>wd{{k6xE?)%uvgzM9mIwa00QrGjmjHAxi9cwJR~jc~Vvq_e>nz%VgC< z1n{4g6u<fX;N;^WWBp8&z?5ZEnxk!qW`lBVxF0!$%L?Y@A*dIxql92baW{=&cLD?W zMD}umjzaRLwV`(i7>WJ@*p$KegWVMjEv3fPccNd$k1=dYQJ$z$w}G~=VRbg7^9_1@ zQ>gE{vM`$K2|7R4Nj6G5dcbyUxkQa$C1ju+S_4Ibci8IkP-8D+?=MdY`qyqr^q9Hs z>sw<O3|+3G!WjvDk)_4Va>n~Fwy{n`zm)Qm2)zB+YcC9Cycdz*o-7s#YQ_wf4p`>U z<itgnbF$))-4@gGt@+6trI`AY{N^j&Iy_^i<oWUN8mm>ODu<@CoS-{cD=^WS1Ftby z5iF3k18#tWL-#xyV?YUExgf-~qY>k>EG!tjHA!abXj~+9pdv`CB%Layu=H_w$QWfQ z*=vBz<5lsZEzj*xNyDDC&_FD%_2nbA_K+~)>8Pclj_WM4v8PX9*YOB3UuZ2*!8T;W z#aX}G%2>^<Y%UoKQ3;R5Dc9FOrM1ih?N@C|7n0?){H>0DfN-UAj_^F?=iR35shk;6 zvb)ToRY;?6tinqpkB93z$!5#To6MKo-)6RhGibsDbf9r^AsIQ-$}cmiz2?*@Vf#cF z9hzC6EOGI#Jm99L*lkHlvRbr%4RrA2BDKO+^9W|pJlf_KkTTG8l%~X9+r_>`(T0Br zFRlKKGcvQ6M1ub9q}h=J84>L&1YobjsPSo${^{&TnT|14qiAWPh!*jHzh{$_uhP;= z;3snTl_;m*If<9BMBnwg=A~5l_Yh7b-xo89+<|KiXSHOe&A-^-n2@BGMVba#MPyS4 zq;YOfUMI-+>vAxDvV+eg0nfSPs#D`|q!$5r=4qz)JDmO*9@+OG+Lth8f#I>d3O{iq z<G>JcSslxpx*Gq9ozKa7x)OwxBcO`Nni><e$LA6dR=8i$!U;WII|4xn>#jeg;J<8m z5Nj&VFbK*=PEQJ#Y_{wo$G4jRhGL|-{1pj^sfwo&m%`E*J4*B5SjHlagZ1DwOmC`j z+QjTD4rF(wO8X;fZs(w<uE*N2fjrWQ;+&=L{0LV4-KW7*wA6)MO%_CZb6jN{gSZ^s zfPqq~1AR7Rm8aM^hghuJ62&E1_zf_q({WLA@y59sK!pC~H3R5}!{9+6nLd2^qImN; zZZh3%5K#*Pm0R0Xhm=7wSN>32r`T{GN^@2`z%5LG@=7$($~%;dqM1d%a#J#C{QWXy zq^CnCBz9?hbxlMtXX%)+5LV}r^{5hInr+(BD@JEwO+@gdmg4e2^~;k-58`miM$~h( z)Px!AbK5y5#yQK%&p3$ggK+kmRL)Thl6)S4l5hJc?O;Oc%vDx|^QfKqsP-crA_|q2 zr*v<et*2s#+IlzABf2o)5vbGA_{hG}Y^rx0Z-DAse}^xAW#>)3_k02l=XRE3z-7zE z;zuPrX4TC{?My$sTK`4qx}$=+ZfP>gG`7}Qc!PXjfXoZFs!2LiS<BI0E4!}Y7=f?j zmg*ZG_QpY_$(BR?Q<l;<_SE)F?*`s7rP9H@j~;Jf$h}Q|4FTS+Dfr<dD#u)ZK7K`x z{!;vvh$4K}_H|2L55}g|g`lbt|GIpDzDn;zS5U5+6G2}O_(q0ec`;}r*2^EQ6MqZy z69(@htq?+4iGFCQ!6DY#(69_-_~MAt-mwoqfQm378Q?BQU!GERfJ#V2Sz-R|70ev< z>G$*;=g{8?x5lcL$03(WVwac3Oof0@W;?@oHd6Lh*wt!Ob*#wYx4FW#;Mh08eBr^b zfyZCNgFvMw@Rn1EaVRo(R3$BhmYV{o21rtL9CT3}ZRa3E^E7#@lUMHPd~3?kK7GNx zp@>>waHL`8Y40l@T<eDPxbdtv$~63E8V)M^KaEh&OqhB5*=t|=Ua9VgMvUz!X5)=6 ze<v}jnu4i_ZM^U(dTNZ4n%{LmkDNKf1mR)hES^>>TGGhut~Jbv^mb=QM)lZuXwDoM z+sgu$<|B|Hh8HOTcZnQ!kBEte2AgIE)?dj@IiCaf?S!+psH<GADY7S1a1Nh)ZNHcL zTka(<oedL@rfeSGWLD-LqU%1K87h7jV@IJ5U%c-`O4zS1s!bGu>tjmAShKmdJO(?u z^kmY!5i!rMuON;KtFxjHe-o{B*=Ss!{PzV{l$WSWHqrf3Zzo{g8P-I+&hdVy8-{#( z<DTl4ez~KW4=_V}TN5??+tTm$kgC(U;>;jc%onGAJ-0kZ*iIotY>JTM@Xe0a{eB+G z1Gch4Uk7LA*xLBSkYJ?&Q6>76=9%=l7*Df9jZ>!sJ0L?R`1e|nIwl+zdM+GYF|^3k zejkN~IY}1&ntCfe?-y8B{7{6RgX11^6F+8D{BFtt#tj*0byO?V#}7S<eHCLNMzYSd zJ({ZWf<`T4>lXS3ah8!|YY}Km)4D%|mRZR_K%czBluqw}+bR=kvCDRz8H@TZ)F6pf zt^?Vv#5TApwPoC3f;_(XY2vT*WGx3%OYz^Su9rW(vE3nzK=5IzKX5+zmeZWT)GC*_ zh9hRfN2`<hjZ5-`_G?#=&5;rGr?Q>`xGvrhq}OsAD{9s3!{BOR<T?$lPH13b>#<34 zOM`@3s*aHLv~YfyMt)f^mDjFCZ-H1YSzlw_{&H1Fz}%9>!B-~_&I3#r*UHC9RQ>#K zpBlwY2)E86>_V~!DL<+rFZ;NxqBz6DDwp(3pZzci$ao1Zpv|<tBLUfh$R_-q8v?Kt z+I~X*AmrCua^dM-Amz5#GWf@2)k{zhE1<cLFu>@zZnPB}W*%#8x0MAeri*>Xs?dBm z)<9JD&w`P?rTHD1H(G?nERX@(;EpHaYdDg@kW`HN5+j$S*ory$L{NjCe#8x!WuY(= zW>_y{g7$#%Qaq}ZTOn4P@V*-V5YGk$!x8?nwjithr7-fPhy_BUM=PLOSTa<N<g_T* z?-6P{I*umYbtEpFaG_3dzLnZsPmfe2sXM6pQm9cVxa=<?g&TMn<nleS?~+J}s1BY5 z#NlK!wBg#OH5u7J{H3NK%s%GLt}hzdVCEi!ErYi3M)|tgN$26D^Z_G0+i1lS9OV9> z#-z(^T21BYobC@;K*^0ml~Dwx)*@e>-@?B`OI|GnNlZlxOfGkHc@inZWa^=ntr`Lt zpLCA(Kls@A=87UXDCV?k3c=%u!v#{gny%k|&dN%K66i7EbUFTs?;k6qqIuOW^%1)+ zw)9wHh=}*)_7jQ)D*5Jk#rs3^E!h{@<#cj+UtyO73JI`&S<IcWnNPe%%S!gqyN$%^ zGuM&MQ-KvX4H2O*{1*tS9NEUo+z~o?;i`fJic6eemmchX1xxQU{YKFEk2xV*uQU^B z7ANk!0?7pI;p@rB-s>R+YhOM>^B5<(%?eHy9gorD_ypMKA=on`W-Li*84esdB35Sn zGDvpB-*=_N;j<RR)O~LUi8k-mcFGwgN-`6@a#0m{#||rG4n0jK8NF9QVRC%srP55W zAYOKwVlXc@`RZmXp9{eNry?L$-$qFv^^-H3jABG9UUQ|Au2?pmPUrX-R;!3!=Fg!; z_lF-VNeCWGa)xwN5mQqy_(%=8QPGPBLpVl_I2P)iGFI?I;bqBDaIthglF~=<83=Vr ze5gLMxbU=#MIUzV7xMn5*BlI>0#qcF8~^lByFfN965=}c8ib939um<Rp7~SJNmI4# z+gr7c+uI?u`#*H{rNt8b+kSR>)!y#PTd1DYQf&+sty@bDH$}pW8V1scIFfMd;*nyg z@{L={5yEY~3zlR}8=m=*0>k61yXy!XZW=c3W~R5+vxtYhpl&ZNoIz221=o;(f|aDE zoU?C$rB*nhG0i(u8D7iB-5|1ZwwjPU-$&kGYmZQScm5#^9R;H9Kh6*lW^NX}<M)2< zM4`>XY&_Cz6LXhFbtW#d=KSSJ?pmt4??2sx>NHFw&v>-6g3Tt!sp$b4?RhVHGP4Nt zC)V2s0I)RgbY5sHtkKXmKh`@%qVo@gl`#|ac-@ehg9JvoAqmu`J$Ne*Fub@Tp6IeQ zQK9Z>7Qso79m_gOR>^ut?S;!T+vucCM>-dB;wIKZ1iQy$0^`>7{JK3yDSvoyS%xvq zPm-~}boT1L0^`R%q7aoy->?SjskI%V^kj4fwG%zNE4ARB<KH;RpW=q>e)OFykAuNR zYKF`0xRbrH$6V0ZDZ&E3ty`BE*819Np>{9KQ@$egrU7Q(L=t&n9h_(^x3tm}9xjEB zOa@mJKCo8IMukg*&Ay0??g|-t%WFi=LEhP59Cwqba)O&QDf6kn4cN(5@kdo6k+ubM zRQ<VN6?=+;F^?L5R5E%Hehh1V1Dp3t(ZSGc<}aFQ{*;=u=!7tayu`cvkB{7GRrNNs zDI|-~uVX23C?NUNI2(bpm#Ba|ubyuzZ$H$g_dgrNZ+Y{TJv@H@Haw<pjf1NUMyU9W z{XQAxnEJ<y)yNnNBFPxw7e>qbxoF@IK=PX}+ds4>=M%nWZd6kIPItU$ov#fJD0_Yo zX#d(<L4D=kx`!1*$*zSqar_2VFuK>KrF6(}HT@@-(tg^34g&=9+!-K1A`0nq4>lsh z7rr=&Hv^l|*QO7#VyAF4<bj2jI1@~wls}(2ILB<`4-BjeJNmF1s@`p0<3(diX${xb z71!CT9(yCW+8Xy)R6-`sLGriC3%ezrsvcN*wS|kWIeo>-I*aZj?+sbdW@3*J5!8;~ z4NV5Gwn$i!5ds|<U~cq3k$f4;!l|;toR|0%O5u|zVmf#2(zJL>hWM2fYj@NrXAnE{ zsn)h7|G>YyP`v$OY_{R{y!(?^3g!;KkqzzxH(<esdVWjHCMEp@jb3-{r*WYbu@0Ng zkczg3Qym)o3>va5Ee$^nrf_c)3L<0(yx?0+HE7bpo&@Z~IG)K?G|9?AU+!EbeVDHe zO3yO-Dd%ku#kIp|E)j(BgC?C5b8(@dLdVx88k4amPQNfwbE3ibb&@nAUy%(Fh)`f? zM<(au2c__W?$UN#ns~x3v83RAgkju?M4Dly!wbPJmJ|iELVc33EKn70WqUjjZGysR zZ-5p{ey|sp7IH3cX?1P~M}O^EgHrwa1aiuB%~fq7Qzgf~He-Q|m5h^@x<2H&Qm^NI zq$U~pS{2j&vX5Ad)GNb*xRsD6X<z&2R#>LZGF8gLXw8_~Y@I<VxU^GD8=b>n0J6l6 zsK@eyz3(KCXDJQFEMt5ei7^^$N$8kR0{+~JIyZd7aWX*C9LGxgPR}msPd70t1G`{i z?5>#iD8<bpu7R0RWV(ldv>`DPE9QRgjzM|3YVCs}5^udmV${TP;FoAp4GomFKAzrK z0Wd+1D>St>uK?SGnamaweD>m=0~sdey5acd#-8*x)IkBCM=_DAY|jO~5W#^0wqSLu zu$FETgLYzsc7@4Wj=OjMXe!*c@~0KxnVYq=v7Izu%$3oc5RrbhN6TNSJ60ma_L7Hi zXKaKONiY$QQ}8yUT>+AK1Z=m%{jQ2dSaCsa5yW$~Wk9QYiJs${hg|gsZTU<iXXF%s z5qW|Kc~fVbihyzzAumshI^kYu+7j|E=s9j^Ru!cvwzb(L_in+0_jDL+{fUYlp_7sN z@862=098{25*C6`K)0v+7qSX2g=s{F5cjN_O|WnBJpNlhPC<4-KSIXbK8+&8^V-@M z-P;?}B@MjG3Rt7S<@Y1uK<T(PahBZ!(e1-qrqj{boJEl#R+Llyp2g$v^8Rn<$f;7; z{X4%EGvu(|C5~GuPEr6q=siW0j3{JB%hsusL$P#xN;!h1XgqI?cIY|!IIl0uu3Md} zHOo;V@NF|aLv*F1{d#Hy^IjYk)G1_a89jXZ(?hH^l4bZW>+QtYr4JeMBDBj?#0zyo z+dWILg-^_kI4nULIVfqyg_;!JIQ1dNN8NN?Wj6Y+Tnpzw0dj(cb(g&nOi3)w8frA~ zYl=QE>h-h$A4-l+Qf#;0k{BhU0wrZ(28KW+oE-Hz_q!{ua}Lx}o^5HSBZ)LKCj+G} zKJt;>*_7(enVP~1DE9G>H{dSs7XHoLfsRy6gqgnFV)Y!HCP_Iwe)|P`CKTcv7y(l@ z)FL0rky@g~8c2i8M-_Bber$i*$3~X(9szW(Cps<}5d2Yxc67#^NIk;Z!Vs}j!h+o> zL+e?K8Hf4dt1hCyp$Ujc3o;|Gd-i!|7bY1yc?s<h-%V6lzj2s2;Hp;DqYH~Zb9ha& zRblxj<TM3W68|~Oy5(OdXtqEk$$G|$Fe?Acw}@ZCvG?~8uIQ~20o>nD|M5S3Sk#>{ z5&ynlsLU^UT&7kM)|4VdTB~nuU6iG1!cy<@SKPOk-;K8j&C4Cm^@k<LvT?^gU!b01 z7^rgJO0yGsW@tv&PmA=4_isd2%|{!*6MzK)J4>K`hp5Lbr3sZwgsXK*B1bM1-$Cd+ z;d!;hukS|}Jaywee+x~?FJREVYNHLV=SoG+PGO<#;!wcM+BLT=@l0-&DmA$un7NGZ z88-I%|FmYSSf60;s85Ded^m5cqQ)CeFVprT1&>D&ODl*{7-}EddMY%nQOiqpX2tEd zIgK9$3b)B>dPRC~H16^}RoC>CS$w600D1V6{Nw)+y!sPsz+5`EG$;-CnthH7noQK( zM<CU()y-?i#N}FkuVX5MpHIOS=(GyR<t38Ciw?~RH`ieS!k-QjA<HbCrm3I6lxSj7 zkoFP;3dzM!M?FR!DX)naKOYL{GnhlEK0^p7BHV_Gv%Zt~gOvF4t(sE%K6c{cC~&j; zpMUD*JmeT5$6(fl##^89!rT+;RE?2UEc!A(W34za=M@d9**<hl8p^iN?eK<h0(gT{ zhQE;UG}NU6Bc#9@#9x?g?5C{yAO?{uQRG7i9lmk6eg$PJKXd!76;Nia^28a8rU&nw zE>K*nZw$^ym)(E3ePWKIr=ClNUG)avYP61`Q|wuR%=q$(+9+eZTkgTc%Evq5jXU99 zicq9XgN8>G*W4;huHT?3YIA?;txciy){lefzZOJvN)n5HMiU?V6)gF%B*&$Z{;E)K zuj&QgOd@3ABGr-E#$-vwBMjJ&&|@>cqUPD_vja0;a;Cshj%n11w2r-ZtSZs35L+<B z1FnL19FYZW4?~u`Yso_TGpeAkTp@v3V2GFA@x=|{An3PX91+cX{?mml=@!};YMHVg z?wkvu4W-qv=#MKC-3;PX8|Tx(Hq4ClH#t6(g{Mh6tbd>5auf1o3Q+)NZLQ4@T8HE= z#K3zDW3aIn$yZo9+^uZH>d>HTngZpB@cbBrVx&dbc~DKM&&WC_uhsatZqmYhn!f41 z1yp-rS7$*qk4@yMO&Pp|67_YMlDk8|5IFZwcaVA)Eo5KkyTvi%qG#7VL#1h%QRSbG z6tu+<Ir$3ZzB>gyybNW=1epra1nn>ymeGXK6m#c=$J2W8B`LL!>48lxiymH!b$d-1 zq#uBdwk_z~Zyix&3oKTy(_T{3h7HI9P5$hNA4o0)bprJp$3GyJjwNcvZM`J?t2gp6 z+RclbK-@Y+H^l5wHg_YwYsGZO@5O-!;i$E@z^uu0()p9i6TC0FQdve=Wf3|t(ld}x zkjU%cr>|4>@_0=P1_jih!VZxQUuqK^-S@V|^6c2@H4m=#ber#{EK3!_NXp*)LI^ep zm<Zy*(`8|3b*Ip*G53c5)lwK-3GYFmo7@ReTE0dtAg*flLd<U?u#MAnS%r39ZS4?} ziZDE0{~KZudOrP27p9T4oiTKj)fDehw4;G{6F<6|JZT?YS<i-Y$KVwYW0B!@T#d`h zKwuO>Hv@jn=2Ld8eLo}K-+!XapAO^dlLi37;ED-%+Ut~GG7>Lf*-ovaI_y%_YPP=M zP&PhKaf*4=zv_RfG5Gli7{HxAB#wKO{IN^Mmw0N>;U%t8G6n05IY@wYNh#%GYwia> z5MUL3SmL{sp+`wpdfV=5muc<y$vyhxACzuK)l?c86&aOw63m#D%@Qve4O@yJJE^P+ ztVWA@?6u#yy6jbLPRbpait-bYqd&nN>m9&O!36ahX=zrFI9yWDF=wFwlzaf#sKxo2 zRffl@Iw&au--WcU!OUchyd0)cf4j9|bQJ`p;Rwso=MN;ULF3u>0rH7Le@((PvIMo6 ze^rQ})iWAlWiOa3G8tYOOj9oA+Aqqm&*Gv#`^1}4c(zwu5b6<qBT507f0I4qiKZ;_ zNPA(Rom5bzq@o!OW-w1f*20UC?}?rWHHW<-Pfp!rQkS^GlOe6zb6mH?cq$j))kqcN z<3@qSdvQ^GNlD2n@)&NDp%S2x^f9qr1w;aLft5n7x3wRygheXt$1V$6ulDLIed95Q zmZ$AZqguHA!AbCRb_Meh4#uPNvzF?)Dg>%A2Lh^o&$@+?&<|Q09g93#1w3z60%=3j zXzswOasg4?c-(0CTQ-VZX)2u5;HzQ9p7pdt?_-Yv47Jn%NlM&E?|)liv<z4Mm~lSM zgGB=Bi)>EZP~kQOmAQMR+=+gR24&xVSIKM&Hxow}^=&CpSt`N1mU&f@5U&>SfjEmH z&Gb@*9SI^yGGws&vxiBF*}p~K(M9#Ew$P9IAC07wKk(fh<IO{qA&WgsMx68vorA*S zfv%pNKmX{eqNkA*&~J%M%^t<N`#J}LID0tds#+YQmAFW;;5jEg$7V{EGUc)|dUY9& z$?MwFf!OedPVYr@6DzTCS<?PwEj77KL=8LwG@hk7Ro925M*mJp8~@eaEAot1wS3q_ z7Jwqh26^Y3pQ_kdKC7;mFP%pQ&xP<}POedjKu08leON>gIs>XoR}|X)6-n3L3=6B1 z(a&36b>5%Jj)lY8PxqORij~w)z0P$C!Eb*6Sr9118Y3+BXXm*^crJ3xt~5n^v+#~T z*XlEoLW@sBXI%uoaP_Ua-qDcx{Wdu^Duy86a=m>`PaU&>{EkE7M}YPDhZb%*?@WA{ zv>-W`WCET2bG_YjxXv_DTlxbYPIO|&fYseQE5By~Jg(D}W5a<-*-wM1El>y=%D>ml zUpUmQ`~z!m)@|?#tHjPR;D{x7`kcD00ih+_zC>jY1+BxhwB7ju0<!#gd;eKin#n%~ zKIBBc7H1q*+@ejm2S~hr`z>xVW54I=N7PBbgpr9D4#4%%1~~}*mVY$-Whjh@II8V; zo%KQAkYR;XBxZfgt-vam^`NCppW<b4pN@5G6%`t6{SzUP=vO62hRXLo&UzlU=Ro>o z+~hXC2i+i~L{iP9jIXQ=ZW*KjTLoSmE=qs0dSH%{!e*k;fC>@k;|*SjAj|AR=X1tU z1j+|Sv5lpl1TU50AQS>?_$Yl0`I40-8ek?_Dcq-hTeYLIw%EyMSXoRo(jjT#307G_ z0cvV9E)-8kwBQ@mwTHnII|?UpySg?1_!z#Nie&dEf;T%XW2$YT(qcGdQ^=`dY{M4@ zLX(U|>eoq9uuXc6VOU{E&uDHUN20z3Mj<q<qUE$0{u!bzOOSL7(oZ{Kpq6v(<@BdM zgTa63p!4fFg-`#4-?_#yEGw4yFYLl?nZP$freC4ec_cm?AmibLE8GpUp6_bNcT5;8 zo@-fJpxsfF-Xow1l}t0^fhdv-!Yq-|vT<R!kF<$}t5|~2U$f!@;jr3lxN#jb3cme_ z&o;y0T8vI2JL`J7!^V2X<?r+k*s0#(J*2`ZTp?EbVF-^c{o-eX;`|2ymwRHGQfmp1 zoEuUiJ=w=UXP(BcoWW%$<OJTgfRos(@a;Q)c}K3lsNbm?Y#P@l*latY0L!@W@l{}f za0wub#GU^>QMu1(dhl!^S|8i@W?I>se^(|!eBT8-#y(8SS5y^D9EvZ4dhYA$p>JI% z>h}{(*I!nJ-xz&JtkHd4v&Ga*gwoK-Q7=q%8F)!7iqf2gq2gR?Pa<V$be2#;O}wxw zm5?8G$Cc!-1X9QeYMd1CQPADl2XcW$(+4sNt<KiyLk~gOG;j_+5><k5y3GJ$3D$Vd zh~5<Ho?pxyo_{`C36Io|?*cE8J?G-&B(f2CncmeA_rIr<+^H}6f6bY*>pBo!dr3B3 zR~0{IyvXRZXpARyTUQB(asDVC%IM(nUyj{m6O3YR&o~tt@LUkwDbO-Z7(f8zAv$N7 z?y9R*&&4)Rwpq;SSr936I(Zt)^!ORu7hFsKY`SzLl<|Z8GL5cZetL<4o6y-9{<rpw z*E}%7H}~)#9<O2QqeYM^k+!mcPLQ+`_K_EA;S$cq(8!pF;zj&2iELiNFMJI`rSJHY z6+o8X`jj+q3|%xp8-F0t)oe95ddo~4stR)UMN^v4&d`_HGPah(g-=Q;0SSozO(s5r z^m**|1&bt?#w>1f8x%3MOPy)acfB#{ajPup-VimBJq(@Mlo(=Z$|0D)TSY^}G@@gr z{z%aGJ7F>T?tZ(C4>2F#m8p5^TmRg0RG=EkBo`0kV-tib#qG&9E41}S_#PhTzUEVF z$k5U=h^6mf9--!AC{br-X5U8WzL+_l>rb^6T$n>Fnu`zN0ZEKjB&3TdC}9$T|E*Ll zcz)px)=Fh)eZF9-Ea{YGDg2^&5a7S_x4KxvCPK$R;*-RLw+r`D?XLrWqlV|;5=R=s zR|AUcPVmL|Pzm?^;$gptkl?`>7Gnuci;~T=K-I~$DDir$F`rx?Z{Gn$x_(oijmZb{ zylvZ)=`U$<FsAGs<@K^GD5+Lp(v+l<>p{~nU}aS9Y&f16^TFA1_ikV&Gb8erhK#`@ z2e4X;)4!OTI<%+{AnhTOmr`<w)={Nb7%{7(lriWb-)nFsN%wbFS$<kwgiI+v_`cJi zxRyN%{>M2-9{<I;ZwxnP^MiCJ%;&`nZOS`=?p|P)z7pa~kL0xKs9<MuETz;Y>KLKw zCrMkKjb;+niyR|?AAfL|tYPT9xex*Dgcd=p8pt5a$0GBP<!wH&eu+K4wh)anYBGL* zq%*=tZvvqecOy+rxgsNpg?2vBi=Q_bKME~5a>P{1fMSZ^R(To-<1Hw;TU#;)bH~M@ zpQVnt_K6ZsBB<ROHS4)DQhb-1L)!E_9HQGos31RvKR5ED^p{mFfCq03fGCQA>7&c3 zElYxwQ76ed0(P$Nk617?n4FxaAVAdbWh#eF;T*2(L*qeK{!MnZKVnVIH!qM1q$j#^ z%QMNj)pwIJ@EBO|H%t-u>N!YlBS-m;Ydep+T0u*@v$$%6vAf+@ImEx~X206a^W6qa zHaLwGRvc?BX%NvaRK|*Srmzj)5%|y2&PL#XUQ3iWMAi2Go%JV|i7~c$e?zvfY(z>- z<<MC9Oc84aEav0roirQP#PCWUbKh1v;ipE_8Fcd~$61#;30MvZhAsPy=h@#Po03wQ zGk4oWU7|hV658b7D5@wvooMuF|9+Oj>?AQQCW+S=Th~(OSQR&5KccWGIRt-JxvbRs z7$sU4XN$l4$7&wy45n)y`6?knkWfR!7;eqD97$vVR(6E7NrJF?id82gl>~!2w7lrR zvvlWICrdp}q=LcTNbo{pyz)P<{#_nRk%)iYlM@tWY%;vnvky_RjTw!7pdW3JTHO6) zE$-b5ayib=F6LfaTHztF{S!yM4>t&WJltvSlIfO&Z8=K^eCGc-J6WT!>y4yWKK&6a zBn!(iIT%F*Y}PJI0Xw*8Ms<4rl#fLFDu~)zCZG%XevM6#NFy<+5o?2X%YeX>IC}Fd zh7&d>YCA<dLS!`=37Z=W*5jXWlJm^?ojbiFiQ6KTY2uGOCR(%csP{glQ_c~OK#7ED zar-@CL`FrcW&S;p&loRtuS8Lch`!3TpIRl%tdmKh*p=m?E<YN`qf}|8Aj<ytltu7Y z?%|EBSYn=!=aoeo+UYzFgK7;PNR*aH*G%R}EV6DMMR0%R4r^-l|E^U|BkqvRql`B- zQA5zmX;sG}Yf(7h*e;%;NH8zo#yGW(9d_TCh`wc(pMpQzDC{~&;Fn*y<q!apP)Mza z)Wh41*pPLu-yOee|K@%e>C&pKnR!d1O~fAhMS}1Kdj%ybT^y^fkjH$jZ@ty8HRTjH zNMMJ1Y9)#`o{+@!Kh(KSiR}>9`yC@z&*+3w?~d{6f}VNf?~)T@&*8hM$XiMJq`xg7 zxuZf3M6{M)IIY%()G<lA8YUMVnzSz!tjjgLik}U)TxszO8o}ObQ06^%mF08ZRl^$8 zMOw=b^pQ&FaL4jk=J!3$m23CXr#_&r$}wK*PtU4fOA&mY?<}dP2tU)7K$z0+WDnnz zHLeii$ra<276tJ3A~s>ewsn$1I9*=+;j{d{l}-A>?wXvH4=kVwaS?g~?<;oip~2xN ziTZeCBPx&-5^P14F4Kh+T6132P#S^=l8PJ7T`j)OQ3uV7bL;UFQz{>adslJ(XEe?Q zhd}0-%WQyR7;FJ>?z3lSp}Ob4CUrh0;zMi;V}Erw3H8RxYm8sAS&*LK_t(ZCi?+0* z`=y<2B6o5DpOr@0AlW{z$co}h>6~M>QYL<**VPR}$MpoYx8hQcl-}Zjq*~~^Qa6^f zY-XuML!z-<%m6hH`g4LTCVPapa*LD@1221RM51ZvO-LTCK2cVoVU<HS<%=_;l=e~H z-{N8k2Bh;};IDncBEjT5Wq620!Vxy6wmxa8i*2@p*&b{%c<*t(+^(Fa-{Ux+UNLy> zIHn0P2j+{MT$}N+?reOJPoFOMc;|y9JGOt{V&0vrZcLu^we9@Wcgs38H&laZJcgxa z0e}7#*#q&SWWZ)C3ktBuStGtSaz)-1X$ER5A(zlD;Q?U=u^l<F!f#qAYv8yeMP%%d z?p@+xbYzP9q?zk@!n*d2rECNT{Y&4ttY-0SW@eSCi%@nKj+bRI0GXih`dL0=ul1iF zoAR6MlB9`>F@IY2cIBt(-DXU66lG%QAm8G=XW-q1?JbG<1g=u3ph$GNntY;p6*a-% zXjXz!y-4Xt;tY1TfYr0cH?X=#JVpQFztMQBJTz*ME8lEB$oZfNBd-bZI-VqJA|N5r zlFUNXI8a^hPMTYK^@2V|i{ns9N^k^~*!~O<G*+ee!qtoaidj1AGo0})pIJ5g=^?P6 zjcBR>%$6U0lz&skBGxWVuLUiV$vR+gpd*TpV)6=#_h4bOl9U+u8dWR0x*IclOFP9w zOLCEJ1D!D;3~}LQsL0TwOOkI+m&6Flm4Qi^r*?xSnYoaJzm?Zgy@M9p{^@CPqYOOC z61(m#Ww6{9F9^PCXGt>rbqV*m-j54P-`z8(wa>B{<i%`V=|RnMG>}DyezZlGbNZ-i zPR}tz7JDJO5cRY+5&z$-ft2yw6OQ{vB=H8b%8md%RW8PL1A}CO6yzzdohR@_zK%&F zOiChobr~hiKn%t&!q2cUZE!S2D&aOlYGaQw9EOLVC}AgA_wSAn<nDWpdxPmvHBm_4 z-*9q1)RK;GNq!As&iefIzrT+;B87`G{=M6BEd*P!sj{aGU||B}!yV|7Q<g2Edigdw zaP5S{L~QZxd2nt^XMsevPnQ&y_<sMr7i+h+)=>56a66F6vyf=GYIlnvrj9sdR6($X zpO!#J^cadlaA_ImkWYi5=#LUhq;A$KuRv+L(Wr)l?ah-NiqW_X`Yu*6Y=GjSp~c%d z^#)TsI#hY2oIquiNdf{O!Cntg$LrbicFaT*grz}pD5pmo7bq!Jz(el1?8e)SsC#lA zZ5I1Ai%UTq-M<$ky#^XWos!OS*dtgy#!_+S=ER)FRtqd%DBS!@EPUpojof<x)=1cj z^>S1Z{XfF-nuOKB0<De_XjAKk`Vp`z+3KirR?JwG$1q7;oSJ2^5icVnRWc_^LcRQY z25|Hx`(2GiUGiwLxiN^=VCNRf;RH%}v9BV3;EKA{h2@TpSAHH^+&{}5v-_@E%c~wX zJ^RJt8oSf&xGC(|;HAZCYo>UqYW3kIyp6s%iCoJU_VGi?yR*D;8Mu=a++m|^Ul=3n zOTK>8+wtmR!ef>j0*A@Jj@|CoT?!8Q3y|}m@UXqR2#>2W3B?TVb{g|&A4;SrOL3#s z;uB(i8dB}EZbz1Zfr{;=3J;<pT&IK<t3<@!HAJHn!l%Lc4#KFp=q@;U9?Rt5UF-?s zBY4cf&VQMK)?IyA!suReM-u^fO%zzM^%sw?tdA-vj^b;#WdT;!H&Q@MIv@d~ZX87~ zRH15)sNUieNxoc3`Z4B8^rraokn-9D6d9RPjdor(JH^6EpOA?6^={JP%j82N+H$K( zJ45N$WS;Er!4n0)eN+ciErLtMiN2`(lYV*(x}!vy{1zG>8W@7=m#=ar7E!_PW5;(_ z9ZBT?-hh%%G(%EhLc@J{#7bNZP$_N1BF_78vQN4KVV5od*y>0N0!OIi-quUqYp*Y^ z?0?efL)f?P^ywAC+C;;jsYbdL-ffRxZo@kGmWV0I^;tg*D(nfgkJomo<t)&qH#8hf z6y^_wCqow2Tbd~zK8dLR@oC6!0Mot<xr!0`R-g{d#~}>c9?}f&u^U!(S2>Xx!39x^ z#>Yxl%+e$QZvSpUB?_xBTl*4q)DHp^a4_u3gK@s+ZLI8QLAmW#G<Z&MD;z$yuQ<<U z|0vS!o@H1t&6@|}7U!8~`O5oT2o+~Y6680Gqn?A^0M#iu=n{-L((YfV?VK;VoBYBb zycOehij&J}G{SWg?(9YmF!2xQr136JI+@B?RAeEE&Ps)LN&kv)mNOUgV_iVf$iJ@v zxdG{<^RI96@+GL`6g~W6+fg(x#NP^cmB*yMqxD4ZqgZ|V*zp^gu>)Z$l0wGD!zaon zbrVZfQ3z(Jdg3}6XugjxP&k#lqaWm%fbHR<qwO5i&vVh^6R-&C5*9Y2Z9#pRQq)QL z8H+{f<1!WlBr}}wMGn9ihHnJLf{$3s$``rdx+$*6^;nEA3t(e32<n+6f&dw=b+GZr z2sbs{uyTPxlg4@?xev;NEzmV4H7pCunr7a8h?b1iZU{Un?BUz54uOnN0u`EJHs<*k zFc_>qLJSF)jcL9c(Ry*Qr%Hn~BCX^1eFo9EUgH0dwdl9oRYY98rP`aEp^&v~eJ_YC z{O`kSz@VFYv{HY+N*#+z1fkc)O<4KRP6WoDJVsz{P*#ll2@4$PjJ0M6(|xKFckD#7 zh37sj1<~Um5qHzZhONRh?%_)sF;=cU_%6*KntzM~H+OM9w!KiIg02`~Jcehe<vaBZ z=A(FwefQF5c}Sd=ks(!I-VF`pLybPwQ^-cq&gleF5?Kp#bw=6BH(emOu>B&TP@k(Z z=QFANyj;luUt*X!l<T;J_Da+XtJx&-U8OPEhZO26Wfc1GuT4<r)tBU!qdPRxJ#lfZ zvBKY?=Ua2RBufL49c;hbTGgin$yOiVc2*^pw92zs6hw|erhl$al{cJ<hxm}o2PAUn z9}8lpsa_W4)z=F{F&3rO-^l8N(zp!u)de_ov>vg>4$O3AHk9UhYW+%B(1MUt`C;nQ z=jox@?vU=oHc9U~b;&y9*W~Vlc9GOYT@qvkT5zJVBPKjIOrQqk_l;jt^DQ_ZYcEU` zug&=W?8<rzRPSxd2FynN16q%`bbqc^>=Z)D_Kpn^)-*;6v#@@ryJgopv=jwU`r3UE zJ<U~nm=94&gu#C!KD{{4L`_e_ZjoQk_(#dF@hnz0z>Kz2GfFmVQ)5ZS0&~p>Idh_L z&0~;Yz5yH(Yd}cNOZZF+f#pnq4e{`m*?;nd)-J>Z^CbGp1mB_;@|DSgmr5Sa8b7`m zLBjQYEPlhjhOp98a^J(u8sLHE170F(#Sly)M&J!EBF|w;e&`)51oYUN454?aXu(|F zPeebYei(g6AUVRV9r@n+;5n4awf@akCnvs`xK*wFH2asSvi2MW?Ik(>97VoSU$P;( z#rMMV?BcL__YwqggF^llyoy;6l%!y}tjrv}hqiRKA62+KDX3xwDZVEbdtkxtaI<BF zCa`+CTMzMYV<v6hMi9+Yi7IQfr<%!Lmr)ur8IB3FuVRW=xp`WE1iqabIyEGiDqGug z*?!#GO6h8w#D7afq@Cp7)Blv#t@?vb&O0dsfG+SHuPRuX>UaM!&v~i%5y^ubsq$vB zGe51Vmvjt&=mh8Y$qe<`u3cQ_x0<21)Mrwq;OHFMWv9f%JC5*Y^Uyd|^gX#`vcbUX zzs=+0H4_{hTU{Sr3LU@j%;W_>f2O%<F(-ULH&C3mqQ^%|E5pSBkE%c6hK{~x2$a<C zoK*!^Z7AiOxokB*@Dev_@+N3&wQI#;WwD{S0WIo2huxBqSq!zvp6@b_Rn{nc15N&; zALfpK0?C+<3PmvGXx74qnNb69ZJYlkFy?&21{6e0O_mK(i2k{>UabcbeCevBE8!F{ zJ0Eu53`7WNq6~K7hUKuIt$XY<%kae^)TEfCjdiLz?+tv6nu14A=X;>)8%dJQ$%30P zk+5^$7}W{f{)VA<v?EvfZ=qdWJ%&^sO_;R9u_tEqi4D`e!yg}~pR*i3d{!QYwEm%( z&8m~T%Pr{rHvrWo5wSWCq^s)Vg`16~=x#YoaxPB0m;lwn%><ERnxK1mOY%eXZPz=) z^PWhNWelBoPD-_P*C>x^4)}UMBYPO$G-)Rzv&%aA*ltxz_bDUK8gB^^eSM00$($eT zq4-Obi+ORPRhMZPnSi2vOX?0*qUx5wHABu0&7H{cJldgDw4v3nUTa)kQ2gY#4r{1I z-+*X2N~BuIa7B{0a*fpSz47*Br^nA29pl5o>MYF=)19{4EDJEylIeRWb1PQnnYkCw z=S^x)8QmVUCn<UxDMo#>2}b=nXg^F`P;X~nOKm|y@zYgB7v}epGe@5z&k{#SuD39G z(u4rrG?h6z<-wp^NP40IJ`%>PQ96<QXLS&il_5kr!{VQX0J!3ACjJ&KNY-jiz6OZ1 z4?HYdKyxcMAsDLOV6(zO#KGz?FfS&@9-HG&2sV+!aSo(lZsw@RcF?ShZnlAs7L>LO zJtb%$@JrxV$H#=a0OB*0PDslN8WREWV^Z0G(?D1<AckV*F^_E#?T_qEv|>>2Ar7WO zqzi+B1C3PfyS4J9G8CpyzYl32fFoH#tVwB(Y*s*9SIah+JHaE0v4~s72$KaVGAU=% zsH-%}G{-rPuwd%oGQZPc-Z|CddUK=?^Fl#`pBgJd&8q09UWLc1y~))vJ}E1j9!hXs zcj>*jXji4yrcx+@@2i+)KjN73Vd&;#GQvUaRWPrZFQg7*0SPFarLIQWKvQwDi(nGk zK-Gq$I8Lrkxy}J7AFRqR^}4zUUOnQxe4!P@suLV4z3z!W5Zy4ezNPAK!?l>uCbu9V zA{<?%MdQ_wdkp0TZ|@I;M*)A)VBsP`vsixqJ|V=vustNTn`(m9A?Ni*fu;8{$q4mh z`g({oeAZRRyPUZ_3v0_t2TGD=VGGrPVPA2Cmy9L2@|3(_SYjQWzkf1)z)+=4ORwCY zjzLKU*H2v%RXTa^sDx^w)goVPZH@v2u3`d+<k(#jtdE5v-<+lvp6)V*?yu!jV(yQ+ zW)WWDGKwJtcIYv%H)vK^D6rm0=+R_{(u8lqse64n34;Q&uAi1Gz04tu(&saTSj;q= z%GDA;?kbphOX)3bvLspc6M*nSc&99gq6`Vgn?nkSI(Dv?nLvrV$`ra>t*GILn3XF( zfYGydg#||&xgZslRoqX33H*ppMbdl-H{(`MQM*}Hfb%WP(n$TwA>u&ODXrsz^<z;p z={xT1C=C2xo?t|5z3wi+I@}(Q%2SpsS)fI5R?P4V^5L60VC5Y3A>?icHDsV-Jun67 z(K9%6iRafLS&x7S{vOYIDYxyvO<YoW>3iZqG;?$n1dKJ4-$le(@nXxhL^-5PUb=-R z+f+Zr<GI#EY=d4~mR%+6c8ujq(k}&`jK-zY->y^qmRJ|S>}3h}9VofY_Cv%vNd`Bi zkl9yb+>=jgsv34Ez00A$(1@R_v>^sZU%}>1{NKCmiKHyq<3WQIz9$oIq?7UDbK%^t z=C^T({a`y{W~_u2Y=4&J7=P0Bc=Rtq?~428ifkLOo2q&U+3g5vzY-mit>(slwGEGI zQ)tox#Q@V{*PJ5gD^w!(bwa*Vs6MkqrE&?V3I_A!YSjk1--f91n%^Ej^du-P^8*~Y zMliCy+Pl2ft5ag(IMk`yE?waW7~Uq*us!yz^f!wraPbj)N#qSrT%{2uV5$1uELBcp zMx-p(l94MwRS?;DMSnPJqS!?2IG0hNRb=P%GQ9i~;>wp8QCdb(&!@_69Ag6?hjv$4 zcOR>7dMD+(i?yAhAS{d}O(%!~DO2D}f4f#CLtC_PDjNYQWOJdy(?SD*Lh6?($8>81 zBLH0PHZOB`2*NXX6P@cs^F?=)a#xk``vSk2$tZK8@#-G|g02^XnI;a^mQvW=S`*z% z4=0bp!p|WNFkFwA@b`bsi0n1Ok7Tyww#`+$!aHy(+0w){u+LQg0bUQ49%1{baHh<@ z>MLu0v>N+ergx9n)VX>@m=;ZIhEZWw3O$2$t{af+2J_r~e$iZJpWKAt0=i-S^)fP< z@y)F)Y#~B$=n|0CO5&L-(}ecSHPrjlPNQ(Skl9V+Znk4Msyp=yDGj&syr|U2`>zPr zJF`CV&|zDeR?5^4+z7C`Bqr-+>g0as!3>#Ql>J|?o=JRjW0u@uyt(qd%V)Bx>p!99 z-}}s$m~i5J#)0(&Jh6VIYajCRMd~iBlhABi=_f<&v9uo>YJ)N8@ntZn9bMaeF7xr8 z%20)vDKgai`>Rg>P-aHWz{w;b=O?sz8&sArN4Ou0c&Kp0bhx;5RBs(jM-|E~_N(_^ z^|QiwEN%8=cx}6?TJ|+8b{Kfb{DCSJ>puo)aE>#$t<}YW;<CC!+LT<nP{;mK5=F-J z%zYV4By3m&%vPj1->B+FhjjZHJA#IF_D4hxz-NFu<=*GQ{}nJ1&+dV;Uf2gm(#0o^ zraJR2aAvr*NXhNi!o`A$P?g#Ggs7ez59H#Q;9!E>6WrkHP{ZS6$_B=d8m7xKh+_}X zM&lKE6gcV(5btf^cj6LEUB^tePCeK4Ya8zD7_jR)9Q>K@EiCV!Pj#fDX5YUxEq@i9 za{q^hDKc%;=qwJNb4bD1q6E$u9IfO^@0<`8;7U+--$bPw{`LK$$X>wqQU1W;%!=;d z<S;>1b&A3$Ip3v>CWJK7cD-f2kuqvx#2#m<n6pg2Qdp}{0d^ROyzsnT-1;6{JWSe$ ze*g#E0<=*z&%U<DbUr->e#XN<;hFE4s|Ayhqy(6Q7`DR5<+B|VD^4smIPvZHJAj*5 zdZ;EFmO9K@=5ATQjqZq_i$c?Qe!6*#YsC)L<D;S;TY-qM5Xe}^K^{<{3Ae3<M7ba- zBp@017Jzkh5E#LKfQ+Swc__Opxg>;E>`-+XM+b(%uL|9hyzK*Dyy2>U2^~p9Bdy?E z<~~GkhAS?t$&(ji&9&m7J0c<i;OB5zV6!_2U=B_lSTpQfs{8J4V@9O3HhnCz{xUx; z(j%}h5jKzsyXpW7Ok7A@?20hv4Z+fi>e4he8K{Xsfg<V+5GmBgL4+tq3DGy|wHZzt zSkn_oZUM=k!AWtwR}W}xOO7nA_Obrz!i2`Fl;E)cPL(nU_*dprx+?UWrOQ~nA$X_; zof*(8z{thag%hrdV-&_tg2*q0R_MX<1q7IMNR%=HGB3;_(iCp+`-3s13i}LNf3s{W zBzkE&7Af)J#;6X9Eh*hX#>L%!5)gGhV|>DU9xA34*&Ps9XT#`d(T-fDlqaBt1|N6G zz^Yz)0R;sRMK3)!hNQ2^_r;-hieY9Vu4<CuZaUxFq8Bg{GnQ}{|NLfm(FH?z1r9O` z944z>{VILM!$41PM^f`<7a|X_WAKqrK+Ks(cgjTrY$&JcnFLp~Mul+ZqSV14s+#s2 z5H?iON^u}G4Pz)PogyBNyH55HftsR$QB^fY@m&c+QUu#psKzhb;kmZrJl7x@vK0JM zTkJccAbtQu4j5%TE#6&dyG21Ku>=CnJ#{m2b0t;+kA=LOf`AGVpqVkneR+L_aFuZZ z1*egW7}UgTB`9N3<1LQLt)$9Q1~f~x1EGjJcMAneK-j}vP64(ForDKBOmJil6ICIX z0YJ690~XDPC%{m#61XDZ^Sf&9SE)nOaZx=PS6eqP&PW%+K32wQ;<)Y@WyUQ=7?7xc zfwyW6!FE_SfPn&V)T;&*NU0OMKEMDZ4M5BY4~O!#xgx`bWC&@%57M4SK$Vau5D%A0 z-e$8pLgptt9AN4bfs9f7K*hX%&Qr&$h*_MQ<&?)<1@?J+WwTY%=!okK<(J4fji5wg z3is+qo(H?WsEdFd0y`@3fn&}umFOB_C~hJmK76yYw4kbfQQI5PgM{f(93#iJOa93a zvf2SEn$*bQ0;*j==s0Df9WUF;qPl!xHM~q&36LA=)M%{iE%yXtqANhpGggMh_LH;+ zCy&Bh!Wsh^kf@en8^RqkQ>Nr0C`o+U=g8KKj>9DLZeV+i09!L)Hlk7pk2?w=N<egw zq!^Yw^z?=VLKuQU>)`5(!*>~#kJaJUth|wAw4LFZ)jwcDs7X!8Neu{J&;SoMtuyYM z7NNrnyPK@wahU}|n9vbf`XV|qh$B@H;y{QKun1U?nn9u4Z4UPaV?d0+`;HFxQqY>< zs`4fskm?bp9PWuldfEx3Fr0?f+4-6ttCQZ4+f-4AJSF0}n7lZJxuW$Hl}QirgN2}z zuZW~zuul9MipGU9Bvf0Kq~8cVH&KJb7LwZgOIqf#hA7<jmM>?htywx?rpD!d%W<-P zcgtIIfCLCL@kB$SX8JaY@68RlanIg?ih5HshZhJA3|DUhtzZCIp$NeKF#xKbRS15S zJkh_405#?b9+W&peiC(xj=&SGGbB>`-JEPqe_keE;7YV#gy20Ge?|bug|No&E_psj z6C|$6K_(`t3DK?RE;Gbx4$y<j9KaSej2b1Q%x{<Iqu_*EH|3~z;&A5GR39A@hPp@7 zvt?sV;)uw{kTI`S{*6&kp96`nbsJJ7?c9dP!rO)4C_F_LZ&KALgxS$p*UXuWgo7Lu zI!l^5#XLQcJY$o_nj^|l0ZQ)q95+se$tQ*j(>K`Vh8J9rh?p5rXrLS}A{dB5k63kR zmPFzBV5ostV=wx%DXG<dF-=7miKU<PJgvU^19)OTA2eoc2CaH{qnhY@nPczQc!C?< z7w2=<dayYXXU}n`wm*c1Z>UAg^p*>AuY5gW^qp#RvFc(t*JD1@7IFX}!-q;m&BG-J zOM0|ZkhwJGYw&wCQYu<IGc%srYnKYn->tZohk+@C`0xaf`P{pc%`LsO0<Ae2(Ff4i zZ~(Pl-T~5|iMy2ry$noxMVVaJ?1)D-5E`^ip8&!@ajd35ul#5Q@!KWk@N}7?Q#aS0 zKC7vvl^+#V_=I-2Y}3=B{KB@FX-O{Q<VMdC<bkN+Qv;!$tOGD=q9Uhb85S}rCPh3b z82`vE#AtKPjCFwKt-MJ}COLoiOAEq5w_w8D2X+<jt%MP0>$zH)38xoRvdbV5RN_E* z7XKw>s!v?%ER^++)7YVK8QNO4iWHArx72gATt^?uWP>|48)FrRrKH)JTLdYF;0069 zp1iU|8pHf(EVdveBS<OQ>Y7`;Wq%d^u6h&2=OzHDDWTAq70I3q%cXt3NbBru#`I#D zn}^}WD-$EI2qP?!px}hSvH?q;B&jvUgN}R{ps|eo9BSMZv<5o=1pR-&=rYJ0V?6Q5 zOOi|SV-%=<6L&eCPaYCciZky571IG|<&GxWDnlq0yg)%H;S%uV3sz?3D8@a1yD`-j zZ==H^QZRQ!P6uK5&}bmd1Cml7<$5Jw&~TK_to#^w1YoIWtHkbvg587C-#O?#!yCo} zdFOFZ-N}!U?^Ge({Y1dT0@ANgf@(Yq!!}(g&nIS}E+B^E3d9D0iur+vz4S0WweWiK zakf?&v_?yT-7+RXj}4s%v_cJR%hE<FoQ%*!pI#^<?+2Q%>O-emC|#@Wr78$4B<)`g zJcbdIE=jao@6oE<-xB{_E@H?Ok}8B#rV?L`D}ke~dCi7-wBa4hvw^VU#Vp>mJTxCg zAVw8RJD+IGq6zRyrM`#&-{xTRSV56AO!kbIJFsW1O4H}Q5{OI5M;xan>Nr25oN}x0 zz`Dr7GQbapP(kSdtOh`2Xoa8oG=Nf&6NjAXjOCbZ(Oak&F_^N`6CQ~Z>7oEhf>DlO zc+#07N0?L7@lK6k>3EY5MM+~hMY@bOV8Qf?8yUMgI+4il$j-$%$ryoa4!b1FTMXJW z=?qPO+_uG2U#CK4BU1sU+Bf8t(XnV104t3-T&)`HG2)ewMx5|n&5Yc0Ei^SLD~d$` z(J<*Wm7cAou1#r?j3qIL8FjS5B<*wZhw?p4$+?4jMdVO%9_TH$m6lN+fyUeyS}kL_ zDG~-{M5xNi5;}~6Asb1-1L!i(YXFU`l>lIcpw2>7!^OfPL`u0@k!@w+3Gv{hxgcPu zX`k-$3qD5@iVj|hB3Y6amEv2drgmICJHGb>mBE7L2}Ihnsl2qCP7)+H<ZnqoRcORZ zq9RPj*K-^)gt}3}r6H?`Gc?(yjKb9&Ue7jVFDa9aKQJ-g>RJ|4w>>=vE3cvc(0pAc z8~xOE#Dou&pM+}PA<@vGRkBm2br*)S$DVH3HI=!mej=x^1BT50n^7wra1(2)C|~kw z(ouAB?E2_as1&yk+``6MoX-@^K*K%Vbvm7Nj^%H4QzB*6L2OW0CUyq<2YFTo(6du5 zh|5OEu)i%crfB&Ioqpo?>10G9_3~!(02zPx${+}#V9yia#2HQ*+h~@_a2x_m2rU@L ztF4`3CGVj!0hpMomAHh~VHrb1!s%|n&d7sO;}8H@6O@OUn$^1@2GAbJCYgXZX^~cD zE5Pemu^H~k`no7;I11m<ss%%*bRoLAv{H|cIojV6z)pyjK_T>?ZRSp%6tQv|4#!WB z7(7cJjt4<}2tJ4_+yIEh8#qp26&nTq@B$W)oCcZl^J^A+ZH<={yVXJnRr!LI#-T_i z#6MjdZ>J~30P-*{G0}-(W6q)MRj>d{3SzYowvme@_Z&gZS?n}Wx6mnxsz+OZtBbU5 zTBb}L_Y2m3XcBi34xG5Q9Z|sKTJ_gRBdLg;&xv4e((yidGe>bk)D}yWuy}HgyVnUq z8hxS;jkP!uc=)_cVgI`QUQ<rPvxhGz0lz}hEQhvWej_A4(09lUDKh)i%0-693VWP; zU~9|OMZx>tOGc%rK&T8HiIbNDNNXBWN&zhmHt)4ynBKfZu@9}F(0eXPSY$u>hhv}& zo4BedsXUA|)RRf|f+(l-21K7tra;BkB(H;wWeFl>GA=V#(0xF0NWV@G2aWK35w2jm z;)5$?Ql+?+T^+mY#e^KKcc2^Kqx!j$<+X+>VzUtto9cm`Sp5BfnO~rM6k*yQfUa&b z)KJT`%);@8Z)LraM3Io<L6J(+&@jMABM4yuC}4~eZLyl2&B7U@n4!^pluWRP;eck( zdI8)qDloo8!WjNs>AYkMC1?0S{A_e7GP812iDZc+XSEX2OCb$Vi<ba&WN=(V;)h$# zej`-801j{&2@r9yei1JUn@O@r88{0qHr4W(<G@vJK+McVIp8rDNZ1GvbW5Z0!`GDv zGlx;?O_A)TjrtS9Pij@+R<{SNKJG4@GIQ>^YxkuYasrG+n-DZdpB4Qo?A!{DE{OBd zTfrq&XIiIkXW}mQsaS^1FdmR6l^}E?sL)Ag1V(whh?E-5+5=?`fB6Aa&oWxGnpxJg zX+>B{V8}|S?TJm3*FH5SV70_~n3lCnN$<92E`j3vlp7}$qQa`szNLpqg{>$9!H<7R zh7SUd55+^$EdgRF89LR`>rOM$W}0TJ+7P9m3cd_!h@usyO*|P<+D#7NLG6O=Q-cd7 z2WiAsEVn-iy5q6|RQ~u#asYr{0vABNAjm^10!s)*FrL7!V@So2G=d=8HyIzb333}i zz>wLHTuoKjVB{n{^^&_eUU(c7lVhrAZ|HzDlGtx)Xn<a&l%{Y><|}xb`N}us4hZ`_ zRwix}dM7V43l5&zJpL(=Mqg<7ks1j-%Y_R_4a-Hy!lPgJeAm{52dJWIgsMiV=9YL! zY#<n9$0GH0=oM%oiB*VO{aDb05?|}X0uaSL0l(8HeZdqc1Q`;Y?gXUWWJOs#z}dfc zsZD28q(wMN?dItjGn9gfGSAY21k$wCTya5UIt86c2?UwQl3k)2{jnnhKyRRjKThOc z2zB%F9QcNUcC-#ogbOyo2S$hHBUn-hd7EiR90(ok!1?gs96J^E{|*rJdWV|gID#e& zeq=kcJl$3ZP$vDE<=(9D+zu#?{3t3$1pbB^lcX$a8{e{|{-T#{BKLy}q(yTT(THLU zFX_5jPxOIJq28!C_?bcOxm{F-EX`1d*}g@d+P`@bureH+*|iFetFLu<oc#>d7RAEW z6bR+{+psNHX9lUvmL8%V00~GQuR0rBY-I?8!S#nUL7J{f@5rofcJ}Zi?hYB@6@+}D z%&F8t07B-CEi{5nS>wUsFnsz702*TYzq;g^e|I9v>SGB@;&Qq)E&-VogG}RkR3te& z;w6_MV(2!!ZpPDUqO?qS#wCQgNYcis%0m*MF^XtrNv(mR(lNz_wBF(Z<=ut`wIvAA ZYA1zov)t1M!z%U=orY8}X9d{g7NlIACawSg diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.ttf new file mode 100755 index 0000000000000000000000000000000000000000..7d2d8a103f95f318e335b4aed0e47b9a971adb8b GIT binary patch literal 50888 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 QG!=M{9HMFLzXyT;0WTmWa{vGU diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-BoldItalic.woff new file mode 100755 index 0000000000000000000000000000000000000000..ca0e943911dc04506568cc7b2c0bf2d90a479a88 GIT binary patch literal 23428 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.eot new file mode 100755 index 0000000000000000000000000000000000000000..182227ddc49e6bf3663e0a459edaaf844d36cd71 GIT binary patch literal 20930 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.ttf new file mode 100755 index 0000000000000000000000000000000000000000..34783336d4c98e8fe1f4fa214fb012fb5be0cb8f GIT binary patch literal 52772 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-Italic.woff new file mode 100755 index 0000000000000000000000000000000000000000..0a1e6a2a013f160859d7f020fe41adc02f07dcfc GIT binary patch literal 23444 zc${Q-bBw1=u=Q_j?AW$#+qP}n+#TDtZQHhIc5K`D_PzK1_jPj8&pD}6U7bogmB(FP zObh@7__wr^0LcICGbI1Z|NkW>rXmXf0G0jw#Q6_a_VKXdBBEmdw4r~T<{ub<X@M8S z737uwX}16XL>B-+vVD<2@FlLSDg*#PRRI9N&;S59ip-H~n!GYS6953y_RpvF4+i%7 z;Woy$h7JG#EXqHB*gx!}LpYlmySWem0B~9VV$}Yji!BcF*v!G)_Mi3$0DvX@%i)la z9H(h+=={%%{Lcq~{68R?+jyG&)8YUCzHb2FPr#k)VxEPmp$Pz>^iKmY{{tJSMTCvT zKk=XT-#z}F1t5Xo1~Im<b@BM89sa9X8UO&P7`(@#u(3D(7pKbbueOPQSW94PIJ7nN z_;;?_=l^*LfO&!G?F?;A0RVNJ|6%|DQ1DCI&{qe0XBPlK<6q4{_y2MpZ-6>9IXIdA z^J<;`^A-L>v(h?Wv%9I$znZn9{&DdCa37)a?~ec5mANeP&HwgstP%46;cbOb9vj96 zCI$w(Kt^x`W<~~v1}0@7`(7bp1hwINm~mfOd#D=VB(ng3-VqqUV`Es$TPE2Q!ylds zYWpEYO%Dk*N#q{Mz{GN<p<2uKNxpjWcqPTT@=5$6wneKoeI=ybvMoGajx_$y$dZ9o zpCBVjA~K{9Ua;VRg9Ow1?b!?8&YzpC2i%z#T%ca_n~&}t=j}~r|84hB9uX9IW{Pwk z?Coy{;^?BiK1AkneV&`@AAvoIj{$o|4}`+`ra-^Jm&OI{X!$&_fZ?XBoIF)vJgq@o zC3mU6WKVYG@{+p5PwHg{lwiiGMlM*UbI=n-I8<PM*;6<DUI!E@-WDhmI5nj#-#JWe zX=)CvrcP+x2tM%J#T2X-s|8E>ONA`?9!pXv%;dt;?9BGholPkVf=6^U2k=S2O;&5O zswkuDeM=z9Gvw`Y_Kxh{?U6qqEpQ5d_}uRdwzcdAc=TpYoVN!2cI66OoY8XoBOuyw z^|$jBm-|NUX*(*(J$NWOhS`_l2Oe)AaSyDz&k<!frLYfcHmX^65nj%t4aKIr^Xelr zg}sHS-#5AytCkBD`*~N|130IyKIwDg-CC#nK7yXl-Tq>S$QUSYbf)|qiw$o&5G#Cc z5h2+_)7xjp%PQ#~g0D&V0;2tD4v80P8Zq6GkJ!|Lqu#i3aRK9Q3y8cr=XLt+4n2BT zQPjzNB9-&t=EU=3=%PDXtne`Q-hZua03~oM^AoFCn#tbLf7HO&Q|?{MtYN!xSP%^2 z$)D#&qJ!(yn)gcEf#-=OCi7pCx28xnI?;Ml0DeaYYLi!m_}o>$qglCM%J(xjWhnLH zPY>CfNGzgkhZ-6;<M?s|8hR0b^&ZjxYOiPmYD-Pl-_6#U`gn!8qk?EhPN)%<dAKK| ztIIxX8A%MIzCQf&3G}^X(DVWDP=j1!znNk`H{f!2)OdkK-#5&<vFWQg{k4jQ1y8ko zKgv6_e!Pzj+nv4zhnsk5*Hhdf&uxv(^j#OuWoe%Z2L&ngEb}eX0LGug`_yi0L-3>6 zxo&+RYeA}I)*{o3jMB3P#kSZ~XXIosB7(ThtgjOmz1;nRxLyb|l4GLU8<FiX?msd7 zqc&X|TFl5tg;jg2*!_gC!TzeCFP1M#+5_!V(}Z$ZzDBa*4F7z7L~U`Sh?n*<(9zNt z@iOp|G_ddVv5NC>kyh{L{|m?&ZGqvkNU%pLiL6gt#5`7a=A$3l9)roTTh2Yrht)?1 z;^Zx+28@mwWzY*1A)Z>0jD?DTsq*zYSno-qeDTR0-^4GR-qKc-xyuQRWPPHUse+v+ zHu&<kDqrzy)a_9CZp@tZ#!-sKqRkjfyK3ubvR|wA4XHf2^lHhCFzK`0sw;Ac|4G2z zO2D{thTh-5z2>NLnJ~Kfkn!HCCN3vO;(Pirlr+T+#vgsm{PL4$f^QrYWw(g(75^2B zrePqd5aDgW>>GuACcAD#jCCZRHwA1C!);Z=orZ&=Ui64?Ov*~w8LZT?Xa~<!D}@~r zGgZEAixraj$Ii^QT`d;wMq@-YtGM~2%K6`WIC!gd&SKhc4wP7%+vSJ1lsID+`sG&E zmEBmVcVaX)J%~0Q#_!JZ-qM-1eCfUM#CHP=ss1pHlLvL@rhbUra@a;%vuX)9egt2c zCH!_u$W5)@!O1A@%+zw|q6In;a;#$Ud@AM~5{5rtl_pm?{cM#X6&{crzye{6yf=$% zdsB;Ksp~Nf)qh9?{V^bpGdf!khC{{lFsN6BInGt_xH%tmS|Dn`BBD|~H{%w6p!dq0 z7WpJ!wuwb|ePc(9a&egQN8Xa$k`I_(%h2en3!?rU&=4(G<*nm0L~77g)6DkkBuM}D z95F*K#<<1~;^|KUJwn%43z&%;fBW5gmu_O%6A#)nrO1e`LTh-2d-U2%+!d{JQD$Wx zY{&~Sc9q-2vc*je$T3H#v+RSx)+Ag<s&h}MldC=wWy?itpy>6r^FTF)d5i?LRlN$o z`1aA4Rr^*6N8$X%{mg_@sg=3(d-@uJ)H#53@8Gwxzn%Ze>Wtd_TRh=hL;mC9h^7;P z8D+|=2FBm+ab91x?Z)I2*!C*w8=z$6x{6SvGbY+qMktGN9#6apBq>osFDiqn#UM?{ zIzC1goCn0=vsUXxOPc6ZHJZP%OyMPSAbory%%_qWqOlqcjs>t8@-Vk@VrH2{X((PY zKel`XfAGX}a_D|E6@I+OL?*fX0*S4d6_kP<q=S2eZ?=qzG4eJRUDHT+R>(2AC0F`A z@Rlv-0*Wl;$u`oNtkj0OOMz2BQchioB0|L!m}%ME8RfOgi2^|%CHlP6{|uNC$u?Zt zflk;=A%-@r`HWuZZ?sYs5>7M5op5AGBfD%eaHNxn_KR31(zT-qB<P_Dy(bd>l<&^6 z=nj<sqJTfVGU2oa<8K5ZnAvJY-Ir0=;1mmmVxuNI8-6c>H1*{ryI_FRUu4ivxRU8N z9}=0*2JQCKATcg>E`VpOgO{D$?{`LM<3q#Z#6x2NMq>#VTL=!|m|{TYJvQ2A+&vY# zH2g)84f$3BTDm%?HFnDBg@<(q+#SZ-BV=E&>Lq~X3o20>3xxTI=?fRR0jeRY4OD4~ zeU)cUk?Cgq2{cidS_ZhK!Ywv_#L5PA$&sJ2bPJNINZH57Vx49G0L@<i!t&UNPMVd% z5kws6J-_~o0Y#*FB2Pvo4Jjy+5|@aOR~Hs!5`67y%m8&NwuBo0TV$-C{Pq$gOnw*S zFim)j@GwdGn<wzFV41ZsF=sqx#<0^oLf`kvRem`L0DC~VkrzE<hc3*3(|=Ta2?_?+ z*z;FYxascQ6arz}ruWpys<gE^7#vxO;v>>C+vM*6MaeBjqsJfG%fgAf%}<vo=g&Ms zt2t(_JmhfX>|v}&$!*?uDRe3&=ZZ?XCG#is)u$}IRs5&)?*e)m6SHY&XA`;Um$r&G zw3}qBDrHY1K9&*0{2Y#|Td7-<>hbf`f&n2a3ek2gLBgZd0-fqRrJjg#@8Yr#PAWGq zcEgIZ*4jN@zTLRqPu!C2f>7Qw@Ypwj`vDz1!yL=~3}hv5#Q6zCsjc;wDrm{=X%lM# z&KU9Wax<KkD}^6Bzj$UA^Cd=F&YJfEo|8tKKZuD+sU9=?uN8%7q)(S{A_=nl-L;(= zg_rAOKit~fZ%AJme4QjYf+X`Li>7-0w(N`L7>93`VuZ($Je@X;bI#09m-+{s6nmT$ zw_OQ}ZQG5LDR(#~NhQwRg&bDQ!q;F@-sW{?z0UWXaNp}c2Znr!S10^cbpfWIDZWs> z9LAXZp1MeWf?gVo`X|j1zj7p|6VD!OHh7aHd1Z1@cO(hA2FSK0P4KFz$$=z30D%8y zKBKLEj=;d=z(1A<%IF{<!U(_3x+V>VPAB{NhWaK(U<)+R7#O+{3_NZ#fuNn7BO);| zFg^Sm86v+{jSURw%#)N246+asjD4n9uq7xN>Hq)^WW<*L&23;{7GQu0E(VU+26D(4 z^hN^<5zqu53>-HMVsgi{#Q13rYgT2zHR2*3C@m-=C?zN-C@Cl_sNXL|sAm{mkZ_*6 zL-X?!JiP~YuHA<LsydxVkVlYD0HSIOr9KU*GX46q`9uDL@I(K3^AWpua{)n)hvVn4 z+y4#Wjd$r&clU45qD7#&#_xHGc*0!zBLX7E2Hu7yMpnkJh{C{7SJzPQ?BL}1aC?6T z0|^Zk85R*PEg>a2IW{p)O+iIjSyoYQZDD13ae97+je&)knU;~Rt)Zp4xwf&+&B4Xl z+1AnS?cwG5@%sJ-0SXQl`a9&0xQLkO=+MY8ISCnKle^24Ogg9k_<r$ZYPCkQ+0%wA z_KN*hlj-Kl6}S84-$r|WVMi;imF@}AKb-QDjhI~K%t;IkCMp5CsoIluPVUN5d|}z@ z?)>fTwj+DQt2H}4&IiYIA;RLAIXpg(pJ2kv)t#`_-L$@ck;&xFbJ?;D&$m3CF=BA( zfvqaQjR0a15wZXEfdJ_hB%e8$dC>+Od}I_B_J=oZ@`u+*>-h)f;NwUCdo#de%qq>S zu);_SUJc@y85EFD9Za2w1p=b6efonA`=vbhC@<I`4h)H!P6cGQ&Kdk)f2-9j-514B za6Kine$$Y`&{`P|4O!NSk=gVIKnXS&6X<4DC+9_?aG&+uh41X@KbUMdpR)UD-C)y` z#5J8bWF!{4pG+@LZJHu!C9J_*#3yCa4==5dMPKqjorTCwD*8}xdlQ;QjPHOcB37qt zwBm+}h!80>*VKt1e&A_lnE0G3icPi@smo5#@}ALY9|(4<?)YJGP1JMe7nw1;SnxKG zs$!@XNR;p@EtHs+y;Dn4cl8cTsZT2mgvk+Ec43apNo-@AH%(Zuwj5AI*feZWD3N6B z38Hu=EhC*AMnJ(%KupKoPn7;T8vG2aS}V*_tCMb7{OqCkEOqDPr^H{?PNL<UgJ>Y; z=HS*HN8ejf!(hKM;f7ZI{r4#wQJal>xp%#=t7N|KDnf>yg;;}1pKxeGo}$rTLJj6c zx#w`cEXC$fWX>xc`6EF-?}@`mN{3kt&BfhC2-LOr5H^^%Bo@NI%RS;~;5Ptov|(Ej zihMvsY7Iv=fh`J0Lvp=9%Bq{1OwKbK?JlKGztiopn0bR^DH~&UMR-(APQ{5QW66?C zxztVR!9psSf;1Zn@8JS45o?j4zNsN=bTrQrlg>yOA0`0vvY>)EDMw=oE%;y|W`7-G zS)&_?W_d5b`*O<L-HvK^{g~7O@>MmTyIh_I|2*L0#YI4UXSs1iBzpFKhUq7>FSr8C z6i>@Gm=p|Q{{_D=xtfCWXBB+y`s#tY%y&iPwg~70dk#;2nG#CoPnv3&nt)NYwPwor zaur(n*pj<&hFVY6B4~t@PX4wJ=D~ZfnHdcusZTF*skyk0*YQRwVhQIf+l3cPt#afM z@cz_&mRuvv&Z=e15d_zCBTwz(uap)!aZSInMc~O;7p{@}AT*Y<o?t?B!!a-%0z*h? zh>*H2P+<)!i~*-#A$2qZh$+$xzmG=$feF^oQ**MSyfk5?nYkV|?l%Vmqj;>&ae)(S zvJO?gE(=vNp*&Qp6jg-zaxaqtJ)Y+vjs{GTw8?ZW#>s?up_9)=L<)O!HubK?Q!9e_ zN0tZW#qdCG(2tdMMS@=a@!q)VE1a-=3$kja3QtGL<Vgjd?hic`RTbDfT#*nBim4`B z8}qLL@oYI^*0~8nGd454ji(ON>Dj&SObkMpGQUr3=xDHO!P2UtDmRCf^9x(e>uf>J zEU1*Cv`kN5YM=OcP0QXf8q-;EK7=-4v0^5h=D-!`?aRcpP#OCK^PskB3TzTv8}pzc z@EFg&t~WX0L<ZMoaHmp-LGaHYhSuFKWIDxe#T4NeqGwMOrSEEGM<Q<(7O~y+%jmjQ zcfzAq4sfK5PbGfviikOts0?TeEJ}8jVEO}_zifoY5bwWGI}J6}?)Ho$KcvQ6V1@XU zhR)~b<*n%z$yM$6nIk4&<aUA#;xf{DyX`wTB#v~eP0|Zn0?W0dC(5m-^Y1EzT_4Kc zw;i9uvsh)>{~{xF*IF)L?HbXcX?(CjSW+g!oWIu%fX^T8D^WZ#WfZw@fxyDRp1M;E zkNl|m+VIULR}7qTB-oRmZ=O0cfPX_=_7=VaoqjO7w1cOfcu$ARv%fpE$f(apJ}Ez9 zr!}u^(ddHMS#$v1#TBZF>l}giC<k-!F6hKOBHq?tL*D@mko$~o!>_f(9w-CmeMWHb zcb$(JESN(3(VQ`Cn9bn~LOEgG(gzJ<IbnMYX1MxNrwkF9LIsC#z~$4B0X(Mg!L@0F zyVl1HuOXZ-Kt2C>8Ye8$F~i!bi#5hE8vQAq!e$=TTwpml&9$LpSvix5|0vAh_cnpq zj{%~x|B{Qh#8)_a$a|xp%-1kM$#=!sOx!y*J?xWvaN2vQpp0*ce$)|Du)bK2^dFE3 zI=0-0m!S^`p#Xv5|M|NE^z#Ei`1dyZLK)zwd)|68cXBs|HkCGYZU}qV7A<!tsHGM! z8|qe0CXh<=nY_7Oa=2x2q{_w|%YisvumH&r;7CFiPm9vU2m~StVc#!;Qv7b2W0?b{ zET+t#v-tAg$xQDy<t_#qU$8o!_TKSD*bB==)Ef0oyA>gbmRDF<`Y6iV_*T0>#(IkN z%01+Kjpyk<7`6I*l@x3|_`6L`>4(SuF+JbLd0M*R?|UbDJ!t*$wS`28!<ge8nsqQU zkRhg&8P$jEA@xf9dm)^0;9)Bv!fA_#y+-Y<nW}KZf~|abLW9U6`XNxlTU)%VxnZEB zz1e?rB9)4l(EJbiBiQ>vvuzHv`JDD1B$Cfa@+0x1)-_=Pxtmh93wARP!bPl8l7drI zY0}L6or36C5fUz=bsh1%_<BVU@5u?mpX#IswT!ECl<&iG7H*bDVtrQ53S6}9XW27| z?m%Ao0Q=Pbbe*D%C~|QbF_2oSgFQ#8j)LMK21d1-lO?O^0=Yw$jB>_T7|D3Y)=k~3 znrAN^Rk={y9LwgkqaPWwdE`h4WI>=FB*$k|^tDvPp<0U1vuwDJnCq)e_ciC&)8d-R z-O@sD_DgOZ*TXf%7sj3W$r!$`$Hgo97G98_=I*ua@BPR+)qswxE%7$XoH(on8Ln{^ zr-FnEN$u{<BbTrstzzYJ$|IFeihu~bWrduB*k8>Vfa|d>48?LlBrN}Ll8sC(gY*oA zx&bprr~+Cud6or>0;F$6MwxZP!DKf=B-Ab*0$PkPP%vxkPb~YZU0VlThP*ec;XWXB zbt8FkSKG?c{bye<+2N3h!YkdUM%wumxtHlt4iNJ%C2#9WGn%K|JCDK|>&5NtkerR} z@(6wGDn9>6?_=l=-&o_W&ena`#L61#HV0na5<P$8BYCp3?emU_R0t@=#Bk@I;cfs+ zpvwu7B2wv9`Dk;a^tc8lDxAt-WQOW%q1JGvdbpZ&Drf{rc_|gD=7J;6U>fyP8=jpd z*9|S89Hlc>dqJ`ZwpDZIBk}SllbrN`^x9z6s(AqE*Y9>DciKV!aR=MzQMj!VE32~b z)sbL7_a)?J^)wx`)PeA$zVJJO>4PB)YjJOFP()3`N}ZbrZ0<I=@ZRekCkxmfu}rZI zs|>ag|BYUcaSk8KUT5>w6y<Ih@!Lw*7ILKAv+$<*n1a|{6|%k~j$NcWiT5$`#F3bh z4hf3Wm!vx`JyCJep$$~4Y;0xaIDmB0G0}YT7jrPAo^UEa?LkFwt%Ex2#SGNU({?%p z57d~(Vj=7~jUOYN=&QB$$uS%@ZeqC)FZns<w=S_tg*I}$1&Nj%kbzoecdXRzL4_L^ zt+qRjuHN5G^hSJ1Qub8sf*QHj*?k0$cjLc<-93*t;G-E=dlQFaYjTq%Z(90S4$aOU zlQst;-hE7K8C**{M`g9onw5{Hdo?-lduM%tJz~DA3RShkiRY4!3+MxmHz95GERZq? z4T+yg<1-aSx|7Zn98eRoMB%c?5F!S&loXBoziQlbE($=l^bv9Ad5ZI!2*I85x~CKB zoXs{rHb3lnQNQ{Nx0Mlci*4D(7wk*)yMNC)&t_c^{iJ!vvI5EP{w^Edax3fpX;F^H zcX-*AJxjF@S3s}k|IHMgAnHZU3+Bz1m{YWD!<3SW`B;z#w0|<;_)|Wr4V3A1gn=Be zTa*ID(dPSee}Z$Lk0iwMOEzywY7MLt@yoIB#$x?wa@l!>>}S5gc(RAn>mqz5W20y8 z^oV@F`IX+=k9S@6C-?$9EniIeuA;E*m5~5CuFW~hr6pkML{ci@8mpd440RozDf@de zHM29Lr|L&a*!@7=V!w08*82!m<7KNiw=;W7;yGx@iG+HW!34u?R)i7JkRm8kZjD8# ziTIZa$IVFo@i}3mg<}Ygo4xIzTPgqCc^#+Fa@(xbJ+4)u+8SgPL@zQ|C=A{H4%rke zq~RLU@~8NlzmK^>5bgQJg&{%|-r9kp_jID86e#PwGH+}Uf9M^AX>--2;<!UfZSDtY zccwRN4z48cwaKZ12nMA<XcICwBvwuA_PYH+4>(r~gohuvgO1!*5uv8IiJ$NcXgrh} z$Y#>GM0oeWDO-CpFlFfx)>@X95qJ23MU(0=&4@+QeZs*L^J)wZ51*fz<E?>@htF<8 z%dbIveQwX6^0Uqw-rHquaycKT#m^e#+%=Zg(0*g2o-1(OTEdzl5QhPp$gIM(wc`Up z>N%y)<hR6D5q-Q9EV@{Kv^_XCA>bJWQKE4JPs~y2R;nP-F%w0tA-oFH5lLFv$MQA1 zKV?()M_Ie2J5uf%YI0jV8$6j?>`2i%^Q{jlffx3hlHzQxrD~&Q1GL#7y!r38ncOkB zf9GlY{o!`e1I<_CqQ?c*QAaC-k`AJ&0*E0ta>#K`-&GN<&q?QA>aazc#RQvIubQ-{ zkH8g$tt_Gm@_90D2XaUl=}D-V`Nd475W4_I)18s{4o_SNFVXaJu}v4#@9TS457_FX z!7w-64uht|SJ*cUGEc0{Pct?amj#JUt)2Dmb=H2KW-g+}X{Q@baE+LI+L(Ph;uDB3 z;A@n)%Vm48b&@&PptqE}s~1nE?@W#BM&OY{P)_W7@&N-viQ`gdt`B>Ut5c5^mF_hd z>LI0z^t>4bu|=&>v5Qw{@{*5upd7LTjaeoH>ktXDy6`DD8%2c%A`U9k21E3~4P?*; zplXO?c)@aoL~`dS7)PSc{YFnPe)++HA!^@8Bi}2VVs5s084_elkHIC6=vrL-zMt}N ztu1)#d|TX0mjw^V{8nq7O)nr(HWI+ktRoiWQVHX5UbvwGV`UyOiR*#}X1}{ATO$(! zW>H<mscnzI4Z^9kNRJypAx-BPgGz)-YN9sK6zr8(<14Mn?Q^;-dzsxl&hDw2UldO6 zkNn*{Y*tJ1lcDTJ92UdxKJ2yEHaXpo^AxY_H#xm;d%}GOalf3=ZpI2gXMxr}5f9MK z8<4_%86mU@U_9qy43uAy{q_zjAHU8ZrXGix>=s4Pai(F+w;|1INPre3#1aS1;7Ui7 zox3tlmc-ZARYMya0&x8_`FtoOBz0};7?)06xi7(af$U~+dO&1UUvq>@y9ylV;|vwz zTo_sLx*o=2j`tRGd%t#tHeb)4%d<1RKU!oQzbYH2GvR5m|IPjQby}m^DQ<MKG1nB% zQzXX-i<?X1&l>Xn-bL(RZ+kQECh1;XjosL{YYx}!I{YsT67^b4SvYly4laGC2bjM7 z`LD|~;DIovT|t_APYOuT9#-AWF;XGY?5+onWhAIUNY#O!^YIj=34C>pgG1WL9#|c4 zah#;Yjg}q6CJK(rp-7XXH{2{O-hK`rDA{{>GXzb1tUEen@0;r82wSlfvNM*2#M&l5 zSFG>O$J#*j1&>Fm01y}?_A#fnDS_~1o4V9>Qqp`%1*8=u=)&3o<lp|mn8Skh4{97B zdYQ};93?P!?H1jm39K^M70`He$jOooTEf3vp}^8V4tY$^;_!1TSuBYfL5hyJ8j>Fz z2L&cGN(HXjhp;S&Xp$7)Ro>5;-t9*o<+wVZLa%BO_&!(;)}imIN=xV&e>mf+#NYrk z*U)+C2PbpuV0ydlP%Kai8_Z+@^zWUIWr2LT20LfnS2s<8pWnReQvRg;+R-h)RLOVm ztlq^o?27Q^`SrwZ@@)BWeBRf$SMSz0XS#)VfVTzpOBpelQwmXq(z}W7q-q+k9Ho!_ z7(xhO3X4}pPoN&09Cm->%qemmT3}*YO1jaL6HBMk>u#q=HNyeWa08~*D}ClOwjIiN z6&8~&vo=}gxbR@uJ+FS~3|BA>?k^v<IIq1H#1amBOf*Y3$E;oM)Z{=Vso(hEz-dc? zu1KufbVZhwi4v}M`|7UbV*(R0u!y;`t)LF?g5YJsF#6OL6b+k~e8JS|$-i)~k{;b! z$+;6~W$QN_<}S*e)@V$<2-es()KY$-EO-X`Wt0u5-~Pe~?;6t4WQV|*h6irSWm7r> z@jAkl|2Z%8|9tI_W~Ie(rDd_(^6}C>h^x10i*#NmB1X{hfB(qkX|`T(_^6=u#nbhk ze(fI`TWsZfeK5D@e(xy>AX{i~_4&zNhIn7-WwXexsos?Ly@a^weMZh!{i?O=o?LV= zDkw%cyWFb0wZ${30$?F|2urK-;HoO4_CpTIl~f$Y1ye+DDUz?}!Oz7g_5#dO@WKqV zRo}~Py-!EsZ@>6EUi7YQyu$D#{3RkVISjsp>-;!xyAX;~QVKB8C?Js1K(2^kcEcGN zi92@<<sdSQm+?Yp&nlZRugE$hgbQV0>Z*&?{A+Ga4WbnLD?SBE7yO+=)MTpcq(_j{ zS>az^mVC?Kz6O>5(&|H~J33mJ^ycMSZny;LvE#+I`0{`Kka3@L`%|4|>CIv5gJ50| z(2k3F7Yo)JbubkY&o3yEpq|=R*24~!2XifXt`rnuqjoJAw|<%a^mC86{l(2X>-ktS zui>uqUJTI<iQVaP`T4GyK3E>*cYn!AOpJzze?ip4H-3(wT~*5-t5*f$G4)D{_tH*> z>nkYaN{TmNpHS0dp%V`J$z`AUT)dMXdEx0Q=s3BnOu6n!;Qk0tByPpS&GFa|xguZn zBhSXnZHJys@<GfgTk5g`i|wMoEVXJj(lPTz6bT~uiS5af%g&e2T)?+2*_1hxA3npo zz8rcX_seK(NdZmd)5$!n&DLBg0?&k*A*l8A;Byyk(E;bz2l{O5)4y1<B+afNE1Ob> zu1l(~VGuEEOu`P})m<VzY$(-Lz@USlf<Vg!taUuh{@fXF+98xyz$55=pN@Z3GB5M9 z&ez09!{xpf^7|XRF<{*IT*q{;MsG9TWll2Pe((k7@}H41UF2P)>}AtzeL4u?5hwUr zXJO~yOX;(-_?z|QZm;mmYcKAAAHP9Wr>u}zqFpqR$+qVy`TXV(fW$;U{Ft5nLjU6Y z)DW{uFf39JH!>woRPW1M1p-W1q)RdOD*}@mP-n!t)v7g%wLZ$F;HUA=nS?Dr#}t8| zx-UfUOlRGEUHU9bw(1?u?c#$`LdnM!VxcuAmlOKOu`BW5Mk~)WT>PP>ts6(-bt3tq z+~D~z=J;#uqWo^Xknsqmp-j8!hHOzAN9);wJBQH+g|f74er%r)b$z*EJmL2$*R~pP zyAnu?P~oUTI+&TrZc@(>0qn7uhxcLvmV2B3rhFC)0iTt{?>r2R%Q4<u)jiNNQ&Y_7 zL6-ZZDptE)BprYd8EX|EEA=b3PLz%_)9)kWjTuJ8eVOM(JJ`79E2}ce#=dAZ7pQxJ zZI-LYoHA3qTTUbjuk)#Xl^<CDMgMLrx>JtFrEo8B6aQ@;q}BJ`9C`My<L<fn4Ub1M zjd%+)hU!?>=&y0f#G`N=s9W(*=#%jUVlm{1PXN-#&Gg5XE<{KUGcQ~F+|H-v^<__e zMtOWk`0)2T+`^mRz>GPO-y<ypiY*`tV-n!BWx+{0c!9HSR5EnH^g-*#(GZ>i9UCQx z!od!%>QrTYbn9H`Dm=gBV*c@HK((C+6T%xy<|Pz9_xnNP)ZvSEkx3woNZXx(uRc*N zDpm>gHK?IR8;Effb^vxUW1{~7X!?M?P<Skidu-AGc#t7Sk^RPw-_3pXGkr%!&u_X0 zkgK((@#BELT;e~Ot((2=D7Dr$x6`(V!vks@i)^6&hvaVoFn*Faf0TOHD-Ly90#)fW zFrRZ+h{@lCyL9Zgs#~G5I!MkZx@;&nu-Yw-6s+xT>(^&rWp=PmABb3ctnFs+SF=F{ zZF}hx6X!Bs9O>p+o%!_z-5m~%8~gAj`Br)z`m;b{KyGC^?XDCT!>Z!0L%QieYe5#Q z(&FcIZN}-1Y;E8qYyUpBLr-tu2ekyn*-81p(quZZ<`lti)}kOalO@tb{shL~{3*&@ z-uH4(D{rPxF>l4XsJFo{Y=f*H)q3y!kA&JsV=2C!XTE3Bc3;LG+kR^|^2~QAR7aK# zO}6nxka=*PxiL6xZWnePFe-~1>TM*~FAQVxy%S@<1QV<Y_?_Ev*L4$!d6LnDIGt=N zxxZ#s*3=-Hqdm$T|5R!PM^|-^EFYjx9NzSA>zOevraqpEvX)Y%kf4bs^erUCb}CrJ z)cSCI;fJ1G>R*5Mb*7f|id8P~7jIfHeQ6VvnIAIygRG#2bDya=>&)lV-se{@lv@t^ z>?Ce}r)eP+;TNbrmOQpvh`)nV);xG~z7&bJ=N#yp2TMlORTe`X8!GUBoiq(f?8xjG z7w}WcbDz0la}ExTH2(}d>G7~jKnS8i7O_8h5U1^-az^OsxquV9sc}F;)M<>rxx8Wi z>AUPR2JU+=nf+Nlfn)c3A3=ZZ4rj&PYWUcqAJ?XVU!xcXV*C?wDP;+L(7+{fuK4Nt z!}JY|es88%6}Aq9CO`8$wb52vZ5uc94SLC{*0!3pCNrZ~{JJ7FQ`+t=I~0h!ADY9y zb$c2eGTR%syDhoPM&uH~S2ITji6X$aH5+dXX=JxWlP{?z`*@dg*Nf-T33FXv`V%cT z_?^S^;`qLE^8M{|r^fp3-K*hUA9b-Yp3@#%S*my)=@84QnFAFeg}!LOB3G#EF6aDI zs))7%s9jmm50t+o%k^%NI_wWnYQUGHj1pkYLqebXJV=RiP|iyDxgAt1aT*YX89OOw z6b+hrkU~4;q1GKDN`tG<l*LG4ZJ)O5MmxA4l8AP?1ja2l5K6?aI~Bl>2tl5NcRqKR z;HYb;`}ta(#>-km%yebZE<LTyup(c~iOz(-;&|Gc!`%!q%Lv+mTaxBu?<+!b2w`|5 z3J#a5?i(Vm59w+L<J1{~XOnMm81IFYOPfHT8Fy&!vqG<*^E3>e5E7uHV!@AEk}hv_ zj$F**N<7EWS@#hLlKpZ~O>~_A<N;BF=W)Jufo9BE_oo$M2k4z@3(%vMb=s&^r=6hF zqP&WtB?3iH>j>`Ti@-AL#hcBJ$Kv(o7gBfCxttB`YFOJ$IUH?UfBRV5+@{zXFX~n! zLubz%?U6{A;*n|IQ<Sk(%jv*Y>lrjhYMcf=TJh3%yOmzk%GRnhx74N?kgkOVBuXjC zz9;aq#VMgC8E_yb!PV~16^)C^%Smh-LO3HIpe8pdjkR`x_R<CuZ_^{gH{-VN6^^RM zM4nZi?mybZI$yTBq-A1ZuGzOay)@@`TZOVurK@&lW^QzpX)nD@Uz;$}3*iHKk4o*2 zo8hY7c}<i%xKn}Gw==>uGS1OtDMi6bGxSZ-qH7hU9VnfSNC;A9N!aGH&P4QIBsR0g zjEQBoZMJ3l84-L6*ajP$djvR~Z1b*8E(2sP4NSj$8>VbgJ)6N*xJ>H_i!uQ77O$i( z=x8G%5fmx6VI!#k#Ek^Q6Ua*xwvg1s2YuV_F;{vw$s&@{MZxgd3rJ33RJKON+U2sa z?2YCrZ{rzl{^di6WRLI+5;E_r?Y-laO1t}1gv)i8-D~4%YC7k0gM-}VsSa#g=V@l| z(Oy1u{O(qNyPs=ozEz}bnbGeUr>F0m-^Q(UaI(xfwE^}wfSYv*7ECJR=i~zXVuLgz zN{FeHxP4ooeozqL++;prUy^3UMt3J4EYq3&fxf5^I|s{>(gl17e}|ghNi*X+Iic<2 zZG`89c+Ywjcs4nrGdV`Jg8(N+e(H7!3JoWahS#Cl%?cq@HT6>p3BQ^VOV{@b8o8Z~ zokezyD(g?3+D};Sdl-!}oRuesU66pXQDoWu;1Uv*GEx;2UFK>?i~w@tUPvVHw5N>D z$h~xhF-?A(PAb>rA2v^R{n`sin>`xqpKtRm`ea_p+as&AXh=M)hf2?3$5CeVw-v?l zR`}87$3M30*AKuv>XsKdk2iiS?&twb&CgtlD}S7G=-uj|TN~DZHV3);=nb7_neiaV zi@V}wspbOI>7lUT4{|F$snEz_BKA?S2sES32w#9N-raLg#7I1SAt@+rpfW|~X&045 zh)QDING@nJJ<DWtwus9WRh1nq47gZJ3hFZscUcH_SUSqR8JY`yg=9l*Hw>mt-UYdI zil4;pLfOTR-?z4&O-g5^8(d~wHlO5E7il1AZVQLz(>ti&K9i9Y(e49%UX@;|-C=M( zG<jU$KSZG4PWG0<O1karqOxfQ1z3N*F+>HU_!<N{qYPo8eFta+d;Kh%#}2O6uS=7M z?oB!vt%i@*Zn*B(=WnL6*$vR|R_f<qA5fWUH>}wyC0W!|v&ROc<+r;ns^oL3c;r6~ zRO${1p*Ll|K5WRA70QxcmOOTDtw#@sAn%*d7@MQ7)BjniH<8GL&EU+f*7f;6gMVGO zuYE;hQFnKXef8RQ%Ih`LI~pZ%@N5_rd~t444<qw}sJI=K@{wYHOD(80+Tm<!E|dnT zJnV4B9E2F~q*N_%Wg4+_x0$f2?1bb_TG+B&Io20a?}Nc49~g(BW7-7t)cnbiAsX}n z1AHYWhiJ@T-Z|~B5Gb>KhT1L0EuDH4`@aF2)qi2Sy|Wk}e1w(JzrFhE=G6YqVY!Iu zY>Tw{*Avd|SCl_+2GyL`obJMJX~SIFg1858jO7>ABv_SYBSjl^cxb-c$7ZC<QjOaz zSddf(zQN(O1@L!l@1!Q8(wGLa%5hawSTHyeQk^aTR;8l^-ob_+yzC9#?0EZC*TzGM zprIA4)3{migmr!~8P(*yo1zWAu)`b%SEAPms=mf;4z6nr!l?z$Fg2!_<SO%gH%Wo2 z>?0O4;U74gW}yQ<&rv%uHjnhL-;p%pq|71_l#=I~glj|5<-eY`@5U*~MA#AJjNczF z<gOk`bY;C2BCxU@LgWmz*t7BpN?4Ndl_MZD+m7{5)XYZwS~1Z&61KC;HFv?<dO1p1 zREbK8N*9D~{TUpr^rTsfeQM!W{H$ZP6ZpU;w*~A6=s9yhx#@n%XHdnE2R@{RjnrdA z^Re{)NKf{5*!hhfX#X5x@4VjV^So@)YkVHu^vR7lW6eL$1py_wEBRsWcK*Rf(5M2^ zQHq<Ar4$3ZwW(_Gu=1hZyn8(B{74m=MF^j!d{_QGxPk6A_-^Sj=5F}awYIPXW+a_j zERTI^^!_5|WvThTxHKn=0P9wKGy2uzYZo`;jF1RvDYepBmb6chCap95jx5!D2a9Qc z8#*P2Z>Dnz`}LI+eh->e5c{kEgbN)F5W@Qg;#?8_X(~4ivp=Mw31Kr1c2u4P9}E$c zj;tRpwA%HV8G`AS6&q}YJD0M*7)cEcL2l&7sK+QoTbu;9P1cW*^$i;?!ID}oONSQb zSXW|o{uB-eMXO-!;(<S5F`XT+XQB^M6{+-WUb-A&_L<=<?rU<%Y6FZ?m(nC5kjt9@ z5DQb;*<l-;&o_^ppW!mJqpCgRdYSuqw>C|fx@;6Sc^3rD{n9wgm<i@z8GO?QKcz{J zVH8&|NNSbo#EnbMJ~D|8@)hC~5u1tE9VjyEY5FFEA&(@?_f?F8H};^P)Loi%@xw8P zq`W!Cvr)ItF)ujVL_MfCmNC0QZC}`DqvKZv)J?2@JW1Ax)1`icY4)D1eiQ#_CzJ3< zTx9!dtM`zgThC=Q#d?n^pT$i;r`3Ez`bJtqtZU19CF<g}PFvA1pNcd^cvkHX#ART8 zYAiDnef&fz_C1B};0_r^XHYY8+NDzcelOP<oMAS^Dg;)m(VjdrMm5gl_h~O5?b291 zI!`ae_*kRfsIiH*%~)@DU-mJ%KA&|Urd%A+NM!VtSHBoSvXzWVUKHNIM*OaDws-cs zt=t?la_Yfhrma?~j!<#Na#c=3W{p-sTqeK{lbbAG5@{A%5<yuqk}F3q15;bzrQcoI zl*r^iMaZNcRBY6H9I6WUsCO!Kn}bbz>x*3vtfR<PMQ>>p#SNiWp$pyv`52K;BO9(S zIdoHQevjJQ$nT)a^pEZ2RhpmQ@u1q^F~QoLRum4Mvxrrt*=AYWgJHG9tEq^^<{C=5 zlB;hqD=V)rnRTWhOhY8MY6$ekZ%te-kRcmotSj0t|68G2$<Z^BFT^<(oAHG6_cW<O zClG}aLHtiAJM#MV(HIG7eB7)x%^(T`)x84&l}J1z!{87W{3WpUVPBK7oFjPk&US05 zo%^zjy0-eysnkx+25-&TOv_9U{tSXVZWdlHUmbH#xot_$%j=`al}MYd@<mC?jPW9| zYvJB1cxg@6WoEBbcysTNM+x=1VV(s+FeMqVZux7r*2EbDmy9}#O0`-M`0+v=R{T-S zFWPSz@lce_RBSGbhc0Sc4d*IMzgt7fg`bVe_Z==jYmbwT=RsSSh(DjXR@_@Lw^I|8 zfv^$@6(Wb3<22%I_qqg~P6Io~9-Sop0wMF;C|6*5U&HOAr@a8*m0&h7y(<g&*UCpO zJrgyw8qpT>1iep>I!Y8%q=AvcdNK_IL(==;P(3|`iHl3$BtN?K&bz*2geZ3I)C1b_ zmhiilrLh)XXLfRItQXc`IJSAVWi5W5E!MepF^J4k+P(h6XW8g)3-2LRS5^0wrV`kG zm06>TmR82y2o=xH4j)!BTkJTu;(Fv=);`ub;w{~&Qme#>{z(qBECF)21XD;4l|C0{ zzdorf%5)t+G8AaALu1n*7NMEhM+w(I>w)?^&+7ueH)-JQQm0Q?HY;$=-t+|o?zimQ zeh%>ni5LUrP9@#Ew$SwE>IxvD^H!>W@l?C=v}h^(2%K<@DJ+_`Ku+b6k@>ck_8QZO z_@c`f(3{QO5|Pu7z8~zb-}+kh3btqYa{XS`&C4h3udubbJiI>kQqFHzmRuvTL(lk& ze%`cq3byTw2UVW7oX^~Iy*K{4S-9PNm{YUsHJTb=p4q^Zt(UfQhsAJ=JI``OYw0yW zkOmc6I6iF7!|kQaac7&%G@^S`@2bOznT}EQ&xB1!Fw4G4wiUtCK?PBYEa3p1#ln=w z)PdGS(2h#QVQN`L)+ilxShdtdR7ciusLB@X7#9yIS~BKa!jAOBoHI-aGba<q>#RcT ziau2n%d%cE=62?L7isUTt@5>4+fYr>(z~#;v~DTm%la4A8<TK)n?m#r2*01Lo|OWO zy{fiTs@Nk|u#IWN*dwFt$WXB9enka6m6+}Lvv^Ijn}4TNtnq*4dhe%??!vTFP_9B& zNOE8jC<S9-!1k%AOmsS;M4ADh%^IPd1%OjnoX<swQhK%p^u11MH^zTzTJ%NP5?SBr zZrdbihQzJL^-J*R2M4&}!q^-fUw|~NT!YZC!*_o+8<)a=$^S)~KPy=Zy9aD7QS1!i zx3_gBJPos-?m{Qa>AH}6HA^bXlHfGG30kcSslh}j?M?`QT6?fcl@+pLMH%V;(P>OI zDEEyMdi?vs>vz9&P|A}kCx^@RDX3ahQ$MiU^H+KE+_p)ZZ7t-I?>)O%*<pA*l+WXJ zZt1Ytx3bb6g15f}Q+ikpVZb5lqF8^Qju+o&9=Jrl_-1ilSjV1uZp!T)G~2M7h0RRR zyq()xd);Q32z-VZH*_XyL|a^3`=D_8sk^>Ij}8t0kNn7pnfJv-_cCMLB7ZPk7n~W~ zh)!lAoYYIWK$(L`^q>1a3KMb-s0`6MbfpZ(;$g&LNjqfd*v_AI^^A^;9wUQjiia~r zUf&#e{~K@H+OCA2LfHoF)HC5n7$1Zzi$_cvA@jf%NW=hCSx-D!PmZku7mg+ViP9=` zF*jU~C4SWYFr{ZI^iUISi2X;Ecl<|ldkZ-D)lTjdFEqQhZ_;;#$>*=?<?oV=84>ZD zdPz%u?=$hUhq_$Ic4|wv&MBT+XvLV-0A(PyKO~hrPL7xp>fkTqjK%P75#uydxay{K z3C)>Kv?IDc>HJjDNHW@Es-tDpDTx~dQs)5c>v$G}Bd`wQ)2~c$`5`N-66;JZtjnP7 zt6J-`FqhVi𝔔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 IlJbcF0NhA(o&W#< diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.eot new file mode 100755 index 0000000000000000000000000000000000000000..f357617da9ae9215ccbb3418c25ae9e75ab01933 GIT binary patch literal 19761 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 VO)*^oN_49*wtYwm&+#-iu7J_?7gYcN diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.ttf new file mode 100755 index 0000000000000000000000000000000000000000..f79169d55efa7aa421c6daca7115cb3254ca1445 GIT binary patch literal 47724 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 PCHv_tMEeWBj{tuI@(y5& diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-Light.woff new file mode 100755 index 0000000000000000000000000000000000000000..5ebb3ed451834d854eee8ad284842a0160825070 GIT binary patch literal 22308 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 b_`h`nOYcS|1{VPEc_{?|00C5z@`V5Z4s}1R diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.eot new file mode 100755 index 0000000000000000000000000000000000000000..e088e1ec6db2575909d6133ef198c7f2c4350b85 GIT binary patch literal 19996 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.ttf new file mode 100755 index 0000000000000000000000000000000000000000..d841010cd106b5559c4df482b81cb976d94a5a21 GIT binary patch literal 48836 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-LightItalic.woff new file mode 100755 index 0000000000000000000000000000000000000000..23e1480f9c1662576ef2aa2b1f43f01b8d24a0ea GIT binary patch literal 22560 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 T1{VPEc_{?|00C5z@`nHbA});7 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.eot new file mode 100755 index 0000000000000000000000000000000000000000..a290e36d512ef4e5e53118e143c089f8b32d3291 GIT binary patch literal 20428 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 Gd8L5Vl{owW diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.ttf new file mode 100755 index 0000000000000000000000000000000000000000..e58c19915dcf2203d058f9ceea844f4029297136 GIT binary patch literal 51272 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 diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-Regular.woff new file mode 100755 index 0000000000000000000000000000000000000000..27951b503ed66aa40222faf9d39c9aefc59cac02 GIT binary patch literal 22980 zc${Q-V{mRwu=Nw$c5+UP6Wg|J+qP{xIpK+I+qP}n{PNy=|9w-nYId*cHQiIQr*`*t zl@$>I00Dl6`Tzjszj;LLf9?N&h=?dj0{}oJKaaTo!NNA~Q&dP;<cAyhv8jJR2TTJz zCn_ha_`}@*0N`5y0CC0f03oEPqOt%0067By07L)qs8WZ{X|js63;+Q1#*a?p2YR-~ z;T?w7`gQ;S4BL-B><4=o5RN8>E>4610Bp~XkID}^SWzG+P3%mq0RT8m001oE$KNg? zIZoYF-|<I_T=C-r`F}t(wQ@K4;Tiw{9(Dl0k62jXAF`RTz7YT*_mdxh=?5&J+7TvZ zKO_JkPyA#5!~zgQh=6RHSv$G?a6&&hvj6}fWqk-l<W{zZKYof{Ke<i(U<Hhn_{v(} z?I*6X*#Bt>f!TlsZS<{;e>k%rpVl93D;#kgubr)<69Az469ee(XU(HEP`d^@2jd^D z`p-T91wUw1SmkMSH8%LkS-s=O2LBItVM;%H{NGcV$s$|-Zyv=S!ucP&r2yP*%}~!s zPj3gv0FKbaKu=%Ks03usBSeI-I(!!^?lWr_O%0rQ8UWBa1OvFOO=_ImDhZ?VTIc2| z$3ZLM44{|SrThxENS=H1Bb>#IeuKc|-NAsPA3_*HAjQ_@p9zuxHct#dGax}Vh#z99 zT%c|+pBzhYu|Acgw6;>K3o^jTs2JYnx_Y|0+}dof-s4W+OmAg$JnER9_+yMH55Fl( zl63oobA4Gv(g4XlAhjnwq}jfO=3S`amP*l`DrX{}im9&F>XPB20A{jKn*+i%B3%NP z&m*>~)z9h{u)Z?BxzRh%)sNpb`mL9x8>L4}@(5T?(<+aZ&3kc&^){6^X+ckGYfUbm zJ!_sg6SPGq`3!69Ujve3BYDze<k8DUVjb#o=hi0o5hjvVz{ZCcIotPr^$6Npm7_^R zox-Y3aEJSX%F5maYR6l>UZkHo4{=(l?jHV^@+6v04^D&OfY+SbHmMaJ_>IajzF+i} zXy*CSP$8;@q6G;cH18VQq)51d)2IoZX2)F~1mPlf8NyFmHFC-f&6*v>a97v`N+m;? zB^CVcw*pq_Wt5?&roTM2Tyo#w6t#A6IoX)n*$kXHoNdrM-<Q!o-}Nb9>WAkFqqor` z=+R`|fo)E!Tp)&tjgtS(wY#zG&~t$F!9~3vt)=K*P{WS2mwtm7Q}Thh@aZ4+isl>A za&(CF&`H@TN7H;y|CRJDat<N1ATKl}(}QmlQ8Ps&xc*uOQenD4zBLWElhyP3&x*j0 zdEr(^y;{0nw#4PA|CKJkqcE*om^#hR7c-tAU1EPL12+Bc71RXcmprj!f_bGN|GU?( z!bU}n=b>Njn4IH5%TOBJiG750f|0?x8PO@zm`G&$Ta6i&w1W;<M~Q7NV2}1Z`n$#$ zx+359>L@ehdtnRb8V3daC5r`40>hghFa*2aHMIpd2*)dACaZeUn1`<tPQ2rjH+pk0 zHJWb6Ms+$}r%qWli0|BFLG6}PC~L+88vV#4<VjwrWO?V0OJ3q4Mg+g^E2wpZF%Fh1 ze*qH+zQXV{K*)E1C}g94sb8de&(_zxwxJmoPmatgeH}&SbRXU3o+%J}_P;4|xZY4r z2CzPnckZ%CFP5;a0!Uvojxs(+4Y`OoAcVdw2O8Zz{l@g2J9E0595Q_|7!u<(`9PLO zw>sJCor4ZeQ@BAs*nL5(mistF7c*Nf7}2wxS90#)X&BZ|#8(7>=|!_Jj^~+Pg>={I zpNT9#c5QpAUAA)2t@08va+rrn52!Kp;C_@1vuE&@i;x{dHggk)o$$kWz`7O*eNOgU zctbqtg1&otSCs>I8%i4u#I<u2pPP`|M~5LLh7ih27*$X)^wLw~?=tzeV(!ggoVK2O z?9OB-C;=&6&EOmh`vYWZ&Sv~<3FK2W4ctoGGS6`^H%vRDX^h%zl5JMk16mIOo$!<A z>@gcXrUXFyZurror7VJ>HP7^DIo87-kCT>)V+Tyocx5gwym7yxD)+uZ*Rzl1%BDy0 zV2p~UR*QGFI~`x4m-m_G{J2iQ>6*o=XCwbkfi|oJvwi&5)sZvgxJYY;h)-nItba>7 zjo`iL_{hFD>w&0jwP=u<>y5w|(Eewi63%fa^q|>G-mIUZ2;&<I+d7S9tLRKH(!Gny z694zT3+%?*KFfXZQ}O|pFDHIYAsJ}Y@yQA{i*oL%tbMD69`yGd`+3;Z)XOQ;_NvH- zvZ0h`zYacV%VoY8*I%AHTJYMb0GTU@xe{xb^UlXpR%5Eh@t0NH=MMfiUaofA->T zgs#)pc}xgyjO3Aj<Xf-Y5t-xFd7~6WGUdYlLS^1pT&N?^@uoM3eMRI*yN<Z<&=efj zr3kwgR1_+Y%-x$aSLPL$_$_7Jx%S>VD@9!+AN1moe6!A(tkP~(2%bY3J!zH%G%1i+ z7f>!t+(+WcYx>uX&ON97>onV{pjL-PeDs0?tJ5|LK)xsx3cR(NVIn6?f`(HrQ57$P zF}U(Z$;Fi`;?*X{YDgoUvHkGeBT`?dCLy$g=1G~~&to2AZo~ncsYfY<q17F}4Y|hH zls1vO3S>wUO}FO~v_AM{wX0X(h8=YKp=rPy-_@haRY*b|@_#)GfGh>t{?os|G{X4G ziBnE+Tq>r6trL7_5p;nJa{03uSN?1hvWGZvs%)-iOaGKdsC(wd;^AO8CNrXaA`}0m zg>s}1noY%IH0P}`?$C1&Yv+x{<iJjCMo(=<LgW8g0lvgMlZHF84ki)NJFm4OO>vaE z3z{X$X+}oJB}>~Ep_`vdzlY|5$FKsnB5@5uc?!aZ<}Ib$gZ&I}kz?Lr=im#aYY&Oh zbKz#5vs@73HFTl+l(0?6oa$wKH%r=jMHmWk?F9UM-=dSIC2;u>hq}+MHZh@osUORd zQc6Pd3#G&*BIMSD1sDZhIUCYJoro-;#RmzE^pf3NfP~5JfE=U=ju0IrNq%wpALK7G z*C+lRjhWJKH;vHsesq>y3;@9H6RqV&PuXAy(&6?V{<{DLgRAe_R2OWxeKUqY*s|(A zF|a6ZZVUuRksyDMbk8>0>?1F_!K`-+rnx8>yIucqigNtOC9;@d<j6${N68+<eh}Z{ zev`nURB$XSmsv1<R9$||(pe^WO#jNKl`=A!baXV5nS5?3dquxawy02a|HZ>JgqZi2 zt>Q-F#;9`iEH%GRfRbFeRfC`CFg0JR@>ZcMqSW(W$vZoxiwCQI*=ck2E;r9kT=xfF z(N=ya_bGVnE8kt87QX&p^Suld1y97;F+_=t)#nOm@vTWCOG5S-(a};9+@?#pZyTR@ zMkdn*dK&hsw|uVSdaGc>M1@qhslAu7f>V;m3pk+!>AlYC_KbpyRnl)xP0m;3&kUY+ z;=laFvqkg9I=$Ac^QD*vujV2|N0D6ZR`oNEjE@((`|RYq?Bq8c3Gyvl_2VhGxJF4u zj-3T;7L0;dU=p6DH74DTckFOqtKa+jJc*abycIQm#vdu(P~B{XSiJ7q$UgiYYV^9t zjS)zH#U>L^@2%Fjlf=2Da?rNL2|M~ox5SO`E2+qU#NPjV7Yy|bHpbZe{geHJ%@Gta zKtKc$f=oKb^#)GHdwK?X#)e??)zInaIuZ2TZZd(O9ULPfv2ZcneCz2VKbH;l^sY>l z<n{Ej5E2Z%CYW%<DClYc0DgKT*#BKyPtU|p4+~rb9I*xDfIi@r8WzH@0X`5oZV<%i zmSKVZ!xYw}LXTs}Nz`AGUx;6VUxr_tUz%UHSAs}KKRQ3*EN7eg`#W%Q7wk;42NP6z zGM6xyFpm&K*&0f95>jdM<$L{`>>J^m_T&0JcK7-mf(#$m$8M+h3&Ios!mH-CHv)nN zf%=M|>oMXHYav(&M1%#r1zm)+gjXJwj;^MruGZ1c!T$c{?iL0T8Y(g@B3x2TLVSE= zY?O+elA^q%tklxX!u<T?>=XwR8!Iy{BVAKXLw$W^ZIzRagT1|_t<}@b!~Ol`?G*wP z94s^_Bv@2PM0j{$XpoGUl)k~$=}{`3-FI~F-*{@JTBFJ1nlsLl?M8#~`qCw*>&0fh zEw7-xg~n3nm~b$=?07vEhbdzc9i5SqpLVL|c#VUrq6AM^wyG;{YpeCp?(gNQ?Jmdt zqdy^nqF8^qydFNl1Q#pYVJkanyf;xuWzKR~vh~k4+#NAv@MwW8%D@c(A`ua>|D6LN z@(WNNV<6+a6*&0NFf8mhcUt@RroP70H_ZO~x9-=vpWBE<nn^*Kfd;$^#1SJXAdf1L zDiIq5L~ZNj8w2)JappmmzfKew5-pt)C{myO^1t(~R55p*7eU2y7tac!CV`=`&>t8u zuMr`&>h*)-uQMdn&Z<n#jYQ=<?Ya%$-qF1`T5~*M_0hP-p(T!MIJV13EO0%ZT%1@p zM%GAJfjN&)%A_4!SR#$S;DS00ksg=#BIooZGL9JC29rmuOj&Ej3l$RjCD&M0BZT;l zubyG#bs{e^-c+b6Jx0TQ`bTr0zf*bJ2b*K8mNT!=gwe^2yN*N|Q#oI(h+AQ<$hhQ< zN}Q^ryKh2uQm!vd=9hT~*3gXD7LIAdm>F}^K6!*y-3GY=amFq`s(aER^6^0g6zmwp zWZd0YG16iGM_9#5L6%C5WYhdd7p;4-D?2X*!Lnu&4f_m4-EU4dPVG^Q-6a)F)=MK! zXyu^I$81DR7S6@))q;+q*`CV?DO#rAYLvP}17ot}^}b>%Fwcrz2eTz9RtG{e9_c9W z39`A5Yz7iqj3Vexu1*4=&fN#Ff!sy05WXF*5r=(20Q}*)EqN%iJ|T$}T<HXsC|ou1 z)qDwyPAXCv_iXgrlp5W3mxq6hYitYInA1yw!zwaL4qO=v=A??nE(-T%5`p9-*--fR z=YX+Tvjo+3HEDyxS*DnDdZPF+KA7h@CB$(VYIA7*dovN+s}S=l?MQU<J3j8`6YkDd zG@Gl3q$ZHhirJjS(lq#|J|_<jLaJNywZmV+r*EfNK2m%9OTY~AG%Wo|fe^Nz@N?tK zDY(JQ;44>`_f#d`OF}n=K<_v+__B)>P*TBZ%3&&e29=iTDWi)O=%phIu7VjVT@~}7 z5e`~;TV7cEZ`~#))bu1?-6+MTqFNqDYpIAu>@O_m9!%AWk%z#06L(oM_0-$T<}rs5 z9Fz52)$>RxO){eDJ|*+O<FQU0Lw5n_Os8FeL>T%bV7P?(kdhD~H65UWYLu9L4oD$2 z)P0C4l5|0b!#`kv)pu7PFDorh7;0p!g^dehqoWs%)jG;|U{2Pe%+qF~Y$TF}YL=jk zFkS3skfX(S@5fbxDU>vttj0VZ6D@G?I*&+Ujn1apQG0Ag5Pi>bqc|Vz%L(|luq;c^ zsXf{qRepgJlx;#$&Q#)RD;hs8!`J?%rKGF?dxI+!phh)TXK7(X>J!bD5oDejBQjwz z!C!l9GoGB@{mR57f+_L&z=4hiyW%gdD6DX?TRJ<pR=>*TXU~F4DNM_B_oniSk5@PE z9-%g#7Ue-`0T%hkVAbfq1if{Um=-E!n_wEyQb~?OY;9#4FaRFo-qZ0a1Dr_bya?`4 zY}XI|5kS|x(}D6wzEeI$@cGx1JF3E0rK0^WPbDUioz;uznq^m_!)7*c<ctpmUhuMr z8KtNUXftdIR;57NeXC6tB14EbB(!#Yb(Py)!^n4u(I!{{9)*Fk*;!djT6r>M8(zkU z@n@Os0KK@3wC+yZHa4+C?MkEcf+qh`&FHaG%gMakGC}A2lD94Ur|>LhY1T~?gwAU7 z#mgOoKj>=jED+`ti7;nxHGSZ-hkFX-j|>@wt{Wh*Ft8`C<by-s%HCEy)5&FhCu|9} zWM}Iqj&$H(5EtDAZ$KyS^iHkdsmGp^;j*l6c1=>MvyqRA4>)O!OB>YMAU0-gK(}!P zDxzA4;9ZJ=Y}|8NF%O70wO7!$06ml*gPZUx4Uu~azge##T!J0PBRVsN&|Y*$Oe;oH zIK5DISeNvEy;yeGF1;y^p416_M21lQ0bFp|G!y`rF??WkTK|sa5#37&`!i72kDbO2 zi+n`4vg~Aud4x`T@<(nxmvY9xl#KdH-@c@j!N_+QrvGb;(BxYWQPFq7$y4kz93$kd zo?q&7kg({h>~t#b4Tl!?(KRsbEtFr%yGS?ckRec4q)RdwWb6-1&i(ViJA{BA-{AlJ z0Rj5{1|YbtHFiR{87?-GcRcgVv0F4P8jGh?{9zq!ia5M7jOG4QSFE<rGPr*Vq6lI{ zo<|at(SxVAqmZDL5Vt|#upLND=O1UM2)Uv3hZZUh;0{IX?%q1u9_*m&z<AgF#B*G- zQfE5y{YjTX@|vZ+q~ZD42>)v&7SZMx0wFvU`Im5%hG#c%iOU!Lt+39g$8{<ju<a}c z`&(m%&nJoh_G9W6t^S+$+ySd_Vo@%ErSEee%z?in#HSHHQGiG4wqR@mg#HAj673RE zngO~#7kvmDd=(+F=ujnTqWr&7>nYGyVkn`x(wLx4lg{$(mJ_Sn_q{ID8`|m1n{_;% zoPL?%i=LbwpgZ<Le$oT9O;R|2BvGi4+GF;pTPEygjS4F<Njdzfybg9Wm-b&aZqA}w zFDSefO)Z-#%Z0j5Rvi2o70c0Qvn?&NYKA*X%D7RLeUTc}kSK<W9{DQw^&D`!uch=H zmgv#Ti;IiPi=Nyzsr5@hk<Dq+cfKNtL-Q91CIP@7MhO>W6g31yV!rt|WE*qKuKCT~ z*9P<Pc?CoJou8e<p6_ol3%KiceJ}n;dHaI0Jg-J?!3*jyw2uNDpM5X@QFvw=-+&jk zAm9?D#=LHnZ1gB`F7#+N%S#r2ReSKD&osdevnTt@6!+N}NK!JThs;D|c*L<hd)KGi zvPIwQKVOX|*`CX7*82MVOoVMsexrs8mbjB=PQ)3toOAYQgufDH)-K?QkQ?3EGm|l_ zQcydthgYCgl?=5UJ&L?P#0ndE4?3(&x04gY|GqAL#rNzMEW<y+Jsoy$Z?DsL`104A z>aE?xOsNr^!Aj#PU2hn#Y_Q5b)>E2V5%ahU)caZ22EEegL+YZMvwZU{1}~KOyyD$4 z=i=d&iO8S|*jFU_p$KycSm4w23Ts4bv_n7zNXZzA6%gH1N{OY&xt;9Z9X<XDg*oLe zb1zglRC+)kf6wf_^)W@%RMnoe_apXzDRUYI7M62%Ok_5KOP5-TlZP;hSlN}Fn;!<V zpVRsXL&iH*BF5ZFZhpW!x>j51vUeKB;J7Kkn%J`CeIE02Rjv4klH<R<&UrhfjU(!M zjlY>jK!WgBGmdwstG8)jM=zg-m#ka=0T*}!7q9^;hwGd-9l?AVt?%2}T%|I7%7&Iw zx&nlwmu2W770nJmX?O}b7G{s}4I5~($_xw6UO{LuiL}(24n&Q5aRE6bcsrCE50UW% z@mro}q$i1@rz``~C3JH(-u@;)J9|VZKmMl_QNKhlFCdWABZh$Y%q)(*e%UFCKlnQf zx30B0IoYLF()!P)rjsK6`*L6=jtbvg+NR0|b7KZM%B4l4=$Sgo24NZwmL}>Uv`s_% zDaFXq%dYAw;Y#UpCX6=w$;#{;ueZ7Z{@uec&kS5%N79|7E%8>O*lbyEjQsRDirh~c zJA6pTC;{14spVIDw{a`XXUYdF8|_ExBIa<$?o5#)mMC-9!uF6&H+PB*DFM9Cz3lh1 zrhjDD+q>xsH)+c;gk3ED)hwZhY|<r8O!wp(fn>45=?We#C<6C=uc9tD?#ofm7wj|W zO*9+OIa40dtO3K4k}B2%w!dmQn}Re(wl^10+C0Vq#9#`Nd<rid!7O#QtHEx#hPxmZ zQAW54?rdS4JtREQ+hmK!sLxHVw>aK$DlP;9N6JlfDm+u6!t9qM?PY9{0vrf(2bUSG zPr6h8+HV8IQnrc=@LzyG2(UItC4o~_eJIG5$IMkGxD8<Qy-vuO8pz!r(N(rRyjicO zvWm1_V#DVeUvwV0m!cw+rJ&%xE6CVIk$**_E&^oQj$rNh0g53BD8CDb_w#BPCrX`I zTst?>s;pPf%2<mm!;1%($txElb@~=pfXRwg8Y+W=!}))~QuQx>KiSg4^}0%-_iKO} z<<%sj13K3F{xr_Jqqv+~+Y^jvWygLc9Py9)_P`y`r;#OiZ;Z|mN&;NW8tkBWfO6pf za1l+OL24v$bNgP@CfF*bX9PKJPT8IF!x><Xnnuu*fNI6k0RJ|v9IOCIkKxx+%Utwl z6MsxJ>XY0N5=Q=HLmLK?aABi&${pT6Wv63ui~Hhnn?%#>*rItDoN>Kbcr1p0c*OJ5 zg?J}*NX_oD^1#+v;jy~O2Vb4~-K++qwzFbRZX?VA_mvA3Mi#!<`a8UvfUFjQ_#5a- zdOo@bAGbt2N(Bot)Sr}1z*ZF#+%7@goKUmG-<%+tZF9O7L{@%04TSauYRnb4>p^VX zY5AYv=t!uD>&DAWznhbp$8>Fa(bkvssnF5RUR5zK_5A)F=L>gQGmteZYm2r>j3OBQ zu7wgns4p5=1~Tp#S+2+fzjUz%HbPa$zqEPkv?i?#4jZ3&2i(6GZ7L4~{WrZ6ku_~c zw9AO(190<Rt<Cu2m&^6m)$K-~Qmo82Hy7(~{E;EkFOzNO`|Nb@Wt_Kl1vqP*HqZ83 z;whs!Z%xHem*WtY^M(3-Mp1wkkDoeok0wN$ZaXGxkAO0!j)*%mkPrM#e>;#9^vk1% zcXHR55kqEFzz~$1*!w)2xx`w4JW43R^kH{&XDaodBcJaP$S>R1)?51y#&5ddS;U!C zm?Qf<{@U$;@V2&yDIox-1t2!VKQuF$*Z|AzLM5$YD0g3ZBv>2S%})}I$lz}Mg9VG4 z?Wt$!VB}waJ!Aj+Adi>sSNhh!*K%71+|dcyXE+=Dn%#bs?(<Hk>n|#!jA!7jGl1jo zy*PeZHso65<P5niAWcQu-laoFLcQd&8p>*j0=b^~9qW?DWu;#Kl746GSH42Uq$ocy z2oR-wHq`tG$~`Q(P(_>_H7A|=&$(#nO~y}0`HPMc)927CUX~_jmlki&Y&z?c4adWw z!S^TYQ-Uq0(=hRM!oO@S`)%Q^G0`aLD+5p>u8%i&nl37QmdE}htKvlUBrm|=BmS^b z;I+J$&7V$WRb$(+x`di!ZF->;E8SR6wu1UeLiV-nCVTw*q4Ln}D)g&VwYg@*2~niy z+<ywNV{#=DO6;jKfsutB?$m)N`z5KJhV5}HNeR_%D|uU-hih6cQ;KaiS=c)Ebt|JO zbgO*z)>17RA~?apH?R2ZL-lQK^okcd8g1A6`kJ~bP0pwM&2bOPvTNIfY;E)Z994|@ z3Q93Qu(MCCF2^Awao=5zUng+fxr4>>aOcJa(g5s%mi*e3__QsUSrHbLeO@Bm8q_Vy z{Q98Xj8H{LewBdns}JAx@s!c0=C+$?HtbV|@Y(YOWrupY=z4z&_rq2jUUF)EJRHrQ zs&f<Cjg#O^!1}LOUvGF0p6qR3^`qd`h9};iMx%he!+hhr`9vG|%AZUpt?8mi2G>&6 zQv->m6UTk+makraJOyYG60Y0u#rCgg)TH=PW%v>8&Yn>Ugs94bcvzPVmP!5IUsU*Y zPkec*Vsdj!_-64Nw>n;kpi6`0>u!0ViKBBUMq>&@mr3HzgLC9uKUeW<9Cwk~fDNxn zS^vYq2bDLw8%wwK^Z0ZbyvqT7>71W;h<5*);hlwWNpW;YKkm#=)+XZ*YDwmArKWmk zhPn^}ck-8B)4A(^sN8vMwDXZQ9B_)|tAnZsw*HZdyw|+%$^Og4YU!!l{jt67b_IkH z5k#)i%!t0>e^f#cRBO^#`vFNl%2>8V2Uk1BA6~p?HfGj#&(4>pvQ}NzyJFjFIqMsH z&&@A6PtEQqUAfJpt8ss?*jnh4HZ~S6%j-Ld3}bV5?o>y+<1FQ&!%uW-%j&B__MJyT zX94<>PofjKBwUbKaI#N?(fEPTt%|i|q{Dtk#Y1sF6=XOTUJ1}70F6I5_@BgcWs3*@ zgKHr_(Wy)%o`I*OqaoYLV~a)Q5oKqt2t`&|0&#M_f+Dc_;NZN0t5E_jH}Pn`Ht;q7 zehewN-7YB2=G{TJ&zWH?0lv8z*$Oub!K#agsF$Ghq8*04=5HKc_sdgN9?!?WVE0>! zj-UA2ZTcT}Ci{u3JP+^H8%}!}O8^4%Z62SSzbSmaU)yjR#h&j|<=<DP&APAYGRr-& z&D%%e-gfz&IlC$_w9UZPsC;wGk#HKY7W*aGEg+BB7bXUxE+}S9*x4dvr7?|!yZJsq z7u1pXiJGp@2RSFJ(Qu(n+djkTj0e3R;9lguy!DYRy)PhiKFoC>y7=f2jfC@bHw3@| zL4JhsXl3E_()@8fMvd@>aEk!k$HvE=fD4iKh+GS;O0X3cgT!v3C6H}#;f&g7d*wH9 z-OO*(4K`1`7H)3m6QQE!>iry_8E&SPdyu=GJtJG0V)e7lHU!<p_LXOeublV!OTq5o zNriM*m>UV4<R_I#5xHbWuQDREMeammSL+qhQcom92sCS0ci37#X|Hwd?bj)7gv+&) z)phretM*vetH-D-dM}h_@B4z;qnP(^JKr{vH~A0{=mJfE$O0KEN@fJ1yrJ+YXxvEy zCRTYPX*LvJUN1Jj3AlH)QW%RNip<B`^0V*f`EyR&WeU|5F#?b0+f=o57Q6l3L@Tej zY0lJOua?IGxd?!l5J@T0DYMR0vQh=LH$R;Z$R_cdOp7NnXTlfydc+t0ngl_ngW-04 z&c2bH{OzQr#A~B3j*vK;&@~x}H(OD}(6E-7G<BP_7zjg#IKms-zeKzeEa^`Xvi}`X zv}Qm`fP_$|DuYGV3PpuKc8%Ky3*U71G_UV*F+A)mytCqik&CBKASZ&dHwsyoy|kg? z-WM;|%tfp5-Zm{w-z6nDYxjxp+^t$6smrbx>MoetZ6<*6CWBb@@J{v6;iU*y=D-(J zbYHba2Oq&Z;}xC6vk363Xc)vRA!q7v=lVf|`((Dc|DDpppAKk>Tu}v*-T0Y<=As>1 zwN!5#UKlM%S?#qr7M|Hu<bBAo7*-KPP!Z(ipV!AtZC}^WN|#r@Xf@C#%0qy>o<Cj3 zg$7+FG157LLqN0*3>iHZr;`nc6_p3ux90}KtK`bc_I~h3b29xc6<txr+U4AqU(E3s z6KyVqAA%2wuRFYJ9K<v?Y4ss<%QT;U1qe5e&_;<w2z~sr0ShBEFs37ajKFGi;z8qv zra!A=YWK@@YT`}n^2&6eJDyK<Si52rODP_Vq<W`deTSfwXwbiSMa?^cvB{lt#{rKk zgqp5zVvWL;z-_R#1>j<G_VRfWQ?$6eWqJI(`crE^WSXTrVTA^qNNn1}`{k|A1x45G z$A@`WyzbYdeKMQ2(HmSFkE_;?@oDJ|-?O{-tM-qDPcZ!1i6_1MH)uJ0FA6MKhWa=- zr0iM^)49w5pQD332)II;?I=cu%pefc6~{XeNm<?{M*7)%O!u2QQQAyQZuSh(yDy)? zCsi;F;4B`P6-<quAbtqB-vxw7q01`{(#&eTF&47XqWOJwG>WX?R+(+gDz@ImE8H!o zJ7&jMSA$&)h!<EgQN*Ocp=$^xvgmw7{l9vr0^vvoROHf>+>%m_m-6#x(cw*`8yB^# z%WGey7uXD)aGAi+u#l5?1&}=nI+671&+9(-?ZL4tCcnwtZ(d?n13zX~MrVyhB$0Z2 z@lFJYD9J8ZEXsl6DWT&kgfTXO;mfglkot(6)4kDE8I}F81Q&?q<WXqu(g&Z?Et_PT zq9&|x%wI>kJdaTJRUc#?C-5@PTj%U<d#>W$Y9_5+MOm7p3Dy>y{}nT1Hoy1JZ_cNR zImuY7U?d*e)TVG~s-|&~rjJM`0fFBRZN%Q@_yV&`gL40_souA<jdrMZGDD+{tS~P3 zLK>34U@+~qJ=}g*v$<aFWbe;j4p4T#t%{`G3cjAyb;8q*&DRv;fuRQDh$ys3VFSYD z@CdnG486O)_*$%X>DPY;M>_pn%;meFy#eu;^96e3Oa80n;Y8w-3lSIwFZ9}b+`R4m z{AB9-x7GLHtKAiOnY{*l`ZK6uh5&OJaNbrma=(!5_E&uul8)MB-{GL`llSu!sKVp9 z=YE_02EJ<i8+&>${-a$j=Nnt$$rCAYAAk0ryd+OX9bV=kUS=W9zIW?K&Qr(B-rtX$ zS{PrpZ|;rwZkaw~oG9h-Db5jdAUSoX)e$k8HY?Pp#jts)>tP>-%<93^W81;*fE-KF zFnxoA4Nj|#kVB#e(kxq`M-zhBz%nZ;q`AAe%u>?{U<^gsS%cAL7*n)g4xpvB{YhT; z<+`0;Z>FuE>5gs5Urj9swgvvE9;ozF2AC?Mv>g1r_*%IHI|5S!=2nyNf6QO^2|T~d zNVa*FLydGV5Z}JW8dF{bB$g;!6VN5QXtXUkponumc&H!Cr%gsYu`t&Iif_o!)<9Q) zfqFVYvkQAj_DP`>)AF|y268TbF4LE2+YY|ym+!tbByEo77t<(pciZ1@1-KT%bjRt$ zt4%B@7Cvv=gz8>y(%QBiH>OdWZL_<{Dp8jBl=-OPM*j(4_;0E*u*`Gz+BJia?B!NC zz218vc+!P_<Bp6QrO=e9M0%jWuclumh+5uQkq9%Es-PHCoO@t!B7txssr6g?ux$ao za^!joVt;A_N-xM8VOoVqE5(A2>%8AtaJlHbN-SFpO$gbX)vs=NZEbC~{;t&!)$6+$ zFt9Q$FVzw?8cY89j@-iQ<gUEMSCd0`OO4Mq#dz}-svIvVhR#5Cw5NJd(4tLOO$8e` zQ`PDF>0;=cjbtkQOgH1FI3d9zSy1WJ^{R7;C48htZwHeG0~#?qm)jcMt=5}rk1Cg} zT=c%LsQ&13%=iXYAKvt141T;$`&ra;-PcOewmaj@$WhIVO7fAJP{v9Pp}CAtK)3%Z z(vVFSVq_V2k(7r9k}VdAydIHe#bakr3zL<;TCvx)G?=kFo|d(ZMCjQ7xwTIC_~+Qw zZ^eP}mQd1|=1;9`0k-9gjJse#iex(EX0n_-UuZkX92IgBOa<xiSv$oG8|)rkJEUK3 zkELyrD<uAvDwj_o{;6WV%GGmi^o~HS?ejYK<$rNbqiNMtIa%NrX5Fmgayo26$MYPH zzHRxnB8)(wvctCk`!u28A2>ljuL2jPD2<M`XjL>JQLE<n%0?rjrkJclRzktR^ba2d z;Yo20V5GKE28zq$u}%XKtCiTT(3!Tmg_3czdpcT+YufS&g7I@T#m7$+bl*X%&bOOY zV?eMdSPj0$3s;IDBDegY8viO$t}YHUZu%))CFSF)1@IT)x0a5H2?_|0-RS8(>W<i~ zCg5Gzmbkw6&vts=7KiqswAy)Edvb9R_vT}C!`0a3L%yY}T|TNg_mq*-BM0k(Ax=Bq zE9K+>8S08?sLZ8-0;aV5xqj6ssbO{ER{Ay`0uOi25K;89ZT^V@=20EMt6et(0LOtI z6{<k-$)Q!rI-H12L}jQ6QyN^!+It!jJKFVkcs6Ax%y;=;h@$VXX*M@R9X4^RZm+O2 zanK{1x4$+wPedJO%3k!7Uwzl|y4ZP~6G4TlySal*rKPWVDJ!ImK!g7-Z|3jGHb6#O z4UcYHwtk7WGHtW3|D9Q>DaGUW?ukP4_}UEuzGv&p$1%PD^Puj)d4e_3rlh}G$|@f2 zVj*?sW1wU_b55)n!T=wMdsKgio_1Eac;2|yp`*wmiOnUgW1D!qQT{^n(?*b`dLG{5 zmFQlS_GLkrATeP%k4nKZD+M3<YaBr`=2W258R2?_GL_4*P^p@1Qr_#X&!1Jr24&Qt z1RJXfYClfW40v6AN7+#JJ>rp43FPb6xv~#t6yfL?-;0oBE+?Sga7uoAOR{8cf8I^A zY=hH*2JbQ(OF3P)HGOmfG9Z#IM{(?A&Std<ODmWK!VBx<J2km!Z-Uxzm4lM%q{!|C z=cwEWRsQBsboSIeZJuw4g=-T4zd@;$L{%B05~IkKMa5lEYZ(5vHNp@uT)GgjTS%GA zXm0)&`tWoao_V|Sg>L($_<#|I;bUp2Et*fXV4n(my^IyxaaAETG-on-qr%Y`EJW;H z>=J&bGS}KM`O`c&!&u!=o#V$Y*Jqa&O}cn+AtUT;brp8__`Z`Fed&N%V)zv-F{&5d z+(W0tUo5N0r%xeE*?2yN;OKM`efOoWt};4?wCi-<PpPsJybsJ8DlT||WgACf>RV9? z=Abn;!sjW4c%(_~V+Q_#s+q;J8G_FG2)ngi-N-KW$~*ih(C*<&Qb-eBGRaFoO@eHU zDELxiCs!gyJ&H)$vAQ?daIT@vbe<;lgVKRca7w!CsSHW~U~spiM(%!eZMFvJW8Z&n z5P+mLP{;22f~1|0q_I^}RvkFGL5CH40F*mHSL9==JnP#aQHCT>lFcSzXpRXkfx!*v zN*VNo5|1WC0?Wt#?Z)GuQ%LoZNCXQWX)4KqN^><eS~aRQHANjcm{Z~)*H>9J(W2ac zZ(xAXSoT|Yw=?5oak>H^rFnR<K16HOS-l1UV|a%u3Q_$7C-E8zios6cH9|K^M7WH< zeY@>g^irgV#v-lo#Bur&=>EY)E)Mmeqxe|Pf1oad)A9SvT=IahLCSg0nP~5Br>XC5 zmo#ch5#oWc<)&oEI5_c4C3CWw<!@B;GNC(9HM%@JO;0{wkK(OkN?lo87ZE(+kaBXt z-PX`r**}qZG+9YKGQV^CL|W33$Vhr=LY$Y8h4K|+A$roJ4XZ@CVaJkgKrt(tDkX6A z-<$EvEt#??^!_s*Wn0j!)-R7Lly;bdsc~U{y32NgAZPP@=CJ%UY2Tj7?(GyL_&kyO zB69|^H0`A3)Pt)I)GO$i5KF5gyJv8>k-JA9L(^_A%Qc$i-4AAXY?|}7+!Sz6CoxlT zQ_nafNT3aQYmgS-G2X%(g{VtsGB)e?e*tkL{jS^+Qsmx(usqfS`G#5Q>ce1coWtnX z!dv0|+^o#;F~jao?uPZvy3Br)`hwW#Uc+E?#@CfHeOj}uN3h~>&UV`@m3}FBE!ST- zzX?5!W%}a-H>7<TnXYje84lem#dJF2N9|*MHN|O~<70JIlzD{j`Stq!PAkj(NNbgi zdy?mrBZ3_|1C>U#PSFfN%-$aYF|qV(1y94KC**W<BbqUx<J1BQy!Lc@|DLs*d4JT8 z-eipN6$P@tN+%IG7V91FryIuZN-ur%W_;QGFs~Tz4vjt9?j5r6GAp6_ZnnBS`zdi) zUb*h_RB8t)4rvfGo&r-N+Bl<UCM5sFkov9|-OC%!0kxSCfH!3pm6?|nK&+?j*`W1g z)vS5mtb2!7te-lWqIi2>nQ`GeKXYeZzQ(g=gn9U`WKIqQ@ZvXVg!<x!G3xFR%tTLw zqLe2wDib+Ni)S;C*iIO!9VP8`tDC%wM?%3xQjf*w{YzN*Z9#OOR;%Q8E%->9**z*- zZ|0|8cWJb;m0_QuF3NYq(!|PRrtqY&vRR+*#<wO;moobF6=!`T%B|jn&-%sX6MeV_ z*dm`Up^ywT;53r^E3i-GNj?F58e{PXGt7}1E<)0+)d<+PNl|-WIyk^S^xqVV-l-B! zXK8dLykoX?92Yq;+3>H~si_lQ=x_?R<wdMy2dtr)f}Uaa+=miOO2b)9Hw=_|NPpoG z#?-WowgGB!7<~;e0?g7=R{V!~*udf&+It>`X@kQE?k}hhWbxmecXDI)?N;dZwMAoq z1BAVB@G~Igd8=P+P>}QFnRu&~>FYF;49d{#lcXtc=KFkB>1DUNE<QUToSx{OC~$jx zhWVbS<^9~;{qL@rJWamW!(~IF%&Tspq`sWnSko5hHy1;n$}eV%Jm8k&ck3^-dVxi= z4K1x>e2C#oC_0-<d`w<c=uDJs`(ni;l*|e=znJGBEu_U&kZSDp@u37{a)shW%zYul zHj!e|9<XKWNwN!Hg``TL>t+v0;PsAOGL>_6C5hD7&=lS@IM5okv`ow2Po{Pw&smgW z8y>6}GqGPhtC2~wZN9a%y~hwOa;&wXnWa4j<FTzyZdxHg=2M>vae%FH+O@5#T%<$$ z+e!u3PbyYtux(GCtzz6e0iLYL;ux!7-GXKcxDecY5KdP$W{Z@4trp5jIrasl+`YeL zC|r@n;2mp}dp1}|!sBwq5j%NgwWZPIN;9G7?FcD_%+bMMGW^IV*+APkvBkqtlO~Q< z{jJWGsJmL76~8B}u8UrZmR^*+%D(eFkB_dh*B3dkGLaqYy)*YS_w8Tydzv<OjHq!4 zc<hF|K5;}Py_Q@SNL(=Kl==BT=VzQ)ZJN<h@E#-fggyAs;Q11D&5Cd$UC-2m0g}Ih z3BqH6@k`7G-yM9v?sIf~A~{;NJ;1hfl6eyP6eq?%4;SJaP{%25uz}ztHi`mLQ*X1^ z@>5;Gz9}3fi%I@~dO<#$*waoRsrkVAf}7PsIV<3>UX@pajiIC&2!;x9!rbE6aIIiR z)dbq28M$U5*Y8H8&k1*mh>1hZ=}65N-I}^wadCN$rifiDXcT5l>g~;Ow<0`&A#<+3 zog9aEDf#A;tdW*Dw3t@WvvJm$E556B&?7dozptSLD(AIcNf*>^rO0{DTp+&}z$p(k z<x;_tL57xae-aRfbRMvnBo-D9?3Ecjju796I4argSwFxq$<F)E9`vb~4;mD`3#d?l zg%)?4|3P_L5<WZorRy@U>JZS?w%fUGVGq)ynX*mNP3RlTM5l}T7?$m9!$@|MHniu? zKS|pwp_G-Yp@Ec`T2UZJj@h7AVPc{6>-Tj5%G<<HSS;(Bw|r;<trpt=>f8aw_IUSe z=e7Pd#^15;!_wj!2|H)&oc6o1*2`>}@sOP%5C~C$z!$idqj%Sj$>%%$3Xce#7r5h@ z&?y~erSmf08uv3gxZpgIjo9}Qnu*Y_84H58RCY{b-zGo)$RO@ZCEWEy+{L+!G!VSf zTI^jzlH~xUA>-5t>ELp{p59$`%5IO$JtEcp(TFemjuc-l^4r*FXJ#uitS!X#8N}yj zCN{;)_Mxkj2RDw-$w@cEn%4Tt&H{>kxS@VLJZ)JKj^FyRti+>`wAek*`=R=w)SOy# z4RnhQEBXcv4C7|T0<+D1z2s&Z@J|uf(>xDyPei{x@!a+zb-jRn3bhz0Xr-h34E%iT z6HG7+*~HZ%sE|l)7R0O>O8G<qgF!_@U0I{Lk=^fGtn=5r7+PQ}T%p|v$LcT{EeOo{ zRCTcs09kwd6%2@wQ~F%-N|~8I@|CF|N$6sU9-mJ4V#S&HEIQ+7I8JuK62&^sWLOYc z%tC$q<pgfgB&bY^L!tlbLDlvYBM`VT|A{}=(em~SjPotLysPs1JTBhD5ZvLWXK^?@ z@Obv~McU@jqBFX06v5#{IlugSE#FN*@V@H$EqcYd*4^;nQoxIeU*FQ)ey}1>%Oem| z1@XH~cklPB=T4grHjfbehj0Z1+i85@D{TZ>gU~e4TjGi~eY`xm$v<bkPc;U5jtsGw z#>NHD%#4mlnnHGVjtr@&Xp#;Znyt4ZlYu)FBp)m%3huHzccXvK5RfoT)U=Qv)M1a* zyj4o6@>Oyg0eS{dkqTJAlIplVuZIhfv`4n__vq`l$2YLcffa=2j~?1YvE1)&pfk34 zZ49E$#w(i@4V;urNwyRs#m19a1p@u(QRJ-&4(5{dkz7zi^Ej%yNsuw3pW)n{t)CEG zvAh_W-Q@Vt#lJwjwX?~F3YnRAWp~-t6d^Yy5SVwBfTY;iUYPo|6HM{ht;6fYz@J9x zNt_)bup*Me+o3T=k;Pk6YS=>WL`jVQ(z~_72Gl)+$>YG11}K<8rAE-OOZzCNaQ)51 zXJ0t8#IlsZg}(`~wPpA<bjG+oNQ2kQ$4g&4&?_c7z#4#}_5i*n__=urSIL!19%;xS zL^V&YPFPQzW(g#CIVsvU6<3|jQ@Ju_NDRu77-?d)BF(`Uj)lZblmy~$FA}Zu2&~NL zV3^<xl35EXMT(s;LWfbI%;0otTeMyad*E5Wx*wf+v8vJ;(wuo5eRY~*b>e)d_oYdu z*>g9!Ju3~aT)*p5^d0!u3vHZCkKH1QCsuyfUF#NCX6H6Hp`fTp{1-n8_YOCvE}CXo zG(H>M+u`SdZ&u`fH?Q3=P*b(e1NF({<WCLms2+eG$7c6uvTndTsq|WHdGB6+GJ9wY zVisZbbb}T<S~;i$mRd&ugOt-<OOLv=#anD_X{$d(g^C`I>?592{?ryGA4<tC5%<bb z4?;HsMZ`RS!8sih9#)9DH;ob1W#Q%A@K3=c%GIZ+?ZAEwsC0_8;9CvrLf?}{G;b*W z{#;mblSeK1zbp(2WAzHe!`iL9omnQ_^}P5Sd(u#BK2idZbgBE|Cb7H4vZ0{U9!@j_ zDwGl%VPzG=A}Wl!Xg+lvM4DuUiU_2DIn?s&Xj<whS!!yj24|P1MiYh>-{)c1{_dtc z;>vAF_{yYMqS@-hk+r$mfx_SS!X>LzOFTkgzikY=w|oQ=Vrz8KCiRJIYq&sAZYnhz zlsANkiigl=Sjy;j*=Gv%^q4t{P#~-GCju`_nlf}G3p><e#vS%qGFPq28y7h)Ov+cs z7HrFB0ilB6jT2%tJ)(i;y#ax0z&zou&s@(4tyc(J4qUv6y|D(|f<vv>SKHeGv%cKl zT)WeFxxG*^m5;ptvLGo`Q>&DMCrJa?=)e|gl+c)WTDh&fvHeFV3XD=x^LG>|YO&a; zsAV+kS|q4bsH*HMdaTx;8BE^ARy7ck9CaLO8w{Xz<=R`I?#xw+4F&K{ux6L$q#i<0 zmrgD5z-7j7G2vNoi@^ySWd=?gIAlCwPh<<`EK<t&;qu*-^EOBH5Rb|&AS)BW;rMxD zAKtLgDUHLaI?p#W`XkEq{mR^xl$kr<p1|nkv@4gJhcdAHfO3{E8#K$M7fB7_%CUj9 zu%mnI`>5ngItgW_q{%UPhH_KBPd&1{ec89}Z7W7kR^2OguLh@gc!7n3)USM<(H!|x z-)T?Mv-|f|Tx-Iilrk=+Dbz2eDsvBM<xBBHd<KZIWs3W~v)|v=ST~#O3iImAdrAI% z?}OL$a1`XZ$TD>@d)w)km<uWrUsctA&0W{Ld$~XuID{Og02!jHF*B`HDI9T>Y<xh0 zN^C;qIlyz4PbS^3Fdw>KFo6|wrG5riiL#*Guimy7Q%!EtK8ZP6-n=EAKVnCBX&_L^ zq36=*0>Diax&T=~L>gK^tw;mr_CEL~ta&`OnMbr(wS1qupz$a@6>d%ffh6NrtmN7# z71)?9V$#ylr6LO56Bm94M@nE<@>+wDqZ=s)SM*w{ZOC`~k+eLYsj?|X&s66tgFA?P z#W_hmgxL+?cuRyj<v<|vRG5CQW{Z+<5_0yDc)8B^*mwvUEh?303&V1|G9WtdLtwKY zB?~WS+*cayXhGRLdXVICl^XtQd|7h(h)H9~C-xE=uMTRy(^xF+(JZdiSk-Wvg{~wc zzUwGAOsvl`Bi-cJ@lV@RXNkDEs{k~PS`j@15OfN?hC(p%5@qa18zFX3Y3b3jAxle3 z?Z!V5Ad$f-(M!oVhYO^%{KK@86OLZ4rxEP!1{MA1x;oUo(REGZST+?sldNI+4gzr^ zJIo6<s*VBJDr&b`3#}I{iM4JjPKN-RCH`AsaZUK?YAIJ|+taQxnjP0Aa0$R`;#J7d z)zuKVWX%#5B%37(&+nezwvfY|40Dn~s0q5!;avIqNYn_mnVrD|4KaQ_<n*c~Gp3Aa ziFxSX!KS}u=9AIO(ECVZ+DUUJzs-kjJ`jD>DRf6nefcp&EHS6(T4vV*kyId%1ta%j z^m_DFOO=u2CW8Vjim)q(xV9jvNYw}r|GN9&!)wYwCz#VI8q!-tg$O1cuTx9mMDC_F zQDdc<8&1HqmxUC9Q$1!9p!I{1OuEb)Qo%^NY%BIZG?}7yR*HT<cDGg+&K-CtE2$h5 zewf3*Kr}AS8303d*a6>Sx-Gk(^Ba{{Hv9@Iu&S@1JYZysjpt9^@MtsQfj<J-urP}B z7bG(xQ()IoM+8fP3Q{BKMD8kR3P!hr86%<j+WUAR*@<6HotnPngsYG!m8O`Q2C*L9 zK*nJE2d&cko4+51$x(}0vJ$Xn6;KJmR#ZAd!wua`o%uyT?DFcQt{pW%lT0$=ESEJw zwNaudCCLS>#Or~~tifLoSy=E_cw)M2u`U=;ZO6z%#0WiYAtK+FU@FNjY>6c_#xAU{ zZS*R7^TyU6O?b$LSVL~6nsir}E%3kwvhwBhN3~yWgW|9Z-Vb^wbr>=d2(5}KOyVE1 zQb78e3cNY7A90iuH!}*s2id3$@i>#@D{g;s%o$F({oqW2o=60%hEYXN?lG~^O{*3V zn3M@^H<V>X%C2o5{RHw0V;rNIq+b!sg9P7vue~#rU-jsr3P0LXX`nRMgq0Lov{IlB zwV$=P#5i&Tb*I4Z+p0543jZF9DhCx#<_dFA2E9O;va9^k@k2D7g?gL*OrOpMrHXrx z1Eh_O(8OSa>hH~Gs^BYGe=iq8-nJ{N&d3{VVXk*GAgE-Bp6;+1Kap{xWD|p^B1mI* z#BuvL1Wedu!?2Q_Urw-SSAcoTML3xJ%n-VczZ}i==uL(dbAhm?L&f+{0aOxtl6gDe zzWD(!pP>RsQ<8^s&svu1>hKj&i-&aB6~H5b#3Ce8A{6#T;WP>f>M>EvO6AHdl8yC4 zrSm0a3(86LtEW)18kDMMTwqMy-olOWueYb&8?9{yriUJwBuZ*=Av9v-e<1VbNRn^4 zs`kpnK(cbOsZ<6r^@5F)D<VZjltf$Y!E8ntb;Ay54)vUIQ}>4^Nu%W~Sr^mK%N_#c z4UKST^Xvwg(Th`J4BgNcPFA%bY}yOoD4m*xDy21Mj2E$IRN_Kd5z&@PQX-7SJdQAD z^jk|6$;h)TW{6|`uX2H*3#YVSbwG5km%!*xY80CV92EtL#WJ5;F6c!o7DnY7P4HBW z;T)BnmoX^iUe6+E9iE|$6-oMq_jF}y20aF*6rg^M;4w9%8N?<i$Be=kbZ?=#gkGu? z%pW8LiCtQ3sbIM;A=@-tlLRN%cG;?ysrQQsnck#^hdj>hntOY)Q8qT^d0XG$J!e7X z`1?NhoTqzUL2WydI!trNGd?F}na=cA@ckp=qB&euv*<}6?DA-aA#TiIVc8cs6v|BY z?VHP?w%j(>JpXg5S@og0<|v^NR39f@%+%e(CBGJZIzD%)#;(@XAso_C;w)O5?Tb3A zoAR!6ioHY%BLpMD-(5MSqY8(sK1f8>G^XxpXLsnPNJ_D&!1(dwT+cyA0^)V~SNvUW zoJ4lBlhG2#;_R##w1(na;%L@>V}{*pk5q7ix8-@(^RH#uwQZ;OI(HI)Ct)%c+<vlA z{Uhm`hkfWBo*kYmR6-}?9l!_19-~aAvY0M^YpKuNKt(lKlA>P0;t8g9I~KuMcj`2% zg*&k*BPak?MTK@wDP8BF)D6lxo4YvD_K)yh{XQZ+9Dv&-o~~|CNfo&naep@=<4C7s zuWa!qjp{({pVKE&`t=Ld`X(7=e_L$BQ9NDKB(t3IGR<f7$kx<epJ39K!U2LmVsqRI z?*%w}4Y@%~e)SivUhm34nQ{kJJy7JLHimm6Ak+a|PG4HV*8l$n5*h90ivT7X(1rje zN=2L+&XWpk4a}V=EsoP_wFa%hVm8bD1>_nz8cHasle-R(QLL3C<FejZsE;)O$B2u~ zNNz7ct3s*Aa;ZcUt*)||s;t%4kYB0?Wl52el2uwJn|r#fO!o52W@j#)*m!a*ujB%f zA@VuYj{fGXz_XI<LZd<=%g@sCY?(K>O8yE;>{v-BE15B@b^m&|vOH%?YdAo);V{Ew zSte#bk-0ie>@GIr@N#5m&%#hH9C1vwb@cRXo9T&n#CxOdL)nXF#}2i2w$iU|?w@Ih zq`cAgpf7B7_O*q(y$v>Bs4tPP!f$5}jdX=OJu!Ek-|QL$P_w!<@--H7kD`C8T)EbW zG=k;?0(;=Z>UuJ5g&MZldN;64N$u)tw)Zj1`<#F>R;$Yyjf6ubQGDG6R=H6><9d~D z9|7jJR<#=;vJbKh&e&KP&PlLqRT@E6$Xw8Y#xC!AY<-Bgue`N*IU8hlEvWxhbN&_6 zQ5@8ULM~@08UjR=;6Z<(c%YnR9X$L8u$ndTa2I1d<#=d9e-_OVENDw{p)@dU0<~02 zow5~4OjiK~@pbQD0MV_6|NEKe{Z2t)Zg)AG8XKZzl&`;V%4g2zb%6dON#?Ch{~!X3 za6il7-h-d0O#dmQ*H#ljr56g>I7p+>%^R>zH(f%ERTZG$d4cybAXTl#!(ThM@Bic6 z)L!aB8of@lt->gUTj@~psVW;l97I~Zpw|k=kdBSAg!I*TjX{vXP+^P(rg-|oa5lR- zJ5uefv6iNWP*1q0gkowglwvBIRqGJYjTJ1cHK_@$va=+*x{c9QGfLw`Wy)$+fI<5z zYvw7Bnk+$#z5+qDu73*yqkc6Vz0a8vf6Yu{46cETfdenC!3Ojz5G>ZZoat0sytyeF zDZ#7Z0`Y1tQ#)B2;yO6}pQS43n#dd}OI<AB^4BshJFuZLE?YrC)oC@lB~Vxem9`QH zD&aGE{@d2V>HD7XubNE8QnEeP(%4YOuP+!&a#34JjAuPGT~ZqHSqn}0-LC2G?rC!& z`onlRm&N~zA}EHsXoiHp&dsURV7Tg9^#ZTLh-Dt=kP7y%0qt9Z7O5(r)HCX7E<ZDs z!K&-*NVK&ySzx2VV32Or(;QX`s^y%a$jUuC*v7+tsopwW%zopt`8(CK8@FXbV;A4j z<vKDneezKD<iL3E;)dYnYsJN?-pdbMn!gi=!MGTj+LYSWGd9-KpZnS9VqbFNvXnS; z?>2F^l|mquzUZzGga-ERd%)0_iN`XVSnd7>R=eMXc8S}4^(@u|yp|7^#hcWlD??2) zYlfO4p@5$@qmx5TO}J^jP*bt&zZhromm~w(mo6{s1<<?C$bw8?SAtA^+K(SPR_G2e z#WyLrLY!0^4|)-;jrX8UVpgt>F9w^ma-IC{6?O8OVx7FF&h1)RE3aF(R-WnBYt+lX zN}UF)Yvys?>5}zwtcqe<+-$QF8iFhdR_SO!T`dLFi+CXOT8Z!+4(h&jcpM(LQ%b#3 z+0}ODTF@6=xNFt;KM%@guJXER65YAZipBoLb@KpcA6+-~Jk&Y}uO_AL2O5o6^BOfx z!&LYM-Gx?i?z&tW!R2%LymhpzY_&mfYMdrB=yjzI-nEwgSxIH9TVwStps}s7d{~*Z zekq@wYS1^H4fqMoFPB7FvmR>^FKGG2k|cK;o@4&bnK8B<o$T%u8;eel!hMymT@c-& zkl7S!3N<xEVB79myD4Z6(j<99r6hUF+S`Ak#7(+m4H%SV)t|e#A~47@eKNu$j0RW7 z;-=P!#oe3DT7a(cTjNqJt`nf-lE;XOAyrA#p;*t4P$8nKR!EbEVO&6j9oZ}+xM5ns zPnQ1xqrS`NYt4Av)H?CFcO}~3U{FQ}!%|-WZuvD>r@-)TLN>HP!nUIf$*k|D6a;0( z?Zt4N^8JFSHJPlzRS`Q`rC>2Tp;ULc64p_Ui&Jbta;-P{I-H^)jfp#0KUgP?K2z_G z7LO=FgQ-$~CG`>0;$PZw&jOs4(5FO5g*vi3%@K)`!b1nHGM~~r>otuVVn<E0U;W6j zBOkr`8~yDk(yT-r|9ewPFk039jls6Y$fv%3$(<kn$;TGvr}M($?8M>26Ir%SR!<Lh zj~STzY<Wd}6pT5&lxYKJThjZc$JQ*fZ<a1st+;%>+WYr0gYW&%KrNTX(zGGv-pV(K znYHtVKn+^^PRTy0wOYW64brpkbXc0KO{`IXp>m^uXk{~`tbM@8D;OT-Ed^d#nL;G< z?<zQ7l>b?2=6umRUa{YR$y)G`uk1L$WM5g=fuB=}SK4_1-*UQSPFjm-rPN*_HaT-4 zp7K>a4_*KUVk%vMB)iI*9~9@O`D+f^qh`$*<ji?I=BpMU%cAkJHAoVuyaPiK_GcOF z8_-#aXq%9R*U2G9wOW{`HWVY;)wqypwxKjSsVk38mR~P+tR0)w;k9q1aU8QL5)S&k zbuQ3`ObzA+N(TB$jVIPHnac>{jY?t2GD5j&6|JgdcuBIl7WvVF#I^lpTw4xB&Xfim z++zLeU}f1A3!<K)m&#ww%6vG=%2#8$RP27E4Bab)?P|Q!=VZJ|dRbh;idw`*xtlgC zuTawhL$yk!-bT}bV0miQBqh9HsgOw~EdI2=kc1Pji@01C>x=mw{GBK0`v~#V6}a>N zmHH?4rbus~?^|dmZLE=FnxF^cdauiAAiPR#DT`^+UdgNfWLfL3iZ>MEmbHkQhBV@$ z^wHv0^yHGefGG5*G}BVfpFH*2<D7p8){o0(4fw2Xn>%a{%kh_zFr-p*$pVp_J!*AW zC@((M(KdL)(aqhCj@ZT<j^=vqn3#>c-gHsmwMfUrT;J&NqjxrXy2ef(y(?xvwrM<- z|9#+@jY(|t9+P^lyaO_m+9G!JXnE&`IyqsOs86if!@;-en#$cA)*tKq!%*PpOeWUk zfik%YO&+3@#g{dDI1Mbmyx9X)1dDs7_RLdftvoYk<VGrj%<ko|B*Pe4;L2L!`Bz`W zdSwASUMM4n^Ne-@1F>idLR62cGUyZ`qft`*Dzv)z8i<+WrBIMG))h@JP$?X!ee{H= zr;^5@W!90>RYsONYIK4IN~IoQ3o0pHy4Y!F<wYz42mEWH>@ivA8SMfFVm+BC2~bfd z70AiT^lC8NCkeaHmq9{OvsZwEli?ug+adJE*??8HvM3O|r5s#?>9gUev9zF;@|9&M z1S(twe`hRzp{!Bj`NvCK;CP}>5*$2m=gOBbWzN7LMlAttd6J~!T&w`SFO(Vv*j)z1 z6*j^u!Xi?i5uhuhq(Ld2MtEFM-&Qppp%ptOtC{v5VcjiO_8y_szN-HSo&j24*@T3< z{`6_3hm_ohaabHI^pKKzS*+8}={%jBOz*3c6PH^?D_S|x1I*xa8`Bg5X!}<b07<C# zP)?wpr$=CNY!#r~^l4LSxCDT?wCb;LJ^;}c3PyT9R)KLf_E!USs1*0BpqngnB(t91 zDmQz6QV{DzgR=^lX)Pf_!Gr8q@|dN3J}GI3Dvm3C#*LLOWU1_uFwkmOc#1D*WXJm( zS!^$)UDGG`N!df?iS;Y*k)F60@P$||axloAxYvl;p^|dP9O+`ReY%*#u5#xmLLVMK z{lpWe$3GmxXY-$=4?e>C@)MpbH=n%u=98PRykcPFIo$N^;ejh@Qt~~oZ<_ww|8rkX z)|a?5pf7n*7{$@Yq#nSATFeUufd{37fXYKZYLt%)(j|WSJVDGOfCY8=P_9D*&LvJ_ zxAcTUdJQUG!X7bL;cD1=ti>7tMTB~kb>$vq=^=WOt}Q>)NO2@nO_k=+aA)#Ysdr@; z`a+YJ<@P)KZ#{a$4M&^CT0J`ZzA5T0!u^E$iKgf7nxDUG?q|#|l*`-(nrmIG$&s49 z`(&tp-`-uDj~w~bv7^Nrq>JQyA1AdNopuXH4}Ve7mV0(EmTNY%j3262tjhSY6xvb0 zRC+9~F67*-$a5}fRn2OFu~w3=qP^UXLkA08l%=q*R+3jtL`gO6O}Go}F9*6ovb}6b zMR)?5!cOK>pcz}!g`lRpBxM=2iEW5-HR<w6H>LlzvXzN)F|7n-wbGy&muDzT?IkPO zO|Mq4lt|M`<EXTU0V;cL-CyxNNuH+{0_`iEJohie26xDFbHVf9!v+8HUz}RLrxkx2 zeU3fXE-3n#ipHMpH^O=aZIg@o5S|P+vU1*32Yqa!kdUft=@V^Yp>S=O!#ZNCqt7`a zH7#3QUSqlzds^z{XZ&^HZ=uIwj#bYOEI!0hdVZj#((?mrBZcP&l7$ry5d8o1*@W~N zz2C-@5^UJX5@;A^)NZ5g2uJ99fKWkqp)hI=HnIoy%1}xcpp;qlO$UWrgn)2n(}y0C z;7C8$`QURo9D^%>N+?Y676wy4t+l8Xm;=zpS|tvbJw`a_4m#z|4&?w4R(^rE#DjDZ zDy@Xeht`9Ba5cOD7kCT9MTIpLy3jC`$ZJ}K6vuh6^icT<Yu8y3Mq}t^?4ung)~?A{ zm>~9v^P)J9z4HSD^CFy}-sShmDcFk^taK0Um8a$iYk5ed>|CoQWVJF^Kt}ORc(MF0 znNTa=*&p$<GXMV-XrVQ$SYWmPzL?$59tVb7*zb(|k)7cItY!7*^<tfxkV>WXX1Ns# zYsjK4v|^EYfO0>a2M$-f-NbG$tyq6sDpRM=%v*kke3E<~HKKWO2Ch``4N;=Uq}UB= zQR)Vzr?o6RuRO6)uSfF+rQKpU==aro>2sv*R%11Fo-^&T5jV<-^HE@RkyHj=rDp+3 zauRd~-s*r?ma<5@kpJD4PkPeLgfyqUPhKHay3KsVja&2I0du)0|B~y58R>CKH(!#f z^LbMzZ>E)Qi<?u9xGlA1H+!-YK_>i<__K0OsOCvajRuhz?Xx2UqqIc}bvMY}NAPFs zvYKpNvnV$IxxcReKKzgLan-Ls^pNXY-;(>Uz{_v&Z-7GhFB6)}Zt|P__&0es{ef?3 z&+TVf&+U5P8k6F<9&0!Q7Rvf=>sdYqqUjh?3vQj7HBi(_r^8_n2K>G{m%ZLmFE`{i ztl5w|Q`Uo-w&$J{<8F(kmbT~qWw9l*)T!IlWuTq9Z!T%iOxT*g$kyycS4wK6uGlWz z%|2+P4-3+ty=*VEBSCo+aY1o%1Q0C=s@!Q@Q0jIKk`l=Zpgn7B53k-7=2z?{znfNf zspvk)&kL~cLI=ft6#A{O`Zfa*RNQC{^FdX!b(@PwFd2BNF3lRNbZQk{qFzg6OmuZ- zI+E@2mc|B}<+%zk7UrKhKVER<%{^bfvtJd_b?z6H8m+HJU*5B#1-nFp<cBgoThaXz z$_!yW9Nvh5NH}F5HS$LptKljJ9)pHZ_|)hmpj7MW!y<t=1*Ma8BSWryF<$T51<}<S zkF_*LLxFl)5#}mj+{pUHt%dOm0~Z#~11Cxt=MIzu=>G){VpmT9004N}V_;-pU|?c6 z`v35is(5~zuMG0cFMuKp7j`UWgVF!z{<mb2W-bSEIe=<`006h`4qJHIV_;-pVDA2R zhk=15@c-QZ$62HqfFda16#$?K2P=5mZIjPy6G0Tmzwb>{T1&cB`~jh<Z6!%VGzpsq zS3;|TppC8+f8ou8cu{&#MD!+z2l1qM^yVL6_0WS}6tQ}+AbKbSg%<2V#efy;C9dBY zw>6b6eDWsy=DnHuerM$(`oTwz!abt=SwKxrqpBgc>NxV+K%d^gPE4bUB@{@HoWOuA zqL*_6DIo1?a)6$LFUPS(k6>7Lp;vcf2m2h*WAN3m&p}i;F5CI8mOWOO!6ws<LA{F( zy@F65vgR3MKr-YF|G!3vCPHaoqn=^>jnE7+_mZ@jugCE$;}|l!m+RXe>}f6|sdvz& zm)QR>N?1hB?wPSi9$~Xqq88?PhHjK}6m@B$$XHY#MM=Ta5sq`HV-6#jiyo-DaozBp zW=W0tnu`S)WBohyO9q`bCtqOn6S`!9a4fT^NCNBdo@YpK{a;9}Xm8hD&;6W2%I?+8 z`9QtB=!fZK@9P+nDWqkIno)cCjzPIV?*_2V>39=ml6Pkr=GxDZa(cgI|F1~OeV&{3 zMv*jGGJ(9@rZ-miH84-G!FdtHUc{go&CrWc#-C(fXL;6TAO3^;+ULgBi*~FR*0Yn; z&Fa1e<{C;)6Mr@IV4C{xVf;oKPXB*CtU@B*#pQe(&X?NXm>7p|UT_ZgBpuW<AWs2v zwJm0;;YV^WW`azTGIQ387=AZtv)_FeMSIWPUB87Y2^{BfNFURaN!K%Nv3+$4ee#O; z;WOX2;91Oec<}xJ{s*mZ004N}V_;y=g2NDoCWae~MNAG%ub8=*RhaFVo0wNI-(dd0 z!o#A&Qoz#3a*9=hHHLK=8ylM%TNm3ab_w<<_5${4?CaRSam?X3!>Pa-$2o=b0OvC< z1Fi_JJgzxh$G9GG^KqMS7jQ4({>Ed%)5NoY=M>K?UNK%L-VEL;yhnIn@k#Jm@CET@ z@crYj;ol};CD0~tKrlmaj^G&~5g|LF5TP@|TEY>+k3@1rmWX^1H4>d5x<T}g7>k&h zSd!Q>u~Xtg;sHQdCw@Z0Mq-Y{9Z5dP63I1ETv8LH_DJ26`X*f<-6efM`jd=}%r=<| zvO=;pvQe^|WUt66$oa@ElKUgSM*fF_nL?SuE=4QF4#fvbDoWFo&MEUL2Pn@`-lzOT zML@+xrAw7T)kAfP>JzmBwNq*@)X!<KXgFvzXq?hy(6rDzqE(@7qy0lyMUPAGo_>`6 z2?GU#8iPBANro+kYYcA~DHxR)#~4pDzGfn2vdL7;G{}t4tiznge1e6AMU}+~OFhe1 zRuxuztZrF5;DA2X5!NZzb=EViPg(!4QL`zr*=NgUt74k~gblU}Y!}#Z*%{b5*v+#0 zXW!%?1OU9>ioyT^0002%06_o+0000000IC!089XL0001(0ki-B004N}t&+=1!$1^< z|D;u^HxxvQ8{@_cXnOIAJMpr!lqw2>i&$d}wuv-pt*bnO3l~0z_!3^8z_;<A(}@&B zS7ykZ@60*#&zX||$Q$!8pq~EO6x-vBP>-{i{pLYhi%}z+qZeRKv%#zf%_bv{nlpWz z<w$t|GkDTG$Q{p`hj4}$%{j~%W12^>VJv7KC7){^N5@DtCy+ODnkO-CrnS9d+AL^( zL($yV{LU-4HGg0@<<AVJ%p|F{!mi(RtV-B%teR)lT(8}5TGpw1aTNw}f?b5T#XVZ^ z;o%xF8?%TymS_**aQ%jK#AuV50V0`~xmHGzV;wem2MrFZPbCu1rFCgLoG+PaBa!z+ zRwHIBHKk>X+A3pJMnZJuM2E2oy^fGCs)}OfI8<~cr&nW$t3PYD|A?uIWA<Si1&%uz z_P2KQL#a;N{O4T}R`|wf^IobiX?_6*vOi|k4!f*+T9EvRp3f{-&Ttv^r01$DuI#Yo zv?lX@>uQae9?xt@)u;3>*vH;^7E1D6j;Ye7x5sE*R<~p>@(yM4HfdA;5hbiq*Qb_8 zm9+AR_f`K!0PhO~e~hvK004N}ZO~UtQ*ji>@$Z4sLfLzRdyji>TZX#@>fU>c0&Num zi&b%<QQR7hi9TsuFKXN~8udYqd&Lp;!Dn}TP+zrh|Gs%%J~{t?&Mzm22-@mT3u*kX zzJNqXq*#c=LKIePL=%IZSmKB$fkcu>CWX{+LOK~_l0`N-<dR1|1r*Yb_H>{lo#;## zy3&pA^q?ob=uIE`qM>8pz=?|@iYcL#e)MMm0~y3%hTz6S8Rb;qWhlcK&Im>_iqVW= zEaMo@1ST?x$xLA?)0oZ-W-^P}%waC`sFWy<vXK^Uu#b;yVi(&vz;TX=m2JFd1AE0L z(d=YDTe!^!iQyn8_{C3tbA(eo;2x)$&jNN+#UrY@&qJQ^m?u2t6E(c#IWIVak00#e z4X=2OKYYP&Y-J$<7O|LG>NrF_OK2cSBO#WujOBc01uJP{6>C_{RSwh4TGp|iuYBhk zXF11p-ttcD5-V{MFA0(;Ns=rnk}7GEE*X-^c`k67E8O8Cm$=JjPD&Oxxh2_>!w$)n zJjs^=DYW`(n;QJOiD3)X1vE`7H+5@D)qB*x$Du53)d&wLb)}(nD4j}|vPfC1EK&Z; zbDQcaSJ&+|0beLsT~*oWH=hizsmp7r2nFlg8ke`MRj<d~BdnoxD4l-+WFen<004N} zWANU=a3UyTBO_y9<Oar_91I)`$psr3Se>>pgff^avNC9aI1W6~j2;{|EE*hQ?5rG6 zp%{iBHYX+{HhEUC5SP<FaRwm=eg`fG)&mTz44gnQey4p53=9rX2o_^zaM`HB*bx}9 z!J#8!BXf$&Ml}#`7e@mFBa1^va!3S7NhA<}Z1Cc+W6|P}U}xpg+QIn0bpuQ9MkWRq R0PuM!1poj6RFd+C005Q1AJzZ> diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.eot b/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.eot new file mode 100755 index 0000000000000000000000000000000000000000..74233f4fd1c1794d5650b29840fa12c7b2464b64 GIT binary patch literal 20189 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 aW(YVCfKiD-%VP}6m7*k+MA7(|(^SyD#jLUb diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.ttf b/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..22d537ccf1b3915b6e6817ec1af76a976917a2b8 GIT binary patch literal 49596 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 GKkyG{1yh~? diff --git a/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.woff b/rhodecode/public/fonts/ProximaNova/ProximaNova-Semibold.woff new file mode 100755 index 0000000000000000000000000000000000000000..d428ac5adc8f7cf9adf344472af0329ea385b3e7 GIT binary patch literal 22772 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 ODFpxk0aTLmi2wkNQO!#L diff --git a/rhodecode/public/fonts/RCIcons/rcicons.eot b/rhodecode/public/fonts/RCIcons/rcicons.eot new file mode 100644 index 0000000000000000000000000000000000000000..fc99ccf781e627211f388605b4e1feebfedf0efc GIT binary patch literal 10780 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 b=TI?$1vT-^2Jv^jO1D4Yh#$u7Fh>3pSkK)s diff --git a/rhodecode/public/fonts/RCIcons/rcicons.svg b/rhodecode/public/fonts/RCIcons/rcicons.svg new file mode 100644 --- /dev/null +++ b/rhodecode/public/fonts/RCIcons/rcicons.svg @@ -0,0 +1,37 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata>RhodeCode GmbH</metadata> +<defs> +<font id="rcicons" horiz-adv-x="1000" > +<font-face font-family="rcicons" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> +<missing-glyph horiz-adv-x="1000" /> +<glyph glyph-name="rc-icon-svn-transparent" unicode="" d="m938 855h-871c-36 0-67-31-67-67v-871c0-36 31-67 67-67h871c36 0 67 31 67 67v871c0 36-31 67-67 67z m-5-936h-864v864h864v-864z m-762 312c8-2 15-5 22-7 7-3 14-3 21-3 15 0 29 3 41 8 12 4 21 12 31 21 9 10 14 19 19 31 5 12 7 24 7 36 0 9-2 16-5 24-2 7-7 11-9 16-5 5-10 10-15 12-4 2-12 5-16 7-5 3-12 5-17 7-5 3-9 5-14 8-5 2-7 4-10 9-2 2-5 7-5 12 0 5 0 9 3 12 2 5 2 7 7 9 2 3 7 5 10 8 4 2 9 2 14 2 5 0 12 0 14-2 5-3 7-5 12-5 2-3 7-5 10-5 2-2 4-2 7-2 2 0 4 0 7 2 2 2 5 2 7 7l17 24c-3 5-8 9-12 12-5 5-10 7-17 9-7 3-12 5-19 8-7 2-14 2-21 2-15 0-27-2-39-7s-21-12-28-19c-7-7-14-17-19-29-5-9-7-21-7-33 0-10 2-19 4-26 3-8 8-12 10-17 5-5 10-10 14-12 5-2 12-5 17-7 5-2 12-5 17-5 4-2 9-5 14-7s7-5 9-10c3-2 5-7 5-11 0-12-2-19-9-27-5-4-15-9-24-9-7 0-14 0-19 2-5 3-10 5-14 7-5 3-8 5-10 8-2 2-7 2-10 2-2 0-4 0-7-2-2-3-4-3-7-5l-21-31c5-5 9-10 14-14 7-5 14-8 21-10z m308-7l126 257h-48c-2 0-5 0-7 0-2 0-5-2-5-2-2 0-2-3-4-5-3-3-3-3-3-5l-59-143c-3-5-8-12-10-19-2-7-5-14-7-21 0 7-2 14-2 21-3 7-3 14-5 19l-26 143c0 5-3 7-5 10-3 2-7 2-12 2h-45l64-257h48z m207 150c0 2 0 5 0 9 0 3 0 8 0 10l90-160c3-2 5-4 7-7 3-2 8-2 12-2h31l31 257h-50l-16-145c0-3 0-7-3-10 0-5 0-7 0-12l-90 160c0 2-3 2-3 5s-4 0-4 0c-3 0-3 0-5 2-3 0-5 0-7 0h-31l-31-257h50l19 150z" horiz-adv-x="1000" /> +<glyph glyph-name="rc-icon-hg-transparent" unicode="" d="m933 850h-871c-36 0-67-31-67-67v-871c0-36 31-67 67-67h871c36 0 67 31 67 67v871c0 36-31 67-67 67z m-2-933h-864v864h864v-864z m-605 421h93l-14-109h57l31 257h-57l-15-110h-92l14 110h-57l-31-257h57l14 109z m238-88c10-9 22-19 34-24 14-5 28-9 43-9 9 0 19 0 26 2 9 0 16 2 24 5 7 2 14 5 21 9 7 3 14 8 21 12l15 107h-86l-5-31c0-2 0-4 3-7 2-2 4-2 7-2h21l-5-43c-4-2-9-5-16-5-5-2-12-2-19-2-10 0-17 2-24 5-7 2-14 7-19 14-5 7-10 14-12 24 2 7 2 16 2 28 0 15 3 29 5 41 5 12 10 21 17 31s14 14 24 19c9 5 19 7 30 7 5 0 10 0 15 0 5 0 7-2 12-2 4-3 7-3 12-5 4-3 7-5 11-7 5-3 10-5 12-3 5 0 8 3 12 7l19 24c-4 5-9 10-14 15-5 4-12 9-19 11-7 3-14 8-24 8-9 2-19 2-31 2-14 0-26-2-38-5-12-2-24-7-33-14-10-7-19-14-29-24-9-9-16-19-21-28-7-12-10-24-14-36-3-12-5-26-5-41 0-16 2-31 7-45 5-17 12-28 21-38z" horiz-adv-x="1000" /> +<glyph glyph-name="rc-icon-git-transparent" unicode="" d="m933 850h-885c-38 0-69-29-69-67v-866c0-36 31-67 66-67h886c38 0 67 31 67 67v866c2 38-29 67-65 67z m-4-931h-879v862h879v-862z m-269 307h57l26 212h67l7 45h-193l-5-45h67l-26-212z m-103 257h-59l-31-257h57l33 257z m-336-219c10-9 22-19 34-23 14-5 28-10 45-10 10 0 19 0 29 2 9 0 16 3 23 5 8 3 15 5 22 10 7 2 14 7 21 12l15 107h-89l-4-31c0-3 0-5 2-7s5-3 7-3h22l-5-43c-5-2-12-4-17-4-5-3-12-3-19-3-9 0-16 3-24 5-7 2-14 7-19 14-4 7-9 15-12 24-2 10-4 19-4 31 0 14 2 29 4 41 5 11 10 21 17 30 7 10 14 15 24 20 9 4 19 7 31 7 5 0 9 0 14 0 5 0 7-3 12-3 5-2 7-2 12-4 5-3 7-5 12-8 5-2 9-4 14-2 5 0 7 2 12 7l19 24c-5 5-9 9-14 14-5 5-12 7-19 12-7 3-15 7-24 7s-17-2-29-2c-14 0-26-2-38-5-12-2-24-7-33-14-10-7-19-14-29-22-9-9-16-19-21-28-7-12-12-24-14-36-3-12-5-26-5-40 0-17 2-31 7-46 5-16 12-28 21-38z" horiz-adv-x="1000" /> +<glyph glyph-name="svn" unicode="" d="m934 850h-868c-36 0-66-30-66-66v-868c0-36 30-66 66-66h868c36 0 66 30 66 66v868c0 36-30 66-66 66z m-779-445c4-4 8-7 13-10 5-2 11-6 18-9 7-2 14-5 22-7 7-3 13-6 21-10 7-4 14-9 19-14 5-6 10-12 13-20 4-7 5-17 5-29 0-16-2-31-8-45-5-13-14-26-24-37-10-10-23-19-38-25-15-6-31-9-50-9-8 0-18 1-27 3-9 2-19 5-26 8-10 2-18 7-25 12-8 5-14 11-19 17l26 33c3 2 5 5 8 6 2 1 6 2 8 2 4 0 8-1 13-3 4-3 9-7 12-10 5-4 10-7 17-10 6-3 13-4 22-4 14 0 24 4 31 11 8 8 12 18 12 33 0 6-2 12-5 16-4 4-8 7-13 11-5 3-11 5-19 8-7 2-13 5-21 7-7 3-14 6-21 9-8 4-13 9-19 14-5 6-10 12-12 21-4 9-5 19-5 31 0 14 2 28 7 41 5 13 13 25 23 35 10 10 22 18 36 24 14 6 30 9 47 9 9 0 18-1 27-3 8-2 16-5 23-7 8-4 14-8 20-13 7-5 12-10 15-15l-18-31c-3-4-5-6-8-7-2-2-5-3-9-3-3 0-6 1-10 4s-7 5-11 7c-4 3-9 5-14 8-5 2-11 4-18 4-7 0-13-2-18-3-5-2-9-5-12-7-4-4-7-8-8-12-4-6-5-11-5-17 0-5 3-10 5-14z m318-215h-65l-79 319h57c7 0 12-1 15-5 4-3 7-6 7-11l33-177c3-7 4-15 5-23 2-9 3-18 4-27 3 9 6 18 10 27 4 8 8 16 11 23l75 177c2 2 3 3 4 6 1 2 4 4 6 5 3 1 5 2 8 4 2 1 5 1 9 1h57l-157-319z m430 0h-38c-5 0-10 1-14 3-3 1-6 5-10 8l-111 197c0-4 0-8-1-12 0-3-1-7-1-11l-23-186h-62l40 319h37c3 0 6 0 8 0 2 0 3-2 5-2 1-1 2-2 3-3 2-2 3-4 4-7l111-197c0 5 2 10 2 15 0 5 1 9 1 14l21 180h63l-35-318z" horiz-adv-x="1000" /> +<glyph glyph-name="hg" unicode="" d="m935 851h-867c-37 0-67-30-67-66v-868c0-36 30-66 67-66h867c36 0 66 30 66 66v868c0 36-30 66-66 66z m-491-660h-71l16 135h-115l-16-135h-72l39 319h71l-16-135h115l16 135h72l-39-319z m180 104c4-11 9-20 15-29 6-7 14-13 22-17 9-4 19-6 29-6 9 0 16 1 24 2 7 1 14 4 20 6l6 53h-27c-4 0-8 1-10 4-3 2-3 5-3 8l5 39h106l-16-134c-9-6-16-11-25-15-9-3-17-7-27-10-10-2-20-5-30-6-10-1-22-2-34-2-20 0-38 3-54 11-16 7-30 17-41 30-11 12-20 27-28 45-6 17-10 36-10 56 0 18 3 35 7 50 3 16 10 31 17 44 8 14 16 26 26 36 10 11 23 20 35 28 13 7 27 13 42 17 15 4 30 6 46 6 14 0 26-1 36-3 11-3 21-7 30-10 9-4 16-9 24-15 6-5 12-12 19-18l-24-29c-4-5-9-8-14-8-5-2-11 0-16 3-5 4-10 7-15 9-5 3-9 5-14 6-5 2-10 3-15 4-5 1-11 1-17 1-14 0-27-2-38-8-11-7-21-14-30-25-9-12-15-24-19-39-5-15-7-31-7-50 0-10 1-23 5-34z" horiz-adv-x="1000" /> +<glyph glyph-name="git" unicode="" d="m934 851h-868c-37 0-66-30-66-67v-869c0-36 29-65 66-65h869c36 0 66 30 66 66v868c0 37-30 67-67 67z m-738-557c4-11 9-20 15-29 7-7 14-14 23-17 9-4 19-7 29-7 8 0 16 2 23 3 8 1 14 4 20 6l7 53h-28c-4 0-7 1-10 3-2 3-4 5-2 9l5 40h106l-16-134c-9-6-17-11-25-15-9-3-18-7-28-10-10-2-20-5-30-6-11-2-22-2-35-2-20 0-37 3-54 11-16 7-30 17-41 30-11 12-20 27-27 45-7 17-10 36-10 56 0 18 2 35 6 50 4 16 10 31 17 44 8 14 17 26 27 36 10 11 22 20 35 28 12 7 26 13 41 17 15 4 30 6 46 6 14 0 26-1 38-3 11-3 21-7 30-10 8-4 16-9 23-15 8-5 13-12 19-18l-25-26c-4-5-9-9-14-9-5-1-11 0-16 4-5 4-10 6-15 9-5 2-9 5-14 6-5 1-10 2-15 4-5 1-11 1-17 1-14 0-26-3-38-9-11-6-21-14-30-25-8-11-15-24-18-39-5-15-8-31-8-50 1-13 3-26 6-37z m340-104h-71l39 319h71l-39-319z m348 263h-81l-33-263h-70l33 263h-83l8 56h233l-7-56z" horiz-adv-x="1000" /> +<glyph glyph-name="plus" unicode="" d="m958 408v-120c0-17-12-34-33-34h-304c-17 0-33-12-33-33v-304c0-17-13-34-34-34h-121c-16 0-33 13-33 34v308c0 17-12 33-33 33h-296c-17 0-33 13-33 34v121c0 16 12 33 33 33h304c17 0 33 12 33 33v296c0 17 13 33 34 33h121c16 0 33-12 33-33v-304c0-17 12-33 33-33h304c13 4 25-13 25-30z" horiz-adv-x="1000" /> +<glyph glyph-name="minus" unicode="" d="m942 258h-884c-8 0-16 9-16 17v154c0 4 8 13 16 13h888c8 0 17-9 17-17v-154c-5-4-13-13-21-13z" horiz-adv-x="1000" /> +<glyph glyph-name="remove" unicode="" d="m942 688l-109 108c-12 12-33 12-45 0l-267-267c-13-12-33-12-46 0l-267 267c-12 12-33 12-45 0l-113-108c-12-13-12-34 0-46l267-267c12-12 12-33 0-46l-267-266c-12-13-12-34 0-46l108-109c17-16 38-16 50-4l267 267c13 12 33 12 46 0l267-267c12-12 33-12 45 0l109 109c12 12 12 33 0 45l-267 267c-12 13-12 33 0 46l267 267c12 12 12 33 0 50z" horiz-adv-x="1000" /> +<glyph glyph-name="bookmark" unicode="" d="m767-96l-234 267c-8 12-25 12-33 0l-233-267c-17-17-42-4-42 25v842c0 17 13 33 25 33h533c13 0 25-16 25-33v-838c0-29-25-46-41-29z" horiz-adv-x="1000" /> +<glyph glyph-name="branch" unicode="" d="m829 579c0 67-54 121-121 121s-125-54-125-121c0-41 21-79 59-104-17-129-125-167-192-179v287c38 21 63 59 63 105 0 66-55 120-125 120s-121-54-121-120c0-46 25-84 62-105v-458c-37-25-62-62-62-108 0-67 54-121 121-121s120 54 120 121c0 46-25 83-62 104v50c58 8 154 29 225 100 50 50 79 117 87 196 46 25 71 66 71 112z m-441 150c20 0 41-16 41-41s-16-42-41-42c-21 0-42 17-42 42s21 41 42 41z m0-750c-21 0-42 17-42 42 0 21 17 42 42 42 20 0 41-17 41-42 0-25-16-42-41-42z m320 642c21 0 42-17 42-42s-17-41-42-41c-20 0-41 16-41 41s16 42 41 42z" horiz-adv-x="1000" /> +<glyph glyph-name="tag" unicode="" d="m433 800l-316 8c-38 0-71-33-71-70l8-317c0-17 9-33 21-46l442-442c25-25 71-25 96 0l308 309c25 25 25 71 0 96l-442 441c-8 13-25 17-46 21z m-83-225c0-37-29-67-67-67-37 0-66 30-66 67-4 38 25 67 62 67s71-29 71-67z" horiz-adv-x="1000" /> +<glyph glyph-name="lock" unicode="" d="m817 429h-50v109c0 8 0 12 0 20 0 5 0 9 0 13 0 4 0 4 0 8 0 9-4 17-4 25 0 4 0 9-5 9-4 8-4 16-8 25 0 0 0 0 0 4-4 8-8 21-12 29 0 4-5 4-5 4-4 8-8 13-12 21 0 4-4 4-4 8-4 4-9 13-13 17 0 4-4 4-4 8-8 9-12 13-21 21 0 0-4 0-4 4-8 4-12 13-21 17-4 0-4 4-8 4-8 4-13 8-21 13-4 0-4 4-8 4-9 4-17 8-29 12 0 0 0 0 0 0-9 4-21 4-30 9-4 0-4 0-8 0-4 0-8 0-8 0 0 0-4 0-4 0 0 0-5 0-5 0 0 0 0 0 0 0 0 0 0 0 0 0-4 0-8 0-8 0-4 0-4 0-8 0-4 0-4 0-9 0 0 0 0 0 0 0-4 0-8 0-8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-4 0-4 0 0 0-4 0-4 0-4 0-9 0-9 0-4 0-8 0-8 0-8 0-21-5-29-9 0 0 0 0 0 0-38-12-50-16-58-21-5 0-5-4-9-4-4 0-12-4-16-8-5-4-9-4-9-4-8-4-16-13-25-17 0 0-4 0-4-4-4-4-12-13-21-21 0 0-4-4-4-8-4 0-12-9-17-13 0-4-4-4-4-8-4-8-8-13-12-21 0 0-4-4-4-4-5-13-9-21-13-29 0-4 0-4-4-9-4-8-4-12-8-20 0-5 0-9-5-9 0-8-4-16-4-25 0-4 0-4 0-8 0-4 0-8 0-13 0-8 0-12 0-20v-109h-46c-16 0-29-12-29-29v-475c0-17 13-29 29-29h638c17 0 29 12 29 29v475c-4 17-17 29-33 29z m-459 109c0 66 50 125 113 137 0 0 4 0 4 0 8 0 17 0 21 4 0 0 4 0 4 0 0 0 0 0 0 0 8 0 17 0 21-4 0 0 4 0 4 0 63-12 113-71 113-137v-109h-280v109z" horiz-adv-x="1000" /> +<glyph glyph-name="unlock" unicode="" d="m817 429h-459v109c0 66 50 125 113 137 0 0 4 0 4 0 8 0 17 0 21 4 0 0 4 0 4 0 0 0 0 0 4 0 9 0 17 0 25-4 0 0 0 0 0 0 9 0 17-4 25-8 0 0 4 0 4-4 9-5 13-9 21-13 0 0 0 0 0 0 9-4 13-8 17-17 0 0 4-4 4-4 4-4 8-8 13-16 0 0 0-5 4-5 4-8 8-12 12-20 0 0 0-5 4-5 5-8 5-12 5-20 0 0 0-5 0-5 0 0 0 0 0-4 4-12 16-25 29-25h66c17 0 30 17 30 34 0 0 0 0 0 0 0 4 0 4 0 4 0 8-5 16-5 25 0 4 0 8-4 8-4 8-4 17-8 21 4 17 4 17 4 21-4 8-8 16-12 29 0 4-5 4-5 4-4 8-8 13-12 21 0 4-4 4-4 8-4 4-9 13-13 17 0 4-4 4-4 8-8 9-12 13-21 21 0 0-4 0-4 4-8 4-12 13-21 17-12-4-16-4-16-4-9 4-13 8-21 12-4 0-4 4-9 4-8 5-16 9-29 13 0 0 0 0 0 0-8 4-21 4-29 8-4 0-4 0-8 0-9 0-17 0-25 4-4 0-9 0-9 0-8 0-16 0-29 0 0 0-4 0-4 0-8 0-21-4-29-4-8 0-13-4-21-4 0 0-4 0-4 0-113-42-188-142-188-262v-109h-50c-16 0-29-12-29-29v-475c0-17 13-29 29-29h634c16 0 29 12 29 29v475c0 17-13 29-29 29z" horiz-adv-x="1000" /> +<glyph glyph-name="delete" unicode="" d="m500 804c-254 0-454-204-454-454 0-250 204-454 454-454s454 204 454 454c0 250-204 454-454 454z m267-491c0-17-17-34-34-34h-466c-21 0-34 13-34 34v75c0 16 17 33 34 33h466c21 0 34-13 34-33v-75z" horiz-adv-x="1000" /> +<glyph glyph-name="ok" unicode="" d="m500 804c-250 0-454-204-454-454 0-250 204-454 454-454s454 204 454 454c0 250-204 454-454 454z m283-346l-358-358c-12-12-33-12-46 0l-162 163c-13 12-13 33 0 45l50 50c12 13 33 13 46 0l66-66c13-13 34-13 46 0l263 262c12 13 33 13 45 0l50-50c13-16 13-37 0-46z" horiz-adv-x="1000" /> +<glyph glyph-name="comment" unicode="" d="m42-13v601c0 87 71 154 154 154h600c87 0 154-71 154-154v-342c0-88-71-154-154-154h-583c-9 0-13-4-17-9l-113-112c-12-17-41-4-41 16z m158 684c-46 0-87-38-87-88v-487l54 54c4 4 12 8 16 8h617c46 0 88 38 88 88v342c0 45-38 87-88 87h-600z" horiz-adv-x="1000" /> +<glyph glyph-name="feed" unicode="" d="m888 804h-780c-37 0-66-29-66-66v-780c0-37 29-66 66-66h780c37 0 66 29 66 66v780c0 37-29 66-66 66z m-638-787c-46 0-83 37-83 83 0 46 37 88 87 88 46 0 88-38 88-88-4-46-46-83-92-83z m292-13c-38 0-71 34-71 71 0 133-108 238-238 238-37 0-75 29-75 66 0 38 25 71 63 71l12 0c209 0 380-171 380-379 0-33-30-67-71-67z m237 0c-37 0-71 34-71 71 0 263-212 475-475 475-37 0-75 29-75 67 0 37 25 71 63 71l12 0c338 0 613-275 613-613 4-37-29-71-67-71z" horiz-adv-x="1000" /> +<glyph glyph-name="right" unicode="" d="m308-96l-75 75c-12 13-12 29 0 42l309 308c12 13 12 29 0 42l-317 312c-12 13-12 30 0 42l75 75c13 13 29 13 42 0l433-433c13-13 13-29 0-42l-425-421c-8-12-29-12-42 0z" horiz-adv-x="1000" /> +<glyph glyph-name="left" unicode="" d="m683 800l75-75c13-12 13-29 0-42l-308-308c-12-12-12-29 0-42l317-316c12-13 12-30 0-42l-75-75c-13-13-29-13-42 0l-433 433c-13 13-13 30 0 42l425 425c12 13 29 13 41 0z" horiz-adv-x="1000" /> +<glyph glyph-name="arrow_down" unicode="" d="m950 542l-412-521c-17-21-50-21-67 0l-417 521c-21 25-4 71 34 71h829c37 0 58-46 33-71z" horiz-adv-x="1000" /> +<glyph glyph-name="group" unicode="" d="m958 221v-17c0-4-4-8-8-8h-167-4c-16 21-41 37-79 46-37 4-58 16-71 25 9 8 17 12 34 16 45 9 62 21 66 38s9 25 0 37c-8 13-33 46-33 84 0 41 0 104 75 108h8 13c75-4 79-71 75-108 0-42-25-71-34-84-8-16-8-25 0-37s21-29 67-38c54-12 58-58 58-62 0 0 0 0 0 0z m-725-17c17 17 38 34 71 38 42 8 63 16 75 25-8 8-21 16-37 21-46 8-63 20-67 37-8 13-8 25 0 38 8 12 33 45 33 83 0 42 0 104-75 108h-12-8c-75-4-80-71-80-108 0-42 25-71 34-83 8-17 8-25 0-38-9-12-21-29-67-37-50-9-54-50-54-59 0 0 0 0 0 0v-16c0-5 4-9 8-9h167 12z m463 13c-75 12-96 37-108 58-13 21-13 42 0 63 12 25 50 70 54 133 4 62 0 167-121 175h-21-17c-116-4-120-113-120-175 4-63 41-113 54-133 12-25 12-42 0-63-13-21-38-46-109-58-75-13-87-84-87-92 0 0 0 0 0 0v-25c0-8 8-17 17-17h262 267c8 0 16 9 16 17v25c0 0 0 0 0 0 0 8-8 79-87 92z" horiz-adv-x="1000" /> +<glyph glyph-name="folder" unicode="" d="m742 17h-659c-12 0-25 8-33 16-8 13-8 25 0 38l179 342c4 12 17 20 34 20h658c12 0 25-8 33-16 9-13 9-25 0-38l-179-341c-8-13-21-21-33-21z m-596 75h575l142 266h-580l-137-266z m-29-38h-75v550c0 21 16 38 37 38h246c8 0 21-4 25-13l54-54h325c21 0 38-17 38-37v-105h-75v67h-300c-9 0-17 4-25 8l-59 59h-191v-513z" horiz-adv-x="1000" /> +<glyph glyph-name="fork" unicode="" d="m838 688c0 66-55 120-121 120-67 0-121-54-121-120 0-42 21-80 54-100-12-100-83-146-150-167-71 21-137 67-150 167 33 20 54 58 54 100 0 66-54 120-121 120s-120-54-120-120c0-46 29-88 66-109 13-129 88-225 213-271v-191c-38-21-63-59-63-100 0-67 54-121 121-121s121 54 121 121c0 46-25 83-58 104v192c120 45 200 137 212 270 33 17 63 59 63 105z m-555 37c21 0 42-17 42-42s-17-41-42-41-41 16-41 41 21 42 41 42z m217-750c-21 0-42 17-42 42 0 21 17 41 42 41s42-16 42-41c0-25-21-42-42-42z m217 750c21 0 41-17 41-42s-16-41-41-41-42 16-42 41 21 42 42 42z" horiz-adv-x="1000" /> +<glyph glyph-name="more" unicode="" d="m592 408v-120c0-17-13-34-34-34h-120c-17 0-34 13-34 34v120c0 17 13 34 34 34h120c21 0 34-17 34-34z m-34 400h-120c-17 0-34-12-34-33v-121c0-16 13-33 34-33h120c17 0 34 12 34 33v121c0 21-13 33-34 33z m0-733h-120c-17 0-34-12-34-33v-121c0-17 13-34 34-34h120c17 0 34 13 34 34v121c0 16-13 33-34 33z" horiz-adv-x="1000" /> +<glyph glyph-name="comment-add" unicode="" d="m48-12v593c0 86 69 155 154 155h596c85 0 154-69 154-155v-338c0-86-69-155-154-155h-584c-7 0-12-2-16-7l-110-110c-14-14-40-4-40 17z m154 679c-47 0-85-38-85-86v-486l52 53c5 4 10 7 17 7h612c47 0 85 38 85 86v340c0 48-38 86-85 86h-596z m479-284l0 48c0 5-5 10-10 10l-114 0c-5 0-9 4-9 9v114c0 5-5 10-10 10h-47c-5 0-10-5-10-10v-114c0-5-5-9-10-9h-114c-5 0-9-5-9-10v-48c0-4 4-9 9-9h114c5 0 10-5 10-10l0-114c0-5 5-9 10-9l47 0c5 0 10 4 10 9v114c0 5 4 10 9 10h114c5-3 10 2 10 9z" horiz-adv-x="1000" /> +</font> +</defs> +</svg> \ No newline at end of file diff --git a/rhodecode/public/fonts/RCIcons/rcicons.ttf b/rhodecode/public/fonts/RCIcons/rcicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..37231133cf013118720f12bac6769ef24573b162 GIT binary patch literal 10616 zc%0=~X>eS}ah`ee?!De#Z?RY$Z}(vrB(S?!0E-29ffNpc5@ZV`WfGti2}@u>Qp9Bt zk|`%~9J^vEv>Z8y6(6z7i5(@jY}W&6TSvJZCeGocQYj~KY`GG<@*|bVj^iJRk8%Pm z^3B@^5TvQ3DwWEg0NClCo}QVW?w;<R1)+qHAbC4sWcGp6J$=K4d*27jckwwhw^UvI zN>}nlLg*Mi_su=AZV~sV_3dc%h1Cm7PrvuQGw44<h;Q{m^~x&f2KrY4)eDPHF1+g- zpU)E_yq6I3zKgZ$ycB-;+k`az9mXpcK~P>`=Lkv0(C@gow0`vxpGlHKXciY&=BiVF zeCD0#e;oaxrRvpH@>xG*Nb>pCa&@UT|LkA?3HqDZ<Nno^E9<ZR?5Cb3q~!$UEv~NB zR=;_f{Q@ETFiw7&Q1%*qFOi5UyjA!DD9<z?{d>|&1*||MM(+AEwJ<(Uj=e@+OR`hj zkCAiiEcp<~beDm7pB9fch8}hMBH0Hh15#{&6}GoI!)t`YCVFcPD&KwY|7SlEA={6! ze}RTWBubXaJIIGg=$QXK*M4qg!i*RykqX^39i&RQjV98=bTC|`EFDhMHagfhEDV%8 zi?lP>L-`-jqqH(OOcVWPJ2m_9+Xuo?jPPM4gJtBnnZQbX+=Ve&2~s;#6qKAC0?m}7 zc2Gzt=<rEJs@T!N@)2+*%tJJ4E2a|fEa%E0n(4GzKl|k72U>EJ=33YV7p6Bq%4WA@ ze_T)4semL%f}$F#7L-L%5CtlVepM9(SrA2;DWXV)u%sw@RQH*7TvaH;kSd2YRSpS~ zD2V~ZX9N_^8dnq_9e&%O$Ygp*78QXB%~Vwj$F|RjOj6q0`wS|cV*=>8_C9tNBJCAz za|U9)%2XO^u_FPWq=>4hh)fj}(GX<_rcg>nDhUGcCX5LxqaiaAjD~!2gPAe~%zl~4 zvI1^dXjf%L$236^o>hJExKDjnk!gMVIVS5LWjHPUWl8dXlnNqv>f1!z{*Ub%dySoP zZQV|4BydbWmu+(GEWVDN`;~rZ-5!Lp2f4u#eXu+1Y%4MhqR5I2>(S0iXJwF^ez0<g z_QCMnUV|`wk;3vex4i&E#}X#{?K>>i=34AyKNURCejxNPZ#UJj7B@q_fEm|AXCw;c zOR}!|f^kD+(2}A{ekEvxL{XF!S%Pk)sBHM4r$8i@ZD~<8T~XPoJ1y`qo2`#8QM$Zb z-;OH*QKf?FQ!ckNxf_0<#)En!5eWws)io}RDp0ve4T=(DRE@U;BON{QCil*4|1<8) zKY4mgL6cQ}XHI9^TAE^ay)%_uLzjd7gSOJo9XH$1C07{NWz5rMkwK5cf~!MZk-<KU zx;Lyd13mNm11-j5T#N5+?ZnYi?1|PaptbqSY^DBh2bxEf-<L*z{!sgY`d>ngv1BM^ z>OMU*1AjLqRa2YHkV@f7u~Z}o1^WGPDp8CEMP1T^N<f1GLjl#NhM>S~>*hy11)gus zZa%^u+4`HW77B&>c1{T}jWSgh)ywUo+|8&cC}t{bM#HH9gS!e$Y~t(7T(kZllxH>- zpgYlxHw_;=MJ|%JaUWb?JA3*_>s@`2n(aaxQ_P@XXLx|=gpc*L3H^PQfiiqcC?W(6 zquY*vlz?s!Nn9<-rUWfl5@wu-8Sb#d><~qyK~RZ>1Ut&r+fI)P{p|V8-)Mmfvn_1i zg`3}ym58aEhL6&4d!Z%J;t!chv#9Dpe>4y`eL+9&nxTc-x|)N5gg+`q;F3OnC?1kz zL85fzo(B&2L?w;zBKoCC##BW<K*Kpzmsco+*;n8$wIa~?QLf~cz5Cb4WKmN@zmbSE z?YE+`BpMnPf<a7E_iLh}$wqS|zOOC96gjB2!vKm(B~g~u@HcTvM5Ya2G8jzyHUx!< z_1~AJKayqND>x}*;va>ApLH|m_GR{Mb{aNFk<&zfak$rn+p@c;9~U1H7(rmLKfxn* zKleyz@hAcVVze8(xqA*v{e2j2r?5eh*}0$)kFnp`{IKUfbM6VZemr4ZF-~;4?R#WR zZw>`aO-{);!DEI$kP5X$+e&G_MyWs1)|qdLhr-RiXp?M&LP0}|r{P<t?@-v*(o;{- zqfb5cbtB;Oi{gMHb-qiJbx}04sphs+&;Is=pGiI~(y9tR_$7^`^DTzwhYcMZC-=b@ z;fE*RaPLH^<L-XgCb(X7$I-d>iTvb3qH%C9$4Sr`9MF#1gL@sU#$j$tkfW)PKcOlu zvMS)@0e?%VJ=)rvj^o(5LQ^~(PMT`cJ9aFSl2n0CPjpVufs^Uu>C-CY=F#m#Egha3 za$8?Dn*4~3Tmk!b6fkh>{9(OWWj>XO5i4P~#Ga%_hw4A33NQS4O|<=P_C>aj^bq-m z?WZ_?9Emxdk>g=Ne)GcRoSn|(j?i*tFpbL>F1vv~5ssPt>59p|7&hu(2_X7C8HiHg zuLfdagO+YlXh{#z_g@XfXoHhR3|ihZypK=d147i336A<D`U>nL-%tpb$=km_-DkE! z%j`3o&&awiv#YXCL!9x+A7nZjRr1dC9D9*v-7}>GKEE@UQK+2hq`6Fp%CQ7BW9Y|t z=oqAxKJ<CHQpR{0{WAN^lAhG-KhT?blhog=Y1F4_^&e>3VxR>$2GAt+r3Mj$g0r}b zYm1GEXnu%h$xnBu^L4%HT1!LLUuFAP2eOHL!zV*li9uE-bG^IgjfaC&*#3?ZRlXfe zQ9~1u8EI;^u^_?|yDt!n1vXzXqh5@CKRW_@7ReA9C2!!qePZnBf&LyV%6%I*7H%3d z6Wqs#>A-FuyTsjaIatnh4)ElJaGULGqewovawQ5!fc<%&Hi$)9VMpj#xjZ4XwT7Rp zv}Wk>%D^biw6tVE?jHkI_}Rfpzui%vFq)_tHIhlgNYX@<_h?}k6-LWr6jRzO(MR8) z&~~F@_j5wOT`}sFXvJ;}+XF_Q)Lp*+YV_dCW-gJ)nOhMofK_q{;T`CL$Xy4u|Mn-@ zr=Wu<UIpssnoXSwIC>TbjpC%R^`L9(B6YI{>~GSI`X9FLrz+ylE3u&%Ek~pE<8sp+ z%^t`y``~_NsdQg!{Y!y_UOyg<(gDu&vZj5jC6_yp&ANNOpPga_^7G_<*z?zZ@yP+c zr#(>4;m?MeV_eteP8%hxi{%D-gbc?rD3W?8Z#zr9=-WfI*Dm$CAR{ZKUdWx1fyvxd zwjAdnNRGpiV{#mr;ug}Vj$?8w0u#TuxS0H+7HJlSMBE<iFZJTa_QSyOH0$j{c49~h zG8(_gkSuhcAjlf;%c74{!-}CKlL$m%xh095CF>|)WxpZ_nuLZ)n&=l%axyR@^A!Ez zuwQsvz+jR3etN7V%6{g4O2=sZHTvo26t{TwD^$XYjK=x)K0eu}Q;vxYg|;j+E|jJ* zR9+GVnKDh5!78a>jf)W<XHaEVl;?~<JsU8L0R7v5vDAM*7NShQzkkV#0q<vTgbzH0 zd-ZcmZVVaNQAP&UL8%w|FuBW@dU^6fMG))f2ya_y86$@%E=Z}j953f8Zv9an$lcX~ z@}Or%&wz5L%?;L#M4`lQvq(9|dg}u_3ZhcLAMm@HS6~Dgj}RQ6Vt^U?NFXdx3C9+> z25vJ`m~vY|Z4oF_4fwm{uwRqKGd0@h+TpEe>8CxFpoqqbU`Mql`2?;$x546?L1O_4 zx(wpOLZaY{+{H97gv?-TZfQvr)7Kta+N*ib_g_H_^P#3tKbHu}g!{gXvXCSyWH3jf zP=p)8VF4b}==Z-=mryR<yh*7f)wd@hN4;o70O(&C5!M0P&71Y@9iDo#n>8kpFCw9x zJHE50jXm3f-k#*vo{0B&fRqu}Q6jo`p2HaZ{+@;T<`30Bh<N;4y50vc!b7uyAl;|` zq!cgIKd5ORa|gkwQ>382K=Y0~Ut^ya{*gpT2jsC6VG;5q!u-JSu`pKvzqUE9iZDWJ zzgJy!rn`jcW5V?4849@dvR`_$-uB^+K15fY370zhDecW|{cb>*X>im(2}spdzhC$Q zM(W854Ah&WXY793i2uLl>Lo;)NuCVz_&-$0rQ&yg=OG3ns-qvIQqg^G6a`!mmyqDq z9cd6m5;c)+H^1*yGyX<Vw_x{_au880Q-bixo|<nh&`hiUH@_~@&c6Ufs(=5_8YH}M z&nZGD>)=J)o@F+_M|&pRL)tw-y1#YdT>^sceky+bqs{v$2!BTX63rgmPnG)f_087( z?%n=%mSSZ$XGVC<B6a3q-p+=#5#V{Qr{&2=gbqX^^)G4KWIRqcVzK&JB{|FSGCo6k zLYoBbfq1<Bkk*J9PcxNu5fkgigFI#=8g&A%7hpWEJm?c%nAG+9pCi{FahI+?0B87w zmSEPTmf!<u{*bSZOtAq-KcVl|HD4BL@LBnW%IgxXQIk}-kFd|z=YyTW`lF#(D?8F^ z3T<0IG7LeBmjt2YPIa4`!n;TgdHpS@-Irz#cA5;edp3?z&3z-mtiy~O&b1=X3vvwB z1X_~#7#(!ka_)OQ*J%f-`&CSkvmz44%|w<D^DlE6!-?C+8-eTyE%oAI`$ej}kQhp3 zblLEy+hi6<QXx@^SDGc7RApaFrZYyjx&xV}c3bl&Gi?k{PM0NCX<^{-r!pN;N)_Q9 zg9SAjZHr3szO%UpJDHUAYmriUFeB)S5SDep`es<6R*;48zGF%xX+#UH>2X<}Xt%m_ zzY#GNUr`DNOoqG=P~}J<8rAcynQ=*;INGK8!x2-~_G^Yp1G;5c?d42Q|C+9@_m{?v zNL#z52gmfJ?DNS<eazGImxXu2zY?gU^cP#2%$UaCNLd6i=q}2yFY>9WuprH*qiJS) zMR7ZID^z<Rjg)Q+|G2fJMP$GK28#rQUjZ5n-jE|(9}|xL($*KApNtznlnqv)<Aym| z|7yU0==Z|944*lp`8ce<p!+7NUjK@aGfY{jn4wFfR5?U;>%8O0Z@uIo8Ee#e_m1Cl zsM42Zch-5XTX>b8>kEnaZm|dIfa@1-sh7zOQ@7F^re=^vcS!6w9q&gG)|&L4Ee}5E zOSU!&JX~RY>5*1m?(q`MN<OrrH+O7(&8^8y+Vt&4aYmDW%F8^C2u`E2vj#%<y)hJe z<9(q4%d7Pc8r65(zh?}z?^b&^Gf&S44xDIIc5bcbt|ENzR;|b1v(E}s&_jr{xwh(T zZ!(Z9y>|?MzYLV!yTEuc1^-R(5?~;Ad$*hurXt2wH_Kc#A{h@uOVhXTNaGdb4aDd> z!`>6-No%Wv<9rO1hFq_*mxRAZKFE;!A=hXj5e;*>ZqEssTREY!n-Uo0>84zAfDEcS z9K;otyI3oQ%n%ueGAkwF>^;JR_nZ{~w_eiaWq;}e9VJ>;bYUKlmO37n#Wj>mVvi_O zZH<3lu*R_-JhW9{e&OT@pFL9l44|@%3gbmu%GR3)6ae~QwnXdyfNI5Mc9)`BiFug1 zrcpuOd9(5KBj0%T(a_-^5FdMulm9Z1{(=krKYC{SpSNr7x6Op8JYN!Tp7%XJ__x2y zHurqf-}p)Kk^ifY`}0HkL19SvclI-)Al@%7ihm$}M_QDgmzR|e<q_q1<vZ%b>eK2= z>Z{r_+PC!c`e%GuSLzh`2>(vKQ4J7-TtRF3R=rgt<XgLE3+`kCv<iCEo28Jrhcn<i z|KSjU+a4|<cXW9;Y8^7*;X3IihdtbfxOIX5S42co!zyp}aEhIt^Kb$9$32_@zwY58 z@S7ekArJnAhs&V<gNN(n4Ea|N_mLbuaq8mAd~FmTYhvmAiM6>)b1TbNPSq|vzF1xJ zdLB4aTf1^;W!dU2mORQtZMn8qU9Zhs=byB$JaM6KeSN`NSX)`Lj;}1Q*A^F7tkt!Z z$7*xy#f$6fs|R~}7Cd@!Ze_{+9&v@tlN#Q-4QP=GvP9046J(9dkxTfjkY(876vi%) z$H^k8V&wL*+k0ogxdwR2?OTYjMN+zhX97ISE?<?b1I~l*Jb4oB74ii3=>v70ETF#t zo)t)Bk>l=M&b^4=6;M{)vByA}1HFi|@L8*f=soydxP!mw?!L5pcl5jbPshD6a4P|Y zKb{wOtSeNd8r7+f`e^_Uk`Og$7?CWB_!Y-9JVBdik~Y&+Vr{O#O;Wh>#ByPMt-5?= zwYpYYUN?8>7ccB3@3LRGw7!?lFkQHKfq^WpE<S!mTDr9S_!W7rwzTp@O+CM|a(St` zc3D1;8FLredi8?1xH5NHetg*l^R>m=dQDiltiZZUSWaB1)#jzOOBXJ#i;J~|bsa9X z@|H*ESKhKLU07Rrd{tgpS)8w}i3=-hm&K)(wVKbHS*Xs>dv}a(Z<Eko6*(ktIpj^# z<1>~u`4S19oOI;V=cb)<%GozFyI@^=)3hUGt1qhvRdaLp`BXaXkQs-J+GE$T-stQ| z!J&D_nq4S3Lf)FUoSRdQm^*iUAJs?4=f+PxG@Z87scX}gGc`4xc8<-YEN6&gLo+kh zMuVw3@9YD~>sd~TkC!;-&8cY%LR_m_jy^R#3yQ_ZbdFUxR+&xB&dkiD9NIlIV>@JO zx;8UYa9G~LI%2j8fuzx?X-Be09N8X$_%jZjEjVJ{hFsSChID?!;v<dCdFznb@i~We zr9mIHu36Wx_C`s{;#eoAXQxutQ!~@{3`UQgp2kp$AIjUg;7EB#8STCf*K}1Qqic`Y zP_aEyb%gT^4xPjPj?`6fl)S}-^o`EFB$D$MU%@#xJHuIK$6O)R{B^}gM#o3G(!0vm z^0zBrZ>&PQA;Kt5JZp_#v#Z<?uBJ$eYtyk(5OPOKhh^>RSYr#{>r8h#FpH#a9c}L< zf8IUNb)U}0r_(7rJ=2vgID!0zAdEZn)v<yT%!ARg9RKKjd^!+&WX1{b-YN6~=oOq0 zmN8tFSkS;6_H}}zv(~j)%Lzhh1;@xwJ~+K0&X3J>IDwjdwcv#FlP9MqPdA9EH0V*6 z9?5Tz(CC|{H$tINhgL_NP&ao{xbDb?pEm(C4mDv3mYtg3;L5{kN3OxVeA}+HjcGf0 zsxi)|!1p<21}B+-{1c$wZmQQY;07U48`^?54PU2}y0(hu$p#U|ADnhV_J}p^_~4W} z^gBCZ&0_n{83xZxBO}*lHzIPkv(}x;Kus~6E!tgh;`t5Ap$R>6n8<H14x92DB8SQR zhQwiWenaLkmETY}Y{_q^9Jb~+G!EPH#0hl&4+Lq4AZ=K{f*>5GAqa;V2*RNaK{)Jy zARJ~P2!}Zc!eJ)_;cy=W;c$Q6I_&yWS039Mv(_k#Fgxn%9Cu_tcdG8Z)79;C;kxAE zsT0=gsN1d%**sSLmmKhyf>YSF0X3a`mqX(v_i)9%TDg6wCvOe7a+bhD$A5BhT%Wsc z%IU=XtQ%;@hV7w^9va6<dU0+DdUrYDwbh}5)0ZzM4i}vM|Be+NHV5`HOhL@7RkSAf z&4dc?y>@NFp1@U}M$AUc!*%VacnM(t0fZ0}-j6?*#nDE)YuAdlWgWhTwJNuUtzu&h zN5q=ovYc6dnU9^Ez9Cr5O5G50ta)aH2RId>(ssG+<G5O*cixj(9%LGkTo|35w;eWG zoyV{+T1^3;<pJi-IaP>+sB0gG?QHCD9OnXXcfoph*~D&yG7+~Ix|iTc(od|475Ry> zt`KOa8X@e~UNHF}*MS9!l=F08ABJj%T(YC$(pc7UdxCGqt#!av89#uhQS#t)(K?L8 z$0hcN7MEp5<#HCid-tZ+hN14}xt?Wg?!E^-2}XBJGs|=Dok!d;<)OT76}i@qBkCTW zDQ<Mr7%tx7UGmgk@{!xQ@5(crcLuuey6DloQ|Z2jjk&Wx+MncsS&B|KSdZ;`*p7C& zbJ=k9A}&c|xqA>S5TO4Dt~l|(<$YXy9#;<A2pxOuou2Vz9O25?IsYg>f7<pG;GJXl z$YVHiym2{^x^WMqMW+{car|}Y#}R93Eb8<DpU699fD>G6<It;h9C>O-Pxt1zJ31$T z-j}~l$UQ(Nfl!XzpTACB${T>Vls9so5g-q69*#_L9*&&kJRCX2d4_?U<~$sEkn?cl zO`L}#XE@I>AZIxbN2WOsM`kz=N6vAcQ6LX-9*#WBc{uV@oQETiaGs+;9_2h7ndLkj zsd65UoX<OhyK0`}9p@0Rc^5kjtmgU?I!Dl1$U8&3+!uJq<-X`*ocofCan{H3&VgOl z%e>>VF1i?JU2-wbx}0|o?y|1%j?230Vx0BOF2-5c@;5Y5*r|+0x*fIVu#Ty#Jf9Q@ zitI0+LIFa52|>AW_g6QFG=hSms{z&9;LFGz+Fp#2v5gM;^hx;X)6*MlerzMhd#|W( g$2;`c({repz=E21W`p><UZUH-;E3-*b{Hf72^zo6H~;_u diff --git a/rhodecode/public/fonts/RCIcons/rcicons.woff b/rhodecode/public/fonts/RCIcons/rcicons.woff new file mode 100644 index 0000000000000000000000000000000000000000..95e017626f842ad954164d6e01971a580c22b7fc GIT binary patch literal 6520 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 S+C`cJHUfa=XxiZC@BaX^`3q+N diff --git a/rhodecode/public/images/RhodeCode_Logo_Black.png b/rhodecode/public/images/RhodeCode_Logo_Black.png new file mode 100644 index 0000000000000000000000000000000000000000..e669a6abe5792ab6de7e8512d4cdcd89a4f6ea87 GIT binary patch literal 13379 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 P*QTbVtynK_6ZQW9?x~js diff --git a/rhodecode/public/images/dt-arrow-dn.png b/rhodecode/public/images/dt-arrow-dn.png new file mode 100644 index 0000000000000000000000000000000000000000..85fda0bbca21cefc6b8cf1726bc83e43bff993c4 GIT binary patch literal 116 zc%17D@N?(olHy`uVBq!ia0vp@K+M9#3?wzWV%32ZXMj(L>;M1%fy~Ir2;r~IJAo|5 zk|4ie28U-i(tsREPZ!6Kid)Guq>ddput17Y#X`7&C779+nL(zFDdZjVkv^az22WQ% Jmvv4FO#tWt9i9LH diff --git a/rhodecode/public/images/dt-arrow-up.png b/rhodecode/public/images/dt-arrow-up.png new file mode 100644 index 0000000000000000000000000000000000000000..1c674316aed41943dae79b01583956db63c8be08 GIT binary patch literal 116 zc%17D@N?(olHy`uVBq!ia0vp@K+M9#3?wzWV%32ZXMj(L>;M1%fy}VT__niwAVJ2G zAirP+hi5m^fE-Cr7srr_TgeGo2?+@gd>DjQ2|6TYNiZ`ri2h~@(drDS1}b9kboFyt I=akR{0K<nI-2eap diff --git a/rhodecode/public/images/favicon.ico b/rhodecode/public/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ddd576cdeeafc67789e3f6bd9510494c91e999a8 GIT binary patch literal 5430 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 diff --git a/rhodecode/public/images/favicon114x114.png b/rhodecode/public/images/favicon114x114.png new file mode 100644 index 0000000000000000000000000000000000000000..145a346ddc84516231bf2b31927d535cfe7fd973 GIT binary patch literal 9548 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 U;gUS?_x~ovw`#JL(&i!m3x+EQPXGV_ diff --git a/rhodecode/public/images/favicon128x128.png b/rhodecode/public/images/favicon128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..3be94f861845bdf7c95437d9e8c13143e821bc4d GIT binary patch literal 10145 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 diff --git a/rhodecode/public/images/favicon16x16.png b/rhodecode/public/images/favicon16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..e344eb8b6361d0de649ddd2f7d6e7c63334dc7ce GIT binary patch literal 1682 zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3 zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e|N`3t%Xkn;4iI8JJlZ z8d?|`IXXKUnVOiG7#WzG8N$rKrq|WN(#+V{z|q;w+{w_;6{yk8*~!qv9LTqHadI<( z>GjMjE=kNwPKD{sMCi4|tJli8C^fMpzbGU>KL?fq0y6ST@{2R_3lyA#%@j0z6O%LZ zKmwYe2!gsbwJ5VJHN~wcKUV=9!d97BTtL|85WOkngql9kG5To91ttVcgCHh6@dG*V z?30=Y%riy6%&}j6;%o*6rURZXjv*DddM3qt1Q&`NKfibP?YH+Vr7!0u<~?vbSF+>b z2mUEjmv9_)sXE!-p>shX$Z7MunwJ}!s!lm@FvmA(yjZHhy7B}6@52hQSyC&u&OX<( zthoN&-Sx%CW7m9I$Sl9(`v=?m_bvB-Ui{#EhQm3<<rBPSE!(O$o%>4G*L5nMpJ&W= znWuPpCzDj5V!2?GkK*4BHc4ka%^uC2ue;o?@ttPlxwP0+?wxq(pManUsiXg|&ark4 zj5Kijyvsyk`vmC|O?Mi9CslKo{189BFgrzbjcDZ5zN-$EuB-+;hm(I-`G{)7E}7t{ z(y-+uTZmyt!G0FC2cJZ>ZTOh))Ui&zdNm<UQ$Tg4sOkHOj8D{(!mK)#=i~^?jJ?fd z)3o<^u21s>6DN1=HCy-@zP@C>AlZ4$vSfv}i=UEjm*YyCbv6mR7p{2m^Vf6H2PHf_ zzsi!z5A9MjD6acG*-oSO?*_BOMQ#%>uT*`vKxNad)UK36r(DZUOGn(jeS7z_6(yV2 zW$|x$Q63RD^+lEP3cj4`J&z58Z-%ejP~rLHE4R;|<4SY=+>Ci{yE1-EddupS`MmM= z+jqQd%@cawGp+7AeEX}(oc|~CT{Zp+Z1}(-uJ`d_<O->GN1m>(OOrU;a%ZoXAqPj( zg=_<f8Og_`6F>jflQCVjaJ|ae)sr@EHkR(JD~wL|-o5tWp`|zT-k$m+*{N;OTe|U2 zctz+uZ4oX(%Y7~^LihWGCf!jv^h-)okYi=#MjxGbRYBoTUwo{vQTSZmGt);+sMl?? znxLbC^!=7M=AK7A(t~w1wJpDFS+-8Dh)v{=ba2`3y^j0%=lV_eRT1LM_*|tZ@!|Z9 z{wd}ii+)7!ncw)w>`&P0tG4Fm>^A3}i;Im}m>MS>e)!?R>M5U&{+4`_bm?WuybTdL z4?h3AcQa?(u|JdlA9v`R9^o<j?6b`)L$cxz>NB!2w7uq9_fV7<RLL-Sy85}Sb4q9e E05z_G%>V!Z diff --git a/rhodecode/public/images/favicon195x195.png b/rhodecode/public/images/favicon195x195.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7ab1d62048715847c1ebba0aea8b2eb163cd62 GIT binary patch literal 14579 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 diff --git a/rhodecode/public/images/favicon32x32.png b/rhodecode/public/images/favicon32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..b822ec02ba6b2a4ca5dbf589baf6f48abe07aaa8 GIT binary patch literal 2804 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 HN@&t=m|U4X diff --git a/rhodecode/public/images/favicon57x57.png b/rhodecode/public/images/favicon57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..f4aa227f84365f3bd9390f2db96fae1246f8d184 GIT binary patch literal 4560 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 NP-fPq4~;#e{|iVm2RQ%$ diff --git a/rhodecode/public/images/favicon72x72.png b/rhodecode/public/images/favicon72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..57112be6b53e07019b0c6bb52ef62f59137163be GIT binary patch literal 5549 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 K(yUdt5BV=kY57?I diff --git a/rhodecode/public/images/icon-left.png b/rhodecode/public/images/icon-left.png new file mode 100644 index 0000000000000000000000000000000000000000..79ea9b781115474bece039edad6e77b53448e232 GIT binary patch literal 1037 zc$|GxO=uHA6kgklKP`d>p&n$|URrGSFWDwpv({!ewSjI3Nx)nbx4V;ONq1-6otjM% z57JA)li=Nh;7JckOF<+Ef)q*>g$kk`ir_)2NDm^2aW-wD2<aSV-g|uCn>TO1x17&i z7(9CFC`D0&*=e;v&d?q>+)wuTmG`&FF@!T^TtpRI*F8v0nrIe+tgX+%0@TgM)peMn zsQwYFRK{g(Mlz7i=plv)Y?lgGY9erTqXsdUg>#l8)8C#nX<(T$eNogn%~fF4nqKr^ zaWPji7HdY*q$kdSR3MQAHpDsz?0LtR0-0{-m53dNSsJt<xF*wkMU}NYP>=_K$cPbx z6L=6$GQ23p<H8saI6lU5Jj+KTd{T<VB#s07izc^uW<@HfQ~P%jPo}FFyAsRR>vg6c zWso<=^2ub9<pfp`A_Nif8xGckh~p1;GN{luJj=xvazN<ovuFX!G~IcE?RL{T{(hTC z!`MJ~S)Sq8e}I~HFx0lYXdf3~<zTd5YPgUsKp!o52Kl(ka7cC~#e+IVUJ0T3P8ai4 zgpprGE>M(q*T9IT8<rCWN82n-ld_JFb;p2NRi;UVu`E*(RaND=L^RH)Gd!OW)2gDX zaV4R|6I@gnPjt8{G8Sy;;11XP%Z>HqhJx5*L(jSf%_$Grp#5;k>Rk)pyOuq!*}E2@ zCzmC~u>XB`Cqy(9nqBb{rz?Nx5Y2l;+|e5enheJ2{7flx_vxqSTVHca8*7_iUVZ#t zx$|cE!H3-+ztY#&TdmgX&p*$EGl>hiVym;LM;l`=N%U-1oh$|KQX4M@DQ=+e{Qb3^ zrt2O%j<*jr)FYYE)#B2<t&@qq_0{o9w^ovykG&I@mFDlEM&AInyVL({`)#cm4rn%$ KQy-?U-24OL*;d*B diff --git a/rhodecode/public/images/icon-right.png b/rhodecode/public/images/icon-right.png new file mode 100644 index 0000000000000000000000000000000000000000..76ee855af4b8d484332157d59d31732de6ccef8b GIT binary patch literal 1036 zc$|GxO=#3W6b|gcQo4Aq2N@zli{1RSYc^rm(oIsk+APa<!99s-GTTktWMVRPvqhvz zJ=CM%!He|jK@mZeij;zvN~@yaLDYi?9t2BK5J6Zc+h!4AJBOL~9^d!o&71G7l!~X5 zy+?W}ib@tH)G|3EyRRof_W4I2Zjz%PYgIgjYPezekQ%elGz105n1N+zSj~%@FiTO1 z0lQMgRee%6k;51fh6x>yidJ?s^bB(jVlWM7Y&S>mJYA=OZRO~5X`RzO1=j6}MITNr z7AxlBoGDrK=qZp5Ws<;w*Z`q3?*?+1quY69Vn<<?25ktQ%h7v9RrL~3kPktcNvBLs z;DIPHd^#<P!VnNReuU+CmLE>>k~}gZa~#-TG`Y>UYI0c}-@l7^Il7LqC$ns$(O??G z4Dx4KUXmo16Iek=5kx9zy4VO)Zg4Elpu)iPZ4cYX1(9z|qXnF!>G%nb*GcOJ`)wi( zV?)DZd4^;E0qXj}P{-+@16+o+gV8~y=|Q#(1GM0q<l}0`BC;ndJ~S}$D+tZUT`biR zMnN5UKvCLV0|UBY+HMpaY_oJ-F1P_UToV@598DsOZCi3$RaKr7$3;G`@w}GKtBR_M zN=6Yg+^}#m6LVE$E;!J|G1uyFGhA10B#1pW^zBQ~8uyU{+7FlQ?zO1hYuV#kU274w zu3VNB!~XZ(afoOrGCSfWPDlRGC7Sn%xUbBDvt%%imL@CO>a#D;-+eDGZ#{YW?e(YK z+O4-M_dfpk^(TLMv(;+7`TF}rG?TbooNC33dbl<8ibUmtI#vnaXJ0%{Qe0nROd9Z7 z*OM#D>uaBrOULCzv3a9sZSb%yH2QC!-?%z^W?S3#cJJPy64cK_iH+5rr3cY`7PO*z IKY!ucU$tCSY5)KL diff --git a/rhodecode/public/images/rhodecode-logo-white-216x60.png b/rhodecode/public/images/rhodecode-logo-white-216x60.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3d3dd162ca2dc1869fc24b559a5a94da312664 GIT binary patch literal 10866 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 IM6N<$f|5Yx4FCWD diff --git a/rhodecode/public/images/rhodecode-logo-white-266x74.png b/rhodecode/public/images/rhodecode-logo-white-266x74.png new file mode 100644 index 0000000000000000000000000000000000000000..8428dcb71885ffd052f8ba7c634434560b81ee74 GIT binary patch literal 9933 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 LNkvXXu0mjf9l^R{ diff --git a/rhodecode/public/images/select2-spinner.gif b/rhodecode/public/images/select2-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zc$}5hdr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSobD81<C?dpgc+<h7t-jP!X0Q zk_SQ}Pi1wnSap|eQLqJkOkYHd%xK%Om8sKCUo+UD9c^t3eN1(xtxNice`VU)^XGTY zZ{{=KGiQF8+cJ!stPp|7PYCkh!2<+AmX?-$KHtK^LPkbLYisLDQc_Z)P$(uQCj5TC zSS%hH836zo42GJT8sz^uQ4i?6^zBcin)1`*H|nuf!RU8sYNO4%$F@t>Y~NEOv({Q$ z>ULXqZL~jIy&H+T5BSu|ElqGbh(z#anG8kwQD2UsX=d`OX<$4n(z|diFd;g3**b~6 zl;#S+uQ=IL7saMKCHDsMN4e$K<U8E1a|O}-_imY;<tZnw(^uloh!_dJ`~A)F3h7>q z1C*jolK_M?#R6AlG)nRib{FVK0=$Hya{9R>nzluSvg{37?3`^=Uz&-0+XQ>2eRIpR zf-v29gvC*#ko2ZnV>lV!bM=lR>oiFohm$Qc8K^VR^n_Oo-K$!nJ8>3(z{X3Tdk#D) zuI>v1xoD*v!zl-qV0ITf0R(h+MO!Y9EjJu`zOD6`@py7sa!5)`kn%CJLIG)Hx}5Bv z_Icd1@r|1CM@}~6&xyOx4n!=eJs+?v86l7OMik&6Y1|o}CDO>$^IzyC+Lzd+`ix@9 zcZ-{5a`Q*i6Jk*cDqW~q&hqH$-sij3=Hg17cR$K<l?tz`J*Ux`Y-$XR`J<PQ6IU>v zC^BnV{;pcozm~pH(68g%Q{7qt6gd++Ai%GjcEChIPhspYZ)ruuiQ5+(XUS_XTjukX zM+~I<*2&}2r5(CoWqguWYk)@uFlDT+LSFaxPTc{u>6yX(hkbO;P>-*|)NU}GG=!wo z{qaPSU@vm=>hii3O4nMNneii-_CupS3y54(9gpRuoMLXg6Sm!xe)k5P34dkHcMWTx z^!DhtQ??hGuXpUuiLWd!{o(VTBJcUQ+NX<wjoZ_drPDQA{?_TOZjV0XJz^L-932wS z9t6CuSpm4@q<dL9r=||1Fpk1=F{o!UTF)CjW;rFBm2S9FHLM&B$A+>wE^^(aM=oCw ziKV)@%XTagb_XmoMQ5d6fSJGW7XcyLw9g~2A_&}?XV)=A1;MCPy;_1qa&2|{`2<~W z--iH#t+$oMh9vzXNZJNhNC7$d_>YD;bzn@MoPPa?$H`?XmAUJ0IvQ%Z($1H?_umMU zF`n;ZxU&G_%@d_68T2^nFeTOB<-B>ek0cv@Zc?ufCy2uJRXoTiEQC;{QZfWaJh#6x zdjNEAtt=N18w8p4$z+crw5Iu?232bg%9L|zzw%deQkf`DvT9oP-_q$1wpnYUc$r7f z*jgm5(|5D=-L^}H*#KA6wqqOz%ZYDXOsk*nj8O=#zwnJi!chEj0?$OS7CxWdhj6i= z4KNHUBp!>Uh`7UAe!4XYtyBF;Gpdoru@^U(MsiLcdUfHGUd_KR{w4s2z3Ju3I`_!w z^(jfR-UXN>O7qS|bm(udJD1?HPUy9wgKGvZXd?ylkDi*941vBYZbw$47~(~I7{l5z z0uu@;M_Hk~jgR)Aq+l?b8b<j-18y&Eu4-2Qg+`Mzq`rS~4m~)gKS5iMrF?Yo#^kCe zjn18x#5>Q9uA>8E=ADRZ=bJ5&eq1wk`DR#zfAHkgyW#%ps~6{$d=YVNX7W)Pph;c~ zwG|^+5~mp|UJVE#>O*-#yPD?faC|cyj#XgT-q4z+hnl*wGm2Z(bT(`#`%j>ONf@>i zl-&~~t#;nq93k-ia|vuKiPFzDn$nCCCUx)lz}sT{v#k7TdzgRGjuZ@mezz%~bF77_ zJT@i`Ve@$q2n!Mo48DS4?NxRZl6kfIX4az${iPoEvXN=<k5QUTlzt@}B8|#dBeMsL z4B3^sw5SgAbsaFD*9=ShI=@~o*+O+Xd(M9vA*z{TircmDtwGDYhR<{z`FT{Lxw{oZ qAuokujfHtzG&I%;x5RB1!U`Tr{i_NL9^Jq;JfonvpeE(vF8d$98xD^E diff --git a/rhodecode/public/images/select2.png b/rhodecode/public/images/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zc$@)c0-F7aP)<h;3K|Lk000e1NJLTq002Ay001Zm1^@s6qPv;@0006kNkl<Zc-rmR z&r1|x9LMps2uh5F)-GaQDk#Z_4iR>#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(q<Oecn6I%nq|DNy|zSyexzN z$5AL0?&Dan9pN5UxC<ug5`<4^!bTJ!40{Z2#(M~pn1C$$pw}f`kJpeHM`McNHFyg? zK;|>Hy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqB<bN zXhRETAUt&UJ4{pqo<W$!4+ziE?D9@4ilQ3gUO=XZ)oyPsiQA7akeNo#WiVk!@H1G( zkAmgh?J@W$gqNtpN{mA2@w%j2(GYBBaKPD;E<cjsBsd99f~(<?&RR6i%jfeou7io} z!W3j)q1|OLVRs>n<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 diff --git a/rhodecode/public/images/select2x2.png b/rhodecode/public/images/select2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bdd5c961d452c49dfa0789c2c7ffb82c238fc24 GIT binary patch literal 845 zc$@)E1G4;yP)<h;3K|Lk000e1NJLTq004LZ002-31^@s6(wnh~0009NNkl<Zc-rlq zv2GJV5I`eA5ebSzqy-%%f8hdLP~9h_qV^Xci^>upQ6WKflyv?C|ADVW!U!t`EpA+x zB)5#EjWk-_X77YJZtQo`E0SF)^1bZr%<ScI;+%s6=ICz#f&syRU}(wBHJi=KJtvV% z&q1&qv^eJpB{$ANuo1Mlh~(%T1ltp=DYaY#8zmuerN1Ub+fTAw3X&{)g1bmADU*y5 zUblqhl?+n{vw|Hrl|2~9qJcUX=wx*w)_|YxX&9mxeE=mzu0C`g40D>)B7Cd`*OK*r z5WG-7e-R9G9^69ksDt29&oyHqxPSt|-S>xi3%PTd+GjY+BGF|nWC(7D-sd(kxqd9~ zS@2YF5vB+>dP8+$l^{oO3-lEWiGA*QI<ZQyKyWv~v4m^Xqu?O1N>U)Wds#9M6RZ9N zcQ4y4)xqQOxD=vwu%7cz1nY#$lT&y8HCmkWgpwQP#3dhnYj9|2aS_R}IUF_^6s#$= zTm%~>A#oM?KIg$kh=<`gJkeoHa2LrulVy$Yx+N_0R3$4I!R*0677f(FKqm`2_o4~W z0h}fQZ`lC^1A+m;fM7uI(R1`S0KtG@KrkQ}5DW+&@cTnDVIow56KciMk7a899t0bC zC1KI<NAq=n6MhK=f(@YLo(pv#^;)>{TsMe5NAR%GD_5`B-@<p{rSMpIB)k$<!Y=ql zC=fhg{GPi}!nVSD;k03YekgqMb862<$PheS!4oBGC%j9%)a;J%LAX>ad4k~K3SO%H z_M31|`HV?E6)u$E3c&*<*n20+V@mRCop>R5;DWuZCmjSo7p@R&OYl<!6QXYf&j`^5 z2wIX~h5Ie!o(UI9@DjnpE|YYF<D+mlkwJf^OtRPLs6AUR@T@`Z1L2FXRdRPirluiy zpsh;Xe!LWZ2ycXE!VBT8@Kdi`MTuYwhYjIDL;SG8HBchh)^TC22*vJVk`Zj@z<=2w zxbkC}P{t%9`0)R&U5Q}xg42=_Y+Z0#a)n^ig42=_Y+P_C8Nv2R^{Fc*c#2>^@G<ZQ XF(xQ&SEjMs00000NkvXXu0mjf{}FjY diff --git a/rhodecode/public/images/sign-in.png b/rhodecode/public/images/sign-in.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc8a8b9a7a3298ced1ecadf03a435631595af86 GIT binary patch literal 4517 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 VccpxdhCsk~<5v^iitE2U`YXy!y<q?V diff --git a/rhodecode/public/js/excanvas.min.js b/rhodecode/public/js/excanvas.min.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/excanvas.min.js @@ -0,0 +1,1 @@ +if(!document.createElement("canvas").getContext){(function(){var R=Math;var S=R.round;var O=R.sin;var a=R.cos;var J=R.abs;var Y=R.sqrt;var A=10;var K=A/2;function G(){return this.context_||(this.context_=new M(this))}var Q=Array.prototype.slice;function b(c,d,e){var Z=Q.call(arguments,2);return function(){return c.apply(d,Z.concat(Q.call(arguments)))}}var H={init:function(Z){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var c=Z||document;c.createElement("canvas");c.attachEvent("onreadystatechange",b(this.init_,this,c))}},init_:function(e){if(!e.namespaces.g_vml_){e.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML")}if(!e.namespaces.g_o_){e.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML")}if(!e.styleSheets.ex_canvas_){var d=e.createStyleSheet();d.owningElement.id="ex_canvas_";d.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=e.getElementsByTagName("canvas");for(var Z=0;Z<c.length;Z++){this.initElement(c[Z])}},initElement:function(c){if(!c.getContext){c.getContext=G;c.innerHTML="";c.attachEvent("onpropertychange",X);c.attachEvent("onresize",B);var Z=c.attributes;if(Z.width&&Z.width.specified){c.style.width=Z.width.nodeValue+"px"}else{c.width=c.clientWidth}if(Z.height&&Z.height.specified){c.style.height=Z.height.nodeValue+"px"}else{c.height=c.clientHeight}}return c}};function X(c){var Z=c.srcElement;switch(c.propertyName){case"width":Z.style.width=Z.attributes.width.nodeValue+"px";Z.getContext().clearRect();break;case"height":Z.style.height=Z.attributes.height.nodeValue+"px";Z.getContext().clearRect();break}}function B(c){var Z=c.srcElement;if(Z.firstChild){Z.firstChild.style.width=Z.clientWidth+"px";Z.firstChild.style.height=Z.clientHeight+"px"}}H.init();var E=[];for(var V=0;V<16;V++){for(var U=0;U<16;U++){E[V*16+U]=V.toString(16)+U.toString(16)}}function N(){return[[1,0,0],[0,1,0],[0,0,1]]}function D(e,d){var c=N();for(var Z=0;Z<3;Z++){for(var h=0;h<3;h++){var f=0;for(var g=0;g<3;g++){f+=e[Z][g]*d[g][h]}c[Z][h]=f}}return c}function T(c,Z){Z.fillStyle=c.fillStyle;Z.lineCap=c.lineCap;Z.lineJoin=c.lineJoin;Z.lineWidth=c.lineWidth;Z.miterLimit=c.miterLimit;Z.shadowBlur=c.shadowBlur;Z.shadowColor=c.shadowColor;Z.shadowOffsetX=c.shadowOffsetX;Z.shadowOffsetY=c.shadowOffsetY;Z.strokeStyle=c.strokeStyle;Z.globalAlpha=c.globalAlpha;Z.arcScaleX_=c.arcScaleX_;Z.arcScaleY_=c.arcScaleY_;Z.lineScale_=c.lineScale_}function C(c){var f,e=1;c=String(c);if(c.substring(0,3)=="rgb"){var h=c.indexOf("(",3);var Z=c.indexOf(")",h+1);var g=c.substring(h+1,Z).split(",");f="#";for(var d=0;d<3;d++){f+=E[Number(g[d])]}if(g.length==4&&c.substr(3,1)=="a"){e=g[3]}}else{f=c}return{color:f,alpha:e}}function P(Z){switch(Z){case"butt":return"flat";case"round":return"round";case"square":default:return"square"}}function M(c){this.m_=N();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=A*1;this.globalAlpha=1;this.canvas=c;var Z=c.ownerDocument.createElement("div");Z.style.width=c.clientWidth+"px";Z.style.height=c.clientHeight+"px";Z.style.overflow="hidden";Z.style.position="absolute";c.appendChild(Z);this.element_=Z;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var I=M.prototype;I.clearRect=function(){this.element_.innerHTML=""};I.beginPath=function(){this.currentPath_=[]};I.moveTo=function(c,Z){var d=this.getCoords_(c,Z);this.currentPath_.push({type:"moveTo",x:d.x,y:d.y});this.currentX_=d.x;this.currentY_=d.y};I.lineTo=function(c,Z){var d=this.getCoords_(c,Z);this.currentPath_.push({type:"lineTo",x:d.x,y:d.y});this.currentX_=d.x;this.currentY_=d.y};I.bezierCurveTo=function(d,c,j,i,h,f){var Z=this.getCoords_(h,f);var g=this.getCoords_(d,c);var e=this.getCoords_(j,i);L(this,g,e,Z)};function L(Z,e,d,c){Z.currentPath_.push({type:"bezierCurveTo",cp1x:e.x,cp1y:e.y,cp2x:d.x,cp2y:d.y,x:c.x,y:c.y});Z.currentX_=c.x;Z.currentY_=c.y}I.quadraticCurveTo=function(h,d,c,Z){var g=this.getCoords_(h,d);var f=this.getCoords_(c,Z);var i={x:this.currentX_+2/3*(g.x-this.currentX_),y:this.currentY_+2/3*(g.y-this.currentY_)};var e={x:i.x+(f.x-this.currentX_)/3,y:i.y+(f.y-this.currentY_)/3};L(this,i,e,f)};I.arc=function(k,i,j,f,c,d){j*=A;var o=d?"at":"wa";var l=k+a(f)*j-K;var n=i+O(f)*j-K;var Z=k+a(c)*j-K;var m=i+O(c)*j-K;if(l==Z&&!d){l+=0.125}var e=this.getCoords_(k,i);var h=this.getCoords_(l,n);var g=this.getCoords_(Z,m);this.currentPath_.push({type:o,x:e.x,y:e.y,radius:j,xStart:h.x,yStart:h.y,xEnd:g.x,yEnd:g.y})};I.rect=function(d,c,Z,e){this.moveTo(d,c);this.lineTo(d+Z,c);this.lineTo(d+Z,c+e);this.lineTo(d,c+e);this.closePath()};I.strokeRect=function(d,c,Z,e){var f=this.currentPath_;this.beginPath();this.moveTo(d,c);this.lineTo(d+Z,c);this.lineTo(d+Z,c+e);this.lineTo(d,c+e);this.closePath();this.stroke();this.currentPath_=f};I.fillRect=function(d,c,Z,e){var f=this.currentPath_;this.beginPath();this.moveTo(d,c);this.lineTo(d+Z,c);this.lineTo(d+Z,c+e);this.lineTo(d,c+e);this.closePath();this.fill();this.currentPath_=f};I.createLinearGradient=function(c,e,Z,d){var f=new W("gradient");f.x0_=c;f.y0_=e;f.x1_=Z;f.y1_=d;return f};I.createRadialGradient=function(e,g,d,c,f,Z){var h=new W("gradientradial");h.x0_=e;h.y0_=g;h.r0_=d;h.x1_=c;h.y1_=f;h.r1_=Z;return h};I.drawImage=function(s,e){var l,j,n,AA,q,o,u,AC;var m=s.runtimeStyle.width;var r=s.runtimeStyle.height;s.runtimeStyle.width="auto";s.runtimeStyle.height="auto";var k=s.width;var y=s.height;s.runtimeStyle.width=m;s.runtimeStyle.height=r;if(arguments.length==3){l=arguments[1];j=arguments[2];q=o=0;u=n=k;AC=AA=y}else{if(arguments.length==5){l=arguments[1];j=arguments[2];n=arguments[3];AA=arguments[4];q=o=0;u=k;AC=y}else{if(arguments.length==9){q=arguments[1];o=arguments[2];u=arguments[3];AC=arguments[4];l=arguments[5];j=arguments[6];n=arguments[7];AA=arguments[8]}else{throw Error("Invalid number of arguments")}}}var AB=this.getCoords_(l,j);var f=u/2;var c=AC/2;var z=[];var Z=10;var i=10;z.push(" <g_vml_:group",' coordsize="',A*Z,",",A*i,'"',' coordorigin="0,0"',' style="width:',Z,"px;height:",i,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]){var g=[];g.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",S(AB.x/A),",","Dy=",S(AB.y/A),"");var x=AB;var v=this.getCoords_(l+n,j);var t=this.getCoords_(l,j+AA);var p=this.getCoords_(l+n,j+AA);x.x=R.max(x.x,v.x,t.x,p.x);x.y=R.max(x.y,v.y,t.y,p.y);z.push("padding:0 ",S(x.x/A),"px ",S(x.y/A),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",g.join(""),", sizingmethod='clip');")}else{z.push("top:",S(AB.y/A),"px;left:",S(AB.x/A),"px;")}z.push(' ">','<g_vml_:image src="',s.src,'"',' style="width:',A*n,"px;"," height:",A*AA,'px;"',' cropleft="',q/k,'"',' croptop="',o/y,'"',' cropright="',(k-q-u)/k,'"',' cropbottom="',(y-o-AC)/y,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",z.join(""))};I.stroke=function(AE){var j=[];var k=false;var AP=C(AE?this.fillStyle:this.strokeStyle);var AA=AP.color;var AK=AP.alpha*this.globalAlpha;var f=10;var m=10;j.push("<g_vml_:shape",' filled="',!!AE,'"',' style="position:absolute;width:',f,"px;height:",m,'px;"',' coordorigin="0 0" coordsize="',A*f," ",A*m,'"',' stroked="',!AE,'"',' path="');var l=false;var AO={x:null,y:null};var w={x:null,y:null};for(var AJ=0;AJ<this.currentPath_.length;AJ++){var AI=this.currentPath_[AJ];var AN;switch(AI.type){case"moveTo":AN=AI;j.push(" m ",S(AI.x),",",S(AI.y));break;case"lineTo":j.push(" l ",S(AI.x),",",S(AI.y));break;case"close":j.push(" x ");AI=null;break;case"bezierCurveTo":j.push(" c ",S(AI.cp1x),",",S(AI.cp1y),",",S(AI.cp2x),",",S(AI.cp2y),",",S(AI.x),",",S(AI.y));break;case"at":case"wa":j.push(" ",AI.type," ",S(AI.x-this.arcScaleX_*AI.radius),",",S(AI.y-this.arcScaleY_*AI.radius)," ",S(AI.x+this.arcScaleX_*AI.radius),",",S(AI.y+this.arcScaleY_*AI.radius)," ",S(AI.xStart),",",S(AI.yStart)," ",S(AI.xEnd),",",S(AI.yEnd));break}if(AI){if(AO.x==null||AI.x<AO.x){AO.x=AI.x}if(w.x==null||AI.x>w.x){w.x=AI.x}if(AO.y==null||AI.y<AO.y){AO.y=AI.y}if(w.y==null||AI.y>w.y){w.y=AI.y}}}j.push(' ">');if(!AE){var v=this.lineScale_*this.lineWidth;if(v<1){AK*=v}j.push("<g_vml_:stroke",' opacity="',AK,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',P(this.lineCap),'"',' weight="',v,'px"',' color="',AA,'" />')}else{if(typeof this.fillStyle=="object"){var n=this.fillStyle;var t=0;var AH={x:0,y:0};var AB=0;var r=1;if(n.type_=="gradient"){var q=n.x0_/this.arcScaleX_;var d=n.y0_/this.arcScaleY_;var o=n.x1_/this.arcScaleX_;var AQ=n.y1_/this.arcScaleY_;var AM=this.getCoords_(q,d);var AL=this.getCoords_(o,AQ);var h=AL.x-AM.x;var g=AL.y-AM.y;t=Math.atan2(h,g)*180/Math.PI;if(t<0){t+=360}if(t<0.000001){t=0}}else{var AM=this.getCoords_(n.x0_,n.y0_);var Z=w.x-AO.x;var e=w.y-AO.y;AH={x:(AM.x-AO.x)/Z,y:(AM.y-AO.y)/e};Z/=this.arcScaleX_*A;e/=this.arcScaleY_*A;var AG=R.max(Z,e);AB=2*n.r0_/AG;r=2*n.r1_/AG-AB}var z=n.colors_;z.sort(function(i,c){return i.offset-c.offset});var u=z.length;var y=z[0].color;var x=z[u-1].color;var AD=z[0].alpha*this.globalAlpha;var AC=z[u-1].alpha*this.globalAlpha;var AF=[];for(var AJ=0;AJ<u;AJ++){var s=z[AJ];AF.push(s.offset*r+AB+" "+s.color)}j.push('<g_vml_:fill type="',n.type_,'"',' method="none" focus="100%"',' color="',y,'"',' color2="',x,'"',' colors="',AF.join(","),'"',' opacity="',AC,'"',' g_o_:opacity2="',AD,'"',' angle="',t,'"',' focusposition="',AH.x,",",AH.y,'" />')}else{j.push('<g_vml_:fill color="',AA,'" opacity="',AK,'" />')}}j.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",j.join(""))};I.fill=function(){this.stroke(true)};I.closePath=function(){this.currentPath_.push({type:"close"})};I.getCoords_=function(d,c){var Z=this.m_;return{x:A*(d*Z[0][0]+c*Z[1][0]+Z[2][0])-K,y:A*(d*Z[0][1]+c*Z[1][1]+Z[2][1])-K}};I.save=function(){var Z={};T(this,Z);this.aStack_.push(Z);this.mStack_.push(this.m_);this.m_=D(N(),this.m_)};I.restore=function(){T(this.aStack_.pop(),this);this.m_=this.mStack_.pop()};I.translate=function(d,c){var Z=[[1,0,0],[0,1,0],[d,c,1]];this.m_=D(Z,this.m_)};I.rotate=function(d){var f=a(d);var e=O(d);var Z=[[f,e,0],[-e,f,0],[0,0,1]];this.m_=D(Z,this.m_)};I.scale=function(f,e){this.arcScaleX_*=f;this.arcScaleY_*=e;var c=[[f,0,0],[0,e,0],[0,0,1]];var Z=this.m_=D(c,this.m_);var d=Z[0][0]*Z[1][1]-Z[0][1]*Z[1][0];this.lineScale_=Y(J(d))};I.clip=function(){};I.arcTo=function(){};I.createPattern=function(){return new F};function W(Z){this.type_=Z;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}W.prototype.addColorStop=function(c,Z){Z=C(Z);this.colors_.push({offset:c,color:Z.color,alpha:Z.alpha})};function F(){}G_vmlCanvasManager=H;CanvasRenderingContext2D=M;CanvasGradient=W;CanvasPattern=F})()}; \ No newline at end of file diff --git a/rhodecode/public/js/jquery.commits-graph.js b/rhodecode/public/js/jquery.commits-graph.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/jquery.commits-graph.js @@ -0,0 +1,304 @@ +/* + * jQuery Commits Graph - v0.1.4 + * A jQuery plugin to display git commits graph using HTML5/Canvas. + * https://github.com/tclh123/commits-graph + * + * Copyright (c) 2014 + * MIT License + * + * Adapted to fit RhodeCode Enterprise changelog graph needs + */ +// -- Route -------------------------------------------------------- + +function Route( commit, data, options ) { + var self = this; + + self._data = data; + self.commit = commit; + self.options = options; + self.from = data[0]; + self.to = data[1]; + self.branch = data[2]; +} + +Route.prototype.drawRoute = function ( ctx ) { + var self = this; + + if (self.options.orientation === "horizontal") { + var from_x_hori = self.options.width * self.options.scaleFactor - (self.commit.idx + 0.5) * self.options.x_step * self.options.scaleFactor; + var from_y_hori = (self.from + 1) * self.options.y_step * self.options.scaleFactor; + + var to_x_hori = self.options.width * self.options.scaleFactor - (self.commit.idx + 0.5 + 1) * self.options.x_step * self.options.scaleFactor; + var to_y_hori = (self.to + 1) * self.options.y_step * self.options.scaleFactor; + + ctx.strokeStyle = self.commit.graph.get_color(self.branch); + ctx.beginPath(); + ctx.moveTo(from_x_hori, from_y_hori); + if (from_y_hori === to_y_hori) { + ctx.lineTo(to_x_hori, to_y_hori); + } else if (from_y_hori > to_y_hori) { + ctx.bezierCurveTo(from_x_hori - self.options.x_step * self.options.scaleFactor / 3 * 2, + from_y_hori + self.options.y_step * self.options.scaleFactor / 4, + to_x_hori + self.options.x_step * self.options.scaleFactor / 3 * 2, + to_y_hori - self.options.y_step * self.options.scaleFactor / 4, + to_x_hori, to_y_hori); + } else if (from_y_hori < to_y_hori) { + ctx.bezierCurveTo(from_x_hori - self.options.x_step * self.options.scaleFactor / 3 * 2, + from_y_hori - self.options.y_step * self.options.scaleFactor / 4, + to_x_hori + self.options.x_step * self.options.scaleFactor / 3 * 2, + to_y_hori + self.options.y_step * self.options.scaleFactor / 4, + to_x_hori, to_y_hori); + } + + } else { + var from_x = self.options.width * self.options.scaleFactor - (self.from + 1) * self.options.x_step * self.options.scaleFactor; + var row = $("#chg_"+(self.commit.idx+1)) + if (row.length) { + var from_y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor; + } + var to_x = self.options.width * self.options.scaleFactor - (self.to + 1) * self.options.x_step * self.options.scaleFactor; + var next_row = $("#chg_"+(self.commit.idx+2)) + if (next_row.length) { + var to_y = ((next_row.offset().top + next_row.height() / 2 - self.options.relaOffset) + 0.2) * self.options.scaleFactor; + } + + ctx.strokeStyle = self.commit.graph.get_color(self.branch); + ctx.beginPath(); + ctx.moveTo(from_x, from_y); + if (from_x === to_x) { + ctx.lineTo(to_x, to_y); + } else { + ctx.bezierCurveTo(from_x - self.options.x_step * self.options.scaleFactor / 4, + from_y + self.options.y_step * self.options.scaleFactor / 3 * 2, + to_x + self.options.x_step * self.options.scaleFactor / 4, + to_y - self.options.y_step * self.options.scaleFactor / 3 * 2, + to_x, to_y); + } + } + + ctx.stroke(); +}; + +// -- Commit Node -------------------------------------------------------- + +function Commit(graph, idx, data, options ) { + var self = this; + + self._data = data; + self.graph = graph; + self.idx = idx; + self.options = options; + self.sha = data[0]; + self.dot = data[1]; + self.dot_offset = self.dot[0]; + self.dot_branch = self.dot[1]; + self.routes = $.map(data[2], function(e) { return new Route(self, e, options); }); +} + +Commit.prototype.drawDot = function ( ctx ) { + var self = this; + var radius = self.options.dotRadius; // dot radius + + if (self.options.orientation === "horizontal") { + var x_hori = self.options.width * self.options.scaleFactor - (self.idx + 0.5) * self.options.x_step * self.options.scaleFactor; + var y_hori = (self.dot_offset + 1) * self.options.y_step * self.options.scaleFactor; + ctx.fillStyle = self.graph.get_color(self.dot_branch); + ctx.beginPath(); + ctx.arc(x_hori, y_hori, radius * self.options.scaleFactor, 0, 2 * Math.PI, true); + + } else { + var x = self.options.width * self.options.scaleFactor - (self.dot_offset + 1) * self.options.x_step * self.options.scaleFactor; + var row = $("#chg_"+(self.idx+1)) + var y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor; + ctx.fillStyle = self.graph.get_color(self.dot_branch); + ctx.beginPath(); + ctx.arc(x, y, radius * self.options.scaleFactor, 0, 2 * Math.PI, true); + } + // ctx.stroke(); + ctx.fill(); +}; + +// -- Graph Canvas -------------------------------------------------------- + +function backingScale() { + if ('devicePixelRatio' in window) { + if (window.devicePixelRatio > 1) { + return window.devicePixelRatio; + } + } + return 1; +} + +function GraphCanvas( data, options ) { + var self = this; + + self.data = data; + self.options = options; + self.canvas = document.createElement("canvas"); + self.canvas.style.height = options.height + "px"; + self.canvas.style.width = options.width + "px"; + self.canvas.height = options.height; + self.canvas.width = options.width; + + var scaleFactor = backingScale(); + if (self.options.orientation === "horizontal") { + if (scaleFactor < 1) { + self.canvas.width = self.canvas.width * scaleFactor; + self.canvas.height = self.canvas.height * scaleFactor; + } + } else { + if (scaleFactor > 1) { + self.canvas.width = self.canvas.width * scaleFactor; + self.canvas.height = self.canvas.height * scaleFactor; + } + } + + self.options.scaleFactor = scaleFactor; + + // or use context.scale(2,2) // not tested + + self.colors = [ + "#e11d21", + //"#eb6420", + "#fbca04", + "#009800", + "#006b75", + "#207de5", + "#0052cc", + "#5319e7", + "#f7c6c7", + "#fad8c7", + "#fef2c0", + "#bfe5bf", + "#c7def8", + "#bfdadc", + "#bfd4f2", + "#d4c5f9", + "#cccccc", + "#84b6eb", + "#e6e6e6", + "#ffffff", + "#cc317c" + ]; + // self.branch_color = {}; +} + +GraphCanvas.prototype.toHTML = function () { + var self = this; + + self.draw(); + + return $(self.canvas); +}; + +GraphCanvas.prototype.get_color = function (branch) { + var self = this; + + var n = self.colors.length; + return self.colors[branch % n]; +}; + +/* + +[ + sha, + [offset, branch], //dot + [ + [from, to, branch], // route1 + [from, to, branch], // route2 + [from, to, branch], + ] // routes +], + +*/ +// draw +GraphCanvas.prototype.draw = function () { + var self = this, + ctx = self.canvas.getContext("2d"); + + ctx.lineWidth = self.options.lineWidth; + + self.options.relaOffset = $("#chg_1").offset().top; + + var n_commits = self.data.length; + for (var i=0; i<n_commits; i++) { + var commit = new Commit(self, i, self.data[i], self.options); + + for (var j=0; j<commit.routes.length; j++) { + var route = commit.routes[j]; + route.drawRoute(ctx); + } + commit.drawDot(ctx); + } +}; + +// -- Function for finding the total number of branches ----------------------- +branchCount = function(data) { + var maxBranch = -1; + for (var i = 0; i < data.length; i++) { + for (var j = 0; j < data[i][2].length; j++) { + if (maxBranch < data[i][2][j][0] || maxBranch < data[i][2][j][1]) { + maxBranch = Math.max.apply(Math, [data[i][2][j][0], data[i][2][j][1]]); + } + } + } + return maxBranch + 1; +}; + +// -- Graph Plugin ------------------------------------------------------------ + +function Graph( element, options ) { + var self = this, + defaults = { + height: 800, + width: 200, + // y_step: 30, + y_step: 20, + x_step: 20, + orientation: "vertical", + dotRadius: 3, + lineWidth: 2, + }; + + self.element = element; + self.$container = $( element ); + self.data = self.$container.data( "graph" ); + + var x_step = $.extend( {}, defaults, options ).x_step; + var y_step = $.extend( {}, defaults, options ).y_step; + + if (options.orientation === "horizontal") { + defaults.width = ( self.data.length + 2 ) * x_step; + defaults.height = ( branchCount(self.data) + 0.5 ) * y_step; + } else { + defaults.width = ( branchCount(self.data) + 0.5 ) * x_step; + defaults.height = ( self.data.length + 2 ) * y_step; + } + + self.options = $.extend( {}, defaults, options ) ; + + self._defaults = defaults; + + self.applyTemplate(); +} + +// Apply results to HTML template +Graph.prototype.applyTemplate = function () { + var self = this, + graphCanvas = new GraphCanvas( self.data, self.options ), + $canvas = graphCanvas.toHTML(); + + $canvas.appendTo( self.$container ); +}; + +// -- Attach plugin to jQuery's prototype -------------------------------------- + +;( function ( $, window, undefined ) { + + $.fn.commits = function ( options ) { + return this.each(function () { + $( this ).data( "plugin_commits_graph", new Graph( this, options ) ); + }); + }; + +}( window.jQuery, window ) ); diff --git a/rhodecode/public/js/jquery.flot.js b/rhodecode/public/js/jquery.flot.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/jquery.flot.js @@ -0,0 +1,3168 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ + +// first an inline dependency, jquery.colorhelpers.js, we inline it here +// for convenience + +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); + +// the actual Flot code +(function($) { + + // Cache the prototype hasOwnProperty for faster access + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM + // operation produces the same effect as detach, i.e. removing the element + // without touching its jQuery data. + + // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. + + if (!$.fn.detach) { + $.fn.detach = function() { + return this.each(function() { + if (this.parentNode) { + this.parentNode.removeChild( this ); + } + }); + }; + } + + /////////////////////////////////////////////////////////////////////////// + // The Canvas object is a wrapper around an HTML5 <canvas> tag. + // + // @constructor + // @param {string} cls List of classes to apply to the canvas. + // @param {element} container Element onto which to append the canvas. + // + // Requiring a container is a little iffy, but unfortunately canvas + // operations don't work unless the canvas is attached to the DOM. + + function Canvas(cls, container) { + + var element = container.children("." + cls)[0]; + + if (element == null) { + + element = document.createElement("canvas"); + element.className = cls; + + $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) + .appendTo(container); + + // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas + + if (!element.getContext) { + if (window.G_vmlCanvasManager) { + element = window.G_vmlCanvasManager.initElement(element); + } else { + throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + } + } + } + + this.element = element; + + var context = this.context = element.getContext("2d"); + + // Determine the screen's ratio of physical to device-independent + // pixels. This is the ratio between the canvas width that the browser + // advertises and the number of pixels actually present in that space. + + // The iPhone 4, for example, has a device-independent width of 320px, + // but its screen is actually 640px wide. It therefore has a pixel + // ratio of 2, while most normal devices have a ratio of 1. + + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + this.pixelRatio = devicePixelRatio / backingStoreRatio; + + // Size the canvas to match the internal dimensions of its container + + this.resize(container.width(), container.height()); + + // Collection of HTML div layers for text overlaid onto the canvas + + this.textContainer = null; + this.text = {}; + + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. + + this._textCache = {}; + } + + // Resizes the canvas to the given dimensions. + // + // @param {number} width New width of the canvas, in pixels. + // @param {number} width New height of the canvas, in pixels. + + Canvas.prototype.resize = function(width, height) { + + if (width <= 0 || height <= 0) { + throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); + } + + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; + + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. + + // Resizing should reset the state (excanvas seems to be buggy though) + + if (this.width != width) { + element.width = width * pixelRatio; + element.style.width = width + "px"; + this.width = width; + } + + if (this.height != height) { + element.height = height * pixelRatio; + element.style.height = height + "px"; + this.height = height; + } + + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. + + context.restore(); + context.save(); + + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. + + context.scale(pixelRatio, pixelRatio); + }; + + // Clears the entire canvas area, not including any overlaid HTML text + + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + // Finishes rendering the canvas, including managing the text overlay. + + Canvas.prototype.render = function() { + + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + + var layer = this.getTextLayer(layerKey), + layerCache = cache[layerKey]; + + layer.hide(); + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var positions = styleCache[key].positions; + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + if (!position.rendered) { + layer.append(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + position.element.detach(); + } + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + + layer.show(); + } + } + }; + + // Creates (if necessary) and returns the text overlay container. + // + // @param {string} classes String of space-separated CSS classes used to + // uniquely identify the text layer. + // @return {object} The jQuery-wrapped text-layer div. + + Canvas.prototype.getTextLayer = function(classes) { + + var layer = this.text[classes]; + + // Create the text layer if it doesn't exist + + if (layer == null) { + + // Create the text layer container, if it doesn't exist + + if (this.textContainer == null) { + this.textContainer = $("<div class='flot-text'></div>") + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0, + 'font-size': "smaller", + color: "#545454" + }) + .insertAfter(this.element); + } + + layer = this.text[classes] = $("<div></div>") + .addClass(classes) + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0 + }) + .appendTo(this.textContainer); + } + + return layer; + }; + + // Creates (if necessary) and returns a text info object. + // + // The object looks like this: + // + // { + // width: Width of the text's wrapper div. + // height: Height of the text's wrapper div. + // element: The jQuery-wrapped HTML div containing the text. + // positions: Array of positions at which this text is drawn. + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // rendered: Flag indicating whether the text is currently visible. + // element: The jQuery-wrapped HTML div containing the text. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + // + // Each position after the first receives a clone of the original element. + // + // The idea is that that the width, height, and general 'identity' of the + // text is constant no matter where it is placed; the placements are a + // secondary property. + // + // Canvas maintains a cache of recently-used text info objects; getTextInfo + // either returns the cached element or creates a new entry. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {string} text Text string to retrieve info for. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @return {object} a text info object. + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = "" + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + // If we can't find a matching element in our cache, create a new one + + if (info == null) { + + var element = $("<div></div>").html(text) + .css({ + position: "absolute", + 'max-width': width, + top: -9999 + }) + .appendTo(this.getTextLayer(layer)); + + if (typeof font === "object") { + element.css({ + font: textStyle, + color: font.color + }); + } else if (typeof font === "string") { + element.addClass(font); + } + + info = styleCache[text] = { + width: element.outerWidth(true), + height: element.outerHeight(true), + element: element, + positions: [] + }; + + element.detach(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + // + // The text isn't drawn immediately; it is marked as rendering, which will + // result in its addition to the canvas on the next render pass. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number} x X coordinate at which to draw the text. + // @param {number} y Y coordinate at which to draw the text. + // @param {string} text Text string to draw. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @param {string=} halign Horizontal alignment of the text; either "left", + // "center" or "right". + // @param {string=} valign Vertical alignment of the text; either "top", + // "middle" or "bottom". + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign == "center") { + x -= info.width / 2; + } else if (halign == "right") { + x -= info.width; + } + + if (valign == "middle") { + y -= info.height / 2; + } else if (valign == "bottom") { + y -= info.height; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.clone() : info.element, + x: x, + y: y + }; + + positions.push(position); + + // Move the element to its final position within the container + + position.element.css({ + top: Math.round(y), + left: Math.round(x), + 'text-align': halign // In case the text wraps + }); + }; + + // Removes one or more text strings from the canvas text overlay. + // + // If no parameters are given, all text within the layer is removed. + // + // Note that the text is not immediately removed; it is simply marked as + // inactive, which will result in its removal on the next render pass. + // This avoids the performance penalty for 'clear and redraw' behavior, + // where we potentially get rid of all text on a layer, but will likely + // add back most or all of it later, as when redrawing axes, for example. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number=} x X coordinate of the text. + // @param {number=} y Y coordinate of the text. + // @param {string=} text Text string to remove. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which the text is rotated, in degrees. + // Angle is currently unused, it will be implemented in the future. + + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + for (var i = 0, position; position = positions[i]; i++) { + position.active = false; + } + } + } + } + } + } + } else { + var positions = this.getTextInfo(layer, text, font, angle).positions; + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = false; + } + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. + + function Plot(placeholder, data_, options_, plugins) { + // data is on the form: + // [ series1, series2 ... ] + // where series is either just the data as [ [x1, y1], [x2, y2], ... ] + // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } + + var series = [], + options = { + // the color theme used for graphs + colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], + legend: { + show: true, + noColumns: 1, // number of colums in legend table + labelFormatter: null, // fn: string -> string + labelBoxBorderColor: "#ccc", // border color for the little label boxes + container: null, // container (as jQuery object) to put legend in, null means default on top of graph + position: "ne", // position of default legend container within plot + margin: 5, // distance from grid edge to default legend container within plot + backgroundColor: null, // null means auto-detect + backgroundOpacity: 0.85, // set to 0 to avoid background + sorted: null // default to no legend sorting + }, + xaxis: { + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoscaleMargin: null, // margin in % to add if auto-setting min/max + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of ticks, or "full" for whole line + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null // number or [number, "unit"] + }, + yaxis: { + autoscaleMargin: 0.02, + position: "left" // or "right" + }, + xaxes: [], + yaxes: [], + series: { + points: { + show: false, + radius: 3, + lineWidth: 2, // in pixels + fill: true, + fillColor: "#ffffff", + symbol: "circle" // or callback + }, + lines: { + // we don't put in show: false so we can see + // whether lines were actively disabled + lineWidth: 2, // in pixels + fill: false, + fillColor: null, + steps: false + // Omit 'zero', so we can later default its value to + // match that of the 'fill' option. + }, + bars: { + show: false, + lineWidth: 2, // in pixels + barWidth: 1, // in units of the x axis + fill: true, + fillColor: null, + align: "left", // "left", "right", or "center" + horizontal: false, + zero: true + }, + shadowSize: 3, + highlightColor: null + }, + grid: { + show: true, + aboveData: false, + color: "#545454", // primary color used for outline and labels + backgroundColor: null, // null for transparent, else color + borderColor: null, // set if different from the grid color + tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" + margin: 0, // distance from the canvas edge to the grid + labelMargin: 5, // in pixels + axisMargin: 8, // in pixels + borderWidth: 2, // in pixels + minBorderMargin: null, // in pixels, null means taken from points radius + markings: null, // array of ranges or fn: axes -> array of ranges + markingsColor: "#f4f4f4", + markingsLineWidth: 2, + // interactive stuff + clickable: false, + hoverable: false, + autoHighlight: true, // highlight in case mouse is near + mouseActiveRadius: 10 // how far the mouse can be away to activate an item + }, + interaction: { + redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow + }, + hooks: {} + }, + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, octx = null, + xaxes = [], yaxes = [], + plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, + plotWidth = 0, plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + drawBackground: [], + drawSeries: [], + draw: [], + bindEvents: [], + drawOverlay: [], + shutdown: [] + }, + plot = this; + + // public functions + plot.setData = setData; + plot.setupGrid = setupGrid; + plot.draw = draw; + plot.getPlaceholder = function() { return placeholder; }; + plot.getCanvas = function() { return surface.element; }; + plot.getPlotOffset = function() { return plotOffset; }; + plot.width = function () { return plotWidth; }; + plot.height = function () { return plotHeight; }; + plot.offset = function () { + var o = eventHolder.offset(); + o.left += plotOffset.left; + o.top += plotOffset.top; + return o; + }; + plot.getData = function () { return series; }; + plot.getAxes = function () { + var res = {}, i; + $.each(xaxes.concat(yaxes), function (_, axis) { + if (axis) + res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; + }); + return res; + }; + plot.getXAxes = function () { return xaxes; }; + plot.getYAxes = function () { return yaxes; }; + plot.c2p = canvasToAxisCoords; + plot.p2c = axisToCanvasCoords; + plot.getOptions = function () { return options; }; + plot.highlight = highlight; + plot.unhighlight = unhighlight; + plot.triggerRedrawOverlay = triggerRedrawOverlay; + plot.pointOffset = function(point) { + return { + left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), + top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) + }; + }; + plot.shutdown = shutdown; + plot.destroy = function () { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + highlights = []; + plot = null; + }; + plot.resize = function () { + var width = placeholder.width(), + height = placeholder.height(); + surface.resize(width, height); + overlay.resize(width, height); + }; + + // public attributes + plot.hooks = hooks; + + // initialize + initPlugins(plot); + parseOptions(options_); + setupCanvases(); + setData(data_); + setupGrid(); + draw(); + bindEvents(); + + + function executeHooks(hook, args) { + args = [plot].concat(args); + for (var i = 0; i < hook.length; ++i) + hook[i].apply(this, args); + } + + function initPlugins() { + + // References to key classes, allowing plugins to modify them + + var classes = { + Canvas: Canvas + }; + + for (var i = 0; i < plugins.length; ++i) { + var p = plugins[i]; + p.init(plot, classes); + if (p.options) + $.extend(true, options, p.options); + } + } + + function parseOptions(opts) { + + $.extend(true, options, opts); + + // $.extend merges arrays, rather than replacing them. When less + // colors are provided than the size of the default palette, we + // end up with those colors plus the remaining defaults, which is + // not expected behavior; avoid it by replacing them here. + + if (opts && opts.colors) { + options.colors = opts.colors; + } + + if (options.xaxis.color == null) + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + if (options.yaxis.color == null) + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility + options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; + if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility + options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; + + if (options.grid.borderColor == null) + options.grid.borderColor = options.grid.color; + if (options.grid.tickColor == null) + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + // Fill in defaults for axis options, including any unspecified + // font-spec fields, if a font-spec was provided. + + // If no x/y axis options were provided, create one of each anyway, + // since the rest of the code assumes that they exist. + + var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, + fontDefaults = { + style: placeholder.css("font-style"), + size: Math.round(0.8 * fontSizeDefault), + variant: placeholder.css("font-variant"), + weight: placeholder.css("font-weight"), + family: placeholder.css("font-family") + }; + + axisCount = options.xaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.xaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.xaxis, axisOptions); + options.xaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + axisCount = options.yaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.yaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.yaxis, axisOptions); + options.yaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + // backwards compatibility, to be removed in future + if (options.xaxis.noTicks && options.xaxis.ticks == null) + options.xaxis.ticks = options.xaxis.noTicks; + if (options.yaxis.noTicks && options.yaxis.ticks == null) + options.yaxis.ticks = options.yaxis.noTicks; + if (options.x2axis) { + options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); + options.xaxes[1].position = "top"; + // Override the inherit to allow the axis to auto-scale + if (options.x2axis.min == null) { + options.xaxes[1].min = null; + } + if (options.x2axis.max == null) { + options.xaxes[1].max = null; + } + } + if (options.y2axis) { + options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); + options.yaxes[1].position = "right"; + // Override the inherit to allow the axis to auto-scale + if (options.y2axis.min == null) { + options.yaxes[1].min = null; + } + if (options.y2axis.max == null) { + options.yaxes[1].max = null; + } + } + if (options.grid.coloredAreas) + options.grid.markings = options.grid.coloredAreas; + if (options.grid.coloredAreasColor) + options.grid.markingsColor = options.grid.coloredAreasColor; + if (options.lines) + $.extend(true, options.series.lines, options.lines); + if (options.points) + $.extend(true, options.series.points, options.points); + if (options.bars) + $.extend(true, options.series.bars, options.bars); + if (options.shadowSize != null) + options.series.shadowSize = options.shadowSize; + if (options.highlightColor != null) + options.series.highlightColor = options.highlightColor; + + // save options on axes for future reference + for (i = 0; i < options.xaxes.length; ++i) + getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; + for (i = 0; i < options.yaxes.length; ++i) + getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; + + // add hooks from options + for (var n in hooks) + if (options.hooks[n] && options.hooks[n].length) + hooks[n] = hooks[n].concat(options.hooks[n]); + + executeHooks(hooks.processOptions, [options]); + } + + function setData(d) { + series = parseData(d); + fillInSeriesOptions(); + processData(); + } + + function parseData(d) { + var res = []; + for (var i = 0; i < d.length; ++i) { + var s = $.extend(true, {}, options.series); + + if (d[i].data != null) { + s.data = d[i].data; // move the data instead of deep-copy + delete d[i].data; + + $.extend(true, s, d[i]); + + d[i].data = s.data; + } + else + s.data = d[i]; + res.push(s); + } + + return res; + } + + function axisNumber(obj, coord) { + var a = obj[coord + "axis"]; + if (typeof a == "object") // if we got a real axis, extract number + a = a.n; + if (typeof a != "number") + a = 1; // default to first axis + return a; + } + + function allAxes() { + // return flat array without annoying null entries + return $.grep(xaxes.concat(yaxes), function (a) { return a; }); + } + + function canvasToAxisCoords(pos) { + // return an object with x/y corresponding to all used axes + var res = {}, i, axis; + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) + res["x" + axis.n] = axis.c2p(pos.left); + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) + res["y" + axis.n] = axis.c2p(pos.top); + } + + if (res.x1 !== undefined) + res.x = res.x1; + if (res.y1 !== undefined) + res.y = res.y1; + + return res; + } + + function axisToCanvasCoords(pos) { + // get canvas coords from the first pair of x/y found in pos + var res = {}, i, axis, key; + + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + key = "x" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "x"; + + if (pos[key] != null) { + res.left = axis.p2c(pos[key]); + break; + } + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + key = "y" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "y"; + + if (pos[key] != null) { + res.top = axis.p2c(pos[key]); + break; + } + } + } + + return res; + } + + function getOrCreateAxis(axes, number) { + if (!axes[number - 1]) + axes[number - 1] = { + n: number, // save the number for future reference + direction: axes == xaxes ? "x" : "y", + options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) + }; + + return axes[number - 1]; + } + + function fillInSeriesOptions() { + + var neededColors = series.length, maxIndex = -1, i; + + // Subtract the number of series that already have fixed colors or + // color indexes from the number that we still need to generate. + + for (i = 0; i < series.length; ++i) { + var sc = series[i].color; + if (sc != null) { + neededColors--; + if (typeof sc == "number" && sc > maxIndex) { + maxIndex = sc; + } + } + } + + // If any of the series have fixed color indexes, then we need to + // generate at least as many colors as the highest index. + + if (neededColors <= maxIndex) { + neededColors = maxIndex + 1; + } + + // Generate all the colors, using first the option colors and then + // variations on those colors once they're exhausted. + + var c, colors = [], colorPool = options.colors, + colorPoolSize = colorPool.length, variation = 0; + + for (i = 0; i < neededColors; i++) { + + c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); + + // Each time we exhaust the colors in the pool we adjust + // a scaling factor used to produce more variations on + // those colors. The factor alternates negative/positive + // to produce lighter/darker colors. + + // Reset the variation after every few cycles, or else + // it will end up producing only white or black colors. + + if (i % colorPoolSize == 0 && i) { + if (variation >= 0) { + if (variation < 0.5) { + variation = -variation - 0.2; + } else variation = 0; + } else variation = -variation; + } + + colors[i] = c.scale('rgb', 1 + variation); + } + + // Finalize the series options, filling in their colors + + var colori = 0, s; + for (i = 0; i < series.length; ++i) { + s = series[i]; + + // assign colors + if (s.color == null) { + s.color = colors[colori].toString(); + ++colori; + } + else if (typeof s.color == "number") + s.color = colors[s.color].toString(); + + // turn on lines automatically in case nothing is set + if (s.lines.show == null) { + var v, show = true; + for (v in s) + if (s[v] && s[v].show) { + show = false; + break; + } + if (show) + s.lines.show = true; + } + + // If nothing was provided for lines.zero, default it to match + // lines.fill, since areas by default should extend to zero. + + if (s.lines.zero == null) { + s.lines.zero = !!s.lines.fill; + } + + // setup axes + s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); + s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); + } + } + + function processData() { + var topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + fakeInfinity = Number.MAX_VALUE, + i, j, k, m, length, + s, points, ps, x, y, axis, val, f, p, + data, format; + + function updateAxis(axis, min, max) { + if (min < axis.datamin && min != -fakeInfinity) + axis.datamin = min; + if (max > axis.datamax && max != fakeInfinity) + axis.datamax = max; + } + + $.each(allAxes(), function (_, axis) { + // init axis + axis.datamin = topSentry; + axis.datamax = bottomSentry; + axis.used = false; + }); + + for (i = 0; i < series.length; ++i) { + s = series[i]; + s.datapoints = { points: [] }; + + executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); + } + + // first pass: clean and copy data + for (i = 0; i < series.length; ++i) { + s = series[i]; + + data = s.data; + format = s.datapoints.format; + + if (!format) { + format = []; + // find out how to copy + format.push({ x: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + s.datapoints.format = format; + } + + if (s.datapoints.pointsize != null) + continue; // already filled in + + s.datapoints.pointsize = format.length; + + ps = s.datapoints.pointsize; + points = s.datapoints.points; + + var insertSteps = s.lines.show && s.lines.steps; + s.xaxis.used = s.yaxis.used = true; + + for (j = k = 0; j < data.length; ++j, k += ps) { + p = data[j]; + + var nullify = p == null; + if (!nullify) { + for (m = 0; m < ps; ++m) { + val = p[m]; + f = format[m]; + + if (f) { + if (f.number && val != null) { + val = +val; // convert to number + if (isNaN(val)) + val = null; + else if (val == Infinity) + val = fakeInfinity; + else if (val == -Infinity) + val = -fakeInfinity; + } + + if (val == null) { + if (f.required) + nullify = true; + + if (f.defaultValue != null) + val = f.defaultValue; + } + } + + points[k + m] = val; + } + } + + if (nullify) { + for (m = 0; m < ps; ++m) { + val = points[k + m]; + if (val != null) { + f = format[m]; + // extract min/max info + if (f.autoscale !== false) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + points[k + m] = null; + } + } + else { + // a little bit of line specific stuff that + // perhaps shouldn't be here, but lacking + // better means... + if (insertSteps && k > 0 + && points[k - ps] != null + && points[k - ps] != points[k] + && points[k - ps + 1] != points[k + 1]) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) + points[k + ps + m] = points[k + m]; + + // middle point has same y + points[k + 1] = points[k - ps + 1]; + + // we've added a point, better reflect that + k += ps; + } + } + } + } + + // give the hooks a chance to run + for (i = 0; i < series.length; ++i) { + s = series[i]; + + executeHooks(hooks.processDatapoints, [ s, s.datapoints]); + } + + // second pass: find datamax/datamin for auto-scaling + for (i = 0; i < series.length; ++i) { + s = series[i]; + points = s.datapoints.points; + ps = s.datapoints.pointsize; + format = s.datapoints.format; + + var xmin = topSentry, ymin = topSentry, + xmax = bottomSentry, ymax = bottomSentry; + + for (j = 0; j < points.length; j += ps) { + if (points[j] == null) + continue; + + for (m = 0; m < ps; ++m) { + val = points[j + m]; + f = format[m]; + if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) + continue; + + if (f.x) { + if (val < xmin) + xmin = val; + if (val > xmax) + xmax = val; + } + if (f.y) { + if (val < ymin) + ymin = val; + if (val > ymax) + ymax = val; + } + } + } + + if (s.bars.show) { + // make sure we got room for the bar on the dancing floor + var delta; + + switch (s.bars.align) { + case "left": + delta = 0; + break; + case "right": + delta = -s.bars.barWidth; + break; + default: + delta = -s.bars.barWidth / 2; + } + + if (s.bars.horizontal) { + ymin += delta; + ymax += delta + s.bars.barWidth; + } + else { + xmin += delta; + xmax += delta + s.bars.barWidth; + } + } + + updateAxis(s.xaxis, xmin, xmax); + updateAxis(s.yaxis, ymin, ymax); + } + + $.each(allAxes(), function (_, axis) { + if (axis.datamin == topSentry) + axis.datamin = null; + if (axis.datamax == bottomSentry) + axis.datamax = null; + }); + } + + function setupCanvases() { + + // Make sure the placeholder is clear of everything except canvases + // from a previous plot in this container that we'll try to re-use. + + placeholder.css("padding", 0) // padding messes up the positioning + .children().filter(function(){ + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); + + if (placeholder.css("position") == 'static') + placeholder.css("position", "relative"); // for positioning labels and overlay + + surface = new Canvas("flot-base", placeholder); + overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features + + ctx = surface.context; + octx = overlay.context; + + // define which element we're listening for events on + eventHolder = $(overlay.element).unbind(); + + // If we're re-using a plot object, shut down the old one + + var existing = placeholder.data("plot"); + + if (existing) { + existing.shutdown(); + overlay.clear(); + } + + // save in case we get replotted + placeholder.data("plot", plot); + } + + function bindEvents() { + // bind events + if (options.grid.hoverable) { + eventHolder.mousemove(onMouseMove); + + // Use bind, rather than .mouseleave, because we officially + // still support jQuery 1.2.6, which doesn't define a shortcut + // for mouseenter or mouseleave. This was a bug/oversight that + // was fixed somewhere around 1.3.x. We can return to using + // .mouseleave when we drop support for 1.2.6. + + eventHolder.bind("mouseleave", onMouseLeave); + } + + if (options.grid.clickable) + eventHolder.click(onClick); + + executeHooks(hooks.bindEvents, [eventHolder]); + } + + function shutdown() { + if (redrawTimeout) + clearTimeout(redrawTimeout); + + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mouseleave", onMouseLeave); + eventHolder.unbind("click", onClick); + + executeHooks(hooks.shutdown, [eventHolder]); + } + + function setTransformationHelpers(axis) { + // set helper functions on the axis, assumes plot area + // has been computed already + + function identity(x) { return x; } + + var s, m, t = axis.options.transform || identity, + it = axis.options.inverseTransform; + + // precompute how much the axis is scaling a point + // in canvas space + if (axis.direction == "x") { + s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); + m = Math.min(t(axis.max), t(axis.min)); + } + else { + s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); + s = -s; + m = Math.max(t(axis.max), t(axis.min)); + } + + // data point to canvas coordinate + if (t == identity) // slight optimization + axis.p2c = function (p) { return (p - m) * s; }; + else + axis.p2c = function (p) { return (t(p) - m) * s; }; + // canvas coordinate to data point + if (!it) + axis.c2p = function (c) { return m + c / s; }; + else + axis.c2p = function (c) { return it(m + c / s); }; + } + + function measureTickLabels(axis) { + + var opts = axis.options, + ticks = axis.ticks || [], + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; + + for (var i = 0; i < ticks.length; ++i) { + + var t = ticks[i]; + + if (!t.label) + continue; + + var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); + + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); + } + + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; + } + + function allocateAxisBoxFirstPhase(axis) { + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, + axisMargin = options.grid.axisMargin, + padding = options.grid.labelMargin, + innermost = true, + outermost = true, + first = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + if (!found) { + first = false; + } + } + }); + + // The outermost axis on each side has no margin + + if (outermost) { + axisMargin = 0; + } + + // The ticks for the first axis in each direction stretch across + + if (tickLength == null) { + tickLength = first ? "full" : 5; + } + + if (!isNaN(+tickLength)) + padding += +tickLength; + + if (isXAxis) { + lh += padding; + + if (pos == "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { top: surface.height - plotOffset.bottom, height: lh }; + } + else { + axis.box = { top: plotOffset.top + axisMargin, height: lh }; + plotOffset.top += lh + axisMargin; + } + } + else { + lw += padding; + + if (pos == "left") { + axis.box = { left: plotOffset.left + axisMargin, width: lw }; + plotOffset.left += lw + axisMargin; + } + else { + plotOffset.right += lw + axisMargin; + axis.box = { left: surface.width - plotOffset.right, width: lw }; + } + } + + // save for future reference + axis.position = pos; + axis.tickLength = tickLength; + axis.box.padding = padding; + axis.innermost = innermost; + } + + function allocateAxisBoxSecondPhase(axis) { + // now that all axis boxes have been placed in one + // dimension, we can set the remaining dimension coordinates + if (axis.direction == "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } + else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; + } + } + + function adjustLayoutForThingsStickingOut() { + // possibly adjust plot offset to ensure everything stays + // inside the canvas and isn't clipped off + + var minMargin = options.grid.minBorderMargin, + axis, i; + + // check stuff from the plot (FIXME: this should just read + // a value from the series, otherwise it's impossible to + // customize) + if (minMargin == null) { + minMargin = 0; + for (i = 0; i < series.length; ++i) + minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); + } + + var margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; + + // check axis labels, note we don't check the actual + // labels but instead use the overall width/height to not + // jump as much around with replots + $.each(allAxes(), function (_, axis) { + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } + } + }); + + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); + } + + function setupGrid() { + var i, axes = allAxes(), showGrid = options.grid.show; + + // Initialize the plot's offset from the edge of the canvas + + for (var a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; + } + + executeHooks(hooks.processOffset, [plotOffset]); + + // If the grid is visible, add its border width to the offset + + for (var a in plotOffset) { + if(typeof(options.grid.borderWidth) == "object") { + plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; + } + else { + plotOffset[a] += showGrid ? options.grid.borderWidth : 0; + } + } + + $.each(axes, function (_, axis) { + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; + setRange(axis); + }); + + if (showGrid) { + + var allocatedAxes = $.grep(axes, function (axis) { + return axis.show || axis.reserveSpace; + }); + + $.each(allocatedAxes, function (_, axis) { + // make the ticks + setupTickGeneration(axis); + setTicks(axis); + snapRangeToTicks(axis, axis.ticks); + // find labelWidth/Height for axis + measureTickLabels(axis); + }); + + // with all dimensions calculated, we can compute the + // axis bounding boxes, start from the outside + // (reverse order) + for (i = allocatedAxes.length - 1; i >= 0; --i) + allocateAxisBoxFirstPhase(allocatedAxes[i]); + + // make sure we've got enough space for things that + // might stick out + adjustLayoutForThingsStickingOut(); + + $.each(allocatedAxes, function (_, axis) { + allocateAxisBoxSecondPhase(axis); + }); + } + + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + // now we got the proper plot dimensions, we can compute the scaling + $.each(axes, function (_, axis) { + setTransformationHelpers(axis); + }); + + if (showGrid) { + drawAxisLabels(); + } + + insertLegend(); + } + + function setRange(axis) { + var opts = axis.options, + min = +(opts.min != null ? opts.min : axis.datamin), + max = +(opts.max != null ? opts.max : axis.datamax), + delta = max - min; + + if (delta == 0.0) { + // degenerate case + var widen = max == 0 ? 1 : 0.01; + + if (opts.min == null) + min -= widen; + // always widen max if we couldn't widen min to ensure we + // don't fall into min == max which doesn't work + if (opts.max == null || opts.min != null) + max += widen; + } + else { + // consider autoscaling + var margin = opts.autoscaleMargin; + if (margin != null) { + if (opts.min == null) { + min -= delta * margin; + // make sure we don't go below zero if all values + // are positive + if (min < 0 && axis.datamin != null && axis.datamin >= 0) + min = 0; + } + if (opts.max == null) { + max += delta * margin; + if (max > 0 && axis.datamax != null && axis.datamax <= 0) + max = 0; + } + } + } + axis.min = min; + axis.max = max; + } + + function setupTickGeneration(axis) { + var opts = axis.options; + + // estimate number of ticks + var noTicks; + if (typeof opts.ticks == "number" && opts.ticks > 0) + noTicks = opts.ticks; + else + // heuristic based on the model a*sqrt(x) fitted to + // some data points that seemed reasonable + noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); + + var delta = (axis.max - axis.min) / noTicks, + dec = -Math.floor(Math.log(delta) / Math.LN10), + maxDec = opts.tickDecimals; + + if (maxDec != null && dec > maxDec) { + dec = maxDec; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + // special case for 2.5, requires an extra decimal + if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { + size = 2.5; + ++dec; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + + if (opts.minTickSize != null && size < opts.minTickSize) { + size = opts.minTickSize; + } + + axis.delta = delta; + axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); + axis.tickSize = opts.tickSize || size; + + // Time mode was moved to a plug-in in 0.8, and since so many people use it + // we'll add an especially friendly reminder to make sure they included it. + + if (opts.mode == "time" && !axis.tickGenerator) { + throw new Error("Time mode requires the flot.time plugin."); + } + + // Flot supports base-10 axes; any other mode else is handled by a plug-in, + // like flot.time.js. + + if (!axis.tickGenerator) { + + axis.tickGenerator = function (axis) { + + var ticks = [], + start = floorInBase(axis.min, axis.tickSize), + i = 0, + v = Number.NaN, + prev; + + do { + prev = v; + v = start + i * axis.tickSize; + ticks.push(v); + ++i; + } while (v < axis.max && v != prev); + return ticks; + }; + + axis.tickFormatter = function (value, axis) { + + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + var formatted = "" + Math.round(value * factor) / factor; + + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."); + var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } + + return formatted; + }; + } + + if ($.isFunction(opts.tickFormatter)) + axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; + + if (opts.alignTicksWithAxis != null) { + var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis != axis) { + // consider snapping min/max to outermost nice ticks + var niceTicks = axis.tickGenerator(axis); + if (niceTicks.length > 0) { + if (opts.min == null) + axis.min = Math.min(axis.min, niceTicks[0]); + if (opts.max == null && niceTicks.length > 1) + axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); + } + + axis.tickGenerator = function (axis) { + // copy ticks, scaled to this axis + var ticks = [], v, i; + for (i = 0; i < otherAxis.ticks.length; ++i) { + v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); + v = axis.min + v * (axis.max - axis.min); + ticks.push(v); + } + return ticks; + }; + + // we might need an extra decimal since forced + // ticks don't necessarily fit naturally + if (!axis.mode && opts.tickDecimals == null) { + var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), + ts = axis.tickGenerator(axis); + + // only proceed if the tick interval rounded + // with an extra decimal doesn't give us a + // zero at end + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) + axis.tickDecimals = extraDec; + } + } + } + } + + function setTicks(axis) { + var oticks = axis.options.ticks, ticks = []; + if (oticks == null || (typeof oticks == "number" && oticks > 0)) + ticks = axis.tickGenerator(axis); + else if (oticks) { + if ($.isFunction(oticks)) + // generate the ticks + ticks = oticks(axis); + else + ticks = oticks; + } + + // clean up/labelify the supplied ticks, copy them over + var i, v; + axis.ticks = []; + for (i = 0; i < ticks.length; ++i) { + var label = null; + var t = ticks[i]; + if (typeof t == "object") { + v = +t[0]; + if (t.length > 1) + label = t[1]; + } + else + v = +t; + if (label == null) + label = axis.tickFormatter(v, axis); + if (!isNaN(v)) + axis.ticks.push({ v: v, label: label }); + } + } + + function snapRangeToTicks(axis, ticks) { + if (axis.options.autoscaleMargin && ticks.length > 0) { + // snap to ticks + if (axis.options.min == null) + axis.min = Math.min(axis.min, ticks[0].v); + if (axis.options.max == null && ticks.length > 1) + axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); + } + } + + function draw() { + + surface.clear(); + + executeHooks(hooks.drawBackground, [ctx]); + + var grid = options.grid; + + // draw background, if any + if (grid.show && grid.backgroundColor) + drawBackground(); + + if (grid.show && !grid.aboveData) { + drawGrid(); + } + + for (var i = 0; i < series.length; ++i) { + executeHooks(hooks.drawSeries, [ctx, series[i]]); + drawSeries(series[i]); + } + + executeHooks(hooks.draw, [ctx]); + + if (grid.show && grid.aboveData) { + drawGrid(); + } + + surface.render(); + + // A draw implies that either the axes or data have changed, so we + // should probably update the overlay highlights as well. + + triggerRedrawOverlay(); + } + + function extractRange(ranges, coord) { + var axis, from, to, key, axes = allAxes(); + + for (var i = 0; i < axes.length; ++i) { + axis = axes[i]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? xaxes[0] : yaxes[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function drawBackground() { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); + ctx.fillRect(0, 0, plotWidth, plotHeight); + ctx.restore(); + } + + function drawGrid() { + var i, axes, bw, bc; + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // draw markings + var markings = options.grid.markings; + if (markings) { + if ($.isFunction(markings)) { + axes = plot.getAxes(); + // xmin etc. is backwards compatibility, to be + // removed in the future + axes.xmin = axes.xaxis.min; + axes.xmax = axes.xaxis.max; + axes.ymin = axes.yaxis.min; + axes.ymax = axes.yaxis.max; + + markings = markings(axes); + } + + for (i = 0; i < markings.length; ++i) { + var m = markings[i], + xrange = extractRange(m, "x"), + yrange = extractRange(m, "y"); + + // fill in missing + if (xrange.from == null) + xrange.from = xrange.axis.min; + if (xrange.to == null) + xrange.to = xrange.axis.max; + if (yrange.from == null) + yrange.from = yrange.axis.min; + if (yrange.to == null) + yrange.to = yrange.axis.max; + + // clip + if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) + continue; + + xrange.from = Math.max(xrange.from, xrange.axis.min); + xrange.to = Math.min(xrange.to, xrange.axis.max); + yrange.from = Math.max(yrange.from, yrange.axis.min); + yrange.to = Math.min(yrange.to, yrange.axis.max); + + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { + continue; + } + + // then draw + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; + ctx.beginPath(); + ctx.strokeStyle = m.color || options.grid.markingsColor; + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } + ctx.stroke(); + } else { + ctx.fillStyle = m.color || options.grid.markingsColor; + ctx.fillRect(xrange.from, yrange.to, + xrange.to - xrange.from, + yrange.from - yrange.to); + } + } + } + + // draw the ticks + axes = allAxes(); + bw = options.grid.borderWidth; + + for (var j = 0; j < axes.length; ++j) { + var axis = axes[j], box = axis.box, + t = axis.tickLength, x, y, xoff, yoff; + if (!axis.show || axis.ticks.length == 0) + continue; + + ctx.lineWidth = 1; + + // find the edges + if (axis.direction == "x") { + x = 0; + if (t == "full") + y = (axis.position == "top" ? 0 : plotHeight); + else + y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); + } + else { + y = 0; + if (t == "full") + x = (axis.position == "left" ? 0 : plotWidth); + else + x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); + } + + // draw tick bar + if (!axis.innermost) { + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + xoff = yoff = 0; + if (axis.direction == "x") + xoff = plotWidth + 1; + else + yoff = plotHeight + 1; + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") { + y = Math.floor(y) + 0.5; + } else { + x = Math.floor(x) + 0.5; + } + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + ctx.stroke(); + } + + // draw ticks + + ctx.strokeStyle = axis.options.tickColor; + + ctx.beginPath(); + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v; + + xoff = yoff = 0; + + if (isNaN(v) || v < axis.min || v > axis.max + // skip those lying on the axes if we got a border + || (t == "full" + && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) + && (v == axis.min || v == axis.max))) + continue; + + if (axis.direction == "x") { + x = axis.p2c(v); + yoff = t == "full" ? -plotHeight : t; + + if (axis.position == "top") + yoff = -yoff; + } + else { + y = axis.p2c(v); + xoff = t == "full" ? -plotWidth : t; + + if (axis.position == "left") + xoff = -xoff; + } + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") + x = Math.floor(x) + 0.5; + else + y = Math.floor(y) + 0.5; + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + } + + ctx.stroke(); + } + + + // draw border + if (bw) { + // If either borderWidth or borderColor is an object, then draw the border + // line by line instead of as one rectangle + bc = options.grid.borderColor; + if(typeof bw == "object" || typeof bc == "object") { + if (typeof bw !== "object") { + bw = {top: bw, right: bw, bottom: bw, left: bw}; + } + if (typeof bc !== "object") { + bc = {top: bc, right: bc, bottom: bc, left: bc}; + } + + if (bw.top > 0) { + ctx.strokeStyle = bc.top; + ctx.lineWidth = bw.top; + ctx.beginPath(); + ctx.moveTo(0 - bw.left, 0 - bw.top/2); + ctx.lineTo(plotWidth, 0 - bw.top/2); + ctx.stroke(); + } + + if (bw.right > 0) { + ctx.strokeStyle = bc.right; + ctx.lineWidth = bw.right; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); + ctx.lineTo(plotWidth + bw.right / 2, plotHeight); + ctx.stroke(); + } + + if (bw.bottom > 0) { + ctx.strokeStyle = bc.bottom; + ctx.lineWidth = bw.bottom; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); + ctx.lineTo(0, plotHeight + bw.bottom / 2); + ctx.stroke(); + } + + if (bw.left > 0) { + ctx.strokeStyle = bc.left; + ctx.lineWidth = bw.left; + ctx.beginPath(); + ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom); + ctx.lineTo(0- bw.left/2, 0); + ctx.stroke(); + } + } + else { + ctx.lineWidth = bw; + ctx.strokeStyle = options.grid.borderColor; + ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); + } + } + + ctx.restore(); + } + + function drawAxisLabels() { + + $.each(allAxes(), function (_, axis) { + var box = axis.box, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", + tick, x, y, halign, valign; + + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. + + surface.removeText(layer); + + if (!axis.show || axis.ticks.length == 0) + return; + + for (var i = 0; i < axis.ticks.length; ++i) { + + tick = axis.ticks[i]; + if (!tick.label || tick.v < axis.min || tick.v > axis.max) + continue; + + if (axis.direction == "x") { + halign = "center"; + x = plotOffset.left + axis.p2c(tick.v); + if (axis.position == "bottom") { + y = box.top + box.padding; + } else { + y = box.top + box.height - box.padding; + valign = "bottom"; + } + } else { + valign = "middle"; + y = plotOffset.top + axis.p2c(tick.v); + if (axis.position == "left") { + x = box.left + box.width - box.padding; + halign = "right"; + } else { + x = box.left + box.padding; + } + } + + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); + } + }); + } + + function drawSeries(series) { + if (series.lines.show) + drawSeriesLines(series); + if (series.bars.show) + drawSeriesBars(series); + if (series.points.show) + drawSeriesPoints(series); + } + + function drawSeriesLines(series) { + function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + prevx = null, prevy = null; + + ctx.beginPath(); + for (var i = ps; i < points.length; i += ps) { + var x1 = points[i - ps], y1 = points[i - ps + 1], + x2 = points[i], y2 = points[i + 1]; + + if (x1 == null || x2 == null) + continue; + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) + continue; // line segment is outside + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) + continue; + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) + continue; + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) + continue; + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 != prevx || y1 != prevy) + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + + prevx = x2; + prevy = y2; + ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); + } + ctx.stroke(); + } + + function plotLineArea(datapoints, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + bottom = Math.min(Math.max(0, axisy.min), axisy.max), + i = 0, top, areaOpen = false, + ypos = 1, segmentStart = 0, segmentEnd = 0; + + // we process each segment in two turns, first forward + // direction to sketch out top, then once we hit the + // end we go backwards to sketch the bottom + while (true) { + if (ps > 0 && i > points.length + ps) + break; + + i += ps; // ps is negative if going backwards + + var x1 = points[i - ps], + y1 = points[i - ps + ypos], + x2 = points[i], y2 = points[i + ypos]; + + if (areaOpen) { + if (ps > 0 && x1 != null && x2 == null) { + // at turning point + segmentEnd = i; + ps = -ps; + ypos = 2; + continue; + } + + if (ps < 0 && i == segmentStart + ps) { + // done with the reverse sweep + ctx.fill(); + areaOpen = false; + ps = -ps; + ypos = 1; + i = segmentStart = segmentEnd + ps; + continue; + } + } + + if (x1 == null || x2 == null) + continue; + + // clip x values + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (!areaOpen) { + // open area + ctx.beginPath(); + ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); + areaOpen = true; + } + + // now first check the case where both is outside + if (y1 >= axisy.max && y2 >= axisy.max) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); + continue; + } + else if (y1 <= axisy.min && y2 <= axisy.min) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); + continue; + } + + // else it's a bit more complicated, there might + // be a flat maxed out rectangle first, then a + // triangular cutout or reverse; to find these + // keep track of the current x values + var x1old = x1, x2old = x2; + + // clip the y values, without shortcutting, we + // go through all cases in turn + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // if the x value was changed we got a rectangle + // to fill + if (x1 != x1old) { + ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); + // it goes to (x1, y1), but we fill that below + } + + // fill triangular section, this sometimes result + // in redundant points if (x1, y1) hasn't changed + // from previous line to, but we just ignore that + ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + + // fill the other rectangle if it's there + if (x2 != x2old) { + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); + } + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + var lw = series.lines.lineWidth, + sw = series.shadowSize; + // FIXME: consider another form of shadow when filling is turned on + if (lw > 0 && sw > 0) { + // draw shadow as a thick and thin line with transparency + ctx.lineWidth = sw; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + // position shadow at angle from the mid of line + var angle = Math.PI/18; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis); + ctx.lineWidth = sw/2; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); + if (fillStyle) { + ctx.fillStyle = fillStyle; + plotLineArea(series.datapoints, series.xaxis, series.yaxis); + } + + if (lw > 0) + plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); + ctx.restore(); + } + + function drawSeriesPoints(series) { + function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var x = points[i], y = points[i + 1]; + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + continue; + + ctx.beginPath(); + x = axisx.p2c(x); + y = axisy.p2c(y) + offset; + if (symbol == "circle") + ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); + else + symbol(ctx, x, y, radius, shadow); + ctx.closePath(); + + if (fillStyle) { + ctx.fillStyle = fillStyle; + ctx.fill(); + } + ctx.stroke(); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var lw = series.points.lineWidth, + sw = series.shadowSize, + radius = series.points.radius, + symbol = series.points.symbol; + + // If the user sets the line width to 0, we change it to a very + // small value. A line width of 0 seems to force the default of 1. + // Doing the conditional here allows the shadow setting to still be + // optional even with a lineWidth of 0. + + if( lw == 0 ) + lw = 0.0001; + + if (lw > 0 && sw > 0) { + // draw shadow in two steps + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + plotPoints(series.datapoints, radius, null, w + w/2, true, + series.xaxis, series.yaxis, symbol); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + plotPoints(series.datapoints, radius, null, w/2, true, + series.xaxis, series.yaxis, symbol); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + plotPoints(series.datapoints, radius, + getFillStyle(series.points, series.color), 0, false, + series.xaxis, series.yaxis, symbol); + ctx.restore(); + } + + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + var left, right, bottom, top, + drawLeft, drawRight, drawTop, drawBottom, + tmp; + + // in horizontal mode, we start the bar from the left + // instead of from the bottom so it appears to be + // horizontal rather than vertical + if (horizontal) { + drawBottom = drawRight = drawTop = true; + drawLeft = false; + left = b; + right = x; + top = y + barLeft; + bottom = y + barRight; + + // account for negative bars + if (right < left) { + tmp = right; + right = left; + left = tmp; + drawLeft = true; + drawRight = false; + } + } + else { + drawLeft = drawRight = drawTop = true; + drawBottom = false; + left = x + barLeft; + right = x + barRight; + bottom = b; + top = y; + + // account for negative bars + if (top < bottom) { + tmp = top; + top = bottom; + bottom = tmp; + drawBottom = true; + drawTop = false; + } + } + + // clip + if (right < axisx.min || left > axisx.max || + top < axisy.min || bottom > axisy.max) + return; + + if (left < axisx.min) { + left = axisx.min; + drawLeft = false; + } + + if (right > axisx.max) { + right = axisx.max; + drawRight = false; + } + + if (bottom < axisy.min) { + bottom = axisy.min; + drawBottom = false; + } + + if (top > axisy.max) { + top = axisy.max; + drawTop = false; + } + + left = axisx.p2c(left); + bottom = axisy.p2c(bottom); + right = axisx.p2c(right); + top = axisy.p2c(top); + + // fill the bar + if (fillStyleCallback) { + c.fillStyle = fillStyleCallback(bottom, top); + c.fillRect(left, top, right - left, bottom - top) + } + + // draw outline + if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { + c.beginPath(); + + // FIXME: inline moveTo is buggy with excanvas + c.moveTo(left, bottom); + if (drawLeft) + c.lineTo(left, top); + else + c.moveTo(left, top); + if (drawTop) + c.lineTo(right, top); + else + c.moveTo(right, top); + if (drawRight) + c.lineTo(right, bottom); + else + c.moveTo(right, bottom); + if (drawBottom) + c.lineTo(left, bottom); + else + c.moveTo(left, bottom); + c.stroke(); + } + } + + function drawSeriesBars(series) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) + continue; + drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // FIXME: figure out a way to add shadows (for instance along the right edge) + ctx.lineWidth = series.bars.lineWidth; + ctx.strokeStyle = series.color; + + var barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; + plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); + ctx.restore(); + } + + function getFillStyle(filloptions, seriesColor, bottom, top) { + var fill = filloptions.fill; + if (!fill) + return null; + + if (filloptions.fillColor) + return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); + + var c = $.color.parse(seriesColor); + c.a = typeof fill == "number" ? fill : 0.4; + c.normalize(); + return c.toString(); + } + + function insertLegend() { + + if (options.legend.container != null) { + $(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } + + if (!options.legend.show) { + return; + } + + var fragments = [], entries = [], rowStarted = false, + lf = options.legend.labelFormatter, s, label; + + // Build a list of legend entries, with each having a label and a color + + for (var i = 0; i < series.length; ++i) { + s = series[i]; + if (s.label) { + label = lf ? lf(s.label, s) : s.label; + if (label) { + entries.push({ + label: label, + color: s.color + }); + } + } + } + + // Sort the legend using either the default or a custom comparator + + if (options.legend.sorted) { + if ($.isFunction(options.legend.sorted)) { + entries.sort(options.legend.sorted); + } else if (options.legend.sorted == "reverse") { + entries.reverse(); + } else { + var ascending = options.legend.sorted != "descending"; + entries.sort(function(a, b) { + return a.label == b.label ? 0 : ( + (a.label < b.label) != ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + // Generate markup for the list of entries, in their final order + + for (var i = 0; i < entries.length; ++i) { + + var entry = entries[i]; + + if (i % options.legend.noColumns == 0) { + if (rowStarted) + fragments.push('</tr>'); + fragments.push('<tr>'); + rowStarted = true; + } + + fragments.push( + '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' + + '<td class="legendLabel">' + entry.label + '</td>' + ); + } + + if (rowStarted) + fragments.push('</tr>'); + + if (fragments.length == 0) + return; + + var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>'; + if (options.legend.container != null) + $(options.legend.container).html(table); + else { + var pos = "", + p = options.legend.position, + m = options.legend.margin; + if (m[0] == null) + m = [m, m]; + if (p.charAt(0) == "n") + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + else if (p.charAt(0) == "s") + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + if (p.charAt(1) == "e") + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + else if (p.charAt(1) == "w") + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder); + if (options.legend.backgroundOpacity != 0.0) { + // put in the transparent background + // separately to avoid blended labels and + // label boxes + var c = options.legend.backgroundColor; + if (c == null) { + c = options.grid.backgroundColor; + if (c && typeof c == "string") + c = $.color.parse(c); + else + c = $.color.extract(legend, 'background-color'); + c.a = 1; + c = c.toString(); + } + var div = legend.children(); + $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity); + } + } + } + + + // interactive features + + var highlights = [], + redrawTimeout = null; + + // returns the data item the mouse is over, or null if none is found + function findNearbyItem(mouseX, mouseY, seriesFilter) { + var maxDistance = options.grid.mouseActiveRadius, + smallestDistance = maxDistance * maxDistance + 1, + item = null, foundPoint = false, i, j, ps; + + for (i = series.length - 1; i >= 0; --i) { + if (!seriesFilter(series[i])) + continue; + + var s = series[i], + axisx = s.xaxis, + axisy = s.yaxis, + points = s.datapoints.points, + mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster + my = axisy.c2p(mouseY), + maxx = maxDistance / axisx.scale, + maxy = maxDistance / axisy.scale; + + ps = s.datapoints.pointsize; + // with inverse transforms, we can't use the maxx/maxy + // optimization, sadly + if (axisx.options.inverseTransform) + maxx = Number.MAX_VALUE; + if (axisy.options.inverseTransform) + maxy = Number.MAX_VALUE; + + if (s.lines.show || s.points.show) { + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1]; + if (x == null) + continue; + + // For points and lines, the cursor must be within a + // certain distance to the data point + if (x - mx > maxx || x - mx < -maxx || + y - my > maxy || y - my < -maxy) + continue; + + // We have to calculate distances in pixels, not in + // data units, because the scales of the axes may be different + var dx = Math.abs(axisx.p2c(x) - mouseX), + dy = Math.abs(axisy.p2c(y) - mouseY), + dist = dx * dx + dy * dy; // we save the sqrt + + // use <= to ensure last point takes precedence + // (last generally means on top of) + if (dist < smallestDistance) { + smallestDistance = dist; + item = [i, j / ps]; + } + } + } + + if (s.bars.show && !item) { // no other point can be nearby + + var barLeft, barRight; + + switch (s.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -s.bars.barWidth; + break; + default: + barLeft = -s.bars.barWidth / 2; + } + + barRight = barLeft + s.bars.barWidth; + + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1], b = points[j + 2]; + if (x == null) + continue; + + // for a bar graph, the cursor must be inside the bar + if (series[i].bars.horizontal ? + (mx <= Math.max(b, x) && mx >= Math.min(b, x) && + my >= y + barLeft && my <= y + barRight) : + (mx >= x + barLeft && mx <= x + barRight && + my >= Math.min(b, y) && my <= Math.max(b, y))) + item = [i, j / ps]; + } + } + } + + if (item) { + i = item[0]; + j = item[1]; + ps = series[i].datapoints.pointsize; + + return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), + dataIndex: j, + series: series[i], + seriesIndex: i }; + } + + return null; + } + + function onMouseMove(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return s["hoverable"] != false; }); + } + + function onMouseLeave(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return false; }); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e, + function (s) { return s["clickable"] != false; }); + } + + // trigger click or hover event (they send the same parameters + // so we share their code) + function triggerClickHoverEvent(eventname, event, seriesFilter) { + var offset = eventHolder.offset(), + canvasX = event.pageX - offset.left - plotOffset.left, + canvasY = event.pageY - offset.top - plotOffset.top, + pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); + + pos.pageX = event.pageX; + pos.pageY = event.pageY; + + var item = findNearbyItem(canvasX, canvasY, seriesFilter); + + if (item) { + // fill in mouse pos for any listeners out there + item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); + item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10); + } + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && + !(item && h.series == item.series && + h.point[0] == item.datapoint[0] && + h.point[1] == item.datapoint[1])) + unhighlight(h.series, h.point); + } + + if (item) + highlight(item.series, item.datapoint, eventname); + } + + placeholder.trigger(eventname, [ pos, item ]); + } + + function triggerRedrawOverlay() { + var t = options.interaction.redrawOverlayInterval; + if (t == -1) { // skip event queue + drawOverlay(); + return; + } + + if (!redrawTimeout) + redrawTimeout = setTimeout(drawOverlay, t); + } + + function drawOverlay() { + redrawTimeout = null; + + // draw highlights + octx.save(); + overlay.clear(); + octx.translate(plotOffset.left, plotOffset.top); + + var i, hi; + for (i = 0; i < highlights.length; ++i) { + hi = highlights[i]; + + if (hi.series.bars.show) + drawBarHighlight(hi.series, hi.point); + else + drawPointHighlight(hi.series, hi.point); + } + octx.restore(); + + executeHooks(hooks.drawOverlay, [octx]); + } + + function highlight(s, point, auto) { + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i == -1) { + highlights.push({ series: s, point: point, auto: auto }); + + triggerRedrawOverlay(); + } + else if (!auto) + highlights[i].auto = false; + } + + function unhighlight(s, point) { + if (s == null && point == null) { + highlights = []; + triggerRedrawOverlay(); + return; + } + + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i != -1) { + highlights.splice(i, 1); + + triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s, p) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s && h.point[0] == p[0] + && h.point[1] == p[1]) + return i; + } + return -1; + } + + function drawPointHighlight(series, point) { + var x = point[0], y = point[1], + axisx = series.xaxis, axisy = series.yaxis, + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); + + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + return; + + var pointRadius = series.points.radius + series.points.lineWidth / 2; + octx.lineWidth = pointRadius; + octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; + x = axisx.p2c(x); + y = axisy.p2c(y); + + octx.beginPath(); + if (series.points.symbol == "circle") + octx.arc(x, y, radius, 0, 2 * Math.PI, false); + else + series.points.symbol(octx, x, y, radius, false); + octx.closePath(); + octx.stroke(); + } + + function drawBarHighlight(series, point) { + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), + fillStyle = highlightColor, + barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + octx.lineWidth = series.bars.lineWidth; + octx.strokeStyle = highlightColor; + + drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, + function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + } + + function getColorOrGradient(spec, bottom, top, defaultColor) { + if (typeof spec == "string") + return spec; + else { + // assume this is a gradient spec; IE currently only + // supports a simple vertical gradient properly, so that's + // what we support too + var gradient = ctx.createLinearGradient(0, top, 0, bottom); + + for (var i = 0, l = spec.colors.length; i < l; ++i) { + var c = spec.colors[i]; + if (typeof c != "string") { + var co = $.color.parse(defaultColor); + if (c.brightness != null) + co = co.scale('rgb', c.brightness); + if (c.opacity != null) + co.a *= c.opacity; + c = co.toString(); + } + gradient.addColorStop(i / (l - 1), c); + } + + return gradient; + } + } + } + + // Add the plot function to the top level of the jQuery object + + $.plot = function(placeholder, data, options) { + //var t0 = new Date(); + var plot = new Plot($(placeholder), data, options, $.plot.plugins); + //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime())); + return plot; + }; + + $.plot.version = "0.8.3"; + + $.plot.plugins = []; + + // Also add the plot function as a chainable property + + $.fn.plot = function(data, options) { + return this.each(function() { + $.plot(this, data, options); + }); + }; + + // round to nearby lower multiple of base + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + +})(jQuery); diff --git a/rhodecode/public/js/jquery.flot.selection.js b/rhodecode/public/js/jquery.flot.selection.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/jquery.flot.selection.js @@ -0,0 +1,360 @@ +/* Flot plugin for selecting regions of a plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + +selection: { + mode: null or "x" or "y" or "xy", + color: color, + shape: "round" or "miter" or "bevel", + minSize: number of pixels +} + +Selection support is enabled by setting the mode to one of "x", "y" or "xy". +In "x" mode, the user will only be able to specify the x range, similarly for +"y" mode. For "xy", the selection becomes a rectangle where both ranges can be +specified. "color" is color of the selection (if you need to change the color +later on, you can get to it with plot.getOptions().selection.color). "shape" +is the shape of the corners of the selection. + +"minSize" is the minimum size a selection can be in pixels. This value can +be customized to determine the smallest size a selection can be and still +have the selection rectangle be displayed. When customizing this value, the +fact that it refers to pixels, not axis units must be taken into account. +Thus, for example, if there is a bar graph in time mode with BarWidth set to 1 +minute, setting "minSize" to 1 will not make the minimum selection size 1 +minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent +"plotunselected" events from being fired when the user clicks the mouse without +dragging. + +When selection support is enabled, a "plotselected" event will be emitted on +the DOM element you passed into the plot function. The event handler gets a +parameter with the ranges selected on the axes, like this: + + placeholder.bind( "plotselected", function( event, ranges ) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished making the +selection. A "plotselecting" event is fired during the process with the same +parameters as the "plotselected" event, in case you want to know what's +happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user clicks the +mouse to remove the selection. As stated above, setting "minSize" to 0 will +destroy this behavior. + +The plugin allso adds the following methods to the plot object: + +- setSelection( ranges, preventEvent ) + + Set the selection rectangle. The passed in ranges is on the same form as + returned in the "plotselected" event. If the selection mode is "x", you + should put in either an xaxis range, if the mode is "y" you need to put in + an yaxis range and both xaxis and yaxis if the selection mode is "xy", like + this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If you don't + want that to happen, e.g. if you're inside a "plotselected" handler, pass + true as the second parameter. If you are using multiple axes, you can + specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of + xaxis, the plugin picks the first one it sees. + +- clearSelection( preventEvent ) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the "plotselected" + event. If there's currently no selection, the function returns null. + +*/ + +(function ($) { + function init(plot) { + var selection = { + first: { x: -1, y: -1}, second: { x: -1, y: -1}, + show: false, + active: false + }; + + // FIXME: The drag handling implemented here should be + // abstracted out, there's some similar code from a library in + // the navigation plugin, this should be massaged a bit to fit + // the Flot cases here better and reused. Doing this would + // make this plugin much slimmer. + var savedhandlers = {}; + + var mouseUpHandler = null; + + function onMouseMove(e) { + if (selection.active) { + updateSelection(e); + + plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]); + } + } + + function onMouseDown(e) { + if (e.which != 1) // only accept left-click + return; + + // cancel out any text selections + document.body.focus(); + + // prevent text selection and drag in old-school browsers + if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) { + savedhandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag !== undefined && savedhandlers.ondrag == null) { + savedhandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + + setSelectionPos(selection.first, e); + + selection.active = true; + + // this is a bit silly, but we have to use a closure to be + // able to whack the same handler again + mouseUpHandler = function (e) { onMouseUp(e); }; + + $(document).one("mouseup", mouseUpHandler); + } + + function onMouseUp(e) { + mouseUpHandler = null; + + // revert drag stuff for old-school browsers + if (document.onselectstart !== undefined) + document.onselectstart = savedhandlers.onselectstart; + if (document.ondrag !== undefined) + document.ondrag = savedhandlers.ondrag; + + // no more dragging + selection.active = false; + updateSelection(e); + + if (selectionIsSane()) + triggerSelectedEvent(); + else { + // this counts as a clear + plot.getPlaceholder().trigger("plotunselected", [ ]); + plot.getPlaceholder().trigger("plotselecting", [ null ]); + } + + return false; + } + + function getSelection() { + if (!selectionIsSane()) + return null; + + if (!selection.show) return null; + + var r = {}, c1 = selection.first, c2 = selection.second; + $.each(plot.getAxes(), function (name, axis) { + if (axis.used) { + var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); + r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) }; + } + }); + return r; + } + + function triggerSelectedEvent() { + var r = getSelection(); + + plot.getPlaceholder().trigger("plotselected", [ r ]); + + // backwards-compat stuff, to be removed in future + if (r.xaxis && r.yaxis) + plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]); + } + + function clamp(min, value, max) { + return value < min ? min: (value > max ? max: value); + } + + function setSelectionPos(pos, e) { + var o = plot.getOptions(); + var offset = plot.getPlaceholder().offset(); + var plotOffset = plot.getPlotOffset(); + pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width()); + pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height()); + + if (o.selection.mode == "y") + pos.x = pos == selection.first ? 0 : plot.width(); + + if (o.selection.mode == "x") + pos.y = pos == selection.first ? 0 : plot.height(); + } + + function updateSelection(pos) { + if (pos.pageX == null) + return; + + setSelectionPos(selection.second, pos); + if (selectionIsSane()) { + selection.show = true; + plot.triggerRedrawOverlay(); + } + else + clearSelection(true); + } + + function clearSelection(preventEvent) { + if (selection.show) { + selection.show = false; + plot.triggerRedrawOverlay(); + if (!preventEvent) + plot.getPlaceholder().trigger("plotunselected", [ ]); + } + } + + // function taken from markings support in Flot + function extractRange(ranges, coord) { + var axis, from, to, key, axes = plot.getAxes(); + + for (var k in axes) { + axis = axes[k]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function setSelection(ranges, preventEvent) { + var axis, range, o = plot.getOptions(); + + if (o.selection.mode == "y") { + selection.first.x = 0; + selection.second.x = plot.width(); + } + else { + range = extractRange(ranges, "x"); + + selection.first.x = range.axis.p2c(range.from); + selection.second.x = range.axis.p2c(range.to); + } + + if (o.selection.mode == "x") { + selection.first.y = 0; + selection.second.y = plot.height(); + } + else { + range = extractRange(ranges, "y"); + + selection.first.y = range.axis.p2c(range.from); + selection.second.y = range.axis.p2c(range.to); + } + + selection.show = true; + plot.triggerRedrawOverlay(); + if (!preventEvent && selectionIsSane()) + triggerSelectedEvent(); + } + + function selectionIsSane() { + var minSize = plot.getOptions().selection.minSize; + return Math.abs(selection.second.x - selection.first.x) >= minSize && + Math.abs(selection.second.y - selection.first.y) >= minSize; + } + + plot.clearSelection = clearSelection; + plot.setSelection = setSelection; + plot.getSelection = getSelection; + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var o = plot.getOptions(); + if (o.selection.mode != null) { + eventHolder.mousemove(onMouseMove); + eventHolder.mousedown(onMouseDown); + } + }); + + + plot.hooks.drawOverlay.push(function (plot, ctx) { + // draw selection + if (selection.show && selectionIsSane()) { + var plotOffset = plot.getPlotOffset(); + var o = plot.getOptions(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var c = $.color.parse(o.selection.color); + + ctx.strokeStyle = c.scale('a', 0.8).toString(); + ctx.lineWidth = 1; + ctx.lineJoin = o.selection.shape; + ctx.fillStyle = c.scale('a', 0.4).toString(); + + var x = Math.min(selection.first.x, selection.second.x) + 0.5, + y = Math.min(selection.first.y, selection.second.y) + 0.5, + w = Math.abs(selection.second.x - selection.first.x) - 1, + h = Math.abs(selection.second.y - selection.first.y) - 1; + + ctx.fillRect(x, y, w, h); + ctx.strokeRect(x, y, w, h); + + ctx.restore(); + } + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mousedown", onMouseDown); + + if (mouseUpHandler) + $(document).unbind("mouseup", mouseUpHandler); + }); + + } + + $.plot.plugins.push({ + init: init, + options: { + selection: { + mode: null, // one of null, "x", "y" or "xy" + color: "#e8cfac", + shape: "round", // one of "round", "miter", or "bevel" + minSize: 5 // minimum number of pixels + } + }, + name: 'selection', + version: '1.1' + }); +})(jQuery); diff --git a/rhodecode/public/js/jquery.flot.time.js b/rhodecode/public/js/jquery.flot.time.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/jquery.flot.time.js @@ -0,0 +1,432 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. + +*/ + +(function($) { + + var options = { + xaxis: { + timezone: null, // "browser" for local to the client or timezone for timezone-js + timeformat: null, // format string to use + twelveHourClock: false, // 12 or 24 time in time mode + monthNames: null // list of names of months + } + }; + + // round to nearby lower multiple of base + + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + + // Returns a string with the date d formatted according to fmt. + // A subset of the Open Group's strftime format is supported. + + function formatDate(d, fmt, monthNames, dayNames) { + + if (typeof d.strftime == "function") { + return d.strftime(fmt); + } + + var leftPad = function(n, pad) { + n = "" + n; + pad = "" + (pad == null ? "0" : pad); + return n.length == 1 ? pad + n : n; + }; + + var r = []; + var escape = false; + var hours = d.getHours(); + var isAM = hours < 12; + + if (monthNames == null) { + monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + } + + if (dayNames == null) { + dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + var hours12; + + if (hours > 12) { + hours12 = hours - 12; + } else if (hours == 0) { + hours12 = 12; + } else { + hours12 = hours; + } + + for (var i = 0; i < fmt.length; ++i) { + + var c = fmt.charAt(i); + + if (escape) { + switch (c) { + case 'a': c = "" + dayNames[d.getDay()]; break; + case 'b': c = "" + monthNames[d.getMonth()]; break; + case 'd': c = leftPad(d.getDate()); break; + case 'e': c = leftPad(d.getDate(), " "); break; + case 'h': // For back-compat with 0.7; remove in 1.0 + case 'H': c = leftPad(hours); break; + case 'I': c = leftPad(hours12); break; + case 'l': c = leftPad(hours12, " "); break; + case 'm': c = leftPad(d.getMonth() + 1); break; + case 'M': c = leftPad(d.getMinutes()); break; + // quarters not in Open Group's strftime specification + case 'q': + c = "" + (Math.floor(d.getMonth() / 3) + 1); break; + case 'S': c = leftPad(d.getSeconds()); break; + case 'y': c = leftPad(d.getFullYear() % 100); break; + case 'Y': c = "" + d.getFullYear(); break; + case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; + case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; + case 'w': c = "" + d.getDay(); break; + } + r.push(c); + escape = false; + } else { + if (c == "%") { + escape = true; + } else { + r.push(c); + } + } + } + + return r.join(""); + } + + // To have a consistent view of time-based data independent of which time + // zone the client happens to be in we need a date-like object independent + // of time zones. This is done through a wrapper that only calls the UTC + // versions of the accessor methods. + + function makeUtcWrapper(d) { + + function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { + sourceObj[sourceMethod] = function() { + return targetObj[targetMethod].apply(targetObj, arguments); + }; + }; + + var utc = { + date: d + }; + + // support strftime, if found + + if (d.strftime != undefined) { + addProxyMethod(utc, "strftime", d, "strftime"); + } + + addProxyMethod(utc, "getTime", d, "getTime"); + addProxyMethod(utc, "setTime", d, "setTime"); + + var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; + + for (var p = 0; p < props.length; p++) { + addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); + addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); + } + + return utc; + }; + + // select time zone strategy. This returns a date-like object tied to the + // desired timezone + + function dateGenerator(ts, opts) { + if (opts.timezone == "browser") { + return new Date(ts); + } else if (!opts.timezone || opts.timezone == "utc") { + return makeUtcWrapper(new Date(ts)); + } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") { + var d = new timezoneJS.Date(); + // timezone-js is fickle, so be sure to set the time zone before + // setting the time. + d.setTimezone(opts.timezone); + d.setTime(ts); + return d; + } else { + return makeUtcWrapper(new Date(ts)); + } + } + + // map of app. size of time units in milliseconds + + var timeUnitSize = { + "second": 1000, + "minute": 60 * 1000, + "hour": 60 * 60 * 1000, + "day": 24 * 60 * 60 * 1000, + "month": 30 * 24 * 60 * 60 * 1000, + "quarter": 3 * 30 * 24 * 60 * 60 * 1000, + "year": 365.2425 * 24 * 60 * 60 * 1000 + }; + + // the allowed tick sizes, after 1 year we use + // an integer algorithm + + var baseSpec = [ + [1, "second"], [2, "second"], [5, "second"], [10, "second"], + [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], + [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], + [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], + [2, "month"] + ]; + + // we don't know which variant(s) we'll need yet, but generating both is + // cheap + + var specMonths = baseSpec.concat([[3, "month"], [6, "month"], + [1, "year"]]); + var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], + [1, "year"]]); + + function init(plot) { + plot.hooks.processOptions.push(function (plot, options) { + $.each(plot.getAxes(), function(axisName, axis) { + + var opts = axis.options; + + if (opts.mode == "time") { + axis.tickGenerator = function(axis) { + + var ticks = []; + var d = dateGenerator(axis.min, opts); + var minSize = 0; + + // make quarter use a possibility if quarters are + // mentioned in either of these options + + var spec = (opts.tickSize && opts.tickSize[1] === + "quarter") || + (opts.minTickSize && opts.minTickSize[1] === + "quarter") ? specQuarters : specMonths; + + if (opts.minTickSize != null) { + if (typeof opts.tickSize == "number") { + minSize = opts.tickSize; + } else { + minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; + } + } + + for (var i = 0; i < spec.length - 1; ++i) { + if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] + + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 + && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { + break; + } + } + + var size = spec[i][0]; + var unit = spec[i][1]; + + // special-case the possibility of several years + + if (unit == "year") { + + // if given a minTickSize in years, just use it, + // ensuring that it's an integer + + if (opts.minTickSize != null && opts.minTickSize[1] == "year") { + size = Math.floor(opts.minTickSize[0]); + } else { + + var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); + var norm = (axis.delta / timeUnitSize.year) / magn; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + } + + // minimum size for years is 1 + + if (size < 1) { + size = 1; + } + } + + axis.tickSize = opts.tickSize || [size, unit]; + var tickSize = axis.tickSize[0]; + unit = axis.tickSize[1]; + + var step = tickSize * timeUnitSize[unit]; + + if (unit == "second") { + d.setSeconds(floorInBase(d.getSeconds(), tickSize)); + } else if (unit == "minute") { + d.setMinutes(floorInBase(d.getMinutes(), tickSize)); + } else if (unit == "hour") { + d.setHours(floorInBase(d.getHours(), tickSize)); + } else if (unit == "month") { + d.setMonth(floorInBase(d.getMonth(), tickSize)); + } else if (unit == "quarter") { + d.setMonth(3 * floorInBase(d.getMonth() / 3, + tickSize)); + } else if (unit == "year") { + d.setFullYear(floorInBase(d.getFullYear(), tickSize)); + } + + // reset smaller components + + d.setMilliseconds(0); + + if (step >= timeUnitSize.minute) { + d.setSeconds(0); + } + if (step >= timeUnitSize.hour) { + d.setMinutes(0); + } + if (step >= timeUnitSize.day) { + d.setHours(0); + } + if (step >= timeUnitSize.day * 4) { + d.setDate(1); + } + if (step >= timeUnitSize.month * 2) { + d.setMonth(floorInBase(d.getMonth(), 3)); + } + if (step >= timeUnitSize.quarter * 2) { + d.setMonth(floorInBase(d.getMonth(), 6)); + } + if (step >= timeUnitSize.year) { + d.setMonth(0); + } + + var carry = 0; + var v = Number.NaN; + var prev; + + do { + + prev = v; + v = d.getTime(); + ticks.push(v); + + if (unit == "month" || unit == "quarter") { + if (tickSize < 1) { + + // a bit complicated - we'll divide the + // month/quarter up but we need to take + // care of fractions so we don't end up in + // the middle of a day + + d.setDate(1); + var start = d.getTime(); + d.setMonth(d.getMonth() + + (unit == "quarter" ? 3 : 1)); + var end = d.getTime(); + d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); + carry = d.getHours(); + d.setHours(0); + } else { + d.setMonth(d.getMonth() + + tickSize * (unit == "quarter" ? 3 : 1)); + } + } else if (unit == "year") { + d.setFullYear(d.getFullYear() + tickSize); + } else { + d.setTime(v + step); + } + } while (v < axis.max && v != prev); + + return ticks; + }; + + axis.tickFormatter = function (v, axis) { + + var d = dateGenerator(v, axis.options); + + // first check global format + + if (opts.timeformat != null) { + return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); + } + + // possibly use quarters if quarters are mentioned in + // any of these places + + var useQuarters = (axis.options.tickSize && + axis.options.tickSize[1] == "quarter") || + (axis.options.minTickSize && + axis.options.minTickSize[1] == "quarter"); + + var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; + var span = axis.max - axis.min; + var suffix = (opts.twelveHourClock) ? " %p" : ""; + var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; + var fmt; + + if (t < timeUnitSize.minute) { + fmt = hourCode + ":%M:%S" + suffix; + } else if (t < timeUnitSize.day) { + if (span < 2 * timeUnitSize.day) { + fmt = hourCode + ":%M" + suffix; + } else { + fmt = "%b %d " + hourCode + ":%M" + suffix; + } + } else if (t < timeUnitSize.month) { + fmt = "%b %d"; + } else if ((useQuarters && t < timeUnitSize.quarter) || + (!useQuarters && t < timeUnitSize.year)) { + if (span < timeUnitSize.year) { + fmt = "%b"; + } else { + fmt = "%b %Y"; + } + } else if (useQuarters && t < timeUnitSize.year) { + if (span < timeUnitSize.year) { + fmt = "Q%q"; + } else { + fmt = "Q%q %Y"; + } + } else { + fmt = "%Y"; + } + + var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); + + return rt; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'time', + version: '1.0' + }); + + // Time-axis support used to be in Flot core, which exposed the + // formatDate function on the plot object. Various plugins depend + // on the function, so we need to re-expose it here. + + $.plot.formatDate = formatDate; + $.plot.dateGenerator = dateGenerator; + +})(jQuery); diff --git a/rhodecode/public/js/jquery.flot.tooltip.js b/rhodecode/public/js/jquery.flot.tooltip.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/jquery.flot.tooltip.js @@ -0,0 +1,488 @@ +/* + * jquery.flot.tooltip + * + * description: easy-to-use tooltips for Flot charts + * version: 0.8.4 + * authors: Krzysztof Urbas @krzysu [myviews.pl],Evan Steinkerchner @Roundaround + * website: https://github.com/krzysu/flot.tooltip + * + * build on 2014-08-06 + * released under MIT License, 2012 +*/ +(function ($) { + // plugin options, default values + var defaultOptions = { + tooltip: false, + tooltipOpts: { + id: "flotTip", + content: "%s | X: %x | Y: %y", + // allowed templates are: + // %s -> series label, + // %lx -> x axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), + // %ly -> y axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels), + // %x -> X value, + // %y -> Y value, + // %x.2 -> precision of X value, + // %p -> percent + xDateFormat: null, + yDateFormat: null, + monthNames: null, + dayNames: null, + shifts: { + x: 10, + y: 20 + }, + defaultTheme: true, + lines: false, + + // callbacks + onHover: function (flotItem, $tooltipEl) {}, + + $compat: false + } + }; + + // object + var FlotTooltip = function (plot) { + // variables + this.tipPosition = {x: 0, y: 0}; + + this.init(plot); + }; + + // main plugin function + FlotTooltip.prototype.init = function (plot) { + var that = this; + + // detect other flot plugins + var plotPluginsLength = $.plot.plugins.length; + this.plotPlugins = []; + + if (plotPluginsLength) { + for (var p = 0; p < plotPluginsLength; p++) { + this.plotPlugins.push($.plot.plugins[p].name); + } + } + + plot.hooks.bindEvents.push(function (plot, eventHolder) { + + // get plot options + that.plotOptions = plot.getOptions(); + + // if not enabled return + if (that.plotOptions.tooltip === false || typeof that.plotOptions.tooltip === 'undefined') return; + + // shortcut to access tooltip options + that.tooltipOptions = that.plotOptions.tooltipOpts; + + if (that.tooltipOptions.$compat) { + that.wfunc = 'width'; + that.hfunc = 'height'; + } else { + that.wfunc = 'innerWidth'; + that.hfunc = 'innerHeight'; + } + + // create tooltip DOM element + var $tip = that.getDomElement(); + + // bind event + $( plot.getPlaceholder() ).bind("plothover", plothover); + + $(eventHolder).bind('mousemove', mouseMove); + }); + + plot.hooks.shutdown.push(function (plot, eventHolder){ + $(plot.getPlaceholder()).unbind("plothover", plothover); + $(eventHolder).unbind("mousemove", mouseMove); + }); + + function mouseMove(e){ + var pos = {}; + pos.x = e.pageX; + pos.y = e.pageY; + plot.setTooltipPosition(pos); + } + + function plothover(event, pos, item) { + // Simple distance formula. + var lineDistance = function (p1x, p1y, p2x, p2y) { + return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y)); + }; + + // Here is some voodoo magic for determining the distance to a line form a given point {x, y}. + var dotLineLength = function (x, y, x0, y0, x1, y1, o) { + if (o && !(o = + function (x, y, x0, y0, x1, y1) { + if (typeof x0 !== 'undefined') return { x: x0, y: y }; + else if (typeof y0 !== 'undefined') return { x: x, y: y0 }; + + var left, + tg = -1 / ((y1 - y0) / (x1 - x0)); + + return { + x: left = (x1 * (x * tg - y + y0) + x0 * (x * -tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), + y: tg * left - tg * x + y + }; + } (x, y, x0, y0, x1, y1), + o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1)) + ) { + var l1 = lineDistance(x, y, x0, y0), l2 = lineDistance(x, y, x1, y1); + return l1 > l2 ? l2 : l1; + } else { + var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1; + return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b); + } + }; + + if (item) { + plot.showTooltip(item, pos); + } else if (that.plotOptions.series.lines.show && that.tooltipOptions.lines === true) { + var maxDistance = that.plotOptions.grid.mouseActiveRadius; + + var closestTrace = { + distance: maxDistance + 1 + }; + + $.each(plot.getData(), function (i, series) { + var xBeforeIndex = 0, + xAfterIndex = -1; + + // Our search here assumes our data is sorted via the x-axis. + // TODO: Improve efficiency somehow - search smaller sets of data. + for (var j = 1; j < series.data.length; j++) { + if (series.data[j - 1][0] <= pos.x && series.data[j][0] >= pos.x) { + xBeforeIndex = j - 1; + xAfterIndex = j; + } + } + + if (xAfterIndex === -1) { + plot.hideTooltip(); + return; + } + + var pointPrev = { x: series.data[xBeforeIndex][0], y: series.data[xBeforeIndex][1] }, + pointNext = { x: series.data[xAfterIndex][0], y: series.data[xAfterIndex][1] }; + + var distToLine = dotLineLength(series.xaxis.p2c(pos.x), series.yaxis.p2c(pos.y), series.xaxis.p2c(pointPrev.x), + series.yaxis.p2c(pointPrev.y), series.xaxis.p2c(pointNext.x), series.yaxis.p2c(pointNext.y), false); + + if (distToLine < closestTrace.distance) { + + var closestIndex = lineDistance(pointPrev.x, pointPrev.y, pos.x, pos.y) < + lineDistance(pos.x, pos.y, pointNext.x, pointNext.y) ? xBeforeIndex : xAfterIndex; + + var pointSize = series.datapoints.pointsize; + + // Calculate the point on the line vertically closest to our cursor. + var pointOnLine = [ + pos.x, + pointPrev.y + ((pointNext.y - pointPrev.y) * ((pos.x - pointPrev.x) / (pointNext.x - pointPrev.x))) + ]; + + var item = { + datapoint: pointOnLine, + dataIndex: closestIndex, + series: series, + seriesIndex: i + }; + + closestTrace = { + distance: distToLine, + item: item + }; + } + }); + + if (closestTrace.distance < maxDistance + 1) + plot.showTooltip(closestTrace.item, pos); + else + plot.hideTooltip(); + } else { + plot.hideTooltip(); + } + } + + // Quick little function for setting the tooltip position. + plot.setTooltipPosition = function (pos) { + var $tip = that.getDomElement(); + + var totalTipWidth = $tip.outerWidth() + that.tooltipOptions.shifts.x; + var totalTipHeight = $tip.outerHeight() + that.tooltipOptions.shifts.y; + if ((pos.x - $(window).scrollLeft()) > ($(window)[that.wfunc]() - totalTipWidth)) { + pos.x -= totalTipWidth; + } + if ((pos.y - $(window).scrollTop()) > ($(window)[that.hfunc]() - totalTipHeight)) { + pos.y -= totalTipHeight; + } + that.tipPosition.x = pos.x; + that.tipPosition.y = pos.y; + }; + + // Quick little function for showing the tooltip. + plot.showTooltip = function (target, position) { + var $tip = that.getDomElement(); + + // convert tooltip content template to real tipText + var tipText = that.stringFormat(that.tooltipOptions.content, target); + + $tip.html(tipText); + plot.setTooltipPosition({ x: position.pageX, y: position.pageY }); + $tip.css({ + left: that.tipPosition.x + that.tooltipOptions.shifts.x, + top: that.tipPosition.y + that.tooltipOptions.shifts.y + }).show(); + + // run callback + if (typeof that.tooltipOptions.onHover === 'function') { + that.tooltipOptions.onHover(target, $tip); + } + }; + + // Quick little function for hiding the tooltip. + plot.hideTooltip = function () { + that.getDomElement().hide().html(''); + }; + }; + + /** + * get or create tooltip DOM element + * @return jQuery object + */ + FlotTooltip.prototype.getDomElement = function () { + var $tip = $('#' + this.tooltipOptions.id); + + if( $tip.length === 0 ){ + $tip = $('<div />').attr('id', this.tooltipOptions.id); + $tip.appendTo('body').hide().css({position: 'absolute'}); + + if(this.tooltipOptions.defaultTheme) { + $tip.css({ + 'background': '#fff', + 'z-index': '1040', + 'padding': '0.4em 0.6em', + 'border-radius': '0.5em', + 'font-size': '0.8em', + 'border': '1px solid #111', + 'display': 'none', + 'white-space': 'nowrap' + }); + } + } + + return $tip; + }; + + /** + * core function, create tooltip content + * @param {string} content - template with tooltip content + * @param {object} item - Flot item + * @return {string} real tooltip content for current item + */ + FlotTooltip.prototype.stringFormat = function (content, item) { + + var percentPattern = /%p\.{0,1}(\d{0,})/; + var seriesPattern = /%s/; + var xLabelPattern = /%lx/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded + var yLabelPattern = /%ly/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded + var xPattern = /%x\.{0,1}(\d{0,})/; + var yPattern = /%y\.{0,1}(\d{0,})/; + var xPatternWithoutPrecision = "%x"; + var yPatternWithoutPrecision = "%y"; + var customTextPattern = "%ct"; + + var x, y, customText, p; + + // for threshold plugin we need to read data from different place + if (typeof item.series.threshold !== "undefined") { + x = item.datapoint[0]; + y = item.datapoint[1]; + customText = item.datapoint[2]; + } else if (typeof item.series.lines !== "undefined" && item.series.lines.steps) { + x = item.series.datapoints.points[item.dataIndex * 2]; + y = item.series.datapoints.points[item.dataIndex * 2 + 1]; + // TODO: where to find custom text in this variant? + customText = ""; + } else { + x = item.series.data[item.dataIndex][0]; + y = item.series.data[item.dataIndex][1]; + customText = item.series.data[item.dataIndex][2]; + } + + // I think this is only in case of threshold plugin + if (item.series.label === null && item.series.originSeries) { + item.series.label = item.series.originSeries.label; + } + + // if it is a function callback get the content string + if (typeof(content) === 'function') { + content = content(item.series.label, x, y, item); + } + + // percent match for pie charts and stacked percent + if (typeof (item.series.percent) !== 'undefined') { + p = item.series.percent; + } else if (typeof (item.series.percents) !== 'undefined') { + p = item.series.percents[item.dataIndex]; + } + if (typeof p === 'number') { + content = this.adjustValPrecision(percentPattern, content, p); + } + + // series match + if (typeof(item.series.label) !== 'undefined') { + content = content.replace(seriesPattern, item.series.label); + } else { + //remove %s if label is undefined + content = content.replace(seriesPattern, ""); + } + + // x axis label match + if (this.hasAxisLabel('xaxis', item)) { + content = content.replace(xLabelPattern, item.series.xaxis.options.axisLabel); + } else { + //remove %lx if axis label is undefined or axislabels plugin not present + content = content.replace(xLabelPattern, ""); + } + + // y axis label match + if (this.hasAxisLabel('yaxis', item)) { + content = content.replace(yLabelPattern, item.series.yaxis.options.axisLabel); + } else { + //remove %ly if axis label is undefined or axislabels plugin not present + content = content.replace(yLabelPattern, ""); + } + + // time mode axes with custom dateFormat + if (this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) { + content = content.replace(xPattern, this.timestampToDate(x, this.tooltipOptions.xDateFormat, item.series.xaxis.options)); + } + if (this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) { + content = content.replace(yPattern, this.timestampToDate(y, this.tooltipOptions.yDateFormat, item.series.yaxis.options)); + } + + // set precision if defined + if (typeof x === 'number') { + content = this.adjustValPrecision(xPattern, content, x); + } + if (typeof y === 'number') { + content = this.adjustValPrecision(yPattern, content, y); + } + + // change x from number to given label, if given + if (typeof item.series.xaxis.ticks !== 'undefined') { + + var ticks; + if (this.hasRotatedXAxisTicks(item)) { + // xaxis.ticks will be an empty array if tickRotor is being used, but the values are available in rotatedTicks + ticks = 'rotatedTicks'; + } else { + ticks = 'ticks'; + } + + // see https://github.com/krzysu/flot.tooltip/issues/65 + var tickIndex = item.dataIndex + item.seriesIndex; + + if (item.series.xaxis[ticks].length > tickIndex && !this.isTimeMode('xaxis', item)) { + var valueX = (this.isCategoriesMode('xaxis', item)) ? item.series.xaxis[ticks][tickIndex].label : item.series.xaxis[ticks][tickIndex].v; + if (valueX === x) { + content = content.replace(xPattern, item.series.xaxis[ticks][tickIndex].label); + } + } + } + + // change y from number to given label, if given + if (typeof item.series.yaxis.ticks !== 'undefined') { + for (var index in item.series.yaxis.ticks) { + if (item.series.yaxis.ticks.hasOwnProperty(index)) { + var valueY = (this.isCategoriesMode('yaxis', item)) ? item.series.yaxis.ticks[index].label : item.series.yaxis.ticks[index].v; + if (valueY === y) { + content = content.replace(yPattern, item.series.yaxis.ticks[index].label); + } + } + } + } + + // if no value customization, use tickFormatter by default + if (typeof item.series.xaxis.tickFormatter !== 'undefined') { + //escape dollar + content = content.replace(xPatternWithoutPrecision, item.series.xaxis.tickFormatter(x, item.series.xaxis).replace(/\$/g, '$$')); + } + if (typeof item.series.yaxis.tickFormatter !== 'undefined') { + //escape dollar + content = content.replace(yPatternWithoutPrecision, item.series.yaxis.tickFormatter(y, item.series.yaxis).replace(/\$/g, '$$')); + } + + if (customText) + content = content.replace(customTextPattern, customText); + + return content; + }; + + // helpers just for readability + FlotTooltip.prototype.isTimeMode = function (axisName, item) { + return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time'); + }; + + FlotTooltip.prototype.isXDateFormat = function (item) { + return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null); + }; + + FlotTooltip.prototype.isYDateFormat = function (item) { + return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null); + }; + + FlotTooltip.prototype.isCategoriesMode = function (axisName, item) { + return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'categories'); + }; + + // + FlotTooltip.prototype.timestampToDate = function (tmst, dateFormat, options) { + var theDate = $.plot.dateGenerator(tmst, options); + return $.plot.formatDate(theDate, dateFormat, this.tooltipOptions.monthNames, this.tooltipOptions.dayNames); + }; + + // + FlotTooltip.prototype.adjustValPrecision = function (pattern, content, value) { + + var precision; + var matchResult = content.match(pattern); + if( matchResult !== null ) { + if(RegExp.$1 !== '') { + precision = RegExp.$1; + value = value.toFixed(precision); + + // only replace content if precision exists, in other case use thickformater + content = content.replace(pattern, value); + } + } + return content; + }; + + // other plugins detection below + + // check if flot-axislabels plugin (https://github.com/markrcote/flot-axislabels) is used and that an axis label is given + FlotTooltip.prototype.hasAxisLabel = function (axisName, item) { + return ($.inArray(this.plotPlugins, 'axisLabels') !== -1 && typeof item.series[axisName].options.axisLabel !== 'undefined' && item.series[axisName].options.axisLabel.length > 0); + }; + + // check whether flot-tickRotor, a plugin which allows rotation of X-axis ticks, is being used + FlotTooltip.prototype.hasRotatedXAxisTicks = function (item) { + return ($.inArray(this.plotPlugins, 'tickRotor') !== -1 && typeof item.series.xaxis.rotatedTicks !== 'undefined'); + }; + + // + var init = function (plot) { + new FlotTooltip(plot); + }; + + // define Flot plugin + $.plot.plugins.push({ + init: init, + options: defaultOptions, + name: 'tooltip', + version: '0.8.4' + }); + +})(jQuery); diff --git a/rhodecode/public/js/mergerly.js b/rhodecode/public/js/mergerly.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mergerly.js @@ -0,0 +1,1606 @@ +"use strict"; + +(function( window, document, jQuery, CodeMirror ){ + +var Mgly = {}; + +Mgly.Timer = function(){ + var self = this; + self.start = function() { self.t0 = new Date().getTime(); }; + self.stop = function() { + var t1 = new Date().getTime(); + var d = t1 - self.t0; + self.t0 = t1; + return d; + }; + self.start(); +}; + +Mgly.ChangeExpression = new RegExp(/(^(?![><\-])*\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/); + +Mgly.DiffParser = function(diff) { + var changes = []; + var change_id = 0; + // parse diff + var diff_lines = diff.split(/\n/); + for (var i = 0; i < diff_lines.length; ++i) { + if (diff_lines[i].length == 0) continue; + var change = {}; + var test = Mgly.ChangeExpression.exec(diff_lines[i]); + if (test == null) continue; + // lines are zero-based + var fr = test[1].split(','); + change['lhs-line-from'] = fr[0] - 1; + if (fr.length == 1) change['lhs-line-to'] = fr[0] - 1; + else change['lhs-line-to'] = fr[1] - 1; + var to = test[3].split(','); + change['rhs-line-from'] = to[0] - 1; + if (to.length == 1) change['rhs-line-to'] = to[0] - 1; + else change['rhs-line-to'] = to[1] - 1; + change['op'] = test[2]; + changes[change_id++] = change; + } + return changes; +}; + +Mgly.sizeOf = function(obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) size++; + } + return size; +}; + +Mgly.LCS = function(x, y) { + this.x = x.replace(/[ ]{1}/g, '\n'); + this.y = y.replace(/[ ]{1}/g, '\n'); +}; + +jQuery.extend(Mgly.LCS.prototype, { + clear: function() { this.ready = 0; }, + diff: function(added, removed) { + var d = new Mgly.diff(this.x, this.y, {ignorews: false}); + var changes = Mgly.DiffParser(d.normal_form()); + var li = 0, lj = 0; + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + if (change.op != 'a') { + // find the starting index of the line + li = d.getLines('lhs').slice(0, change['lhs-line-from']).join(' ').length; + // get the index of the the span of the change + lj = change['lhs-line-to'] + 1; + // get the changed text + var lchange = d.getLines('lhs').slice(change['lhs-line-from'], lj).join(' '); + if (change.op == 'd') lchange += ' ';// include the leading space + else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word + // output the changed index and text + removed(li, li + lchange.length); + } + if (change.op != 'd') { + // find the starting index of the line + li = d.getLines('rhs').slice(0, change['rhs-line-from']).join(' ').length; + // get the index of the the span of the change + lj = change['rhs-line-to'] + 1; + // get the changed text + var rchange = d.getLines('rhs').slice(change['rhs-line-from'], lj).join(' '); + if (change.op == 'a') rchange += ' ';// include the leading space + else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word + // output the changed index and text + added(li, li + rchange.length); + } + } + } +}); + +Mgly.CodeifyText = function(settings) { + this._max_code = 0; + this._diff_codes = {}; + this.ctxs = {}; + this.options = {ignorews: false}; + jQuery.extend(this, settings); + this.lhs = settings.lhs.split('\n'); + this.rhs = settings.rhs.split('\n'); +}; + +jQuery.extend(Mgly.CodeifyText.prototype, { + getCodes: function(side) { + if (!this.ctxs.hasOwnProperty(side)) { + var ctx = this._diff_ctx(this[side]); + this.ctxs[side] = ctx; + ctx.codes.length = Object.keys(ctx.codes).length; + } + return this.ctxs[side].codes; + }, + getLines: function(side) { + return this.ctxs[side].lines; + }, + _diff_ctx: function(lines) { + var ctx = {i: 0, codes: {}, lines: lines}; + this._codeify(lines, ctx); + return ctx; + }, + _codeify: function(lines, ctx) { + var code = this._max_code; + for (var i = 0; i < lines.length; ++i) { + var line = lines[i]; + if (this.options.ignorews) { + line = line.replace(/\s+/g, ''); + } + var aCode = this._diff_codes[line]; + if (aCode != undefined) { + ctx.codes[i] = aCode; + } + else { + this._max_code++; + this._diff_codes[line] = this._max_code; + ctx.codes[i] = this._max_code; + } + } + } +}); + +Mgly.diff = function(lhs, rhs, options) { + var opts = jQuery.extend({ignorews: false}, options); + this.codeify = new Mgly.CodeifyText({ + lhs: lhs, + rhs: rhs, + options: opts + }); + var lhs_ctx = { + codes: this.codeify.getCodes('lhs'), + modified: {} + }; + var rhs_ctx = { + codes: this.codeify.getCodes('rhs'), + modified: {} + }; + var max = (lhs_ctx.codes.length + rhs_ctx.codes.length + 1); + var vector_d = []; + var vector_u = []; + this._lcs(lhs_ctx, 0, lhs_ctx.codes.length, rhs_ctx, 0, rhs_ctx.codes.length, vector_u, vector_d); + this._optimize(lhs_ctx); + this._optimize(rhs_ctx); + this.items = this._create_diffs(lhs_ctx, rhs_ctx); +}; + +jQuery.extend(Mgly.diff.prototype, { + changes: function() { return this.items; }, + getLines: function(side) { + return this.codeify.getLines(side); + }, + normal_form: function() { + var nf = ''; + for (var index = 0; index < this.items.length; ++index) { + var item = this.items[index]; + var lhs_str = ''; + var rhs_str = ''; + var change = 'c'; + if (item.lhs_deleted_count == 0 && item.rhs_inserted_count > 0) change = 'a'; + else if (item.lhs_deleted_count > 0 && item.rhs_inserted_count == 0) change = 'd'; + + if (item.lhs_deleted_count == 1) lhs_str = item.lhs_start + 1; + else if (item.lhs_deleted_count == 0) lhs_str = item.lhs_start; + else lhs_str = (item.lhs_start + 1) + ',' + (item.lhs_start + item.lhs_deleted_count); + + if (item.rhs_inserted_count == 1) rhs_str = item.rhs_start + 1; + else if (item.rhs_inserted_count == 0) rhs_str = item.rhs_start; + else rhs_str = (item.rhs_start + 1) + ',' + (item.rhs_start + item.rhs_inserted_count); + nf += lhs_str + change + rhs_str + '\n'; + + var lhs_lines = this.getLines('lhs'); + var rhs_lines = this.getLines('rhs'); + if (rhs_lines && lhs_lines) { + var i; + // if rhs/lhs lines have been retained, output contextual diff + for (i = item.lhs_start; i < item.lhs_start + item.lhs_deleted_count; ++i) { + nf += '< ' + lhs_lines[i] + '\n'; + } + if (item.rhs_inserted_count && item.lhs_deleted_count) nf += '---\n'; + for (i = item.rhs_start; i < item.rhs_start + item.rhs_inserted_count; ++i) { + nf += '> ' + rhs_lines[i] + '\n'; + } + } + } + return nf; + }, + _lcs: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) { + while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_lower] == rhs_ctx.codes[rhs_lower]) ) { + ++lhs_lower; + ++rhs_lower; + } + while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_upper - 1] == rhs_ctx.codes[rhs_upper - 1]) ) { + --lhs_upper; + --rhs_upper; + } + if (lhs_lower == lhs_upper) { + while (rhs_lower < rhs_upper) { + rhs_ctx.modified[ rhs_lower++ ] = true; + } + } + else if (rhs_lower == rhs_upper) { + while (lhs_lower < lhs_upper) { + lhs_ctx.modified[ lhs_lower++ ] = true; + } + } + else { + var sms = this._sms(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d); + this._lcs(lhs_ctx, lhs_lower, sms.x, rhs_ctx, rhs_lower, sms.y, vector_u, vector_d); + this._lcs(lhs_ctx, sms.x, lhs_upper, rhs_ctx, sms.y, rhs_upper, vector_u, vector_d); + } + }, + _sms: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) { + var max = lhs_ctx.codes.length + rhs_ctx.codes.length + 1; + var kdown = lhs_lower - rhs_lower; + var kup = lhs_upper - rhs_upper; + var delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower); + var odd = (delta & 1) != 0; + var offset_down = max - kdown; + var offset_up = max - kup; + var maxd = ((lhs_upper - lhs_lower + rhs_upper - rhs_lower) / 2) + 1; + vector_d[ offset_down + kdown + 1 ] = lhs_lower; + vector_u[ offset_up + kup - 1 ] = lhs_upper; + var ret = {x:0,y:0}, d, k, x, y; + for (d = 0; d <= maxd; ++d) { + for (k = kdown - d; k <= kdown + d; k += 2) { + if (k == kdown - d) { + x = vector_d[ offset_down + k + 1 ];//down + } + else { + x = vector_d[ offset_down + k - 1 ] + 1;//right + if ((k < (kdown + d)) && (vector_d[ offset_down + k + 1 ] >= x)) { + x = vector_d[ offset_down + k + 1 ];//down + } + } + y = x - k; + // find the end of the furthest reaching forward D-path in diagonal k. + while ((x < lhs_upper) && (y < rhs_upper) && (lhs_ctx.codes[x] == rhs_ctx.codes[y])) { + x++; y++; + } + vector_d[ offset_down + k ] = x; + // overlap ? + if (odd && (kup - d < k) && (k < kup + d)) { + if (vector_u[offset_up + k] <= vector_d[offset_down + k]) { + ret.x = vector_d[offset_down + k]; + ret.y = vector_d[offset_down + k] - k; + return (ret); + } + } + } + // Extend the reverse path. + for (k = kup - d; k <= kup + d; k += 2) { + // find the only or better starting point + if (k == kup + d) { + x = vector_u[offset_up + k - 1]; // up + } else { + x = vector_u[offset_up + k + 1] - 1; // left + if ((k > kup - d) && (vector_u[offset_up + k - 1] < x)) + x = vector_u[offset_up + k - 1]; // up + } + y = x - k; + while ((x > lhs_lower) && (y > rhs_lower) && (lhs_ctx.codes[x - 1] == rhs_ctx.codes[y - 1])) { + // diagonal + x--; + y--; + } + vector_u[offset_up + k] = x; + // overlap ? + if (!odd && (kdown - d <= k) && (k <= kdown + d)) { + if (vector_u[offset_up + k] <= vector_d[offset_down + k]) { + ret.x = vector_d[offset_down + k]; + ret.y = vector_d[offset_down + k] - k; + return (ret); + } + } + } + } + throw "the algorithm should never come here."; + }, + _optimize: function(ctx) { + var start = 0, end = 0; + while (start < ctx.length) { + while ((start < ctx.length) && (ctx.modified[start] == undefined || ctx.modified[start] == false)) { + start++; + } + end = start; + while ((end < ctx.length) && (ctx.modified[end] == true)) { + end++; + } + if ((end < ctx.length) && (ctx.ctx[start] == ctx.codes[end])) { + ctx.modified[start] = false; + ctx.modified[end] = true; + } + else { + start = end; + } + } + }, + _create_diffs: function(lhs_ctx, rhs_ctx) { + var items = []; + var lhs_start = 0, rhs_start = 0; + var lhs_line = 0, rhs_line = 0; + + while (lhs_line < lhs_ctx.codes.length || rhs_line < rhs_ctx.codes.length) { + if ((lhs_line < lhs_ctx.codes.length) && (!lhs_ctx.modified[lhs_line]) + && (rhs_line < rhs_ctx.codes.length) && (!rhs_ctx.modified[rhs_line])) { + // equal lines + lhs_line++; + rhs_line++; + } + else { + // maybe deleted and/or inserted lines + lhs_start = lhs_line; + rhs_start = rhs_line; + + while (lhs_line < lhs_ctx.codes.length && (rhs_line >= rhs_ctx.codes.length || lhs_ctx.modified[lhs_line])) + lhs_line++; + + while (rhs_line < rhs_ctx.codes.length && (lhs_line >= lhs_ctx.codes.length || rhs_ctx.modified[rhs_line])) + rhs_line++; + + if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) { + // store a new difference-item + items.push({ + lhs_start: lhs_start, + rhs_start: rhs_start, + lhs_deleted_count: lhs_line - lhs_start, + rhs_inserted_count: rhs_line - rhs_start + }); + } + } + } + return items; + } +}); + +Mgly.mergely = function(el, options) { + if (el) { + this.init(el, options); + } +}; + +jQuery.extend(Mgly.mergely.prototype, { + name: 'mergely', + //http://jupiterjs.com/news/writing-the-perfect-jquery-plugin + init: function(el, options) { + this.diffView = new Mgly.CodeMirrorDiffView(el, options); + this.bind(el); + }, + bind: function(el) { + this.diffView.bind(el); + } +}); + +Mgly.CodeMirrorDiffView = function(el, options) { + CodeMirror.defineExtension('centerOnCursor', function() { + var coords = this.cursorCoords(null, 'local'); + this.scrollTo(null, + (coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2)); + }); + this.init(el, options); +}; + +jQuery.extend(Mgly.CodeMirrorDiffView.prototype, { + init: function(el, options) { + this.settings = { + autoupdate: true, + autoresize: true, + rhs_margin: 'right', + wrap_lines: false, + line_numbers: true, + lcs: true, + sidebar: true, + viewport: false, + ignorews: false, + fadein: 'fast', + editor_width: '650px', + editor_height: '400px', + resize_timeout: 500, + change_timeout: 150, + fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f', // color for differences (soft color) + ca:'#4b73ff',cc:'#434343',cd:'#ff4f4f'}, // color for currently active difference (bright color) + bgcolor: '#eee', + vpcolor: 'rgba(0, 0, 200, 0.5)', + lhs: function(setValue) { }, + rhs: function(setValue) { }, + loaded: function() { }, + _auto_width: function(w) { return w; }, + resize: function(init) { + var scrollbar = init ? 16 : 0; + var w = jQuery(el).parent().width() + scrollbar, h = 0; + if (this.width == 'auto') { + w = this._auto_width(w); + } + else { + w = this.width; + this.editor_width = w; + } + if (this.height == 'auto') { + //h = this._auto_height(h); + h = jQuery(el).parent().height(); + } + else { + h = this.height; + this.editor_height = h; + } + var content_width = w / 2.0 - 2 * 8 - 8; + var content_height = h; + var self = jQuery(el); + self.find('.mergely-column').css({ width: content_width + 'px' }); + self.find('.mergely-column, .mergely-canvas, .mergely-margin, .mergely-column textarea, .CodeMirror-scroll, .cm-s-default').css({ height: content_height + 'px' }); + self.find('.mergely-canvas').css({ height: content_height + 'px' }); + self.find('.mergely-column textarea').css({ width: content_width + 'px' }); + self.css({ width: w, height: h, clear: 'both' }); + if (self.css('display') == 'none') { + if (this.fadein != false) self.fadeIn(this.fadein); + else self.show(); + if (this.loaded) this.loaded(); + } + if (this.resized) this.resized(); + }, + _debug: '', //scroll,draw,calc,diff,markup,change + resized: function() { }, + finished: function () { } + }; + var cmsettings = { + mode: 'text/plain', + readOnly: false, + lineWrapping: this.settings.wrap_lines, + lineNumbers: this.settings.line_numbers, + gutters: ['merge', 'CodeMirror-linenumbers'] + }; + this.lhs_cmsettings = {}; + this.rhs_cmsettings = {}; + + // save this element for faster queries + this.element = jQuery(el); + + // save options if there are any + if (options && options.cmsettings) jQuery.extend(this.lhs_cmsettings, cmsettings, options.cmsettings, options.lhs_cmsettings); + if (options && options.cmsettings) jQuery.extend(this.rhs_cmsettings, cmsettings, options.cmsettings, options.rhs_cmsettings); + //if (options) jQuery.extend(this.settings, options); + + // bind if the element is destroyed + this.element.bind('destroyed', jQuery.proxy(this.teardown, this)); + + // save this instance in jQuery data, binding this view to the node + jQuery.data(el, 'mergely', this); + + this._setOptions(options); + }, + unbind: function() { + if (this.changed_timeout != null) clearTimeout(this.changed_timeout); + this.editor[this.id + '-lhs'].toTextArea(); + this.editor[this.id + '-rhs'].toTextArea(); + jQuery(window).off('.mergely'); + }, + destroy: function() { + this.element.unbind('destroyed', this.teardown); + this.teardown(); + }, + teardown: function() { + this.unbind(); + }, + lhs: function(text) { + this.editor[this.id + '-lhs'].setValue(text); + }, + rhs: function(text) { + this.editor[this.id + '-rhs'].setValue(text); + }, + update: function() { + this._changing(this.id + '-lhs', this.id + '-rhs'); + }, + unmarkup: function() { + this._clear(); + }, + scrollToDiff: function(direction) { + if (!this.changes.length) return; + if (direction == 'next') { + this._current_diff = Math.min(++this._current_diff, this.changes.length - 1); + } + else { + this._current_diff = Math.max(--this._current_diff, 0); + } + this._scroll_to_change(this.changes[this._current_diff]); + this._changed(this.id + '-lhs', this.id + '-rhs'); + }, + mergeCurrentChange: function(side) { + if (!this.changes.length) return; + if (side == 'lhs' && !this.lhs_cmsettings.readOnly) { + this._merge_change(this.changes[this._current_diff], 'rhs', 'lhs'); + } + else if (side == 'rhs' && !this.rhs_cmsettings.readOnly) { + this._merge_change(this.changes[this._current_diff], 'lhs', 'rhs'); + } + }, + scrollTo: function(side, num) { + var le = this.editor[this.id + '-lhs']; + var re = this.editor[this.id + '-rhs']; + if (side == 'lhs') { + le.setCursor(num); + le.centerOnCursor(); + } + else { + re.setCursor(num); + re.centerOnCursor(); + } + }, + _setOptions: function(opts) { + jQuery.extend(this.settings, opts); + if (this.settings.hasOwnProperty('rhs_margin')) { + // dynamically swap the margin + if (this.settings.rhs_margin == 'left') { + this.element.find('.mergely-margin:last-child').insertAfter( + this.element.find('.mergely-canvas')); + } + else { + var target = this.element.find('.mergely-margin').last(); + target.appendTo(target.parent()); + } + } + if (this.settings.hasOwnProperty('sidebar')) { + // dynamically enable sidebars + if (this.settings.sidebar) { + jQuery(this.element).find('.mergely-margin').css({display: 'block'}); + } + else { + jQuery(this.element).find('.mergely-margin').css({display: 'none'}); + } + } + var le, re; + if (this.settings.hasOwnProperty('wrap_lines')) { + if (this.editor) { + le = this.editor[this.id + '-lhs']; + re = this.editor[this.id + '-rhs']; + le.setOption('lineWrapping', this.settings.wrap_lines); + re.setOption('lineWrapping', this.settings.wrap_lines); + } + } + if (this.settings.hasOwnProperty('line_numbers')) { + if (this.editor) { + le = this.editor[this.id + '-lhs']; + re = this.editor[this.id + '-rhs']; + le.setOption('lineNumbers', this.settings.line_numbers); + re.setOption('lineNumbers', this.settings.line_numbers); + } + } + }, + options: function(opts) { + if (opts) { + this._setOptions(opts); + if (this.settings.autoresize) this.resize(); + if (this.settings.autoupdate) this.update(); + } + else { + return this.settings; + } + }, + swap: function() { + if (this.lhs_cmsettings.readOnly || this.rhs_cmsettings.readOnly) return; + var le = this.editor[this.id + '-lhs']; + var re = this.editor[this.id + '-rhs']; + var tmp = re.getValue(); + re.setValue(le.getValue()); + le.setValue(tmp); + }, + merge: function(side) { + var le = this.editor[this.id + '-lhs']; + var re = this.editor[this.id + '-rhs']; + if (side == 'lhs' && !this.lhs_cmsettings.readOnly) le.setValue(re.getValue()); + else if (!this.rhs_cmsettings.readOnly) re.setValue(le.getValue()); + }, + get: function(side) { + var ed = this.editor[this.id + '-' + side]; + var t = ed.getValue(); + if (t == undefined) return ''; + return t; + }, + clear: function(side) { + if (side == 'lhs' && this.lhs_cmsettings.readOnly) return; + if (side == 'rhs' && this.rhs_cmsettings.readOnly) return; + var ed = this.editor[this.id + '-' + side]; + ed.setValue(''); + }, + cm: function(side) { + return this.editor[this.id + '-' + side]; + }, + search: function(side, query, direction) { + var le = this.editor[this.id + '-lhs']; + var re = this.editor[this.id + '-rhs']; + var editor; + if (side == 'lhs') editor = le; + else editor = re; + direction = (direction == 'prev') ? 'findPrevious' : 'findNext'; + if ((editor.getSelection().length == 0) || (this.prev_query[side] != query)) { + this.cursor[this.id] = editor.getSearchCursor(query, { line: 0, ch: 0 }, false); + this.prev_query[side] = query; + } + var cursor = this.cursor[this.id]; + + if (cursor[direction]()) { + editor.setSelection(cursor.from(), cursor.to()); + } + else { + cursor = editor.getSearchCursor(query, { line: 0, ch: 0 }, false); + } + }, + resize: function() { + this.settings.resize(); + this._changing(this.id + '-lhs', this.id + '-rhs'); + this._set_top_offset(this.id + '-lhs'); + }, + diff: function() { + var lhs = this.editor[this.id + '-lhs'].getValue(); + var rhs = this.editor[this.id + '-rhs'].getValue(); + var d = new Mgly.diff(lhs, rhs, this.settings); + return d.normal_form(); + }, + bind: function(el) { + this.element.hide();//hide + this.id = jQuery(el).attr('id'); + this.changed_timeout = null; + this.chfns = {}; + this.chfns[this.id + '-lhs'] = []; + this.chfns[this.id + '-rhs'] = []; + this.prev_query = []; + this.cursor = []; + this._skipscroll = {}; + this.change_exp = new RegExp(/(\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/); + var merge_lhs_button; + var merge_rhs_button; + if (jQuery.button != undefined) { + //jquery ui + merge_lhs_button = '<button title="Merge left"></button>'; + merge_rhs_button = '<button title="Merge right"></button>'; + } + else { + // homebrew + var style = 'opacity:0.4;width:10px;height:15px;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;margin-top: -2px;'; + merge_lhs_button = '<div style="' + style + '" title="Merge left"><</div>'; + merge_rhs_button = '<div style="' + style + '" title="Merge right">></div>'; + } + this.merge_rhs_button = jQuery(merge_rhs_button); + this.merge_lhs_button = jQuery(merge_lhs_button); + + // create the textarea and canvas elements + var height = this.settings.editor_height; + var width = this.settings.editor_width; + this.element.append(jQuery('<div class="mergely-margin" style="height: ' + height + '"><canvas id="' + this.id + '-lhs-margin" width="8px" height="' + height + '"></canvas></div>')); + this.element.append(jQuery('<div style="position:relative;width:' + width + '; height:' + height + '" id="' + this.id + '-editor-lhs" class="mergely-column"><textarea style="" id="' + this.id + '-lhs"></textarea></div>')); + this.element.append(jQuery('<div class="mergely-canvas" style="height: ' + height + '"><canvas id="' + this.id + '-lhs-' + this.id + '-rhs-canvas" style="width:28px" width="28px" height="' + height + '"></canvas></div>')); + var rmargin = jQuery('<div class="mergely-margin" style="height: ' + height + '"><canvas id="' + this.id + '-rhs-margin" width="8px" height="' + height + '"></canvas></div>'); + if (!this.settings.sidebar) { + this.element.find('.mergely-margin').css({display: 'none'}); + } + if (this.settings.rhs_margin == 'left') { + this.element.append(rmargin); + } + this.element.append(jQuery('<div style="width:' + width + '; height:' + height + '" id="' + this.id + '-editor-rhs" class="mergely-column"><textarea style="" id="' + this.id + '-rhs"></textarea></div>')); + if (this.settings.rhs_margin != 'left') { + this.element.append(rmargin); + } + //codemirror + var cmstyle = '#' + this.id + ' .CodeMirror-gutter-text { padding: 5px 0 0 0; }' + + '#' + this.id + ' .CodeMirror-lines pre, ' + '#' + this.id + ' .CodeMirror-gutter-text pre { line-height: 18px; }' + + '.CodeMirror-linewidget { overflow: hidden; };'; + if (this.settings.autoresize) { + cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }'; + } + // adjust the margin line height + cmstyle += '\n.CodeMirror { line-height: 18px; }'; + jQuery('<style type="text/css">' + cmstyle + '</style>').appendTo('head'); + + //bind + var rhstx = jQuery('#' + this.id + '-rhs').get(0); + if (!rhstx) { + console.error('rhs textarea not defined - Mergely not initialized properly'); + return; + } + var lhstx = jQuery('#' + this.id + '-lhs').get(0); + if (!rhstx) { + console.error('lhs textarea not defined - Mergely not initialized properly'); + return; + } + var self = this; + this.editor = []; + this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings); + this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings); + this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); }); + this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); }); + this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); }); + this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); }); + // resize + if (this.settings.autoresize) { + var sz_timeout1 = null; + var sz = function(init) { + //self.em_height = null; //recalculate + if (self.settings.resize) self.settings.resize(init); + self.editor[self.id + '-lhs'].refresh(); + self.editor[self.id + '-rhs'].refresh(); + if (self.settings.autoupdate) { + self._changing(self.id + '-lhs', self.id + '-rhs'); + } + }; + jQuery(window).on('resize.mergely', + function () { + if (sz_timeout1) clearTimeout(sz_timeout1); + sz_timeout1 = setTimeout(sz, self.settings.resize_timeout); + } + ); + sz(true); + } + //bind + var setv; + if (this.settings.lhs) { + setv = this.editor[this.id + '-lhs'].getDoc().setValue; + this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc())); + } + if (this.settings.rhs) { + setv = this.editor[this.id + '-rhs'].getDoc().setValue; + this.settings.rhs(setv.bind(this.editor[this.id + '-rhs'].getDoc())); + } + }, + + _scroll_to_change : function(change) { + if (!change) return; + var self = this; + var led = self.editor[self.id+'-lhs']; + var red = self.editor[self.id+'-rhs']; + + var yref = led.getScrollerElement().offsetHeight * 0.5; // center between >0 and 1/2 + + // set cursors + led.setCursor(Math.max(change["lhs-line-from"],0), 0); // use led.getCursor().ch ? + red.setCursor(Math.max(change["rhs-line-from"],0), 0); + + // using directly CodeMirror breaks canvas alignment + // var ly = led.charCoords({line: Math.max(change["lhs-line-from"],0), ch: 0}, "local").top; + + // calculate scroll offset for current change. Warning: returns relative y position so we scroll to 0 first. + led.scrollTo(null, 0); + red.scrollTo(null, 0); + self._calculate_offsets(self.id+'-lhs', self.id+'-rhs', [change]); + led.scrollTo(null, Math.max(change["lhs-y-start"]-yref, 0)); + red.scrollTo(null, Math.max(change["rhs-y-start"]-yref, 0)); + // right pane should simply follows + }, + + _scrolling: function(editor_name) { + if (this._skipscroll[editor_name] === true) { + // scrolling one side causes the other to event - ignore it + this._skipscroll[editor_name] = false; + return; + } + var scroller = jQuery(this.editor[editor_name].getScrollerElement()); + if (this.midway == undefined) { + this.midway = (scroller.height() / 2.0 + scroller.offset().top).toFixed(2); + } + // balance-line + var midline = this.editor[editor_name].coordsChar({left:0, top:this.midway}); + var top_to = scroller.scrollTop(); + var left_to = scroller.scrollLeft(); + + this.trace('scroll', 'side', editor_name); + this.trace('scroll', 'midway', this.midway); + this.trace('scroll', 'midline', midline); + this.trace('scroll', 'top_to', top_to); + this.trace('scroll', 'left_to', left_to); + + var editor_name1 = this.id + '-lhs'; + var editor_name2 = this.id + '-rhs'; + + for (var name in this.editor) { + if (!this.editor.hasOwnProperty(name)) continue; + if (editor_name == name) continue; //same editor + var this_side = editor_name.replace(this.id + '-', ''); + var other_side = name.replace(this.id + '-', ''); + var top_adjust = 0; + + // find the last change that is less than or within the midway point + // do not move the rhs until the lhs end point is >= the rhs end point. + var last_change = null; + var force_scroll = false; + for (var i = 0; i < this.changes.length; ++i) { + var change = this.changes[i]; + if ((midline.line >= change[this_side+'-line-from'])) { + last_change = change; + if (midline.line >= last_change[this_side+'-line-to']) { + if (!change.hasOwnProperty(this_side+'-y-start') || + !change.hasOwnProperty(this_side+'-y-end') || + !change.hasOwnProperty(other_side+'-y-start') || + !change.hasOwnProperty(other_side+'-y-end')){ + // change outside of viewport + force_scroll = true; + } + else { + top_adjust += + (change[this_side+'-y-end'] - change[this_side+'-y-start']) - + (change[other_side+'-y-end'] - change[other_side+'-y-start']); + } + } + } + } + + var vp = this.editor[name].getViewport(); + var scroll = true; + if (last_change) { + this.trace('scroll', 'last change before midline', last_change); + if (midline.line >= vp.from && midline <= vp.to) { + scroll = false; + } + } + this.trace('scroll', 'scroll', scroll); + if (scroll || force_scroll) { + // scroll the other side + this.trace('scroll', 'scrolling other side', top_to - top_adjust); + this._skipscroll[name] = true;//disable next event + this.editor[name].scrollTo(left_to, top_to - top_adjust); + } + else this.trace('scroll', 'not scrolling other side'); + + if (this.settings.autoupdate) { + var timer = new Mgly.Timer(); + this._calculate_offsets(editor_name1, editor_name2, this.changes); + this.trace('change', 'offsets time', timer.stop()); + this._markup_changes(editor_name1, editor_name2, this.changes); + this.trace('change', 'markup time', timer.stop()); + this._draw_diff(editor_name1, editor_name2, this.changes); + this.trace('change', 'draw time', timer.stop()); + } + this.trace('scroll', 'scrolled'); + } + }, + _changing: function(editor_name1, editor_name2) { + this.trace('change', 'changing-timeout', this.changed_timeout); + var self = this; + if (this.changed_timeout != null) clearTimeout(this.changed_timeout); + this.changed_timeout = setTimeout(function(){ + var timer = new Mgly.Timer(); + self._changed(editor_name1, editor_name2); + self.trace('change', 'total time', timer.stop()); + }, this.settings.change_timeout); + }, + _changed: function(editor_name1, editor_name2) { + this._clear(); + this._diff(editor_name1, editor_name2); + }, + _clear: function() { + var self = this, name, editor, fns, timer, i, change, l; + + var clear_changes = function() { + timer = new Mgly.Timer(); + for (i = 0, l = editor.lineCount(); i < l; ++i) { + editor.removeLineClass(i, 'background'); + } + for (i = 0; i < fns.length; ++i) { + //var edid = editor.getDoc().id; + change = fns[i]; + //if (change.doc.id != edid) continue; + if (change.lines.length) { + self.trace('change', 'clear text', change.lines[0].text); + } + change.clear(); + } + editor.clearGutter('merge'); + self.trace('change', 'clear time', timer.stop()); + }; + + for (name in this.editor) { + if (!this.editor.hasOwnProperty(name)) continue; + editor = this.editor[name]; + fns = self.chfns[name]; + // clear editor changes + editor.operation(clear_changes); + } + self.chfns[name] = []; + + var ex = this._draw_info(this.id + '-lhs', this.id + '-rhs'); + var ctx_lhs = ex.clhs.get(0).getContext('2d'); + var ctx_rhs = ex.crhs.get(0).getContext('2d'); + var ctx = ex.dcanvas.getContext('2d'); + + ctx_lhs.beginPath(); + ctx_lhs.fillStyle = this.settings.bgcolor; + ctx_lhs.strokeStyle = '#888'; + ctx_lhs.fillRect(0, 0, 6.5, ex.visible_page_height); + ctx_lhs.strokeRect(0, 0, 6.5, ex.visible_page_height); + + ctx_rhs.beginPath(); + ctx_rhs.fillStyle = this.settings.bgcolor; + ctx_rhs.strokeStyle = '#888'; + ctx_rhs.fillRect(0, 0, 6.5, ex.visible_page_height); + ctx_rhs.strokeRect(0, 0, 6.5, ex.visible_page_height); + + ctx.beginPath(); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, this.draw_mid_width, ex.visible_page_height); + }, + _diff: function(editor_name1, editor_name2) { + var lhs = this.editor[editor_name1].getValue(); + var rhs = this.editor[editor_name2].getValue(); + var timer = new Mgly.Timer(); + var d = new Mgly.diff(lhs, rhs, this.settings); + this.trace('change', 'diff time', timer.stop()); + this.changes = Mgly.DiffParser(d.normal_form()); + this.trace('change', 'parse time', timer.stop()); + + if (this._current_diff === undefined && this.changes.length) { + // go to first difference on start-up + this._current_diff = 0; + this._scroll_to_change(this.changes[0]); + } + + this.trace('change', 'scroll_to_change time', timer.stop()); + this._calculate_offsets(editor_name1, editor_name2, this.changes); + this.trace('change', 'offsets time', timer.stop()); + this._markup_changes(editor_name1, editor_name2, this.changes); + this.trace('change', 'markup time', timer.stop()); + this._draw_diff(editor_name1, editor_name2, this.changes); + this.trace('change', 'draw time', timer.stop()); + }, + _parse_diff: function (editor_name1, editor_name2, diff) { + this.trace('diff', 'diff results:\n', diff); + var changes = []; + var change_id = 0; + // parse diff + var diff_lines = diff.split(/\n/); + for (var i = 0; i < diff_lines.length; ++i) { + if (diff_lines[i].length == 0) continue; + var change = {}; + var test = this.change_exp.exec(diff_lines[i]); + if (test == null) continue; + // lines are zero-based + var fr = test[1].split(','); + change['lhs-line-from'] = fr[0] - 1; + if (fr.length == 1) change['lhs-line-to'] = fr[0] - 1; + else change['lhs-line-to'] = fr[1] - 1; + var to = test[3].split(','); + change['rhs-line-from'] = to[0] - 1; + if (to.length == 1) change['rhs-line-to'] = to[0] - 1; + else change['rhs-line-to'] = to[1] - 1; + // TODO: optimize for changes that are adds/removes + if (change['lhs-line-from'] < 0) change['lhs-line-from'] = 0; + if (change['lhs-line-to'] < 0) change['lhs-line-to'] = 0; + if (change['rhs-line-from'] < 0) change['rhs-line-from'] = 0; + if (change['rhs-line-to'] < 0) change['rhs-line-to'] = 0; + change['op'] = test[2]; + changes[change_id++] = change; + this.trace('diff', 'change', change); + } + return changes; + }, + _get_viewport: function(editor_name1, editor_name2) { + var lhsvp = this.editor[editor_name1].getViewport(); + var rhsvp = this.editor[editor_name2].getViewport(); + return {from: Math.min(lhsvp.from, rhsvp.from), to: Math.max(lhsvp.to, rhsvp.to)}; + }, + _is_change_in_view: function(vp, change) { + if (!this.settings.viewport) return true; + if ((change['lhs-line-from'] < vp.from && change['lhs-line-to'] < vp.to) || + (change['lhs-line-from'] > vp.from && change['lhs-line-to'] > vp.to) || + (change['rhs-line-from'] < vp.from && change['rhs-line-to'] < vp.to) || + (change['rhs-line-from'] > vp.from && change['rhs-line-to'] > vp.to)) { + // if the change is outside the viewport, skip + return false; + } + return true; + }, + _set_top_offset: function (editor_name1) { + // save the current scroll position of the editor + var saveY = this.editor[editor_name1].getScrollInfo().top; + // temporarily scroll to top + this.editor[editor_name1].scrollTo(null, 0); + + // this is the distance from the top of the screen to the top of the + // content of the first codemirror editor + var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first(); + var top_offset = topnode.offset().top - 4; + if(!top_offset) return false; + + // restore editor's scroll position + this.editor[editor_name1].scrollTo(null, saveY); + + this.draw_top_offset = 0.5 - top_offset; + return true; + }, + _calculate_offsets: function (editor_name1, editor_name2, changes) { + if (this.em_height == null) { + if(!this._set_top_offset(editor_name1)) return; //try again + this.em_height = this.editor[editor_name1].defaultTextHeight(); + if (!this.em_height) { + console.warn('Failed to calculate offsets, using 18 by default'); + this.em_height = 18; + } + this.draw_lhs_min = 0.5; + var c = jQuery('#' + editor_name1 + '-' + editor_name2 + '-canvas'); + if (!c.length) { + console.error('failed to find canvas', '#' + editor_name1 + '-' + editor_name2 + '-canvas'); + } + if (!c.width()) { + console.error('canvas width is 0'); + return; + } + this.draw_mid_width = jQuery('#' + editor_name1 + '-' + editor_name2 + '-canvas').width(); + this.draw_rhs_max = this.draw_mid_width - 0.5; //24.5; + this.draw_lhs_width = 5; + this.draw_rhs_width = 5; + this.trace('calc', 'change offsets calculated', {top_offset: this.draw_top_offset, lhs_min: this.draw_lhs_min, rhs_max: this.draw_rhs_max, lhs_width: this.draw_lhs_width, rhs_width: this.draw_rhs_width}); + } + var lhschc = this.editor[editor_name1].charCoords({line: 0}); + var rhschc = this.editor[editor_name2].charCoords({line: 0}); + var vp = this._get_viewport(editor_name1, editor_name2); + + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + + if (!this.settings.sidebar && !this._is_change_in_view(vp, change)) { + // if the change is outside the viewport, skip + delete change['lhs-y-start']; + delete change['lhs-y-end']; + delete change['rhs-y-start']; + delete change['rhs-y-end']; + continue; + } + var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0; + var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0; + var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0; + var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0; + + var ls, le, rs, re, tls, tle, lhseh, lhssh, rhssh, rhseh; + if (this.editor[editor_name1].getOption('lineWrapping') || this.editor[editor_name2].getOption('lineWrapping')) { + // If using line-wrapping, we must get the height of the line + tls = this.editor[editor_name1].cursorCoords({line: llf, ch: 0}, 'page'); + lhssh = this.editor[editor_name1].getLineHandle(llf); + ls = { top: tls.top, bottom: tls.top + lhssh.height }; + + tle = this.editor[editor_name1].cursorCoords({line: llt, ch: 0}, 'page'); + lhseh = this.editor[editor_name1].getLineHandle(llt); + le = { top: tle.top, bottom: tle.top + lhseh.height }; + + tls = this.editor[editor_name2].cursorCoords({line: rlf, ch: 0}, 'page'); + rhssh = this.editor[editor_name2].getLineHandle(rlf); + rs = { top: tls.top, bottom: tls.top + rhssh.height }; + + tle = this.editor[editor_name2].cursorCoords({line: rlt, ch: 0}, 'page'); + rhseh = this.editor[editor_name2].getLineHandle(rlt); + re = { top: tle.top, bottom: tle.top + rhseh.height }; + } + else { + // If not using line-wrapping, we can calculate the line position + ls = { + top: lhschc.top + llf * this.em_height, + bottom: lhschc.bottom + llf * this.em_height + 2 + }; + le = { + top: lhschc.top + llt * this.em_height, + bottom: lhschc.bottom + llt * this.em_height + 2 + }; + rs = { + top: rhschc.top + rlf * this.em_height, + bottom: rhschc.bottom + rlf * this.em_height + 2 + }; + re = { + top: rhschc.top + rlt * this.em_height, + bottom: rhschc.bottom + rlt * this.em_height + 2 + }; + } + + if (change['op'] == 'a') { + // adds (right), normally start from the end of the lhs, + // except for the case when the start of the rhs is 0 + if (rlf > 0) { + ls.top = ls.bottom; + ls.bottom += this.em_height; + le = ls; + } + } + else if (change['op'] == 'd') { + // deletes (left) normally finish from the end of the rhs, + // except for the case when the start of the lhs is 0 + if (llf > 0) { + rs.top = rs.bottom; + rs.bottom += this.em_height; + re = rs; + } + } + change['lhs-y-start'] = this.draw_top_offset + ls.top; + if (change['op'] == 'c' || change['op'] == 'd') { + change['lhs-y-end'] = this.draw_top_offset + le.bottom; + } + else { + change['lhs-y-end'] = this.draw_top_offset + le.top; + } + change['rhs-y-start'] = this.draw_top_offset + rs.top; + if (change['op'] == 'c' || change['op'] == 'a') { + change['rhs-y-end'] = this.draw_top_offset + re.bottom; + } + else { + change['rhs-y-end'] = this.draw_top_offset + re.top; + } + this.trace('calc', 'change calculated', i, change); + } + return changes; + }, + _markup_changes: function (editor_name1, editor_name2, changes) { + jQuery('.merge-button').remove(); // clear + + var self = this; + var led = this.editor[editor_name1]; + var red = this.editor[editor_name2]; + + var timer = new Mgly.Timer(); + led.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0; + var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0; + var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0; + var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0; + + var clazz = ['mergely', 'lhs', change['op'], 'cid-' + i]; + led.addLineClass(llf, 'background', 'start'); + led.addLineClass(llt, 'background', 'end'); + + if (llf == 0 && llt == 0 && rlf == 0) { + led.addLineClass(llf, 'background', clazz.join(' ')); + led.addLineClass(llf, 'background', 'first'); + } + else { + // apply change for each line in-between the changed lines + for (var j = llf; j <= llt; ++j) { + led.addLineClass(j, 'background', clazz.join(' ')); + led.addLineClass(j, 'background', clazz.join(' ')); + } + } + + if (!red.getOption('readOnly')) { + // add widgets to lhs, if rhs is not read only + var rhs_button = self.merge_rhs_button.clone(); + if (rhs_button.button) { + //jquery-ui support + rhs_button.button({icons: {primary: 'ui-icon-triangle-1-e'}, text: false}); + } + rhs_button.addClass('merge-button'); + rhs_button.attr('id', 'merge-rhs-' + i); + led.setGutterMarker(llf, 'merge', rhs_button.get(0)); + } + } + }); + + var vp = this._get_viewport(editor_name1, editor_name2); + + this.trace('change', 'markup lhs-editor time', timer.stop()); + red.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0; + var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0; + var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0; + var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0; + + if (!self._is_change_in_view(vp, change)) { + // if the change is outside the viewport, skip + continue; + } + + var clazz = ['mergely', 'rhs', change['op'], 'cid-' + i]; + red.addLineClass(rlf, 'background', 'start'); + red.addLineClass(rlt, 'background', 'end'); + + if (rlf == 0 && rlt == 0 && llf == 0) { + red.addLineClass(rlf, 'background', clazz.join(' ')); + red.addLineClass(rlf, 'background', 'first'); + } + else { + // apply change for each line in-between the changed lines + for (var j = rlf; j <= rlt; ++j) { + red.addLineClass(j, 'background', clazz.join(' ')); + red.addLineClass(j, 'background', clazz.join(' ')); + } + } + + if (!led.getOption('readOnly')) { + // add widgets to rhs, if lhs is not read only + var lhs_button = self.merge_lhs_button.clone(); + if (lhs_button.button) { + //jquery-ui support + lhs_button.button({icons: {primary: 'ui-icon-triangle-1-w'}, text: false}); + } + lhs_button.addClass('merge-button'); + lhs_button.attr('id', 'merge-lhs-' + i); + red.setGutterMarker(rlf, 'merge', lhs_button.get(0)); + } + } + }); + this.trace('change', 'markup rhs-editor time', timer.stop()); + + // mark text deleted, LCS changes + var marktext = [], i, j, k, p; + for (i = 0; this.settings.lcs && i < changes.length; ++i) { + var change = changes[i]; + var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0; + var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0; + var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0; + var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0; + + if (!this._is_change_in_view(vp, change)) { + // if the change is outside the viewport, skip + continue; + } + if (change['op'] == 'd') { + // apply delete to cross-out (left-hand side only) + var from = llf; + var to = llt; + var to_ln = led.lineInfo(to); + if (to_ln) { + marktext.push([led, {line:from, ch:0}, {line:to, ch:to_ln.text.length}, {className: 'mergely ch d lhs'}]); + } + } + else if (change['op'] == 'c') { + // apply LCS changes to each line + for (j = llf, k = rlf, p = 0; + ((j >= 0) && (j <= llt)) || ((k >= 0) && (k <= rlt)); + ++j, ++k) { + var lhs_line, rhs_line; + if (k + p > rlt) { + // lhs continues past rhs, mark lhs as deleted + lhs_line = led.getLine( j ); + marktext.push([led, {line:j, ch:0}, {line:j, ch:lhs_line.length}, {className: 'mergely ch d lhs'}]); + continue; + } + if (j + p > llt) { + // rhs continues past lhs, mark rhs as added + rhs_line = red.getLine( k ); + marktext.push([red, {line:k, ch:0}, {line:k, ch:rhs_line.length}, {className: 'mergely ch a rhs'}]); + continue; + } + lhs_line = led.getLine( j ); + rhs_line = red.getLine( k ); + var lcs = new Mgly.LCS(lhs_line, rhs_line); + lcs.diff( + function added (from, to) { + marktext.push([red, {line:k, ch:from}, {line:k, ch:to}, {className: 'mergely ch a rhs'}]); + }, + function removed (from, to) { + marktext.push([led, {line:j, ch:from}, {line:j, ch:to}, {className: 'mergely ch d lhs'}]); + } + ); + } + } + } + this.trace('change', 'LCS marktext time', timer.stop()); + + // mark changes outside closure + led.operation(function() { + // apply lhs markup + for (var i = 0; i < marktext.length; ++i) { + var m = marktext[i]; + if (m[0].doc.id != led.getDoc().id) continue; + self.chfns[self.id + '-lhs'].push(m[0].markText(m[1], m[2], m[3])); + } + }); + red.operation(function() { + // apply lhs markup + for (var i = 0; i < marktext.length; ++i) { + var m = marktext[i]; + if (m[0].doc.id != red.getDoc().id) continue; + self.chfns[self.id + '-rhs'].push(m[0].markText(m[1], m[2], m[3])); + } + }); + this.trace('change', 'LCS markup time', timer.stop()); + + // merge buttons + var ed = {lhs:led, rhs:red}; + jQuery('.merge-button').on('click', function(ev){ + // side of mouseenter + var side = 'rhs'; + var oside = 'lhs'; + var parent = jQuery(this).parents('#' + self.id + '-editor-lhs'); + if (parent.length) { + side = 'lhs'; + oside = 'rhs'; + } + var pos = ed[side].coordsChar({left:ev.pageX, top:ev.pageY}); + + // get the change id + var cid = null; + var info = ed[side].lineInfo(pos.line); + jQuery.each(info.bgClass.split(' '), function(i, clazz) { + if (clazz.indexOf('cid-') == 0) { + cid = parseInt(clazz.split('-')[1], 10); + return false; + } + }); + var change = self.changes[cid]; + self._merge_change(change, side, oside); + return false; + }); + this.trace('change', 'markup buttons time', timer.stop()); + }, + _merge_change : function(change, side, oside) { + if (!change) return; + var led = this.editor[this.id+'-lhs']; + var red = this.editor[this.id+'-rhs']; + var ed = {lhs:led, rhs:red}; + var i, from, to; + + var text = ed[side].getRange( + CodeMirror.Pos(change[side + '-line-from'], 0), + CodeMirror.Pos(change[side + '-line-to'] + 1, 0)); + + if (change['op'] == 'c') { + ed[oside].replaceRange(text, + CodeMirror.Pos(change[oside + '-line-from'], 0), + CodeMirror.Pos(change[oside + '-line-to'] + 1, 0)); + } + else if (side == 'rhs') { + if (change['op'] == 'a') { + ed[oside].replaceRange(text, + CodeMirror.Pos(change[oside + '-line-from'] + 1, 0), + CodeMirror.Pos(change[oside + '-line-to'] + 1, 0)); + } + else {// 'd' + from = parseInt(change[oside + '-line-from'], 10); + to = parseInt(change[oside + '-line-to'], 10); + for (i = to; i >= from; --i) { + ed[oside].setCursor({line: i, ch: -1}); + ed[oside].execCommand('deleteLine'); + } + } + } + else if (side == 'lhs') { + if (change['op'] == 'a') { + from = parseInt(change[oside + '-line-from'], 10); + to = parseInt(change[oside + '-line-to'], 10); + for (i = to; i >= from; --i) { + //ed[oside].removeLine(i); + ed[oside].setCursor({line: i, ch: -1}); + ed[oside].execCommand('deleteLine'); + } + } + else {// 'd' + ed[oside].replaceRange( text, + CodeMirror.Pos(change[oside + '-line-from'] + 1, 0)); + } + } + //reset + ed['lhs'].setValue(ed['lhs'].getValue()); + ed['rhs'].setValue(ed['rhs'].getValue()); + + this._scroll_to_change(change); + }, + _draw_info: function(editor_name1, editor_name2) { + var visible_page_height = jQuery(this.editor[editor_name1].getScrollerElement()).height(); + var gutter_height = jQuery(this.editor[editor_name1].getScrollerElement()).children(':first-child').height(); + var dcanvas = document.getElementById(editor_name1 + '-' + editor_name2 + '-canvas'); + if (dcanvas == undefined) throw 'Failed to find: ' + editor_name1 + '-' + editor_name2 + '-canvas'; + var clhs = jQuery('#' + this.id + '-lhs-margin'); + var crhs = jQuery('#' + this.id + '-rhs-margin'); + return { + visible_page_height: visible_page_height, + gutter_height: gutter_height, + visible_page_ratio: (visible_page_height / gutter_height), + margin_ratio: (visible_page_height / gutter_height), + lhs_scroller: jQuery(this.editor[editor_name1].getScrollerElement()), + rhs_scroller: jQuery(this.editor[editor_name2].getScrollerElement()), + lhs_lines: this.editor[editor_name1].lineCount(), + rhs_lines: this.editor[editor_name2].lineCount(), + dcanvas: dcanvas, + clhs: clhs, + crhs: crhs, + lhs_xyoffset: jQuery(clhs).offset(), + rhs_xyoffset: jQuery(crhs).offset() + }; + }, + _draw_diff: function(editor_name1, editor_name2, changes) { + var ex = this._draw_info(editor_name1, editor_name2); + var mcanvas_lhs = ex.clhs.get(0); + var mcanvas_rhs = ex.crhs.get(0); + var ctx = ex.dcanvas.getContext('2d'); + var ctx_lhs = mcanvas_lhs.getContext('2d'); + var ctx_rhs = mcanvas_rhs.getContext('2d'); + + this.trace('draw', 'visible_page_height', ex.visible_page_height); + this.trace('draw', 'gutter_height', ex.gutter_height); + this.trace('draw', 'visible_page_ratio', ex.visible_page_ratio); + this.trace('draw', 'lhs-scroller-top', ex.lhs_scroller.scrollTop()); + this.trace('draw', 'rhs-scroller-top', ex.rhs_scroller.scrollTop()); + + jQuery.each(jQuery.find('#' + this.id + ' canvas'), function () { + jQuery(this).get(0).height = ex.visible_page_height; + }); + + ex.clhs.unbind('click'); + ex.crhs.unbind('click'); + + ctx_lhs.beginPath(); + ctx_lhs.fillStyle = this.settings.bgcolor; + ctx_lhs.strokeStyle = '#888'; + ctx_lhs.fillRect(0, 0, 6.5, ex.visible_page_height); + ctx_lhs.strokeRect(0, 0, 6.5, ex.visible_page_height); + + ctx_rhs.beginPath(); + ctx_rhs.fillStyle = this.settings.bgcolor; + ctx_rhs.strokeStyle = '#888'; + ctx_rhs.fillRect(0, 0, 6.5, ex.visible_page_height); + ctx_rhs.strokeRect(0, 0, 6.5, ex.visible_page_height); + + var vp = this._get_viewport(editor_name1, editor_name2); + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + + this.trace('draw', change); + // margin indicators + var lhs_y_start = ((change['lhs-y-start'] + ex.lhs_scroller.scrollTop()) * ex.visible_page_ratio); + var lhs_y_end = ((change['lhs-y-end'] + ex.lhs_scroller.scrollTop()) * ex.visible_page_ratio) + 1; + var rhs_y_start = ((change['rhs-y-start'] + ex.rhs_scroller.scrollTop()) * ex.visible_page_ratio); + var rhs_y_end = ((change['rhs-y-end'] + ex.rhs_scroller.scrollTop()) * ex.visible_page_ratio) + 1; + this.trace('draw', 'marker calculated', lhs_y_start, lhs_y_end, rhs_y_start, rhs_y_end); + + ctx_lhs.beginPath(); + ctx_lhs.fillStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']]; + ctx_lhs.strokeStyle = '#000'; + ctx_lhs.lineWidth = 0.5; + ctx_lhs.fillRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5)); + ctx_lhs.strokeRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5)); + + ctx_rhs.beginPath(); + ctx_rhs.fillStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']]; + ctx_rhs.strokeStyle = '#000'; + ctx_rhs.lineWidth = 0.5; + ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5)); + ctx_rhs.strokeRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5)); + + if (!this._is_change_in_view(vp, change)) { + continue; + } + + lhs_y_start = change['lhs-y-start']; + lhs_y_end = change['lhs-y-end']; + rhs_y_start = change['rhs-y-start']; + rhs_y_end = change['rhs-y-end']; + + var radius = 3; + + // draw left box + ctx.beginPath(); + ctx.strokeStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']]; + ctx.lineWidth = (this._current_diff==i) ? 1.5 : 1; + + var rectWidth = this.draw_lhs_width; + var rectHeight = lhs_y_end - lhs_y_start - 1; + var rectX = this.draw_lhs_min; + var rectY = lhs_y_start; + // top and top top-right corner + + // draw left box + ctx.moveTo(rectX, rectY); + if (navigator.appName == 'Microsoft Internet Explorer') { + // IE arcs look awful + ctx.lineTo(this.draw_lhs_min + this.draw_lhs_width, lhs_y_start); + ctx.lineTo(this.draw_lhs_min + this.draw_lhs_width, lhs_y_end + 1); + ctx.lineTo(this.draw_lhs_min, lhs_y_end + 1); + } + else { + if (rectHeight <= 0) { + ctx.lineTo(rectX + rectWidth, rectY); + } + else { + ctx.arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + radius, radius); + ctx.arcTo(rectX + rectWidth, rectY + rectHeight, rectX + rectWidth - radius, rectY + rectHeight, radius); + } + // bottom line + ctx.lineTo(rectX, rectY + rectHeight); + } + ctx.stroke(); + + rectWidth = this.draw_rhs_width; + rectHeight = rhs_y_end - rhs_y_start - 1; + rectX = this.draw_rhs_max; + rectY = rhs_y_start; + + // draw right box + ctx.moveTo(rectX, rectY); + if (navigator.appName == 'Microsoft Internet Explorer') { + ctx.lineTo(this.draw_rhs_max - this.draw_rhs_width, rhs_y_start); + ctx.lineTo(this.draw_rhs_max - this.draw_rhs_width, rhs_y_end + 1); + ctx.lineTo(this.draw_rhs_max, rhs_y_end + 1); + } + else { + if (rectHeight <= 0) { + ctx.lineTo(rectX - rectWidth, rectY); + } + else { + ctx.arcTo(rectX - rectWidth, rectY, rectX - rectWidth, rectY + radius, radius); + ctx.arcTo(rectX - rectWidth, rectY + rectHeight, rectX - radius, rectY + rectHeight, radius); + } + ctx.lineTo(rectX, rectY + rectHeight); + } + ctx.stroke(); + + // connect boxes + var cx = this.draw_lhs_min + this.draw_lhs_width; + var cy = lhs_y_start + (lhs_y_end + 1 - lhs_y_start) / 2.0; + var dx = this.draw_rhs_max - this.draw_rhs_width; + var dy = rhs_y_start + (rhs_y_end + 1 - rhs_y_start) / 2.0; + ctx.moveTo(cx, cy); + if (cy == dy) { + ctx.lineTo(dx, dy); + } + else { + // fancy! + ctx.bezierCurveTo( + cx + 12, cy - 3, // control-1 X,Y + dx - 12, dy - 3, // control-2 X,Y + dx, dy); + } + ctx.stroke(); + } + + // visible window feedback + ctx_lhs.fillStyle = this.settings.vpcolor; + ctx_rhs.fillStyle = this.settings.vpcolor; + + var lto = ex.clhs.height() * ex.visible_page_ratio; + var lfrom = (ex.lhs_scroller.scrollTop() / ex.gutter_height) * ex.clhs.height(); + var rto = ex.crhs.height() * ex.visible_page_ratio; + var rfrom = (ex.rhs_scroller.scrollTop() / ex.gutter_height) * ex.crhs.height(); + this.trace('draw', 'cls.height', ex.clhs.height()); + this.trace('draw', 'lhs_scroller.scrollTop()', ex.lhs_scroller.scrollTop()); + this.trace('draw', 'gutter_height', ex.gutter_height); + this.trace('draw', 'visible_page_ratio', ex.visible_page_ratio); + this.trace('draw', 'lhs from', lfrom, 'lhs to', lto); + this.trace('draw', 'rhs from', rfrom, 'rhs to', rto); + + ctx_lhs.fillRect(1.5, lfrom, 4.5, lto); + ctx_rhs.fillRect(1.5, rfrom, 4.5, rto); + + ex.clhs.click(function (ev) { + var y = ev.pageY - ex.lhs_xyoffset.top - (lto / 2); + var sto = Math.max(0, (y / mcanvas_lhs.height) * ex.lhs_scroller.get(0).scrollHeight); + ex.lhs_scroller.scrollTop(sto); + }); + ex.crhs.click(function (ev) { + var y = ev.pageY - ex.rhs_xyoffset.top - (rto / 2); + var sto = Math.max(0, (y / mcanvas_rhs.height) * ex.rhs_scroller.get(0).scrollHeight); + ex.rhs_scroller.scrollTop(sto); + }); + }, + trace: function(name) { + if(this.settings._debug.indexOf(name) >= 0) { + arguments[0] = name + ':'; + console.log([].slice.apply(arguments)); + } + } +}); + +jQuery.pluginMaker = function(plugin) { + // add the plugin function as a jQuery plugin + jQuery.fn[plugin.prototype.name] = function(options) { + // get the arguments + var args = jQuery.makeArray(arguments), + after = args.slice(1); + var rc; + this.each(function() { + // see if we have an instance + var instance = jQuery.data(this, plugin.prototype.name); + if (instance) { + // call a method on the instance + if (typeof options == "string") { + rc = instance[options].apply(instance, after); + } else if (instance.update) { + // call update on the instance + return instance.update.apply(instance, args); + } + } else { + // create the plugin + var _plugin = new plugin(this, options); + } + }); + if (rc != undefined) return rc; + }; +}; + +// make the mergely widget +jQuery.pluginMaker(Mgly.mergely); + +})( window, document, jQuery, CodeMirror ); \ No newline at end of file diff --git a/rhodecode/public/js/mode/apl/apl.js b/rhodecode/public/js/mode/apl/apl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/apl/apl.js @@ -0,0 +1,174 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("apl", function() { + var builtInOps = { + ".": "innerProduct", + "\\": "scan", + "/": "reduce", + "⌿": "reduce1Axis", + "⍀": "scan1Axis", + "¨": "each", + "⍣": "power" + }; + var builtInFuncs = { + "+": ["conjugate", "add"], + "−": ["negate", "subtract"], + "×": ["signOf", "multiply"], + "÷": ["reciprocal", "divide"], + "⌈": ["ceiling", "greaterOf"], + "⌊": ["floor", "lesserOf"], + "∣": ["absolute", "residue"], + "⍳": ["indexGenerate", "indexOf"], + "?": ["roll", "deal"], + "⋆": ["exponentiate", "toThePowerOf"], + "⍟": ["naturalLog", "logToTheBase"], + "○": ["piTimes", "circularFuncs"], + "!": ["factorial", "binomial"], + "⌹": ["matrixInverse", "matrixDivide"], + "<": [null, "lessThan"], + "≤": [null, "lessThanOrEqual"], + "=": [null, "equals"], + ">": [null, "greaterThan"], + "≥": [null, "greaterThanOrEqual"], + "≠": [null, "notEqual"], + "≡": ["depth", "match"], + "≢": [null, "notMatch"], + "∈": ["enlist", "membership"], + "⍷": [null, "find"], + "∪": ["unique", "union"], + "∩": [null, "intersection"], + "∼": ["not", "without"], + "∨": [null, "or"], + "∧": [null, "and"], + "⍱": [null, "nor"], + "⍲": [null, "nand"], + "⍴": ["shapeOf", "reshape"], + ",": ["ravel", "catenate"], + "⍪": [null, "firstAxisCatenate"], + "⌽": ["reverse", "rotate"], + "⊖": ["axis1Reverse", "axis1Rotate"], + "⍉": ["transpose", null], + "↑": ["first", "take"], + "↓": [null, "drop"], + "⊂": ["enclose", "partitionWithAxis"], + "⊃": ["diclose", "pick"], + "⌷": [null, "index"], + "⍋": ["gradeUp", null], + "⍒": ["gradeDown", null], + "⊤": ["encode", null], + "⊥": ["decode", null], + "⍕": ["format", "formatByExample"], + "⍎": ["execute", null], + "⊣": ["stop", "left"], + "⊢": ["pass", "right"] + }; + + var isOperator = /[\.\/⌿⍀¨⍣]/; + var isNiladic = /⍬/; + var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/; + var isArrow = /←/; + var isComment = /[⍝#].*$/; + + var stringEater = function(type) { + var prev; + prev = false; + return function(c) { + prev = c; + if (c === type) { + return prev === "\\"; + } + return true; + }; + }; + return { + startState: function() { + return { + prev: false, + func: false, + op: false, + string: false, + escape: false + }; + }, + token: function(stream, state) { + var ch, funcName; + if (stream.eatSpace()) { + return null; + } + ch = stream.next(); + if (ch === '"' || ch === "'") { + stream.eatWhile(stringEater(ch)); + stream.next(); + state.prev = true; + return "string"; + } + if (/[\[{\(]/.test(ch)) { + state.prev = false; + return null; + } + if (/[\]}\)]/.test(ch)) { + state.prev = true; + return null; + } + if (isNiladic.test(ch)) { + state.prev = false; + return "niladic"; + } + if (/[¯\d]/.test(ch)) { + if (state.func) { + state.func = false; + state.prev = false; + } else { + state.prev = true; + } + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperator.test(ch)) { + return "operator apl-" + builtInOps[ch]; + } + if (isArrow.test(ch)) { + return "apl-arrow"; + } + if (isFunction.test(ch)) { + funcName = "apl-"; + if (builtInFuncs[ch] != null) { + if (state.prev) { + funcName += builtInFuncs[ch][1]; + } else { + funcName += builtInFuncs[ch][0]; + } + } + state.func = true; + state.prev = false; + return "function " + funcName; + } + if (isComment.test(ch)) { + stream.skipToEnd(); + return "comment"; + } + if (ch === "∘" && stream.peek() === ".") { + stream.next(); + return "function jot-dot"; + } + stream.eatWhile(/[\w\$_]/); + state.prev = true; + return "keyword"; + } + }; +}); + +CodeMirror.defineMIME("text/apl", "apl"); + +}); diff --git a/rhodecode/public/js/mode/asciiarmor/asciiarmor.js b/rhodecode/public/js/mode/asciiarmor/asciiarmor.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/asciiarmor/asciiarmor.js @@ -0,0 +1,73 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function errorIfNotEmpty(stream) { + var nonWS = stream.match(/^\s*\S/); + stream.skipToEnd(); + return nonWS ? "error" : null; + } + + CodeMirror.defineMode("asciiarmor", function() { + return { + token: function(stream, state) { + var m; + if (state.state == "top") { + if (stream.sol() && (m = stream.match(/^-----BEGIN (.*)?-----\s*$/))) { + state.state = "headers"; + state.type = m[1]; + return "tag"; + } + return errorIfNotEmpty(stream); + } else if (state.state == "headers") { + if (stream.sol() && stream.match(/^\w+:/)) { + state.state = "header"; + return "atom"; + } else { + var result = errorIfNotEmpty(stream); + if (result) state.state = "body"; + return result; + } + } else if (state.state == "header") { + stream.skipToEnd(); + state.state = "headers"; + return "string"; + } else if (state.state == "body") { + if (stream.sol() && (m = stream.match(/^-----END (.*)?-----\s*$/))) { + if (m[1] != state.type) return "error"; + state.state = "end"; + return "tag"; + } else { + if (stream.eatWhile(/[A-Za-z0-9+\/=]/)) { + return null; + } else { + stream.next(); + return "error"; + } + } + } else if (state.state == "end") { + return errorIfNotEmpty(stream); + } + }, + blankLine: function(state) { + if (state.state == "headers") state.state = "body"; + }, + startState: function() { + return {state: "top", type: null}; + } + }; + }); + + CodeMirror.defineMIME("application/pgp", "asciiarmor"); + CodeMirror.defineMIME("application/pgp-keys", "asciiarmor"); + CodeMirror.defineMIME("application/pgp-signature", "asciiarmor"); +}); diff --git a/rhodecode/public/js/mode/asn.1/asn.1.js b/rhodecode/public/js/mode/asn.1/asn.1.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/asn.1/asn.1.js @@ -0,0 +1,204 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("asn.1", function(config, parserConfig) { + var indentUnit = config.indentUnit, + keywords = parserConfig.keywords || {}, + cmipVerbs = parserConfig.cmipVerbs || {}, + compareTypes = parserConfig.compareTypes || {}, + status = parserConfig.status || {}, + tags = parserConfig.tags || {}, + storage = parserConfig.storage || {}, + modifier = parserConfig.modifier || {}, + accessTypes = parserConfig.accessTypes|| {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false; + var isOperatorChar = /[\|\^]/; + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]\(\){}:=,;]/.test(ch)) { + curPunc = ch; + return "punctuation"; + } + if (ch == "-"){ + if (stream.eat("-")) { + stream.skipToEnd(); + return "comment"; + } + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + + stream.eatWhile(/[\w\-]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + if (cmipVerbs.propertyIsEnumerable(cur)) return "variable cmipVerbs"; + if (compareTypes.propertyIsEnumerable(cur)) return "atom compareTypes"; + if (status.propertyIsEnumerable(cur)) return "comment status"; + if (tags.propertyIsEnumerable(cur)) return "variable-3 tags"; + if (storage.propertyIsEnumerable(cur)) return "builtin storage"; + if (modifier.propertyIsEnumerable(cur)) return "string-2 modifier"; + if (accessTypes.propertyIsEnumerable(cur)) return "atom accessTypes"; + + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped){ + var afterNext = stream.peek(); + //look if the character if the quote is like the B in '10100010'B + if (afterNext){ + afterNext = afterNext.toLowerCase(); + if(afterNext == "b" || afterNext == "h" || afterNext == "o") + stream.next(); + } + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + //Interface + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") + && ctx.type == "statement"){ + popContext(state); + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && (((ctx.type == "}" || ctx.type == "top") + && curPunc != ';') || (ctx.type == "statement" + && curPunc == "newstatement"))) + pushContext(state, stream.column(), "statement"); + + state.startOfLine = false; + return style; + }, + + electricChars: "{}", + lineComment: "--", + fold: "brace" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + CodeMirror.defineMIME("text/x-ttcn-asn", { + name: "asn.1", + keywords: words("DEFINITIONS OBJECTS IF DERIVED INFORMATION ACTION" + + " REPLY ANY NAMED CHARACTERIZED BEHAVIOUR REGISTERED" + + " WITH AS IDENTIFIED CONSTRAINED BY PRESENT BEGIN" + + " IMPORTS FROM UNITS SYNTAX MIN-ACCESS MAX-ACCESS" + + " MINACCESS MAXACCESS REVISION STATUS DESCRIPTION" + + " SEQUENCE SET COMPONENTS OF CHOICE DistinguishedName" + + " ENUMERATED SIZE MODULE END INDEX AUGMENTS EXTENSIBILITY" + + " IMPLIED EXPORTS"), + cmipVerbs: words("ACTIONS ADD GET NOTIFICATIONS REPLACE REMOVE"), + compareTypes: words("OPTIONAL DEFAULT MANAGED MODULE-TYPE MODULE_IDENTITY" + + " MODULE-COMPLIANCE OBJECT-TYPE OBJECT-IDENTITY" + + " OBJECT-COMPLIANCE MODE CONFIRMED CONDITIONAL" + + " SUBORDINATE SUPERIOR CLASS TRUE FALSE NULL" + + " TEXTUAL-CONVENTION"), + status: words("current deprecated mandatory obsolete"), + tags: words("APPLICATION AUTOMATIC EXPLICIT IMPLICIT PRIVATE TAGS" + + " UNIVERSAL"), + storage: words("BOOLEAN INTEGER OBJECT IDENTIFIER BIT OCTET STRING" + + " UTCTime InterfaceIndex IANAifType CMIP-Attribute" + + " REAL PACKAGE PACKAGES IpAddress PhysAddress" + + " NetworkAddress BITS BMPString TimeStamp TimeTicks" + + " TruthValue RowStatus DisplayString GeneralString" + + " GraphicString IA5String NumericString" + + " PrintableString SnmpAdminAtring TeletexString" + + " UTF8String VideotexString VisibleString StringStore" + + " ISO646String T61String UniversalString Unsigned32" + + " Integer32 Gauge Gauge32 Counter Counter32 Counter64"), + modifier: words("ATTRIBUTE ATTRIBUTES MANDATORY-GROUP MANDATORY-GROUPS" + + " GROUP GROUPS ELEMENTS EQUALITY ORDERING SUBSTRINGS" + + " DEFINED"), + accessTypes: words("not-accessible accessible-for-notify read-only" + + " read-create read-write"), + multiLineStrings: true + }); +}); diff --git a/rhodecode/public/js/mode/asterisk/asterisk.js b/rhodecode/public/js/mode/asterisk/asterisk.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/asterisk/asterisk.js @@ -0,0 +1,196 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + * ===================================================================================== + * + * Filename: mode/asterisk/asterisk.js + * + * Description: CodeMirror mode for Asterisk dialplan + * + * Created: 05/17/2012 09:20:25 PM + * Revision: none + * + * Author: Stas Kobzar (stas@modulis.ca), + * Company: Modulis.ca Inc. + * + * ===================================================================================== + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("asterisk", function() { + var atoms = ["exten", "same", "include","ignorepat","switch"], + dpcmd = ["#include","#exec"], + apps = [ + "addqueuemember","adsiprog","aelsub","agentlogin","agentmonitoroutgoing","agi", + "alarmreceiver","amd","answer","authenticate","background","backgrounddetect", + "bridge","busy","callcompletioncancel","callcompletionrequest","celgenuserevent", + "changemonitor","chanisavail","channelredirect","chanspy","clearhash","confbridge", + "congestion","continuewhile","controlplayback","dahdiacceptr2call","dahdibarge", + "dahdiras","dahdiscan","dahdisendcallreroutingfacility","dahdisendkeypadfacility", + "datetime","dbdel","dbdeltree","deadagi","dial","dictate","directory","disa", + "dumpchan","eagi","echo","endwhile","exec","execif","execiftime","exitwhile","extenspy", + "externalivr","festival","flash","followme","forkcdr","getcpeid","gosub","gosubif", + "goto","gotoif","gotoiftime","hangup","iax2provision","ices","importvar","incomplete", + "ivrdemo","jabberjoin","jabberleave","jabbersend","jabbersendgroup","jabberstatus", + "jack","log","macro","macroexclusive","macroexit","macroif","mailboxexists","meetme", + "meetmeadmin","meetmechanneladmin","meetmecount","milliwatt","minivmaccmess","minivmdelete", + "minivmgreet","minivmmwi","minivmnotify","minivmrecord","mixmonitor","monitor","morsecode", + "mp3player","mset","musiconhold","nbscat","nocdr","noop","odbc","odbc","odbcfinish", + "originate","ospauth","ospfinish","osplookup","ospnext","page","park","parkandannounce", + "parkedcall","pausemonitor","pausequeuemember","pickup","pickupchan","playback","playtones", + "privacymanager","proceeding","progress","queue","queuelog","raiseexception","read","readexten", + "readfile","receivefax","receivefax","receivefax","record","removequeuemember", + "resetcdr","retrydial","return","ringing","sayalpha","saycountedadj","saycountednoun", + "saycountpl","saydigits","saynumber","sayphonetic","sayunixtime","senddtmf","sendfax", + "sendfax","sendfax","sendimage","sendtext","sendurl","set","setamaflags", + "setcallerpres","setmusiconhold","sipaddheader","sipdtmfmode","sipremoveheader","skel", + "slastation","slatrunk","sms","softhangup","speechactivategrammar","speechbackground", + "speechcreate","speechdeactivategrammar","speechdestroy","speechloadgrammar","speechprocessingsound", + "speechstart","speechunloadgrammar","stackpop","startmusiconhold","stopmixmonitor","stopmonitor", + "stopmusiconhold","stopplaytones","system","testclient","testserver","transfer","tryexec", + "trysystem","unpausemonitor","unpausequeuemember","userevent","verbose","vmauthenticate", + "vmsayname","voicemail","voicemailmain","wait","waitexten","waitfornoise","waitforring", + "waitforsilence","waitmusiconhold","waituntil","while","zapateller" + ]; + + function basicToken(stream,state){ + var cur = ''; + var ch = stream.next(); + // comment + if(ch == ";") { + stream.skipToEnd(); + return "comment"; + } + // context + if(ch == '[') { + stream.skipTo(']'); + stream.eat(']'); + return "header"; + } + // string + if(ch == '"') { + stream.skipTo('"'); + return "string"; + } + if(ch == "'") { + stream.skipTo("'"); + return "string-2"; + } + // dialplan commands + if(ch == '#') { + stream.eatWhile(/\w/); + cur = stream.current(); + if(dpcmd.indexOf(cur) !== -1) { + stream.skipToEnd(); + return "strong"; + } + } + // application args + if(ch == '$'){ + var ch1 = stream.peek(); + if(ch1 == '{'){ + stream.skipTo('}'); + stream.eat('}'); + return "variable-3"; + } + } + // extension + stream.eatWhile(/\w/); + cur = stream.current(); + if(atoms.indexOf(cur) !== -1) { + state.extenStart = true; + switch(cur) { + case 'same': state.extenSame = true; break; + case 'include': + case 'switch': + case 'ignorepat': + state.extenInclude = true;break; + default:break; + } + return "atom"; + } + } + + return { + startState: function() { + return { + extenStart: false, + extenSame: false, + extenInclude: false, + extenExten: false, + extenPriority: false, + extenApplication: false + }; + }, + token: function(stream, state) { + + var cur = ''; + if(stream.eatSpace()) return null; + // extension started + if(state.extenStart){ + stream.eatWhile(/[^\s]/); + cur = stream.current(); + if(/^=>?$/.test(cur)){ + state.extenExten = true; + state.extenStart = false; + return "strong"; + } else { + state.extenStart = false; + stream.skipToEnd(); + return "error"; + } + } else if(state.extenExten) { + // set exten and priority + state.extenExten = false; + state.extenPriority = true; + stream.eatWhile(/[^,]/); + if(state.extenInclude) { + stream.skipToEnd(); + state.extenPriority = false; + state.extenInclude = false; + } + if(state.extenSame) { + state.extenPriority = false; + state.extenSame = false; + state.extenApplication = true; + } + return "tag"; + } else if(state.extenPriority) { + state.extenPriority = false; + state.extenApplication = true; + stream.next(); // get comma + if(state.extenSame) return null; + stream.eatWhile(/[^,]/); + return "number"; + } else if(state.extenApplication) { + stream.eatWhile(/,/); + cur = stream.current(); + if(cur === ',') return null; + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + state.extenApplication = false; + if(apps.indexOf(cur) !== -1){ + return "def strong"; + } + } else{ + return basicToken(stream,state); + } + + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-asterisk", "asterisk"); + +}); diff --git a/rhodecode/public/js/mode/brainfuck/brainfuck.js b/rhodecode/public/js/mode/brainfuck/brainfuck.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/brainfuck/brainfuck.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Brainfuck mode created by Michael Kaminsky https://github.com/mkaminsky11 + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) + define(["../../lib/codemirror"], mod) + else + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + var reserve = "><+-.,[]".split(""); + /* + comments can be either: + placed behind lines + + +++ this is a comment + + where reserved characters cannot be used + or in a loop + [ + this is ok to use [ ] and stuff + ] + or preceded by # + */ + CodeMirror.defineMode("brainfuck", function() { + return { + startState: function() { + return { + commentLine: false, + left: 0, + right: 0, + commentLoop: false + } + }, + token: function(stream, state) { + if (stream.eatSpace()) return null + if(stream.sol()){ + state.commentLine = false; + } + var ch = stream.next().toString(); + if(reserve.indexOf(ch) !== -1){ + if(state.commentLine === true){ + if(stream.eol()){ + state.commentLine = false; + } + return "comment"; + } + if(ch === "]" || ch === "["){ + if(ch === "["){ + state.left++; + } + else{ + state.right++; + } + return "bracket"; + } + else if(ch === "+" || ch === "-"){ + return "keyword"; + } + else if(ch === "<" || ch === ">"){ + return "atom"; + } + else if(ch === "." || ch === ","){ + return "def"; + } + } + else{ + state.commentLine = true; + if(stream.eol()){ + state.commentLine = false; + } + return "comment"; + } + if(stream.eol()){ + state.commentLine = false; + } + } + }; + }); +CodeMirror.defineMIME("text/x-brainfuck","brainfuck") +}); diff --git a/rhodecode/public/js/mode/clike/clike.js b/rhodecode/public/js/mode/clike/clike.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/clike/clike.js @@ -0,0 +1,591 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("clike", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + keywords = parserConfig.keywords || {}, + types = parserConfig.types || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + defKeywords = parserConfig.defKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false, + indentSwitch = parserConfig.indentSwitch !== false, + namespaceSeparator = parserConfig.namespaceSeparator; + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + var curPunc, isDefKeyword; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + if (namespaceSeparator) while (stream.match(namespaceSeparator)) + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + if (defKeywords.propertyIsEnumerable(cur)) isDefKeyword = true; + return "keyword"; + } + if (types.propertyIsEnumerable(cur)) return "variable-3"; + if (builtin.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "builtin"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function isStatement(type) { + return type == "statement" || type == "switchstatement" || type == "namespace"; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && isStatement(state.context.type) && !isStatement(type)) + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + function typeBefore(stream, state) { + if (state.prevToken == "variable" || state.prevToken == "variable-3") return true; + if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true; + } + + function isTopScope(context) { + for (;;) { + if (!context || context.type == "top") return true; + if (context.type == "}" && context.prev.type != "namespace") return false; + context = context.prev; + } + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true, + prevToken: null + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = isDefKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",")) + while (isStatement(state.context.type)) popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (isStatement(ctx.type)) ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (isStatement(ctx.type)) ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && + (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || + (isStatement(ctx.type) && curPunc == "newstatement"))) { + var type = "statement"; + if (curPunc == "newstatement" && indentSwitch && stream.current() == "switch") + type = "switchstatement"; + else if (style == "keyword" && stream.current() == "namespace") + type = "namespace"; + pushContext(state, stream.column(), type); + } + + if (style == "variable" && + ((state.prevToken == "def" || + (parserConfig.typeFirstDefinitions && typeBefore(stream, state) && + isTopScope(state.context) && stream.match(/^\s*\(/, false))))) + style = "def"; + + if (hooks.token) { + var result = hooks.token(stream, state, style); + if (result !== undefined) style = result; + } + + if (style == "def" && parserConfig.styleDefs === false) style = "variable"; + + state.startOfLine = false; + state.prevToken = isDefKeyword ? "def" : style || curPunc; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev; + var closing = firstChar == ctx.type; + var switchBlock = ctx.prev && ctx.prev.type == "switchstatement"; + if (isStatement(ctx.type)) + return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + if (ctx.align && (!dontAlignCalls || ctx.type != ")")) + return ctx.column + (closing ? 0 : 1); + if (ctx.type == ")" && !closing) + return ctx.indented + statementIndentUnit; + + return ctx.indented + (closing ? 0 : indentUnit) + + (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); + }, + + electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + fold: "brace" + }; +}); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var cKeywords = "auto if break case register continue return default do sizeof " + + "static else struct switch extern typedef float union for " + + "goto while enum const volatile"; + var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t"; + + function cppHook(stream, state) { + if (!state.startOfLine) return false; + for (;;) { + if (stream.skipTo("\\")) { + stream.next(); + if (stream.eol()) { + state.tokenize = cppHook; + break; + } + } else { + stream.skipToEnd(); + state.tokenize = null; + break; + } + } + return "meta"; + } + + function pointerHook(_stream, state) { + if (state.prevToken == "variable-3") return "variable-3"; + return false; + } + + function cpp11StringHook(stream, state) { + stream.backUp(1); + // Raw strings. + if (stream.match(/(R|u8R|uR|UR|LR)/)) { + var match = stream.match(/"([^\s\\()]{0,16})\(/); + if (!match) { + return false; + } + state.cpp11RawStringDelim = match[1]; + state.tokenize = tokenRawString; + return tokenRawString(stream, state); + } + // Unicode strings/chars. + if (stream.match(/(u8|u|U|L)/)) { + if (stream.match(/["']/, /* eat */ false)) { + return "string"; + } + return false; + } + // Ignore this hook. + stream.next(); + return false; + } + + function cppLooksLikeConstructor(word) { + var lastTwo = /(\w+)::(\w+)$/.exec(word); + return lastTwo && lastTwo[1] == lastTwo[2]; + } + + // C#-style strings where "" escapes a quote. + function tokenAtString(stream, state) { + var next; + while ((next = stream.next()) != null) { + if (next == '"' && !stream.eat('"')) { + state.tokenize = null; + break; + } + } + return "string"; + } + + // C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where + // <delim> can be a string up to 16 characters long. + function tokenRawString(stream, state) { + // Escape characters that have special regex meanings. + var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); + var match = stream.match(new RegExp(".*?\\)" + delim + '"')); + if (match) + state.tokenize = null; + else + stream.skipToEnd(); + return "string"; + } + + function def(mimes, mode) { + if (typeof mimes == "string") mimes = [mimes]; + var words = []; + function add(obj) { + if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) + words.push(prop); + } + add(mode.keywords); + add(mode.types); + add(mode.builtin); + add(mode.atoms); + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i = 0; i < mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def(["text/x-csrc", "text/x-c", "text/x-chdr"], { + name: "clike", + keywords: words(cKeywords), + types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " + + "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " + + "uint32_t uint64_t"), + blockKeywords: words("case do else for if switch while struct"), + defKeywords: words("struct"), + typeFirstDefinitions: true, + atoms: words("null true false"), + hooks: {"#": cppHook, "*": pointerHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def(["text/x-c++src", "text/x-c++hdr"], { + name: "clike", + keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " + + "static_cast typeid catch operator template typename class friend private " + + "this using const_cast inline public throw virtual delete mutable protected " + + "alignas alignof constexpr decltype nullptr noexcept thread_local final " + + "static_assert override"), + types: words(cTypes + " bool wchar_t"), + blockKeywords: words("catch class do else finally for if struct switch try while"), + defKeywords: words("class namespace struct enum union"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: { + "#": cppHook, + "*": pointerHook, + "u": cpp11StringHook, + "U": cpp11StringHook, + "L": cpp11StringHook, + "R": cpp11StringHook, + token: function(stream, state, style) { + if (style == "variable" && stream.peek() == "(" && + (state.prevToken == ";" || state.prevToken == null || + state.prevToken == "}") && + cppLooksLikeConstructor(stream.current())) + return "def"; + } + }, + namespaceSeparator: "::", + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-java", { + name: "clike", + keywords: words("abstract assert break case catch class const continue default " + + "do else enum extends final finally float for goto if implements import " + + "instanceof interface native new package private protected public " + + "return static strictfp super switch synchronized this throw throws transient " + + "try volatile while"), + types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + + "Integer Long Number Object Short String StringBuffer StringBuilder Void"), + blockKeywords: words("catch class do else finally for if switch try while"), + defKeywords: words("class interface package enum"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + }, + modeProps: {fold: ["brace", "import"]} + }); + + def("text/x-csharp", { + name: "clike", + keywords: words("abstract as async await base break case catch checked class const continue" + + " default delegate do else enum event explicit extern finally fixed for" + + " foreach goto if implicit in interface internal is lock namespace new" + + " operator out override params private protected public readonly ref return sealed" + + " sizeof stackalloc static struct switch this throw try typeof unchecked" + + " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + + " global group into join let orderby partial remove select set value var yield"), + types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" + + " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" + + " UInt64 bool byte char decimal double short int long object" + + " sbyte float string ushort uint ulong"), + blockKeywords: words("catch class do else finally for foreach if struct switch try while"), + defKeywords: words("class interface namespace struct var"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: { + "@": function(stream, state) { + if (stream.eat('"')) { + state.tokenize = tokenAtString; + return tokenAtString(stream, state); + } + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); + + function tokenTripleString(stream, state) { + var escaped = false; + while (!stream.eol()) { + if (!escaped && stream.match('"""')) { + state.tokenize = null; + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + def("text/x-scala", { + name: "clike", + keywords: words( + + /* scala */ + "abstract case catch class def do else extends false final finally for forSome if " + + "implicit import lazy match new null object override package private protected return " + + "sealed super this throw trait try type val var while with yield _ : = => <- <: " + + "<% >: # @ " + + + /* package scala */ + "assert assume require print println printf readLine readBoolean readByte readShort " + + "readChar readInt readLong readFloat readDouble " + + + ":: #:: " + ), + types: words( + "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " + + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + + + /* package java.lang */ + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + ), + multiLineStrings: true, + blockKeywords: words("catch class do else finally for forSome if match switch try while"), + defKeywords: words("class def object package trait type val var"), + atoms: words("true false null"), + indentStatements: false, + indentSwitch: false, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '"': function(stream, state) { + if (!stream.match('""')) return false; + state.tokenize = tokenTripleString; + return state.tokenize(stream, state); + }, + "'": function(stream) { + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + return "atom"; + } + }, + modeProps: {closeBrackets: {triples: '"'}} + }); + + def(["x-shader/x-vertex", "x-shader/x-fragment"], { + name: "clike", + keywords: words("sampler1D sampler2D sampler3D samplerCube " + + "sampler1DShadow sampler2DShadow " + + "const attribute uniform varying " + + "break continue discard return " + + "for while do if else struct " + + "in out inout"), + types: words("float int bool void " + + "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " + + "mat2 mat3 mat4"), + blockKeywords: words("for while do if else struct"), + builtin: words("radians degrees sin cos tan asin acos atan " + + "pow exp log exp2 sqrt inversesqrt " + + "abs sign floor ceil fract mod min max clamp mix step smoothstep " + + "length distance dot cross normalize ftransform faceforward " + + "reflect refract matrixCompMult " + + "lessThan lessThanEqual greaterThan greaterThanEqual " + + "equal notEqual any all not " + + "texture1D texture1DProj texture1DLod texture1DProjLod " + + "texture2D texture2DProj texture2DLod texture2DProjLod " + + "texture3D texture3DProj texture3DLod texture3DProjLod " + + "textureCube textureCubeLod " + + "shadow1D shadow2D shadow1DProj shadow2DProj " + + "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " + + "dFdx dFdy fwidth " + + "noise1 noise2 noise3 noise4"), + atoms: words("true false " + + "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " + + "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " + + "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " + + "gl_FogCoord gl_PointCoord " + + "gl_Position gl_PointSize gl_ClipVertex " + + "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " + + "gl_TexCoord gl_FogFragCoord " + + "gl_FragCoord gl_FrontFacing " + + "gl_FragData gl_FragDepth " + + "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + + "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + + "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + + "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + + "gl_ProjectionMatrixInverseTranspose " + + "gl_ModelViewProjectionMatrixInverseTranspose " + + "gl_TextureMatrixInverseTranspose " + + "gl_NormalScale gl_DepthRange gl_ClipPlane " + + "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " + + "gl_FrontLightModelProduct gl_BackLightModelProduct " + + "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " + + "gl_FogParameters " + + "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " + + "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " + + "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " + + "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " + + "gl_MaxDrawBuffers"), + indentSwitch: false, + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-nesc", { + name: "clike", + keywords: words(cKeywords + "as atomic async call command component components configuration event generic " + + "implementation includes interface module new norace nx_struct nx_union post provides " + + "signal task uses abstract extends"), + types: words(cTypes), + blockKeywords: words("case do else for if switch while struct"), + atoms: words("null true false"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-objectivec", { + name: "clike", + keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in " + + "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"), + types: words(cTypes), + atoms: words("YES NO NULL NILL ON OFF true false"), + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$]/); + return "keyword"; + }, + "#": cppHook + }, + modeProps: {fold: "brace"} + }); + +}); diff --git a/rhodecode/public/js/mode/clojure/clojure.js b/rhodecode/public/js/mode/clojure/clojure.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/clojure/clojure.js @@ -0,0 +1,244 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Author: Hans Engel + * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun) + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("clojure", function (options) { + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2", + ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword", VAR = "variable"; + var INDENT_WORD_SKIP = options.indentUnit || 2; + var NORMAL_INDENT_UNIT = options.indentUnit || 2; + + function makeKeywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var atoms = makeKeywords("true false nil"); + + var keywords = makeKeywords( + "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle"); + + var builtins = makeKeywords( + "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->>"); + + var indentKeys = makeKeywords( + // Built-ins + "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " + + + // Binding forms + "let letfn binding loop for doseq dotimes when-let if-let " + + + // Data structures + "defstruct struct-map assoc " + + + // clojure.test + "testing deftest " + + + // contrib + "handler-case handle dotrace deftrace"); + + var tests = { + digit: /\d/, + digit_or_colon: /[\d:]/, + hex: /[0-9a-f]/i, + sign: /[+-]/, + exponent: /e/i, + keyword_char: /[^\s\(\[\;\)\]]/, + symbol: /[\w*+!\-\._?:<>\/\xa1-\uffff]/ + }; + + function stateStack(indent, type, prev) { // represents a state stack object + this.indent = indent; + this.type = type; + this.prev = prev; + } + + function pushStack(state, indent, type) { + state.indentStack = new stateStack(indent, type, state.indentStack); + } + + function popStack(state) { + state.indentStack = state.indentStack.prev; + } + + function isNumber(ch, stream){ + // hex + if ( ch === '0' && stream.eat(/x/i) ) { + stream.eatWhile(tests.hex); + return true; + } + + // leading sign + if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) { + stream.eat(tests.sign); + ch = stream.next(); + } + + if ( tests.digit.test(ch) ) { + stream.eat(ch); + stream.eatWhile(tests.digit); + + if ( '.' == stream.peek() ) { + stream.eat('.'); + stream.eatWhile(tests.digit); + } + + if ( stream.eat(tests.exponent) ) { + stream.eat(tests.sign); + stream.eatWhile(tests.digit); + } + + return true; + } + + return false; + } + + // Eat character that starts after backslash \ + function eatCharacter(stream) { + var first = stream.next(); + // Read special literals: backspace, newline, space, return. + // Just read all lowercase letters. + if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) { + return; + } + // Read unicode character: \u1000 \uA0a1 + if (first === "u") { + stream.match(/[0-9a-z]{4}/i, true); + } + } + + return { + startState: function () { + return { + indentStack: null, + indentation: 0, + mode: false + }; + }, + + token: function (stream, state) { + if (state.indentStack == null && stream.sol()) { + // update indentation, but only if indentStack is empty + state.indentation = stream.indentation(); + } + + // skip spaces + if (stream.eatSpace()) { + return null; + } + var returnType = null; + + switch(state.mode){ + case "string": // multi-line string parsing mode + var next, escaped = false; + while ((next = stream.next()) != null) { + if (next == "\"" && !escaped) { + + state.mode = false; + break; + } + escaped = !escaped && next == "\\"; + } + returnType = STRING; // continue on in string mode + break; + default: // default parsing mode + var ch = stream.next(); + + if (ch == "\"") { + state.mode = "string"; + returnType = STRING; + } else if (ch == "\\") { + eatCharacter(stream); + returnType = CHARACTER; + } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) { + returnType = ATOM; + } else if (ch == ";") { // comment + stream.skipToEnd(); // rest of the line is a comment + returnType = COMMENT; + } else if (isNumber(ch,stream)){ + returnType = NUMBER; + } else if (ch == "(" || ch == "[" || ch == "{" ) { + var keyWord = '', indentTemp = stream.column(), letter; + /** + Either + (indent-word .. + (non-indent-word .. + (;something else, bracket, etc. + */ + + if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) { + keyWord += letter; + } + + if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) || + /^(?:def|with)/.test(keyWord))) { // indent-word + pushStack(state, indentTemp + INDENT_WORD_SKIP, ch); + } else { // non-indent word + // we continue eating the spaces + stream.eatSpace(); + if (stream.eol() || stream.peek() == ";") { + // nothing significant after + // we restart indentation the user defined spaces after + pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch); + } else { + pushStack(state, indentTemp + stream.current().length, ch); // else we match + } + } + stream.backUp(stream.current().length - 1); // undo all the eating + + returnType = BRACKET; + } else if (ch == ")" || ch == "]" || ch == "}") { + returnType = BRACKET; + if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) { + popStack(state); + } + } else if ( ch == ":" ) { + stream.eatWhile(tests.symbol); + return ATOM; + } else { + stream.eatWhile(tests.symbol); + + if (keywords && keywords.propertyIsEnumerable(stream.current())) { + returnType = KEYWORD; + } else if (builtins && builtins.propertyIsEnumerable(stream.current())) { + returnType = BUILTIN; + } else if (atoms && atoms.propertyIsEnumerable(stream.current())) { + returnType = ATOM; + } else { + returnType = VAR; + } + } + } + + return returnType; + }, + + indent: function (state) { + if (state.indentStack == null) return state.indentation; + return state.indentStack.indent; + }, + + closeBrackets: {pairs: "()[]{}\"\""}, + lineComment: ";;" + }; +}); + +CodeMirror.defineMIME("text/x-clojure", "clojure"); + +}); diff --git a/rhodecode/public/js/mode/cmake/cmake.js b/rhodecode/public/js/mode/cmake/cmake.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/cmake/cmake.js @@ -0,0 +1,97 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) + define(["../../lib/codemirror"], mod); + else + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("cmake", function () { + var variable_regex = /({)?[a-zA-Z0-9_]+(})?/; + + function tokenString(stream, state) { + var current, prev, found_var = false; + while (!stream.eol() && (current = stream.next()) != state.pending) { + if (current === '$' && prev != '\\' && state.pending == '"') { + found_var = true; + break; + } + prev = current; + } + if (found_var) { + stream.backUp(1); + } + if (current == state.pending) { + state.continueString = false; + } else { + state.continueString = true; + } + return "string"; + } + + function tokenize(stream, state) { + var ch = stream.next(); + + // Have we found a variable? + if (ch === '$') { + if (stream.match(variable_regex)) { + return 'variable-2'; + } + return 'variable'; + } + // Should we still be looking for the end of a string? + if (state.continueString) { + // If so, go through the loop again + stream.backUp(1); + return tokenString(stream, state); + } + // Do we just have a function on our hands? + // In 'cmake_minimum_required (VERSION 2.8.8)', 'cmake_minimum_required' is matched + if (stream.match(/(\s+)?\w+\(/) || stream.match(/(\s+)?\w+\ \(/)) { + stream.backUp(1); + return 'def'; + } + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + // Have we found a string? + if (ch == "'" || ch == '"') { + // Store the type (single or double) + state.pending = ch; + // Perform the looping function to find the end + return tokenString(stream, state); + } + if (ch == '(' || ch == ')') { + return 'bracket'; + } + if (ch.match(/[0-9]/)) { + return 'number'; + } + stream.eatWhile(/[\w-]/); + return null; + } + return { + startState: function () { + var state = {}; + state.inDefinition = false; + state.inInclude = false; + state.continueString = false; + state.pending = false; + return state; + }, + token: function (stream, state) { + if (stream.eatSpace()) return null; + return tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME("text/x-cmake", "cmake"); + +}); diff --git a/rhodecode/public/js/mode/cobol/cobol.js b/rhodecode/public/js/mode/cobol/cobol.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/cobol/cobol.js @@ -0,0 +1,255 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Author: Gautam Mehta + * Branched from CodeMirror's Scheme mode + */ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("cobol", function () { + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", + ATOM = "atom", NUMBER = "number", KEYWORD = "keyword", MODTAG = "header", + COBOLLINENUM = "def", PERIOD = "link"; + function makeKeywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var atoms = makeKeywords("TRUE FALSE ZEROES ZEROS ZERO SPACES SPACE LOW-VALUE LOW-VALUES "); + var keywords = makeKeywords( + "ACCEPT ACCESS ACQUIRE ADD ADDRESS " + + "ADVANCING AFTER ALIAS ALL ALPHABET " + + "ALPHABETIC ALPHABETIC-LOWER ALPHABETIC-UPPER ALPHANUMERIC ALPHANUMERIC-EDITED " + + "ALSO ALTER ALTERNATE AND ANY " + + "ARE AREA AREAS ARITHMETIC ASCENDING " + + "ASSIGN AT ATTRIBUTE AUTHOR AUTO " + + "AUTO-SKIP AUTOMATIC B-AND B-EXOR B-LESS " + + "B-NOT B-OR BACKGROUND-COLOR BACKGROUND-COLOUR BEEP " + + "BEFORE BELL BINARY BIT BITS " + + "BLANK BLINK BLOCK BOOLEAN BOTTOM " + + "BY CALL CANCEL CD CF " + + "CH CHARACTER CHARACTERS CLASS CLOCK-UNITS " + + "CLOSE COBOL CODE CODE-SET COL " + + "COLLATING COLUMN COMMA COMMIT COMMITMENT " + + "COMMON COMMUNICATION COMP COMP-0 COMP-1 " + + "COMP-2 COMP-3 COMP-4 COMP-5 COMP-6 " + + "COMP-7 COMP-8 COMP-9 COMPUTATIONAL COMPUTATIONAL-0 " + + "COMPUTATIONAL-1 COMPUTATIONAL-2 COMPUTATIONAL-3 COMPUTATIONAL-4 COMPUTATIONAL-5 " + + "COMPUTATIONAL-6 COMPUTATIONAL-7 COMPUTATIONAL-8 COMPUTATIONAL-9 COMPUTE " + + "CONFIGURATION CONNECT CONSOLE CONTAINED CONTAINS " + + "CONTENT CONTINUE CONTROL CONTROL-AREA CONTROLS " + + "CONVERTING COPY CORR CORRESPONDING COUNT " + + "CRT CRT-UNDER CURRENCY CURRENT CURSOR " + + "DATA DATE DATE-COMPILED DATE-WRITTEN DAY " + + "DAY-OF-WEEK DB DB-ACCESS-CONTROL-KEY DB-DATA-NAME DB-EXCEPTION " + + "DB-FORMAT-NAME DB-RECORD-NAME DB-SET-NAME DB-STATUS DBCS " + + "DBCS-EDITED DE DEBUG-CONTENTS DEBUG-ITEM DEBUG-LINE " + + "DEBUG-NAME DEBUG-SUB-1 DEBUG-SUB-2 DEBUG-SUB-3 DEBUGGING " + + "DECIMAL-POINT DECLARATIVES DEFAULT DELETE DELIMITED " + + "DELIMITER DEPENDING DESCENDING DESCRIBED DESTINATION " + + "DETAIL DISABLE DISCONNECT DISPLAY DISPLAY-1 " + + "DISPLAY-2 DISPLAY-3 DISPLAY-4 DISPLAY-5 DISPLAY-6 " + + "DISPLAY-7 DISPLAY-8 DISPLAY-9 DIVIDE DIVISION " + + "DOWN DROP DUPLICATE DUPLICATES DYNAMIC " + + "EBCDIC EGI EJECT ELSE EMI " + + "EMPTY EMPTY-CHECK ENABLE END END. END-ACCEPT END-ACCEPT. " + + "END-ADD END-CALL END-COMPUTE END-DELETE END-DISPLAY " + + "END-DIVIDE END-EVALUATE END-IF END-INVOKE END-MULTIPLY " + + "END-OF-PAGE END-PERFORM END-READ END-RECEIVE END-RETURN " + + "END-REWRITE END-SEARCH END-START END-STRING END-SUBTRACT " + + "END-UNSTRING END-WRITE END-XML ENTER ENTRY " + + "ENVIRONMENT EOP EQUAL EQUALS ERASE " + + "ERROR ESI EVALUATE EVERY EXCEEDS " + + "EXCEPTION EXCLUSIVE EXIT EXTEND EXTERNAL " + + "EXTERNALLY-DESCRIBED-KEY FD FETCH FILE FILE-CONTROL " + + "FILE-STREAM FILES FILLER FINAL FIND " + + "FINISH FIRST FOOTING FOR FOREGROUND-COLOR " + + "FOREGROUND-COLOUR FORMAT FREE FROM FULL " + + "FUNCTION GENERATE GET GIVING GLOBAL " + + "GO GOBACK GREATER GROUP HEADING " + + "HIGH-VALUE HIGH-VALUES HIGHLIGHT I-O I-O-CONTROL " + + "ID IDENTIFICATION IF IN INDEX " + + "INDEX-1 INDEX-2 INDEX-3 INDEX-4 INDEX-5 " + + "INDEX-6 INDEX-7 INDEX-8 INDEX-9 INDEXED " + + "INDIC INDICATE INDICATOR INDICATORS INITIAL " + + "INITIALIZE INITIATE INPUT INPUT-OUTPUT INSPECT " + + "INSTALLATION INTO INVALID INVOKE IS " + + "JUST JUSTIFIED KANJI KEEP KEY " + + "LABEL LAST LD LEADING LEFT " + + "LEFT-JUSTIFY LENGTH LENGTH-CHECK LESS LIBRARY " + + "LIKE LIMIT LIMITS LINAGE LINAGE-COUNTER " + + "LINE LINE-COUNTER LINES LINKAGE LOCAL-STORAGE " + + "LOCALE LOCALLY LOCK " + + "MEMBER MEMORY MERGE MESSAGE METACLASS " + + "MODE MODIFIED MODIFY MODULES MOVE " + + "MULTIPLE MULTIPLY NATIONAL NATIVE NEGATIVE " + + "NEXT NO NO-ECHO NONE NOT " + + "NULL NULL-KEY-MAP NULL-MAP NULLS NUMBER " + + "NUMERIC NUMERIC-EDITED OBJECT OBJECT-COMPUTER OCCURS " + + "OF OFF OMITTED ON ONLY " + + "OPEN OPTIONAL OR ORDER ORGANIZATION " + + "OTHER OUTPUT OVERFLOW OWNER PACKED-DECIMAL " + + "PADDING PAGE PAGE-COUNTER PARSE PERFORM " + + "PF PH PIC PICTURE PLUS " + + "POINTER POSITION POSITIVE PREFIX PRESENT " + + "PRINTING PRIOR PROCEDURE PROCEDURE-POINTER PROCEDURES " + + "PROCEED PROCESS PROCESSING PROGRAM PROGRAM-ID " + + "PROMPT PROTECTED PURGE QUEUE QUOTE " + + "QUOTES RANDOM RD READ READY " + + "REALM RECEIVE RECONNECT RECORD RECORD-NAME " + + "RECORDS RECURSIVE REDEFINES REEL REFERENCE " + + "REFERENCE-MONITOR REFERENCES RELATION RELATIVE RELEASE " + + "REMAINDER REMOVAL RENAMES REPEATED REPLACE " + + "REPLACING REPORT REPORTING REPORTS REPOSITORY " + + "REQUIRED RERUN RESERVE RESET RETAINING " + + "RETRIEVAL RETURN RETURN-CODE RETURNING REVERSE-VIDEO " + + "REVERSED REWIND REWRITE RF RH " + + "RIGHT RIGHT-JUSTIFY ROLLBACK ROLLING ROUNDED " + + "RUN SAME SCREEN SD SEARCH " + + "SECTION SECURE SECURITY SEGMENT SEGMENT-LIMIT " + + "SELECT SEND SENTENCE SEPARATE SEQUENCE " + + "SEQUENTIAL SET SHARED SIGN SIZE " + + "SKIP1 SKIP2 SKIP3 SORT SORT-MERGE " + + "SORT-RETURN SOURCE SOURCE-COMPUTER SPACE-FILL " + + "SPECIAL-NAMES STANDARD STANDARD-1 STANDARD-2 " + + "START STARTING STATUS STOP STORE " + + "STRING SUB-QUEUE-1 SUB-QUEUE-2 SUB-QUEUE-3 SUB-SCHEMA " + + "SUBFILE SUBSTITUTE SUBTRACT SUM SUPPRESS " + + "SYMBOLIC SYNC SYNCHRONIZED SYSIN SYSOUT " + + "TABLE TALLYING TAPE TENANT TERMINAL " + + "TERMINATE TEST TEXT THAN THEN " + + "THROUGH THRU TIME TIMES TITLE " + + "TO TOP TRAILING TRAILING-SIGN TRANSACTION " + + "TYPE TYPEDEF UNDERLINE UNEQUAL UNIT " + + "UNSTRING UNTIL UP UPDATE UPON " + + "USAGE USAGE-MODE USE USING VALID " + + "VALIDATE VALUE VALUES VARYING VLR " + + "WAIT WHEN WHEN-COMPILED WITH WITHIN " + + "WORDS WORKING-STORAGE WRITE XML XML-CODE " + + "XML-EVENT XML-NTEXT XML-TEXT ZERO ZERO-FILL " ); + + var builtins = makeKeywords("- * ** / + < <= = > >= "); + var tests = { + digit: /\d/, + digit_or_colon: /[\d:]/, + hex: /[0-9a-f]/i, + sign: /[+-]/, + exponent: /e/i, + keyword_char: /[^\s\(\[\;\)\]]/, + symbol: /[\w*+\-]/ + }; + function isNumber(ch, stream){ + // hex + if ( ch === '0' && stream.eat(/x/i) ) { + stream.eatWhile(tests.hex); + return true; + } + // leading sign + if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) { + stream.eat(tests.sign); + ch = stream.next(); + } + if ( tests.digit.test(ch) ) { + stream.eat(ch); + stream.eatWhile(tests.digit); + if ( '.' == stream.peek()) { + stream.eat('.'); + stream.eatWhile(tests.digit); + } + if ( stream.eat(tests.exponent) ) { + stream.eat(tests.sign); + stream.eatWhile(tests.digit); + } + return true; + } + return false; + } + return { + startState: function () { + return { + indentStack: null, + indentation: 0, + mode: false + }; + }, + token: function (stream, state) { + if (state.indentStack == null && stream.sol()) { + // update indentation, but only if indentStack is empty + state.indentation = 6 ; //stream.indentation(); + } + // skip spaces + if (stream.eatSpace()) { + return null; + } + var returnType = null; + switch(state.mode){ + case "string": // multi-line string parsing mode + var next = false; + while ((next = stream.next()) != null) { + if (next == "\"" || next == "\'") { + state.mode = false; + break; + } + } + returnType = STRING; // continue on in string mode + break; + default: // default parsing mode + var ch = stream.next(); + var col = stream.column(); + if (col >= 0 && col <= 5) { + returnType = COBOLLINENUM; + } else if (col >= 72 && col <= 79) { + stream.skipToEnd(); + returnType = MODTAG; + } else if (ch == "*" && col == 6) { // comment + stream.skipToEnd(); // rest of the line is a comment + returnType = COMMENT; + } else if (ch == "\"" || ch == "\'") { + state.mode = "string"; + returnType = STRING; + } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) { + returnType = ATOM; + } else if (ch == ".") { + returnType = PERIOD; + } else if (isNumber(ch,stream)){ + returnType = NUMBER; + } else { + if (stream.current().match(tests.symbol)) { + while (col < 71) { + if (stream.eat(tests.symbol) === undefined) { + break; + } else { + col++; + } + } + } + if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = KEYWORD; + } else if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = BUILTIN; + } else if (atoms && atoms.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = ATOM; + } else returnType = null; + } + } + return returnType; + }, + indent: function (state) { + if (state.indentStack == null) return state.indentation; + return state.indentStack.indent; + } + }; +}); + +CodeMirror.defineMIME("text/x-cobol", "cobol"); + +}); diff --git a/rhodecode/public/js/mode/coffeescript/coffeescript.js b/rhodecode/public/js/mode/coffeescript/coffeescript.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/coffeescript/coffeescript.js @@ -0,0 +1,369 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Link to the project's GitHub page: + * https://github.com/pickhardt/coffeescript-codemirror-mode + */ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("coffeescript", function(conf, parserConf) { + var ERRORCLASS = "error"; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/; + var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/; + var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/; + var properties = /^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/; + + var wordOperators = wordRegexp(["and", "or", "not", + "is", "isnt", "in", + "instanceof", "typeof"]); + var indentKeywords = ["for", "while", "loop", "if", "unless", "else", + "switch", "try", "catch", "finally", "class"]; + var commonKeywords = ["break", "by", "continue", "debugger", "delete", + "do", "in", "of", "new", "return", "then", + "this", "@", "throw", "when", "until", "extends"]; + + var keywords = wordRegexp(indentKeywords.concat(commonKeywords)); + + indentKeywords = wordRegexp(indentKeywords); + + + var stringPrefixes = /^('{3}|\"{3}|['\"])/; + var regexPrefixes = /^(\/{3}|\/)/; + var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"]; + var constants = wordRegexp(commonConstants); + + // Tokenizers + function tokenBase(stream, state) { + // Handle scope changes + if (stream.sol()) { + if (state.scope.align === null) state.scope.align = false; + var scopeOffset = state.scope.offset; + if (stream.eatSpace()) { + var lineOffset = stream.indentation(); + if (lineOffset > scopeOffset && state.scope.type == "coffee") { + return "indent"; + } else if (lineOffset < scopeOffset) { + return "dedent"; + } + return null; + } else { + if (scopeOffset > 0) { + dedent(stream, state); + } + } + } + if (stream.eatSpace()) { + return null; + } + + var ch = stream.peek(); + + // Handle docco title comment (single line) + if (stream.match("####")) { + stream.skipToEnd(); + return "comment"; + } + + // Handle multi line comments + if (stream.match("###")) { + state.tokenize = longComment; + return state.tokenize(stream, state); + } + + // Single line comment + if (ch === "#") { + stream.skipToEnd(); + return "comment"; + } + + // Handle number literals + if (stream.match(/^-?[0-9\.]/, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) { + floatLiteral = true; + } + if (stream.match(/^-?\d+\.\d*/)) { + floatLiteral = true; + } + if (stream.match(/^-?\.\d+/)) { + floatLiteral = true; + } + + if (floatLiteral) { + // prevent from getting extra . on 1.. + if (stream.peek() == "."){ + stream.backUp(1); + } + return "number"; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^-?0x[0-9a-f]+/i)) { + intLiteral = true; + } + // Decimal + if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) { + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^-?0(?![\dx])/i)) { + intLiteral = true; + } + if (intLiteral) { + return "number"; + } + } + + // Handle strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenFactory(stream.current(), false, "string"); + return state.tokenize(stream, state); + } + // Handle regex literals + if (stream.match(regexPrefixes)) { + if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division + state.tokenize = tokenFactory(stream.current(), true, "string-2"); + return state.tokenize(stream, state); + } else { + stream.backUp(1); + } + } + + // Handle operators and delimiters + if (stream.match(operators) || stream.match(wordOperators)) { + return "operator"; + } + if (stream.match(delimiters)) { + return "punctuation"; + } + + if (stream.match(constants)) { + return "atom"; + } + + if (stream.match(keywords)) { + return "keyword"; + } + + if (stream.match(identifiers)) { + return "variable"; + } + + if (stream.match(properties)) { + return "property"; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenFactory(delimiter, singleline, outclass) { + return function(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\/\\]/); + if (stream.eat("\\")) { + stream.next(); + if (singleline && stream.eol()) { + return outclass; + } + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return outclass; + } else { + stream.eat(/['"\/]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + outclass = ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return outclass; + }; + } + + function longComment(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^#]/); + if (stream.match("###")) { + state.tokenize = tokenBase; + break; + } + stream.eatWhile("#"); + } + return "comment"; + } + + function indent(stream, state, type) { + type = type || "coffee"; + var offset = 0, align = false, alignOffset = null; + for (var scope = state.scope; scope; scope = scope.prev) { + if (scope.type === "coffee" || scope.type == "}") { + offset = scope.offset + conf.indentUnit; + break; + } + } + if (type !== "coffee") { + align = null; + alignOffset = stream.column() + stream.current().length; + } else if (state.scope.align) { + state.scope.align = false; + } + state.scope = { + offset: offset, + type: type, + prev: state.scope, + align: align, + alignOffset: alignOffset + }; + } + + function dedent(stream, state) { + if (!state.scope.prev) return; + if (state.scope.type === "coffee") { + var _indent = stream.indentation(); + var matched = false; + for (var scope = state.scope; scope; scope = scope.prev) { + if (_indent === scope.offset) { + matched = true; + break; + } + } + if (!matched) { + return true; + } + while (state.scope.prev && state.scope.offset !== _indent) { + state.scope = state.scope.prev; + } + return false; + } else { + state.scope = state.scope.prev; + return false; + } + } + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle "." connected identifiers + if (current === ".") { + style = state.tokenize(stream, state); + current = stream.current(); + if (/^\.[\w$]+$/.test(current)) { + return "variable"; + } else { + return ERRORCLASS; + } + } + + // Handle scope changes. + if (current === "return") { + state.dedent = true; + } + if (((current === "->" || current === "=>") && + !state.lambda && + !stream.peek()) + || style === "indent") { + indent(stream, state); + } + var delimiter_index = "[({".indexOf(current); + if (delimiter_index !== -1) { + indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1)); + } + if (indentKeywords.exec(current)){ + indent(stream, state); + } + if (current == "then"){ + dedent(stream, state); + } + + + if (style === "dedent") { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + delimiter_index = "])}".indexOf(current); + if (delimiter_index !== -1) { + while (state.scope.type == "coffee" && state.scope.prev) + state.scope = state.scope.prev; + if (state.scope.type == current) + state.scope = state.scope.prev; + } + if (state.dedent && stream.eol()) { + if (state.scope.type == "coffee" && state.scope.prev) + state.scope = state.scope.prev; + state.dedent = false; + } + + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false}, + lastToken: null, + lambda: false, + dedent: 0 + }; + }, + + token: function(stream, state) { + var fillAlign = state.scope.align === null && state.scope; + if (fillAlign && stream.sol()) fillAlign.align = false; + + var style = tokenLexer(stream, state); + if (fillAlign && style && style != "comment") fillAlign.align = true; + + state.lastToken = {style:style, content: stream.current()}; + + if (stream.eol() && stream.lambda) { + state.lambda = false; + } + + return style; + }, + + indent: function(state, text) { + if (state.tokenize != tokenBase) return 0; + var scope = state.scope; + var closer = text && "])}".indexOf(text.charAt(0)) > -1; + if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev; + var closes = closer && scope.type === text.charAt(0); + if (scope.align) + return scope.alignOffset - (closes ? 1 : 0); + else + return (closes ? scope.prev : scope).offset; + }, + + lineComment: "#", + fold: "indent" + }; + return external; +}); + +CodeMirror.defineMIME("text/x-coffeescript", "coffeescript"); + +}); diff --git a/rhodecode/public/js/mode/commonlisp/commonlisp.js b/rhodecode/public/js/mode/commonlisp/commonlisp.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/commonlisp/commonlisp.js @@ -0,0 +1,123 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("commonlisp", function (config) { + var specialForm = /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/; + var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/; + var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/; + var symbol = /[^\s'`,@()\[\]";]/; + var type; + + function readSym(stream) { + var ch; + while (ch = stream.next()) { + if (ch == "\\") stream.next(); + else if (!symbol.test(ch)) { stream.backUp(1); break; } + } + return stream.current(); + } + + function base(stream, state) { + if (stream.eatSpace()) {type = "ws"; return null;} + if (stream.match(numLiteral)) return "number"; + var ch = stream.next(); + if (ch == "\\") ch = stream.next(); + + if (ch == '"') return (state.tokenize = inString)(stream, state); + else if (ch == "(") { type = "open"; return "bracket"; } + else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; } + else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; } + else if (/['`,@]/.test(ch)) return null; + else if (ch == "|") { + if (stream.skipTo("|")) { stream.next(); return "symbol"; } + else { stream.skipToEnd(); return "error"; } + } else if (ch == "#") { + var ch = stream.next(); + if (ch == "[") { type = "open"; return "bracket"; } + else if (/[+\-=\.']/.test(ch)) return null; + else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null; + else if (ch == "|") return (state.tokenize = inComment)(stream, state); + else if (ch == ":") { readSym(stream); return "meta"; } + else return "error"; + } else { + var name = readSym(stream); + if (name == ".") return null; + type = "symbol"; + if (name == "nil" || name == "t" || name.charAt(0) == ":") return "atom"; + if (state.lastType == "open" && (specialForm.test(name) || assumeBody.test(name))) return "keyword"; + if (name.charAt(0) == "&") return "variable-2"; + return "variable"; + } + } + + function inString(stream, state) { + var escaped = false, next; + while (next = stream.next()) { + if (next == '"' && !escaped) { state.tokenize = base; break; } + escaped = !escaped && next == "\\"; + } + return "string"; + } + + function inComment(stream, state) { + var next, last; + while (next = stream.next()) { + if (next == "#" && last == "|") { state.tokenize = base; break; } + last = next; + } + type = "ws"; + return "comment"; + } + + return { + startState: function () { + return {ctx: {prev: null, start: 0, indentTo: 0}, lastType: null, tokenize: base}; + }, + + token: function (stream, state) { + if (stream.sol() && typeof state.ctx.indentTo != "number") + state.ctx.indentTo = state.ctx.start + 1; + + type = null; + var style = state.tokenize(stream, state); + if (type != "ws") { + if (state.ctx.indentTo == null) { + if (type == "symbol" && assumeBody.test(stream.current())) + state.ctx.indentTo = state.ctx.start + config.indentUnit; + else + state.ctx.indentTo = "next"; + } else if (state.ctx.indentTo == "next") { + state.ctx.indentTo = stream.column(); + } + state.lastType = type; + } + if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null}; + else if (type == "close") state.ctx = state.ctx.prev || state.ctx; + return style; + }, + + indent: function (state, _textAfter) { + var i = state.ctx.indentTo; + return typeof i == "number" ? i : state.ctx.start + 1; + }, + + closeBrackets: {pairs: "()[]{}\"\""}, + lineComment: ";;", + blockCommentStart: "#|", + blockCommentEnd: "|#" + }; +}); + +CodeMirror.defineMIME("text/x-common-lisp", "commonlisp"); + +}); diff --git a/rhodecode/public/js/mode/crystal/crystal.js b/rhodecode/public/js/mode/crystal/crystal.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/crystal/crystal.js @@ -0,0 +1,391 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("crystal", function(config) { + function wordRegExp(words, end) { + return new RegExp((end ? "" : "^") + "(?:" + words.join("|") + ")" + (end ? "$" : "\\b")); + } + + function chain(tokenize, stream, state) { + state.tokenize.push(tokenize); + return tokenize(stream, state); + } + + var operators = /^(?:[-+/%|&^]|\*\*?|[<>]{2})/; + var conditionalOperators = /^(?:[=!]~|===|<=>|[<>=!]=?|[|&]{2}|~)/; + var indexingOperators = /^(?:\[\][?=]?)/; + var anotherOperators = /^(?:\.(?:\.{2})?|->|[?:])/; + var idents = /^[a-z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/; + var types = /^[A-Z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/; + var keywords = wordRegExp([ + "abstract", "alias", "as", "asm", "begin", "break", "case", "class", "def", "do", + "else", "elsif", "end", "ensure", "enum", "extend", "for", "fun", "if", "ifdef", + "include", "instance_sizeof", "lib", "macro", "module", "next", "of", "out", "pointerof", + "private", "protected", "rescue", "return", "require", "sizeof", "struct", + "super", "then", "type", "typeof", "union", "unless", "until", "when", "while", "with", + "yield", "__DIR__", "__FILE__", "__LINE__" + ]); + var atomWords = wordRegExp(["true", "false", "nil", "self"]); + var indentKeywordsArray = [ + "def", "fun", "macro", + "class", "module", "struct", "lib", "enum", "union", + "if", "unless", "case", "while", "until", "begin", "then", + "do", + "for", "ifdef" + ]; + var indentKeywords = wordRegExp(indentKeywordsArray); + var dedentKeywordsArray = [ + "end", + "else", "elsif", + "rescue", "ensure" + ]; + var dedentKeywords = wordRegExp(dedentKeywordsArray); + var dedentPunctualsArray = ["\\)", "\\}", "\\]"]; + var dedentPunctuals = new RegExp("^(?:" + dedentPunctualsArray.join("|") + ")$"); + var nextTokenizer = { + "def": tokenFollowIdent, "fun": tokenFollowIdent, "macro": tokenMacroDef, + "class": tokenFollowType, "module": tokenFollowType, "struct": tokenFollowType, + "lib": tokenFollowType, "enum": tokenFollowType, "union": tokenFollowType + }; + var matching = {"[": "]", "{": "}", "(": ")", "<": ">"}; + + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return null; + } + + // Macros + if (state.lastToken != "\\" && stream.match("{%", false)) { + return chain(tokenMacro("%", "%"), stream, state); + } + + if (state.lastToken != "\\" && stream.match("{{", false)) { + return chain(tokenMacro("{", "}"), stream, state); + } + + // Comments + if (stream.peek() == "#") { + stream.skipToEnd(); + return "comment"; + } + + // Variables and keywords + var matched; + if (stream.match(idents)) { + stream.eat(/[?!]/); + + matched = stream.current(); + if (stream.eat(":")) { + return "atom"; + } else if (state.lastToken == ".") { + return "property"; + } else if (keywords.test(matched)) { + if (state.lastToken != "abstract" && indentKeywords.test(matched)) { + if (!(matched == "fun" && state.blocks.indexOf("lib") >= 0)) { + state.blocks.push(matched); + state.currentIndent += 1; + } + } else if (dedentKeywords.test(matched)) { + state.blocks.pop(); + state.currentIndent -= 1; + } + + if (nextTokenizer.hasOwnProperty(matched)) { + state.tokenize.push(nextTokenizer[matched]); + } + + return "keyword"; + } else if (atomWords.test(matched)) { + return "atom"; + } + + return "variable"; + } + + // Class variables and instance variables + // or attributes + if (stream.eat("@")) { + if (stream.peek() == "[") { + return chain(tokenNest("[", "]", "meta"), stream, state); + } + + stream.eat("@"); + stream.match(idents) || stream.match(types); + return "variable-2"; + } + + // Global variables + if (stream.eat("$")) { + stream.eat(/[0-9]+|\?/) || stream.match(idents) || stream.match(types); + return "variable-3"; + } + + // Constants and types + if (stream.match(types)) { + return "tag"; + } + + // Symbols or ':' operator + if (stream.eat(":")) { + if (stream.eat("\"")) { + return chain(tokenQuote("\"", "atom", false), stream, state); + } else if (stream.match(idents) || stream.match(types) || + stream.match(operators) || stream.match(conditionalOperators) || stream.match(indexingOperators)) { + return "atom"; + } + stream.eat(":"); + return "operator"; + } + + // Strings + if (stream.eat("\"")) { + return chain(tokenQuote("\"", "string", true), stream, state); + } + + // Strings or regexps or macro variables or '%' operator + if (stream.peek() == "%") { + var style = "string"; + var embed = true; + var delim; + + if (stream.match("%r")) { + // Regexps + style = "string-2"; + delim = stream.next(); + } else if (stream.match("%w")) { + embed = false; + delim = stream.next(); + } else { + if(delim = stream.match(/^%([^\w\s=])/)) { + delim = delim[1]; + } else if (stream.match(/^%[a-zA-Z0-9_\u009F-\uFFFF]*/)) { + // Macro variables + return "meta"; + } else { + // '%' operator + return "operator"; + } + } + + if (matching.hasOwnProperty(delim)) { + delim = matching[delim]; + } + return chain(tokenQuote(delim, style, embed), stream, state); + } + + // Characters + if (stream.eat("'")) { + stream.match(/^(?:[^']|\\(?:[befnrtv0'"]|[0-7]{3}|u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]{1,6}\})))/); + stream.eat("'"); + return "atom"; + } + + // Numbers + if (stream.eat("0")) { + if (stream.eat("x")) { + stream.match(/^[0-9a-fA-F]+/); + } else if (stream.eat("o")) { + stream.match(/^[0-7]+/); + } else if (stream.eat("b")) { + stream.match(/^[01]+/); + } + return "number"; + } + + if (stream.eat(/\d/)) { + stream.match(/^\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/); + return "number"; + } + + // Operators + if (stream.match(operators)) { + stream.eat("="); // Operators can follow assigin symbol. + return "operator"; + } + + if (stream.match(conditionalOperators) || stream.match(anotherOperators)) { + return "operator"; + } + + // Parens and braces + if (matched = stream.match(/[({[]/, false)) { + matched = matched[0]; + return chain(tokenNest(matched, matching[matched], null), stream, state); + } + + // Escapes + if (stream.eat("\\")) { + stream.next(); + return "meta"; + } + + stream.next(); + return null; + } + + function tokenNest(begin, end, style, started) { + return function (stream, state) { + if (!started && stream.match(begin)) { + state.tokenize[state.tokenize.length - 1] = tokenNest(begin, end, style, true); + state.currentIndent += 1; + return style; + } + + var nextStyle = tokenBase(stream, state); + if (stream.current() === end) { + state.tokenize.pop(); + state.currentIndent -= 1; + nextStyle = style; + } + + return nextStyle; + }; + } + + function tokenMacro(begin, end, started) { + return function (stream, state) { + if (!started && stream.match("{" + begin)) { + state.currentIndent += 1; + state.tokenize[state.tokenize.length - 1] = tokenMacro(begin, end, true); + return "meta"; + } + + if (stream.match(end + "}")) { + state.currentIndent -= 1; + state.tokenize.pop(); + return "meta"; + } + + return tokenBase(stream, state); + }; + } + + function tokenMacroDef(stream, state) { + if (stream.eatSpace()) { + return null; + } + + var matched; + if (matched = stream.match(idents)) { + if (matched == "def") { + return "keyword"; + } + stream.eat(/[?!]/); + } + + state.tokenize.pop(); + return "def"; + } + + function tokenFollowIdent(stream, state) { + if (stream.eatSpace()) { + return null; + } + + if (stream.match(idents)) { + stream.eat(/[!?]/); + } else { + stream.match(operators) || stream.match(conditionalOperators) || stream.match(indexingOperators); + } + state.tokenize.pop(); + return "def"; + } + + function tokenFollowType(stream, state) { + if (stream.eatSpace()) { + return null; + } + + stream.match(types); + state.tokenize.pop(); + return "def"; + } + + function tokenQuote(end, style, embed) { + return function (stream, state) { + var escaped = false; + + while (stream.peek()) { + if (!escaped) { + if (stream.match("{%", false)) { + state.tokenize.push(tokenMacro("%", "%")); + return style; + } + + if (stream.match("{{", false)) { + state.tokenize.push(tokenMacro("{", "}")); + return style; + } + + if (embed && stream.match("#{", false)) { + state.tokenize.push(tokenNest("#{", "}", "meta")); + return style; + } + + var ch = stream.next(); + + if (ch == end) { + state.tokenize.pop(); + return style; + } + + escaped = ch == "\\"; + } else { + stream.next(); + escaped = false; + } + } + + return style; + }; + } + + return { + startState: function () { + return { + tokenize: [tokenBase], + currentIndent: 0, + lastToken: null, + blocks: [] + }; + }, + + token: function (stream, state) { + var style = state.tokenize[state.tokenize.length - 1](stream, state); + var token = stream.current(); + + if (style && style != "comment") { + state.lastToken = token; + } + + return style; + }, + + indent: function (state, textAfter) { + textAfter = textAfter.replace(/^\s*(?:\{%)?\s*|\s*(?:%\})?\s*$/g, ""); + + if (dedentKeywords.test(textAfter) || dedentPunctuals.test(textAfter)) { + return config.indentUnit * (state.currentIndent - 1); + } + + return config.indentUnit * state.currentIndent; + }, + + fold: "indent", + electricInput: wordRegExp(dedentPunctualsArray.concat(dedentKeywordsArray), true), + lineComment: '#' + }; + }); + + CodeMirror.defineMIME("text/x-crystal", "crystal"); +}); diff --git a/rhodecode/public/js/mode/css/css.js b/rhodecode/public/js/mode/css/css.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/css/css.js @@ -0,0 +1,754 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("css", function(config, parserConfig) { + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + + var indentUnit = config.indentUnit, + tokenHooks = parserConfig.tokenHooks, + documentTypes = parserConfig.documentTypes || {}, + mediaTypes = parserConfig.mediaTypes || {}, + mediaFeatures = parserConfig.mediaFeatures || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + counterDescriptors = parserConfig.counterDescriptors || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + allowNested = parserConfig.allowNested; + + var type, override; + function ret(style, tp) { type = tp; return style; } + + // Tokenizers + + function tokenBase(stream, state) { + var ch = stream.next(); + if (tokenHooks[ch]) { + var result = tokenHooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == "@") { + stream.eatWhile(/[\w\\\-]/); + return ret("def", stream.current()); + } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { + return ret(null, "compare"); + } else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "#") { + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "hash"); + } else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (ch === "-") { + if (/[\d.]/.test(stream.peek())) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (stream.match(/^-[\w\\\-]+/)) { + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ret("variable-2", "variable-definition"); + return ret("variable-2", "variable"); + } else if (stream.match(/^\w+-/)) { + return ret("meta", "meta"); + } + } else if (/[,+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { + return ret("qualifier", "qualifier"); + } else if (/[:;{}\[\]\(\)]/.test(ch)) { + return ret(null, ch); + } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) || + (ch == "d" && stream.match("omain(")) || + (ch == "r" && stream.match("egexp("))) { + stream.backUp(1); + state.tokenize = tokenParenthesized; + return ret("property", "word"); + } else if (/[\w\\\-]/.test(ch)) { + stream.eatWhile(/[\w\\\-]/); + return ret("property", "word"); + } else { + return ret(null, null); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ret("string", "string"); + }; + } + + function tokenParenthesized(stream, state) { + stream.next(); // Must be '(' + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return ret(null, "("); + } + + // Context management + + function Context(type, indent, prev) { + this.type = type; + this.indent = indent; + this.prev = prev; + } + + function pushContext(state, stream, type) { + state.context = new Context(type, stream.indentation() + indentUnit, state.context); + return type; + } + + function popContext(state) { + state.context = state.context.prev; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + // Parser + + function wordAsValue(stream) { + var word = stream.current().toLowerCase(); + if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "variable"; + } + + var states = {}; + + states.top = function(type, stream, state) { + if (type == "{") { + return pushContext(state, stream, "block"); + } else if (type == "}" && state.context.prev) { + return popContext(state); + } else if (/@(media|supports|(-moz-)?document)/.test(type)) { + return pushContext(state, stream, "atBlock"); + } else if (/@(font-face|counter-style)/.test(type)) { + state.stateArg = type; + return "restricted_atBlock_before"; + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { + return "keyframes"; + } else if (type && type.charAt(0) == "@") { + return pushContext(state, stream, "at"); + } else if (type == "hash") { + override = "builtin"; + } else if (type == "word") { + override = "tag"; + } else if (type == "variable-definition") { + return "maybeprop"; + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } else if (type == ":") { + return "pseudo"; + } else if (allowNested && type == "(") { + return pushContext(state, stream, "parens"); + } + return state.context.type; + }; + + states.block = function(type, stream, state) { + if (type == "word") { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { + override = "property"; + return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; + } else if (allowNested) { + override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; + return "block"; + } else { + override += " error"; + return "maybeprop"; + } + } else if (type == "meta") { + return "block"; + } else if (!allowNested && (type == "hash" || type == "qualifier")) { + override = "error"; + return "block"; + } else { + return states.top(type, stream, state); + } + }; + + states.maybeprop = function(type, stream, state) { + if (type == ":") return pushContext(state, stream, "prop"); + return pass(type, stream, state); + }; + + states.prop = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); + if (type == "}" || type == "{") return popAndPass(type, stream, state); + if (type == "(") return pushContext(state, stream, "parens"); + + if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { + override += " error"; + } else if (type == "word") { + wordAsValue(stream); + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } + return "prop"; + }; + + states.propBlock = function(type, _stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { override = "property"; return "maybeprop"; } + return state.context.type; + }; + + states.parens = function(type, stream, state) { + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + if (type == "word") wordAsValue(stream); + return "parens"; + }; + + states.pseudo = function(type, stream, state) { + if (type == "word") { + override = "variable-3"; + return state.context.type; + } + return pass(type, stream, state); + }; + + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); + if (type == "}") return popAndPass(type, stream, state); + if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); + + if (type == "word") { + var word = stream.current().toLowerCase(); + if (word == "only" || word == "not" || word == "and" || word == "or") + override = "keyword"; + else if (documentTypes.hasOwnProperty(word)) + override = "tag"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else if (propertyKeywords.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else + override = "error"; + } + return state.context.type; + }; + + states.atBlock_parens = function(type, stream, state) { + if (type == ")") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); + return states.atBlock(type, stream, state); + }; + + states.restricted_atBlock_before = function(type, stream, state) { + if (type == "{") + return pushContext(state, stream, "restricted_atBlock"); + if (type == "word" && state.stateArg == "@counter-style") { + override = "variable"; + return "restricted_atBlock_before"; + } + return pass(type, stream, state); + }; + + states.restricted_atBlock = function(type, stream, state) { + if (type == "}") { + state.stateArg = null; + return popContext(state); + } + if (type == "word") { + if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || + (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) + override = "error"; + else + override = "property"; + return "maybeprop"; + } + return "restricted_atBlock"; + }; + + states.keyframes = function(type, stream, state) { + if (type == "word") { override = "variable"; return "keyframes"; } + if (type == "{") return pushContext(state, stream, "top"); + return pass(type, stream, state); + }; + + states.at = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == "word") override = "tag"; + else if (type == "hash") override = "builtin"; + return "at"; + }; + + states.interpolation = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "{" || type == ";") return popAndPass(type, stream, state); + if (type == "word") override = "variable"; + else if (type != "variable" && type != "(" && type != ")") override = "error"; + return "interpolation"; + }; + + return { + startState: function(base) { + return {tokenize: null, + state: "top", + stateArg: null, + context: new Context("top", base || 0, null)}; + }, + + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + state.state = states[state.state](type, stream, state); + return override; + }, + + indent: function(state, textAfter) { + var cx = state.context, ch = textAfter && textAfter.charAt(0); + var indent = cx.indent; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; + if (cx.prev && + (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "restricted_atBlock") || + ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at" || cx.type == "atBlock"))) { + indent = cx.indent - indentUnit; + cx = cx.prev; + } + return indent; + }, + + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + fold: "brace" + }; +}); + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var documentTypes_ = [ + "domain", "regexp", "url", "url-prefix" + ], documentTypes = keySet(documentTypes_); + + var mediaTypes_ = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ], mediaTypes = keySet(mediaTypes_); + + var mediaFeatures_ = [ + "width", "min-width", "max-width", "height", "min-height", "max-height", + "device-width", "min-device-width", "max-device-width", "device-height", + "min-device-height", "max-device-height", "aspect-ratio", + "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", + "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", + "max-color", "color-index", "min-color-index", "max-color-index", + "monochrome", "min-monochrome", "max-monochrome", "resolution", + "min-resolution", "max-resolution", "scan", "grid" + ], mediaFeatures = keySet(mediaFeatures_); + + var propertyKeywords_ = [ + "align-content", "align-items", "align-self", "alignment-adjust", + "alignment-baseline", "anchor-point", "animation", "animation-delay", + "animation-direction", "animation-duration", "animation-fill-mode", + "animation-iteration-count", "animation-name", "animation-play-state", + "animation-timing-function", "appearance", "azimuth", "backface-visibility", + "background", "background-attachment", "background-clip", "background-color", + "background-image", "background-origin", "background-position", + "background-repeat", "background-size", "baseline-shift", "binding", + "bleed", "bookmark-label", "bookmark-level", "bookmark-state", + "bookmark-target", "border", "border-bottom", "border-bottom-color", + "border-bottom-left-radius", "border-bottom-right-radius", + "border-bottom-style", "border-bottom-width", "border-collapse", + "border-color", "border-image", "border-image-outset", + "border-image-repeat", "border-image-slice", "border-image-source", + "border-image-width", "border-left", "border-left-color", + "border-left-style", "border-left-width", "border-radius", "border-right", + "border-right-color", "border-right-style", "border-right-width", + "border-spacing", "border-style", "border-top", "border-top-color", + "border-top-left-radius", "border-top-right-radius", "border-top-style", + "border-top-width", "border-width", "bottom", "box-decoration-break", + "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", + "caption-side", "clear", "clip", "color", "color-profile", "column-count", + "column-fill", "column-gap", "column-rule", "column-rule-color", + "column-rule-style", "column-rule-width", "column-span", "column-width", + "columns", "content", "counter-increment", "counter-reset", "crop", "cue", + "cue-after", "cue-before", "cursor", "direction", "display", + "dominant-baseline", "drop-initial-after-adjust", + "drop-initial-after-align", "drop-initial-before-adjust", + "drop-initial-before-align", "drop-initial-size", "drop-initial-value", + "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", + "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", + "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", + "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "font-stretch", "font-style", "font-synthesis", "font-variant", + "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", + "font-variant-ligatures", "font-variant-numeric", "font-variant-position", + "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", + "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end", + "grid-column-start", "grid-row", "grid-row-end", "grid-row-start", + "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", + "icon", "image-orientation", "image-rendering", "image-resolution", + "inline-box-align", "justify-content", "left", "letter-spacing", + "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "line-stacking-shift", "line-stacking-strategy", "list-style", + "list-style-image", "list-style-position", "list-style-type", "margin", + "margin-bottom", "margin-left", "margin-right", "margin-top", + "marker-offset", "marks", "marquee-direction", "marquee-loop", + "marquee-play-count", "marquee-speed", "marquee-style", "max-height", + "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", + "nav-left", "nav-right", "nav-up", "object-fit", "object-position", + "opacity", "order", "orphans", "outline", + "outline-color", "outline-offset", "outline-style", "outline-width", + "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", + "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", + "page", "page-break-after", "page-break-before", "page-break-inside", + "page-policy", "pause", "pause-after", "pause-before", "perspective", + "perspective-origin", "pitch", "pitch-range", "play-during", "position", + "presentation-level", "punctuation-trim", "quotes", "region-break-after", + "region-break-before", "region-break-inside", "region-fragment", + "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", + "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", + "shape-outside", "size", "speak", "speak-as", "speak-header", + "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", + "tab-size", "table-layout", "target", "target-name", "target-new", + "target-position", "text-align", "text-align-last", "text-decoration", + "text-decoration-color", "text-decoration-line", "text-decoration-skip", + "text-decoration-style", "text-emphasis", "text-emphasis-color", + "text-emphasis-position", "text-emphasis-style", "text-height", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", + "text-wrap", "top", "transform", "transform-origin", "transform-style", + "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "unicode-bidi", + "vertical-align", "visibility", "voice-balance", "voice-duration", + "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", + "voice-volume", "volume", "white-space", "widows", "width", "word-break", + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "text-anchor", "writing-mode" + ], propertyKeywords = keySet(propertyKeywords_); + + var nonStandardPropertyKeywords_ = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); + + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var counterDescriptors_ = [ + "additive-symbols", "fallback", "negative", "pad", "prefix", "range", + "speak-as", "suffix", "symbols", "system" + ], counterDescriptors = keySet(counterDescriptors_); + + var colorKeywords_ = [ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" + ], colorKeywords = keySet(colorKeywords_); + + var valueKeywords_ = [ + "above", "absolute", "activeborder", "additive", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", + "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "column", "compact", "condensed", "contain", "content", + "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "cyclic", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", + "disc", "discard", "disclosure-closed", "disclosure-open", "document", + "dot-dash", "dot-dot-dash", + "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", + "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", + "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", + "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", + "ethiopic-halehame-gez", "ethiopic-halehame-om-et", + "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "ew-resize", "expanded", "extends", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", + "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", + "help", "hidden", "hide", "higher", "highlight", "highlighttext", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", + "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", + "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", + "inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert", + "italic", "japanese-formal", "japanese-informal", "justify", "kannada", + "katakana", "katakana-iroha", "keep-all", "khmer", + "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", + "landscape", "lao", "large", "larger", "left", "level", "lighter", + "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", + "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", + "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", + "lower-roman", "lowercase", "ltr", "malayalam", "match", "matrix", "matrix3d", + "media-controls-background", "media-current-time-display", + "media-fullscreen-button", "media-mute-button", "media-play-button", + "media-return-to-realtime-button", "media-rewind-button", + "media-seek-back-button", "media-seek-forward-button", "media-slider", + "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", + "media-volume-slider-container", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", "menulist-text", + "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", + "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", + "progress", "push-button", "radial-gradient", "radio", "read-only", + "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeating-linear-gradient", + "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", + "rotateZ", "round", "row-resize", "rtl", "run-in", "running", + "s-resize", "sans-serif", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", + "scroll", "scrollbar", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "simp-chinese-formal", "simp-chinese-informal", "single", + "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", + "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", + "small", "small-caps", "small-caption", "smaller", "solid", "somali", + "source-atop", "source-in", "source-out", "source-over", "space", "spell-out", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", + "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "tamil", + "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", + "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", + "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "trad-chinese-formal", "trad-chinese-informal", + "translate", "translate3d", "translateX", "translateY", "translateZ", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", + "window", "windowframe", "windowtext", "words", "x-large", "x-small", "xor", + "xx-large", "xx-small" + ], valueKeywords = keySet(valueKeywords_); + + var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(propertyKeywords_) + .concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_); + CodeMirror.registerHelper("hintWords", "css", allWords); + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + CodeMirror.defineMIME("text/css", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css" + }); + + CodeMirror.defineMIME("text/x-scss", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + ":": function(stream) { + if (stream.match(/\s*\{/)) + return [null, "{"]; + return false; + }, + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "#": function(stream) { + if (!stream.eat("{")) return false; + return [null, "interpolation"]; + } + }, + name: "css", + helperType: "scss" + }); + + CodeMirror.defineMIME("text/x-less", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + "@": function(stream) { + if (stream.eat("{")) return [null, "interpolation"]; + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "&": function() { + return ["atom", "atom"]; + } + }, + name: "css", + helperType: "less" + }); + +}); diff --git a/rhodecode/public/js/mode/css/gss_test.js b/rhodecode/public/js/mode/css/gss_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/css/gss_test.js @@ -0,0 +1,17 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } + + MT("atComponent", + "[def @component] {", + "[tag foo] {", + " [property color]: [keyword black];", + "}", + "}"); + +})(); diff --git a/rhodecode/public/js/mode/css/less_test.js b/rhodecode/public/js/mode/css/less_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/css/less_test.js @@ -0,0 +1,54 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); } + + MT("variable", + "[variable-2 @base]: [atom #f04615];", + "[qualifier .class] {", + " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]", + " [property color]: [variable saturate]([variable-2 @base], [number 5%]);", + "}"); + + MT("amp", + "[qualifier .child], [qualifier .sibling] {", + " [qualifier .parent] [atom &] {", + " [property color]: [keyword black];", + " }", + " [atom &] + [atom &] {", + " [property color]: [keyword red];", + " }", + "}"); + + MT("mixin", + "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", + " [property color]: [variable darken]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable light]; [variable-2 @color]) {", + " [property color]: [variable lighten]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", + " [property display]: [atom block];", + "}", + "[variable-2 @switch]: [variable light];", + "[qualifier .class] {", + " [qualifier .mixin]([variable-2 @switch]; [atom #888]);", + "}"); + + MT("nest", + "[qualifier .one] {", + " [def @media] ([property width]: [number 400px]) {", + " [property font-size]: [number 1.2em];", + " [def @media] [attribute print] [keyword and] [property color] {", + " [property color]: [keyword blue];", + " }", + " }", + "}"); + + + MT("interpolation", ".@{[variable foo]} { [property font-weight]: [atom bold]; }"); +})(); diff --git a/rhodecode/public/js/mode/css/scss_test.js b/rhodecode/public/js/mode/css/scss_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/css/scss_test.js @@ -0,0 +1,110 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } + + MT('url_with_quotation', + "[tag foo] { [property background]:[atom url]([string test.jpg]) }"); + + MT('url_with_double_quotes', + "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }"); + + MT('url_with_single_quotes', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }"); + + MT('string', + "[def @import] [string \"compass/css3\"]"); + + MT('important_keyword', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }"); + + MT('variable', + "[variable-2 $blue]:[atom #333]"); + + MT('variable_as_attribute', + "[tag foo] { [property color]:[variable-2 $blue] }"); + + MT('numbers', + "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }"); + + MT('number_percentage', + "[tag foo] { [property width]:[number 80%] }"); + + MT('selector', + "[builtin #hello][qualifier .world]{}"); + + MT('singleline_comment', + "[comment // this is a comment]"); + + MT('multiline_comment', + "[comment /*foobar*/]"); + + MT('attribute_with_hyphen', + "[tag foo] { [property font-size]:[number 10px] }"); + + MT('string_after_attribute', + "[tag foo] { [property content]:[string \"::\"] }"); + + MT('directives', + "[def @include] [qualifier .mixin]"); + + MT('basic_structure', + "[tag p] { [property background]:[keyword red]; }"); + + MT('nested_structure', + "[tag p] { [tag a] { [property color]:[keyword red]; } }"); + + MT('mixin', + "[def @mixin] [tag table-base] {}"); + + MT('number_without_semicolon', + "[tag p] {[property width]:[number 12]}", + "[tag a] {[property color]:[keyword red];}"); + + MT('atom_in_nested_block', + "[tag p] { [tag a] { [property color]:[atom #000]; } }"); + + MT('interpolation_in_property', + "[tag foo] { #{[variable-2 $hello]}:[number 2]; }"); + + MT('interpolation_in_selector', + "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }"); + + MT('interpolation_error', + "[tag foo]#{[variable foo]} { [property color]:[atom #000]; }"); + + MT("divide_operator", + "[tag foo] { [property width]:[number 4] [operator /] [number 2] }"); + + MT('nested_structure_with_id_selector', + "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }"); + + MT('indent_mixin', + "[def @mixin] [tag container] (", + " [variable-2 $a]: [number 10],", + " [variable-2 $b]: [number 10])", + "{}"); + + MT('indent_nested', + "[tag foo] {", + " [tag bar] {", + " }", + "}"); + + MT('indent_parentheses', + "[tag foo] {", + " [property color]: [variable darken]([variable-2 $blue],", + " [number 9%]);", + "}"); + + MT('indent_vardef', + "[variable-2 $name]:", + " [string 'val'];", + "[tag tag] {", + " [tag inner] {", + " [property margin]: [number 3px];", + " }", + "}"); +})(); diff --git a/rhodecode/public/js/mode/cypher/cypher.js b/rhodecode/public/js/mode/cypher/cypher.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/cypher/cypher.js @@ -0,0 +1,146 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// By the Neo4j Team and contributors. +// https://github.com/neo4j-contrib/CodeMirror + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var wordRegexp = function(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + }; + + CodeMirror.defineMode("cypher", function(config) { + var tokenBase = function(stream/*, state*/) { + var ch = stream.next(); + if (ch === "\"" || ch === "'") { + stream.match(/.+?["']/); + return "string"; + } + if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return "node"; + } else if (ch === "/" && stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return null; + } else { + stream.eatWhile(/[_\w\d]/); + if (stream.eat(":")) { + stream.eatWhile(/[\w\d_\-]/); + return "atom"; + } + var word = stream.current(); + if (funcs.test(word)) return "builtin"; + if (preds.test(word)) return "def"; + if (keywords.test(word)) return "keyword"; + return "variable"; + } + }; + var pushContext = function(state, type, col) { + return state.context = { + prev: state.context, + indent: state.indent, + col: col, + type: type + }; + }; + var popContext = function(state) { + state.indent = state.context.indent; + return state.context = state.context.prev; + }; + var indentUnit = config.indentUnit; + var curPunc; + var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "right", "round", "rtrim", "shortestPath", "sign", "sin", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "trim", "type", "upper"]); + var preds = wordRegexp(["all", "and", "any", "has", "in", "none", "not", "or", "single", "xor"]); + var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "distinct", "drop", "else", "end", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]); + var operatorChars = /[*+\-<>=&|~%^]/; + + return { + startState: function(/*base*/) { + return { + tokenize: tokenBase, + context: null, + indent: 0, + col: 0 + }; + }, + token: function(stream, state) { + if (stream.sol()) { + if (state.context && (state.context.align == null)) { + state.context.align = false; + } + state.indent = stream.indentation(); + } + if (stream.eatSpace()) { + return null; + } + var style = state.tokenize(stream, state); + if (style !== "comment" && state.context && (state.context.align == null) && state.context.type !== "pattern") { + state.context.align = true; + } + if (curPunc === "(") { + pushContext(state, ")", stream.column()); + } else if (curPunc === "[") { + pushContext(state, "]", stream.column()); + } else if (curPunc === "{") { + pushContext(state, "}", stream.column()); + } else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type === "pattern") { + popContext(state); + } + if (state.context && curPunc === state.context.type) { + popContext(state); + } + } else if (curPunc === "." && state.context && state.context.type === "pattern") { + popContext(state); + } else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) { + pushContext(state, "pattern", stream.column()); + } else if (state.context.type === "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + return style; + }, + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) { + while (context && context.type === "pattern") { + context = context.prev; + } + } + var closing = context && firstChar === context.type; + if (!context) return 0; + if (context.type === "keywords") return CodeMirror.commands.newlineAndIndent; + if (context.align) return context.col + (closing ? 0 : 1); + return context.indent + (closing ? 0 : indentUnit); + } + }; + }); + + CodeMirror.modeExtensions["cypher"] = { + autoFormatLineBreaks: function(text) { + var i, lines, reProcessedPortion; + var lines = text.split("\n"); + var reProcessedPortion = /\s+\b(return|where|order by|match|with|skip|limit|create|delete|set)\b\s/g; + for (var i = 0; i < lines.length; i++) + lines[i] = lines[i].replace(reProcessedPortion, " \n$1 ").trim(); + return lines.join("\n"); + } + }; + + CodeMirror.defineMIME("application/x-cypher-query", "cypher"); + +}); diff --git a/rhodecode/public/js/mode/d/d.js b/rhodecode/public/js/mode/d/d.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/d/d.js @@ -0,0 +1,218 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("d", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + keywords = parserConfig.keywords || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings; + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("+")) { + state.tokenize = tokenComment; + return tokenNestedComment(stream, state); + } + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + if (builtin.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "builtin"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenNestedComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "+"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}" + }; +}); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var blockKeywords = "body catch class do else enum for foreach foreach_reverse if in interface mixin " + + "out scope struct switch try union unittest version while with"; + + CodeMirror.defineMIME("text/x-d", { + name: "d", + keywords: words("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue " + + "debug default delegate delete deprecated export extern final finally function goto immutable " + + "import inout invariant is lazy macro module new nothrow override package pragma private " + + "protected public pure ref return shared short static super synchronized template this " + + "throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters " + + blockKeywords), + blockKeywords: words(blockKeywords), + builtin: words("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte " + + "ucent uint ulong ushort wchar wstring void size_t sizediff_t"), + atoms: words("exit failure success true false null"), + hooks: { + "@": function(stream, _state) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); + +}); diff --git a/rhodecode/public/js/mode/dart/dart.js b/rhodecode/public/js/mode/dart/dart.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/dart/dart.js @@ -0,0 +1,50 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../clike/clike")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../clike/clike"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var keywords = ("this super static final const abstract class extends external factory " + + "implements get native operator set typedef with enum throw rethrow " + + "assert break case continue default in return new deferred async await " + + "try catch finally do else for if switch while import library export " + + "part of show hide is").split(" "); + var blockKeywords = "try catch finally do else for if switch while".split(" "); + var atoms = "true false null".split(" "); + var builtins = "void bool num int double dynamic var String".split(" "); + + function set(words) { + var obj = {}; + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + CodeMirror.defineMIME("application/dart", { + name: "clike", + keywords: set(keywords), + multiLineStrings: true, + blockKeywords: set(blockKeywords), + builtin: set(builtins), + atoms: set(atoms), + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); + + CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins)); + + // This is needed to make loading through meta.js work. + CodeMirror.defineMode("dart", function(conf) { + return CodeMirror.getMode(conf, "application/dart"); + }, "clike"); +}); diff --git a/rhodecode/public/js/mode/diff/diff.js b/rhodecode/public/js/mode/diff/diff.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/diff/diff.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("diff", function() { + + var TOKEN_NAMES = { + '+': 'positive', + '-': 'negative', + '@': 'meta' + }; + + return { + token: function(stream) { + var tw_pos = stream.string.search(/[\t ]+?$/); + + if (!stream.sol() || tw_pos === 0) { + stream.skipToEnd(); + return ("error " + ( + TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, ''); + } + + var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd(); + + if (tw_pos === -1) { + stream.skipToEnd(); + } else { + stream.pos = tw_pos; + } + + return token_name; + } + }; +}); + +CodeMirror.defineMIME("text/x-diff", "diff"); + +}); diff --git a/rhodecode/public/js/mode/django/django.js b/rhodecode/public/js/mode/django/django.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/django/django.js @@ -0,0 +1,350 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("django:inner", function() { + var keywords = ["block", "endblock", "for", "endfor", "true", "false", + "loop", "none", "self", "super", "if", "endif", "as", + "else", "import", "with", "endwith", "without", "context", "ifequal", "endifequal", + "ifnotequal", "endifnotequal", "extends", "include", "load", "comment", + "endcomment", "empty", "url", "static", "trans", "blocktrans", "now", "regroup", + "lorem", "ifchanged", "endifchanged", "firstof", "debug", "cycle", "csrf_token", + "autoescape", "endautoescape", "spaceless", "ssi", "templatetag", + "verbatim", "endverbatim", "widthratio"], + filters = ["add", "addslashes", "capfirst", "center", "cut", "date", + "default", "default_if_none", "dictsort", + "dictsortreversed", "divisibleby", "escape", "escapejs", + "filesizeformat", "first", "floatformat", "force_escape", + "get_digit", "iriencode", "join", "last", "length", + "length_is", "linebreaks", "linebreaksbr", "linenumbers", + "ljust", "lower", "make_list", "phone2numeric", "pluralize", + "pprint", "random", "removetags", "rjust", "safe", + "safeseq", "slice", "slugify", "stringformat", "striptags", + "time", "timesince", "timeuntil", "title", "truncatechars", + "truncatechars_html", "truncatewords", "truncatewords_html", + "unordered_list", "upper", "urlencode", "urlize", + "urlizetrunc", "wordcount", "wordwrap", "yesno"], + operators = ["==", "!=", "<", ">", "<=", ">=", "in", "not", "or", "and"]; + + keywords = new RegExp("^\\b(" + keywords.join("|") + ")\\b"); + filters = new RegExp("^\\b(" + filters.join("|") + ")\\b"); + operators = new RegExp("^\\b(" + operators.join("|") + ")\\b"); + + // We have to return "null" instead of null, in order to avoid string + // styling as the default, when using Django templates inside HTML + // element attributes + function tokenBase (stream, state) { + // Attempt to identify a variable, template or comment tag respectively + if (stream.match("{{")) { + state.tokenize = inVariable; + return "tag"; + } else if (stream.match("{%")) { + state.tokenize = inTag; + return "tag"; + } else if (stream.match("{#")) { + state.tokenize = inComment; + return "comment"; + } + + // Ignore completely any stream series that do not match the + // Django template opening tags. + while (stream.next() != null && !stream.match("{{", false) && !stream.match("{%", false)) {} + return null; + } + + // A string can be included in either single or double quotes (this is + // the delimeter). Mark everything as a string until the start delimeter + // occurs again. + function inString (delimeter, previousTokenizer) { + return function (stream, state) { + if (!state.escapeNext && stream.eat(delimeter)) { + state.tokenize = previousTokenizer; + } else { + if (state.escapeNext) { + state.escapeNext = false; + } + + var ch = stream.next(); + + // Take into account the backslash for escaping characters, such as + // the string delimeter. + if (ch == "\\") { + state.escapeNext = true; + } + } + + return "string"; + }; + } + + // Apply Django template variable syntax highlighting + function inVariable (stream, state) { + // Attempt to match a dot that precedes a property + if (state.waitDot) { + state.waitDot = false; + + if (stream.peek() != ".") { + return "null"; + } + + // Dot folowed by a non-word character should be considered an error. + if (stream.match(/\.\W+/)) { + return "error"; + } else if (stream.eat(".")) { + state.waitProperty = true; + return "null"; + } else { + throw Error ("Unexpected error while waiting for property."); + } + } + + // Attempt to match a pipe that precedes a filter + if (state.waitPipe) { + state.waitPipe = false; + + if (stream.peek() != "|") { + return "null"; + } + + // Pipe folowed by a non-word character should be considered an error. + if (stream.match(/\.\W+/)) { + return "error"; + } else if (stream.eat("|")) { + state.waitFilter = true; + return "null"; + } else { + throw Error ("Unexpected error while waiting for filter."); + } + } + + // Highlight properties + if (state.waitProperty) { + state.waitProperty = false; + if (stream.match(/\b(\w+)\b/)) { + state.waitDot = true; // A property can be followed by another property + state.waitPipe = true; // A property can be followed by a filter + return "property"; + } + } + + // Highlight filters + if (state.waitFilter) { + state.waitFilter = false; + if (stream.match(filters)) { + return "variable-2"; + } + } + + // Ignore all white spaces + if (stream.eatSpace()) { + state.waitProperty = false; + return "null"; + } + + // Identify numbers + if (stream.match(/\b\d+(\.\d+)?\b/)) { + return "number"; + } + + // Identify strings + if (stream.match("'")) { + state.tokenize = inString("'", state.tokenize); + return "string"; + } else if (stream.match('"')) { + state.tokenize = inString('"', state.tokenize); + return "string"; + } + + // Attempt to find the variable + if (stream.match(/\b(\w+)\b/) && !state.foundVariable) { + state.waitDot = true; + state.waitPipe = true; // A property can be followed by a filter + return "variable"; + } + + // If found closing tag reset + if (stream.match("}}")) { + state.waitProperty = null; + state.waitFilter = null; + state.waitDot = null; + state.waitPipe = null; + state.tokenize = tokenBase; + return "tag"; + } + + // If nothing was found, advance to the next character + stream.next(); + return "null"; + } + + function inTag (stream, state) { + // Attempt to match a dot that precedes a property + if (state.waitDot) { + state.waitDot = false; + + if (stream.peek() != ".") { + return "null"; + } + + // Dot folowed by a non-word character should be considered an error. + if (stream.match(/\.\W+/)) { + return "error"; + } else if (stream.eat(".")) { + state.waitProperty = true; + return "null"; + } else { + throw Error ("Unexpected error while waiting for property."); + } + } + + // Attempt to match a pipe that precedes a filter + if (state.waitPipe) { + state.waitPipe = false; + + if (stream.peek() != "|") { + return "null"; + } + + // Pipe folowed by a non-word character should be considered an error. + if (stream.match(/\.\W+/)) { + return "error"; + } else if (stream.eat("|")) { + state.waitFilter = true; + return "null"; + } else { + throw Error ("Unexpected error while waiting for filter."); + } + } + + // Highlight properties + if (state.waitProperty) { + state.waitProperty = false; + if (stream.match(/\b(\w+)\b/)) { + state.waitDot = true; // A property can be followed by another property + state.waitPipe = true; // A property can be followed by a filter + return "property"; + } + } + + // Highlight filters + if (state.waitFilter) { + state.waitFilter = false; + if (stream.match(filters)) { + return "variable-2"; + } + } + + // Ignore all white spaces + if (stream.eatSpace()) { + state.waitProperty = false; + return "null"; + } + + // Identify numbers + if (stream.match(/\b\d+(\.\d+)?\b/)) { + return "number"; + } + + // Identify strings + if (stream.match("'")) { + state.tokenize = inString("'", state.tokenize); + return "string"; + } else if (stream.match('"')) { + state.tokenize = inString('"', state.tokenize); + return "string"; + } + + // Attempt to match an operator + if (stream.match(operators)) { + return "operator"; + } + + // Attempt to match a keyword + var keywordMatch = stream.match(keywords); + if (keywordMatch) { + if (keywordMatch[0] == "comment") { + state.blockCommentTag = true; + } + return "keyword"; + } + + // Attempt to match a variable + if (stream.match(/\b(\w+)\b/)) { + state.waitDot = true; + state.waitPipe = true; // A property can be followed by a filter + return "variable"; + } + + // If found closing tag reset + if (stream.match("%}")) { + state.waitProperty = null; + state.waitFilter = null; + state.waitDot = null; + state.waitPipe = null; + // If the tag that closes is a block comment tag, we want to mark the + // following code as comment, until the tag closes. + if (state.blockCommentTag) { + state.blockCommentTag = false; // Release the "lock" + state.tokenize = inBlockComment; + } else { + state.tokenize = tokenBase; + } + return "tag"; + } + + // If nothing was found, advance to the next character + stream.next(); + return "null"; + } + + // Mark everything as comment inside the tag and the tag itself. + function inComment (stream, state) { + if (stream.match("#}")) { + state.tokenize = tokenBase; + } + return "comment"; + } + + // Mark everything as a comment until the `blockcomment` tag closes. + function inBlockComment (stream, state) { + if (stream.match(/\{%\s*endcomment\s*%\}/, false)) { + state.tokenize = inTag; + stream.match("{%"); + return "tag"; + } else { + stream.next(); + return "comment"; + } + } + + return { + startState: function () { + return {tokenize: tokenBase}; + }, + token: function (stream, state) { + return state.tokenize(stream, state); + }, + blockCommentStart: "{% comment %}", + blockCommentEnd: "{% endcomment %}" + }; + }); + + CodeMirror.defineMode("django", function(config) { + var htmlBase = CodeMirror.getMode(config, "text/html"); + var djangoInner = CodeMirror.getMode(config, "django:inner"); + return CodeMirror.overlayMode(htmlBase, djangoInner); + }); + + CodeMirror.defineMIME("text/x-django", "django"); +}); diff --git a/rhodecode/public/js/mode/dockerfile/dockerfile.js b/rhodecode/public/js/mode/dockerfile/dockerfile.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/dockerfile/dockerfile.js @@ -0,0 +1,76 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../addon/mode/simple")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../addon/mode/simple"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + // Collect all Dockerfile directives + var instructions = ["from", "maintainer", "run", "cmd", "expose", "env", + "add", "copy", "entrypoint", "volume", "user", + "workdir", "onbuild"], + instructionRegex = "(" + instructions.join('|') + ")", + instructionOnlyLine = new RegExp(instructionRegex + "\\s*$", "i"), + instructionWithArguments = new RegExp(instructionRegex + "(\\s+)", "i"); + + CodeMirror.defineSimpleMode("dockerfile", { + start: [ + // Block comment: This is a line starting with a comment + { + regex: /#.*$/, + token: "comment" + }, + // Highlight an instruction without any arguments (for convenience) + { + regex: instructionOnlyLine, + token: "variable-2" + }, + // Highlight an instruction followed by arguments + { + regex: instructionWithArguments, + token: ["variable-2", null], + next: "arguments" + }, + { + regex: /./, + token: null + } + ], + arguments: [ + { + // Line comment without instruction arguments is an error + regex: /#.*$/, + token: "error", + next: "start" + }, + { + regex: /[^#]+\\$/, + token: null + }, + { + // Match everything except for the inline comment + regex: /[^#]+/, + token: null, + next: "start" + }, + { + regex: /$/, + token: null, + next: "start" + }, + // Fail safe return to start + { + token: null, + next: "start" + } + ] + }); + + CodeMirror.defineMIME("text/x-dockerfile", "dockerfile"); +}); diff --git a/rhodecode/public/js/mode/dtd/dtd.js b/rhodecode/public/js/mode/dtd/dtd.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/dtd/dtd.js @@ -0,0 +1,142 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + DTD mode + Ported to CodeMirror by Peter Kroon <plakroon@gmail.com> + Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues + GitHub: @peterkroon +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("dtd", function(config) { + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch == "<" && stream.eat("!") ) { + if (stream.eatWhile(/[\-]/)) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } else if (stream.eatWhile(/[\w]/)) return ret("keyword", "doindent"); + } else if (ch == "<" && stream.eat("?")) { //xml declaration + state.tokenize = inBlock("meta", "?>"); + return ret("meta", ch); + } else if (ch == "#" && stream.eatWhile(/[\w]/)) return ret("atom", "tag"); + else if (ch == "|") return ret("keyword", "seperator"); + else if (ch.match(/[\(\)\[\]\-\.,\+\?>]/)) return ret(null, ch);//if(ch === ">") return ret(null, "endtag"); else + else if (ch.match(/[\[\]]/)) return ret("rule", ch); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (stream.eatWhile(/[a-zA-Z\?\+\d]/)) { + var sc = stream.current(); + if( sc.substr(sc.length-1,sc.length).match(/\?|\+/) !== null )stream.backUp(1); + return ret("tag", "tag"); + } else if (ch == "%" || ch == "*" ) return ret("number", "number"); + else { + stream.eatWhile(/[\w\\\-_%.{,]/); + return ret(null, null); + } + } + + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = tokenBase; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return ret("string", "tag"); + }; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = tokenBase; + break; + } + stream.next(); + } + return style; + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + stack: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + var context = state.stack[state.stack.length-1]; + if (stream.current() == "[" || type === "doindent" || type == "[") state.stack.push("rule"); + else if (type === "endtag") state.stack[state.stack.length-1] = "endtag"; + else if (stream.current() == "]" || type == "]" || (type == ">" && context == "rule")) state.stack.pop(); + else if (type == "[") state.stack.push("["); + return style; + }, + + indent: function(state, textAfter) { + var n = state.stack.length; + + if( textAfter.match(/\]\s+|\]/) )n=n-1; + else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){ + if(textAfter.substr(0,1) === "<")n; + else if( type == "doindent" && textAfter.length > 1 )n; + else if( type == "doindent")n--; + else if( type == ">" && textAfter.length > 1)n; + else if( type == "tag" && textAfter !== ">")n; + else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--; + else if( type == "tag")n++; + else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--; + else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule")n; + else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1; + else if( textAfter === ">")n; + else n=n-1; + //over rule them all + if(type == null || type == "]")n--; + } + + return state.baseIndent + n * indentUnit; + }, + + electricChars: "]>" + }; +}); + +CodeMirror.defineMIME("application/xml-dtd", "dtd"); + +}); diff --git a/rhodecode/public/js/mode/dylan/dylan.js b/rhodecode/public/js/mode/dylan/dylan.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/dylan/dylan.js @@ -0,0 +1,291 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("dylan", function(_config) { + // Words + var words = { + // Words that introduce unnamed definitions like "define interface" + unnamedDefinition: ["interface"], + + // Words that introduce simple named definitions like "define library" + namedDefinition: ["module", "library", "macro", + "C-struct", "C-union", + "C-function", "C-callable-wrapper" + ], + + // Words that introduce type definitions like "define class". + // These are also parameterized like "define method" and are + // appended to otherParameterizedDefinitionWords + typeParameterizedDefinition: ["class", "C-subtype", "C-mapped-subtype"], + + // Words that introduce trickier definitions like "define method". + // These require special definitions to be added to startExpressions + otherParameterizedDefinition: ["method", "function", + "C-variable", "C-address" + ], + + // Words that introduce module constant definitions. + // These must also be simple definitions and are + // appended to otherSimpleDefinitionWords + constantSimpleDefinition: ["constant"], + + // Words that introduce module variable definitions. + // These must also be simple definitions and are + // appended to otherSimpleDefinitionWords + variableSimpleDefinition: ["variable"], + + // Other words that introduce simple definitions + // (without implicit bodies). + otherSimpleDefinition: ["generic", "domain", + "C-pointer-type", + "table" + ], + + // Words that begin statements with implicit bodies. + statement: ["if", "block", "begin", "method", "case", + "for", "select", "when", "unless", "until", + "while", "iterate", "profiling", "dynamic-bind" + ], + + // Patterns that act as separators in compound statements. + // This may include any general pattern that must be indented + // specially. + separator: ["finally", "exception", "cleanup", "else", + "elseif", "afterwards" + ], + + // Keywords that do not require special indentation handling, + // but which should be highlighted + other: ["above", "below", "by", "from", "handler", "in", + "instance", "let", "local", "otherwise", "slot", + "subclass", "then", "to", "keyed-by", "virtual" + ], + + // Condition signaling function calls + signalingCalls: ["signal", "error", "cerror", + "break", "check-type", "abort" + ] + }; + + words["otherDefinition"] = + words["unnamedDefinition"] + .concat(words["namedDefinition"]) + .concat(words["otherParameterizedDefinition"]); + + words["definition"] = + words["typeParameterizedDefinition"] + .concat(words["otherDefinition"]); + + words["parameterizedDefinition"] = + words["typeParameterizedDefinition"] + .concat(words["otherParameterizedDefinition"]); + + words["simpleDefinition"] = + words["constantSimpleDefinition"] + .concat(words["variableSimpleDefinition"]) + .concat(words["otherSimpleDefinition"]); + + words["keyword"] = + words["statement"] + .concat(words["separator"]) + .concat(words["other"]); + + // Patterns + var symbolPattern = "[-_a-zA-Z?!*@<>$%]+"; + var symbol = new RegExp("^" + symbolPattern); + var patterns = { + // Symbols with special syntax + symbolKeyword: symbolPattern + ":", + symbolClass: "<" + symbolPattern + ">", + symbolGlobal: "\\*" + symbolPattern + "\\*", + symbolConstant: "\\$" + symbolPattern + }; + var patternStyles = { + symbolKeyword: "atom", + symbolClass: "tag", + symbolGlobal: "variable-2", + symbolConstant: "variable-3" + }; + + // Compile all patterns to regular expressions + for (var patternName in patterns) + if (patterns.hasOwnProperty(patternName)) + patterns[patternName] = new RegExp("^" + patterns[patternName]); + + // Names beginning "with-" and "without-" are commonly + // used as statement macro + patterns["keyword"] = [/^with(?:out)?-[-_a-zA-Z?!*@<>$%]+/]; + + var styles = {}; + styles["keyword"] = "keyword"; + styles["definition"] = "def"; + styles["simpleDefinition"] = "def"; + styles["signalingCalls"] = "builtin"; + + // protected words lookup table + var wordLookup = {}; + var styleLookup = {}; + + [ + "keyword", + "definition", + "simpleDefinition", + "signalingCalls" + ].forEach(function(type) { + words[type].forEach(function(word) { + wordLookup[word] = type; + styleLookup[word] = styles[type]; + }); + }); + + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function tokenBase(stream, state) { + // String + var ch = stream.peek(); + if (ch == "'" || ch == '"') { + stream.next(); + return chain(stream, state, tokenString(ch, "string")); + } + // Comment + else if (ch == "/") { + stream.next(); + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } else { + stream.skipTo(" "); + return "operator"; + } + } + // Decimal + else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/); + return "number"; + } + // Hash + else if (ch == "#") { + stream.next(); + // Symbol with string syntax + ch = stream.peek(); + if (ch == '"') { + stream.next(); + return chain(stream, state, tokenString('"', "string-2")); + } + // Binary number + else if (ch == "b") { + stream.next(); + stream.eatWhile(/[01]/); + return "number"; + } + // Hex number + else if (ch == "x") { + stream.next(); + stream.eatWhile(/[\da-f]/i); + return "number"; + } + // Octal number + else if (ch == "o") { + stream.next(); + stream.eatWhile(/[0-7]/); + return "number"; + } + // Hash symbol + else { + stream.eatWhile(/[-a-zA-Z]/); + return "keyword"; + } + } else if (stream.match("end")) { + return "keyword"; + } + for (var name in patterns) { + if (patterns.hasOwnProperty(name)) { + var pattern = patterns[name]; + if ((pattern instanceof Array && pattern.some(function(p) { + return stream.match(p); + })) || stream.match(pattern)) + return patternStyles[name]; + } + } + if (stream.match("define")) { + return "def"; + } else { + stream.eatWhile(/[\w\-]/); + // Keyword + if (wordLookup[stream.current()]) { + return styleLookup[stream.current()]; + } else if (stream.current().match(symbol)) { + return "variable"; + } else { + stream.next(); + return "variable-2"; + } + } + } + + function tokenComment(stream, state) { + var maybeEnd = false, + ch; + while ((ch = stream.next())) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(quote, style) { + return function(stream, state) { + var next, end = false; + while ((next = stream.next()) != null) { + if (next == quote) { + end = true; + break; + } + } + if (end) + state.tokenize = tokenBase; + return style; + }; + } + + // Interface + return { + startState: function() { + return { + tokenize: tokenBase, + currentIndent: 0 + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) + return null; + var style = state.tokenize(stream, state); + return style; + }, + blockCommentStart: "/*", + blockCommentEnd: "*/" + }; +}); + +CodeMirror.defineMIME("text/x-dylan", "dylan"); + +}); diff --git a/rhodecode/public/js/mode/ebnf/ebnf.js b/rhodecode/public/js/mode/ebnf/ebnf.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ebnf/ebnf.js @@ -0,0 +1,195 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("ebnf", function (config) { + var commentType = {slash: 0, parenthesis: 1}; + var stateType = {comment: 0, _string: 1, characterClass: 2}; + var bracesMode = null; + + if (config.bracesMode) + bracesMode = CodeMirror.getMode(config, config.bracesMode); + + return { + startState: function () { + return { + stringType: null, + commentType: null, + braced: 0, + lhs: true, + localState: null, + stack: [], + inDefinition: false + }; + }, + token: function (stream, state) { + if (!stream) return; + + //check for state changes + if (state.stack.length === 0) { + //strings + if ((stream.peek() == '"') || (stream.peek() == "'")) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.stack.unshift(stateType._string); + } else if (stream.match(/^\/\*/)) { //comments starting with /* + state.stack.unshift(stateType.comment); + state.commentType = commentType.slash; + } else if (stream.match(/^\(\*/)) { //comments starting with (* + state.stack.unshift(stateType.comment); + state.commentType = commentType.parenthesis; + } + } + + //return state + //stack has + switch (state.stack[0]) { + case stateType._string: + while (state.stack[0] === stateType._string && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.stack.shift(); // Clear flag + } else if (stream.peek() === "\\") { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + + case stateType.comment: + while (state.stack[0] === stateType.comment && !stream.eol()) { + if (state.commentType === commentType.slash && stream.match(/\*\//)) { + state.stack.shift(); // Clear flag + state.commentType = null; + } else if (state.commentType === commentType.parenthesis && stream.match(/\*\)/)) { + state.stack.shift(); // Clear flag + state.commentType = null; + } else { + stream.match(/^.[^\*]*/); + } + } + return "comment"; + + case stateType.characterClass: + while (state.stack[0] === stateType.characterClass && !stream.eol()) { + if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) { + state.stack.shift(); + } + } + return "operator"; + } + + var peek = stream.peek(); + + if (bracesMode !== null && (state.braced || peek === "{")) { + if (state.localState === null) + state.localState = bracesMode.startState(); + + var token = bracesMode.token(stream, state.localState), + text = stream.current(); + + if (!token) { + for (var i = 0; i < text.length; i++) { + if (text[i] === "{") { + if (state.braced === 0) { + token = "matchingbracket"; + } + state.braced++; + } else if (text[i] === "}") { + state.braced--; + if (state.braced === 0) { + token = "matchingbracket"; + } + } + } + } + return token; + } + + //no stack + switch (peek) { + case "[": + stream.next(); + state.stack.unshift(stateType.characterClass); + return "bracket"; + case ":": + case "|": + case ";": + stream.next(); + return "operator"; + case "%": + if (stream.match("%%")) { + return "header"; + } else if (stream.match(/[%][A-Za-z]+/)) { + return "keyword"; + } else if (stream.match(/[%][}]/)) { + return "matchingbracket"; + } + break; + case "/": + if (stream.match(/[\/][A-Za-z]+/)) { + return "keyword"; + } + case "\\": + if (stream.match(/[\][a-z]+/)) { + return "string-2"; + } + case ".": + if (stream.match(".")) { + return "atom"; + } + case "*": + case "-": + case "+": + case "^": + if (stream.match(peek)) { + return "atom"; + } + case "$": + if (stream.match("$$")) { + return "builtin"; + } else if (stream.match(/[$][0-9]+/)) { + return "variable-3"; + } + case "<": + if (stream.match(/<<[a-zA-Z_]+>>/)) { + return "builtin"; + } + } + + if (stream.match(/^\/\//)) { + stream.skipToEnd(); + return "comment"; + } else if (stream.match(/return/)) { + return "operator"; + } else if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) { + if (stream.match(/(?=[\(.])/)) { + return "variable"; + } else if (stream.match(/(?=[\s\n]*[:=])/)) { + return "def"; + } + return "variable-2"; + } else if (["[", "]", "(", ")"].indexOf(stream.peek()) != -1) { + stream.next(); + return "bracket"; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; + }); + + CodeMirror.defineMIME("text/x-ebnf", "ebnf"); +}); diff --git a/rhodecode/public/js/mode/ecl/ecl.js b/rhodecode/public/js/mode/ecl/ecl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ecl/ecl.js @@ -0,0 +1,206 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("ecl", function(config) { + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + function metaHook(stream, state) { + if (!state.startOfLine) return false; + stream.skipToEnd(); + return "meta"; + } + + var indentUnit = config.indentUnit; + var keyword = words("abs acos allnodes ascii asin asstring atan atan2 ave case choose choosen choosesets clustersize combine correlation cos cosh count covariance cron dataset dedup define denormalize distribute distributed distribution ebcdic enth error evaluate event eventextra eventname exists exp failcode failmessage fetch fromunicode getisvalid global graph group hash hash32 hash64 hashcrc hashmd5 having if index intformat isvalid iterate join keyunicode length library limit ln local log loop map matched matchlength matchposition matchtext matchunicode max merge mergejoin min nolocal nonempty normalize parse pipe power preload process project pull random range rank ranked realformat recordof regexfind regexreplace regroup rejected rollup round roundup row rowdiff sample set sin sinh sizeof soapcall sort sorted sqrt stepped stored sum table tan tanh thisnode topn tounicode transfer trim truncate typeof ungroup unicodeorder variance which workunit xmldecode xmlencode xmltext xmlunicode"); + var variable = words("apply assert build buildindex evaluate fail keydiff keypatch loadxml nothor notify output parallel sequential soapcall wait"); + var variable_2 = words("__compressed__ all and any as atmost before beginc++ best between case const counter csv descend encrypt end endc++ endmacro except exclusive expire export extend false few first flat from full function group header heading hole ifblock import in interface joined keep keyed last left limit load local locale lookup macro many maxcount maxlength min skew module named nocase noroot noscan nosort not of only opt or outer overwrite packed partition penalty physicallength pipe quote record relationship repeat return right scan self separator service shared skew skip sql store terminator thor threshold token transform trim true type unicodeorder unsorted validate virtual whole wild within xml xpath"); + var variable_3 = words("ascii big_endian boolean data decimal ebcdic integer pattern qstring real record rule set of string token udecimal unicode unsigned varstring varunicode"); + var builtin = words("checkpoint deprecated failcode failmessage failure global independent onwarning persist priority recovery stored success wait when"); + var blockKeywords = words("catch class do else finally for if switch try while"); + var atoms = words("true false null"); + var hooks = {"#": metaHook}; + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current().toLowerCase(); + if (keyword.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } else if (variable.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "variable"; + } else if (variable_2.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "variable-2"; + } else if (variable_3.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "variable-3"; + } else if (builtin.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "builtin"; + } else { //Data types are of from KEYWORD## + var i = cur.length - 1; + while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_')) + --i; + + if (i > 0) { + var cur2 = cur.substr(0, i + 1); + if (variable_3.propertyIsEnumerable(cur2)) { + if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement"; + return "variable-3"; + } + } + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return null; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !escaped) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return 0; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}" + }; +}); + +CodeMirror.defineMIME("text/x-ecl", "ecl"); + +}); diff --git a/rhodecode/public/js/mode/eiffel/eiffel.js b/rhodecode/public/js/mode/eiffel/eiffel.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/eiffel/eiffel.js @@ -0,0 +1,160 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("eiffel", function() { + function wordObj(words) { + var o = {}; + for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; + return o; + } + var keywords = wordObj([ + 'note', + 'across', + 'when', + 'variant', + 'until', + 'unique', + 'undefine', + 'then', + 'strip', + 'select', + 'retry', + 'rescue', + 'require', + 'rename', + 'reference', + 'redefine', + 'prefix', + 'once', + 'old', + 'obsolete', + 'loop', + 'local', + 'like', + 'is', + 'inspect', + 'infix', + 'include', + 'if', + 'frozen', + 'from', + 'external', + 'export', + 'ensure', + 'end', + 'elseif', + 'else', + 'do', + 'creation', + 'create', + 'check', + 'alias', + 'agent', + 'separate', + 'invariant', + 'inherit', + 'indexing', + 'feature', + 'expanded', + 'deferred', + 'class', + 'Void', + 'True', + 'Result', + 'Precursor', + 'False', + 'Current', + 'create', + 'attached', + 'detachable', + 'as', + 'and', + 'implies', + 'not', + 'or' + ]); + var operators = wordObj([":=", "and then","and", "or","<<",">>"]); + + function chain(newtok, stream, state) { + state.tokenize.push(newtok); + return newtok(stream, state); + } + + function tokenBase(stream, state) { + if (stream.eatSpace()) return null; + var ch = stream.next(); + if (ch == '"'||ch == "'") { + return chain(readQuoted(ch, "string"), stream, state); + } else if (ch == "-"&&stream.eat("-")) { + stream.skipToEnd(); + return "comment"; + } else if (ch == ":"&&stream.eat("=")) { + return "operator"; + } else if (/[0-9]/.test(ch)) { + stream.eatWhile(/[xXbBCc0-9\.]/); + stream.eat(/[\?\!]/); + return "ident"; + } else if (/[a-zA-Z_0-9]/.test(ch)) { + stream.eatWhile(/[a-zA-Z_0-9]/); + stream.eat(/[\?\!]/); + return "ident"; + } else if (/[=+\-\/*^%<>~]/.test(ch)) { + stream.eatWhile(/[=+\-\/*^%<>~]/); + return "operator"; + } else { + return null; + } + } + + function readQuoted(quote, style, unescaped) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize.pop(); + break; + } + escaped = !escaped && ch == "%"; + } + return style; + }; + } + + return { + startState: function() { + return {tokenize: [tokenBase]}; + }, + + token: function(stream, state) { + var style = state.tokenize[state.tokenize.length-1](stream, state); + if (style == "ident") { + var word = stream.current(); + style = keywords.propertyIsEnumerable(stream.current()) ? "keyword" + : operators.propertyIsEnumerable(stream.current()) ? "operator" + : /^[A-Z][A-Z_0-9]*$/g.test(word) ? "tag" + : /^0[bB][0-1]+$/g.test(word) ? "number" + : /^0[cC][0-7]+$/g.test(word) ? "number" + : /^0[xX][a-fA-F0-9]+$/g.test(word) ? "number" + : /^([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+)$/g.test(word) ? "number" + : /^[0-9]+$/g.test(word) ? "number" + : "variable"; + } + return style; + }, + lineComment: "--" + }; +}); + +CodeMirror.defineMIME("text/x-eiffel", "eiffel"); + +}); diff --git a/rhodecode/public/js/mode/elm/elm.js b/rhodecode/public/js/mode/elm/elm.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/elm/elm.js @@ -0,0 +1,205 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("elm", function() { + + function switchState(source, setState, f) { + setState(f); + return f(source, setState); + } + + // These should all be Unicode extended, as per the Haskell 2010 report + var smallRE = /[a-z_]/; + var largeRE = /[A-Z]/; + var digitRE = /[0-9]/; + var hexitRE = /[0-9A-Fa-f]/; + var octitRE = /[0-7]/; + var idRE = /[a-z_A-Z0-9\']/; + var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:\u03BB\u2192]/; + var specialRE = /[(),;[\]`{}]/; + var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer + + function normal() { + return function (source, setState) { + if (source.eatWhile(whiteCharRE)) { + return null; + } + + var ch = source.next(); + if (specialRE.test(ch)) { + if (ch == '{' && source.eat('-')) { + var t = "comment"; + if (source.eat('#')) t = "meta"; + return switchState(source, setState, ncomment(t, 1)); + } + return null; + } + + if (ch == '\'') { + if (source.eat('\\')) + source.next(); // should handle other escapes here + else + source.next(); + + if (source.eat('\'')) + return "string"; + return "error"; + } + + if (ch == '"') { + return switchState(source, setState, stringLiteral); + } + + if (largeRE.test(ch)) { + source.eatWhile(idRE); + if (source.eat('.')) + return "qualifier"; + return "variable-2"; + } + + if (smallRE.test(ch)) { + var isDef = source.pos === 1; + source.eatWhile(idRE); + return isDef ? "variable-3" : "variable"; + } + + if (digitRE.test(ch)) { + if (ch == '0') { + if (source.eat(/[xX]/)) { + source.eatWhile(hexitRE); // should require at least 1 + return "integer"; + } + if (source.eat(/[oO]/)) { + source.eatWhile(octitRE); // should require at least 1 + return "number"; + } + } + source.eatWhile(digitRE); + var t = "number"; + if (source.eat('.')) { + t = "number"; + source.eatWhile(digitRE); // should require at least 1 + } + if (source.eat(/[eE]/)) { + t = "number"; + source.eat(/[-+]/); + source.eatWhile(digitRE); // should require at least 1 + } + return t; + } + + if (symbolRE.test(ch)) { + if (ch == '-' && source.eat(/-/)) { + source.eatWhile(/-/); + if (!source.eat(symbolRE)) { + source.skipToEnd(); + return "comment"; + } + } + source.eatWhile(symbolRE); + return "builtin"; + } + + return "error"; + } + } + + function ncomment(type, nest) { + if (nest == 0) { + return normal(); + } + return function(source, setState) { + var currNest = nest; + while (!source.eol()) { + var ch = source.next(); + if (ch == '{' && source.eat('-')) { + ++currNest; + } else if (ch == '-' && source.eat('}')) { + --currNest; + if (currNest == 0) { + setState(normal()); + return type; + } + } + } + setState(ncomment(type, currNest)); + return type; + } + } + + function stringLiteral(source, setState) { + while (!source.eol()) { + var ch = source.next(); + if (ch == '"') { + setState(normal()); + return "string"; + } + if (ch == '\\') { + if (source.eol() || source.eat(whiteCharRE)) { + setState(stringGap); + return "string"; + } + if (!source.eat('&')) source.next(); // should handle other escapes here + } + } + setState(normal()); + return "error"; + } + + function stringGap(source, setState) { + if (source.eat('\\')) { + return switchState(source, setState, stringLiteral); + } + source.next(); + setState(normal()); + return "error"; + } + + + var wellKnownWords = (function() { + var wkw = {}; + + var keywords = [ + "case", "of", "as", + "if", "then", "else", + "let", "in", + "infix", "infixl", "infixr", + "type", "alias", + "input", "output", "foreign", "loopback", + "module", "where", "import", "exposing", + "_", "..", "|", ":", "=", "\\", "\"", "->", "<-" + ]; + + for (var i = keywords.length; i--;) + wkw[keywords[i]] = "keyword"; + + return wkw; + })(); + + + + return { + startState: function () { return { f: normal() }; }, + copyState: function (s) { return { f: s.f }; }, + + token: function(stream, state) { + var t = state.f(stream, function(s) { state.f = s; }); + var w = stream.current(); + return (wellKnownWords.hasOwnProperty(w)) ? wellKnownWords[w] : t; + } + }; + + }); + + CodeMirror.defineMIME("text/x-elm", "elm"); +})(); diff --git a/rhodecode/public/js/mode/erlang/erlang.js b/rhodecode/public/js/mode/erlang/erlang.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/erlang/erlang.js @@ -0,0 +1,622 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/*jshint unused:true, eqnull:true, curly:true, bitwise:true */ +/*jshint undef:true, latedef:true, trailing:true */ +/*global CodeMirror:true */ + +// erlang mode. +// tokenizer -> token types -> CodeMirror styles +// tokenizer maintains a parse stack +// indenter uses the parse stack + +// TODO indenter: +// bit syntax +// old guard/bif/conversion clashes (e.g. "float/1") +// type/spec/opaque + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMIME("text/x-erlang", "erlang"); + +CodeMirror.defineMode("erlang", function(cmCfg) { + "use strict"; + +///////////////////////////////////////////////////////////////////////////// +// constants + + var typeWords = [ + "-type", "-spec", "-export_type", "-opaque"]; + + var keywordWords = [ + "after","begin","catch","case","cond","end","fun","if", + "let","of","query","receive","try","when"]; + + var separatorRE = /[\->,;]/; + var separatorWords = [ + "->",";",","]; + + var operatorAtomWords = [ + "and","andalso","band","bnot","bor","bsl","bsr","bxor", + "div","not","or","orelse","rem","xor"]; + + var operatorSymbolRE = /[\+\-\*\/<>=\|:!]/; + var operatorSymbolWords = [ + "=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"]; + + var openParenRE = /[<\(\[\{]/; + var openParenWords = [ + "<<","(","[","{"]; + + var closeParenRE = /[>\)\]\}]/; + var closeParenWords = [ + "}","]",")",">>"]; + + var guardWords = [ + "is_atom","is_binary","is_bitstring","is_boolean","is_float", + "is_function","is_integer","is_list","is_number","is_pid", + "is_port","is_record","is_reference","is_tuple", + "atom","binary","bitstring","boolean","function","integer","list", + "number","pid","port","record","reference","tuple"]; + + var bifWords = [ + "abs","adler32","adler32_combine","alive","apply","atom_to_binary", + "atom_to_list","binary_to_atom","binary_to_existing_atom", + "binary_to_list","binary_to_term","bit_size","bitstring_to_list", + "byte_size","check_process_code","contact_binary","crc32", + "crc32_combine","date","decode_packet","delete_module", + "disconnect_node","element","erase","exit","float","float_to_list", + "garbage_collect","get","get_keys","group_leader","halt","hd", + "integer_to_list","internal_bif","iolist_size","iolist_to_binary", + "is_alive","is_atom","is_binary","is_bitstring","is_boolean", + "is_float","is_function","is_integer","is_list","is_number","is_pid", + "is_port","is_process_alive","is_record","is_reference","is_tuple", + "length","link","list_to_atom","list_to_binary","list_to_bitstring", + "list_to_existing_atom","list_to_float","list_to_integer", + "list_to_pid","list_to_tuple","load_module","make_ref","module_loaded", + "monitor_node","node","node_link","node_unlink","nodes","notalive", + "now","open_port","pid_to_list","port_close","port_command", + "port_connect","port_control","pre_loaded","process_flag", + "process_info","processes","purge_module","put","register", + "registered","round","self","setelement","size","spawn","spawn_link", + "spawn_monitor","spawn_opt","split_binary","statistics", + "term_to_binary","time","throw","tl","trunc","tuple_size", + "tuple_to_list","unlink","unregister","whereis"]; + +// upper case: [A-Z] [Ø-Þ] [À-Ö] +// lower case: [a-z] [ß-ö] [ø-ÿ] + var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/; + var escapesRE = + /[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/; + +///////////////////////////////////////////////////////////////////////////// +// tokenizer + + function tokenizer(stream,state) { + // in multi-line string + if (state.in_string) { + state.in_string = (!doubleQuote(stream)); + return rval(state,stream,"string"); + } + + // in multi-line atom + if (state.in_atom) { + state.in_atom = (!singleQuote(stream)); + return rval(state,stream,"atom"); + } + + // whitespace + if (stream.eatSpace()) { + return rval(state,stream,"whitespace"); + } + + // attributes and type specs + if (!peekToken(state) && + stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) { + if (is_member(stream.current(),typeWords)) { + return rval(state,stream,"type"); + }else{ + return rval(state,stream,"attribute"); + } + } + + var ch = stream.next(); + + // comment + if (ch == '%') { + stream.skipToEnd(); + return rval(state,stream,"comment"); + } + + // colon + if (ch == ":") { + return rval(state,stream,"colon"); + } + + // macro + if (ch == '?') { + stream.eatSpace(); + stream.eatWhile(anumRE); + return rval(state,stream,"macro"); + } + + // record + if (ch == "#") { + stream.eatSpace(); + stream.eatWhile(anumRE); + return rval(state,stream,"record"); + } + + // dollar escape + if (ch == "$") { + if (stream.next() == "\\" && !stream.match(escapesRE)) { + return rval(state,stream,"error"); + } + return rval(state,stream,"number"); + } + + // dot + if (ch == ".") { + return rval(state,stream,"dot"); + } + + // quoted atom + if (ch == '\'') { + if (!(state.in_atom = (!singleQuote(stream)))) { + if (stream.match(/\s*\/\s*[0-9]/,false)) { + stream.match(/\s*\/\s*[0-9]/,true); + return rval(state,stream,"fun"); // 'f'/0 style fun + } + if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) { + return rval(state,stream,"function"); + } + } + return rval(state,stream,"atom"); + } + + // string + if (ch == '"') { + state.in_string = (!doubleQuote(stream)); + return rval(state,stream,"string"); + } + + // variable + if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) { + stream.eatWhile(anumRE); + return rval(state,stream,"variable"); + } + + // atom/keyword/BIF/function + if (/[a-z_ß-öø-ÿ]/.test(ch)) { + stream.eatWhile(anumRE); + + if (stream.match(/\s*\/\s*[0-9]/,false)) { + stream.match(/\s*\/\s*[0-9]/,true); + return rval(state,stream,"fun"); // f/0 style fun + } + + var w = stream.current(); + + if (is_member(w,keywordWords)) { + return rval(state,stream,"keyword"); + }else if (is_member(w,operatorAtomWords)) { + return rval(state,stream,"operator"); + }else if (stream.match(/\s*\(/,false)) { + // 'put' and 'erlang:put' are bifs, 'foo:put' is not + if (is_member(w,bifWords) && + ((peekToken(state).token != ":") || + (peekToken(state,2).token == "erlang"))) { + return rval(state,stream,"builtin"); + }else if (is_member(w,guardWords)) { + return rval(state,stream,"guard"); + }else{ + return rval(state,stream,"function"); + } + }else if (is_member(w,operatorAtomWords)) { + return rval(state,stream,"operator"); + }else if (lookahead(stream) == ":") { + if (w == "erlang") { + return rval(state,stream,"builtin"); + } else { + return rval(state,stream,"function"); + } + }else if (is_member(w,["true","false"])) { + return rval(state,stream,"boolean"); + }else if (is_member(w,["true","false"])) { + return rval(state,stream,"boolean"); + }else{ + return rval(state,stream,"atom"); + } + } + + // number + var digitRE = /[0-9]/; + var radixRE = /[0-9a-zA-Z]/; // 36#zZ style int + if (digitRE.test(ch)) { + stream.eatWhile(digitRE); + if (stream.eat('#')) { // 36#aZ style integer + if (!stream.eatWhile(radixRE)) { + stream.backUp(1); //"36#" - syntax error + } + } else if (stream.eat('.')) { // float + if (!stream.eatWhile(digitRE)) { + stream.backUp(1); // "3." - probably end of function + } else { + if (stream.eat(/[eE]/)) { // float with exponent + if (stream.eat(/[-+]/)) { + if (!stream.eatWhile(digitRE)) { + stream.backUp(2); // "2e-" - syntax error + } + } else { + if (!stream.eatWhile(digitRE)) { + stream.backUp(1); // "2e" - syntax error + } + } + } + } + } + return rval(state,stream,"number"); // normal integer + } + + // open parens + if (nongreedy(stream,openParenRE,openParenWords)) { + return rval(state,stream,"open_paren"); + } + + // close parens + if (nongreedy(stream,closeParenRE,closeParenWords)) { + return rval(state,stream,"close_paren"); + } + + // separators + if (greedy(stream,separatorRE,separatorWords)) { + return rval(state,stream,"separator"); + } + + // operators + if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) { + return rval(state,stream,"operator"); + } + + return rval(state,stream,null); + } + +///////////////////////////////////////////////////////////////////////////// +// utilities + function nongreedy(stream,re,words) { + if (stream.current().length == 1 && re.test(stream.current())) { + stream.backUp(1); + while (re.test(stream.peek())) { + stream.next(); + if (is_member(stream.current(),words)) { + return true; + } + } + stream.backUp(stream.current().length-1); + } + return false; + } + + function greedy(stream,re,words) { + if (stream.current().length == 1 && re.test(stream.current())) { + while (re.test(stream.peek())) { + stream.next(); + } + while (0 < stream.current().length) { + if (is_member(stream.current(),words)) { + return true; + }else{ + stream.backUp(1); + } + } + stream.next(); + } + return false; + } + + function doubleQuote(stream) { + return quote(stream, '"', '\\'); + } + + function singleQuote(stream) { + return quote(stream,'\'','\\'); + } + + function quote(stream,quoteChar,escapeChar) { + while (!stream.eol()) { + var ch = stream.next(); + if (ch == quoteChar) { + return true; + }else if (ch == escapeChar) { + stream.next(); + } + } + return false; + } + + function lookahead(stream) { + var m = stream.match(/([\n\s]+|%[^\n]*\n)*(.)/,false); + return m ? m.pop() : ""; + } + + function is_member(element,list) { + return (-1 < list.indexOf(element)); + } + + function rval(state,stream,type) { + + // parse stack + pushToken(state,realToken(type,stream)); + + // map erlang token type to CodeMirror style class + // erlang -> CodeMirror tag + switch (type) { + case "atom": return "atom"; + case "attribute": return "attribute"; + case "boolean": return "atom"; + case "builtin": return "builtin"; + case "close_paren": return null; + case "colon": return null; + case "comment": return "comment"; + case "dot": return null; + case "error": return "error"; + case "fun": return "meta"; + case "function": return "tag"; + case "guard": return "property"; + case "keyword": return "keyword"; + case "macro": return "variable-2"; + case "number": return "number"; + case "open_paren": return null; + case "operator": return "operator"; + case "record": return "bracket"; + case "separator": return null; + case "string": return "string"; + case "type": return "def"; + case "variable": return "variable"; + default: return null; + } + } + + function aToken(tok,col,ind,typ) { + return {token: tok, + column: col, + indent: ind, + type: typ}; + } + + function realToken(type,stream) { + return aToken(stream.current(), + stream.column(), + stream.indentation(), + type); + } + + function fakeToken(type) { + return aToken(type,0,0,type); + } + + function peekToken(state,depth) { + var len = state.tokenStack.length; + var dep = (depth ? depth : 1); + + if (len < dep) { + return false; + }else{ + return state.tokenStack[len-dep]; + } + } + + function pushToken(state,token) { + + if (!(token.type == "comment" || token.type == "whitespace")) { + state.tokenStack = maybe_drop_pre(state.tokenStack,token); + state.tokenStack = maybe_drop_post(state.tokenStack); + } + } + + function maybe_drop_pre(s,token) { + var last = s.length-1; + + if (0 < last && s[last].type === "record" && token.type === "dot") { + s.pop(); + }else if (0 < last && s[last].type === "group") { + s.pop(); + s.push(token); + }else{ + s.push(token); + } + return s; + } + + function maybe_drop_post(s) { + var last = s.length-1; + + if (s[last].type === "dot") { + return []; + } + if (s[last].type === "fun" && s[last-1].token === "fun") { + return s.slice(0,last-1); + } + switch (s[s.length-1].token) { + case "}": return d(s,{g:["{"]}); + case "]": return d(s,{i:["["]}); + case ")": return d(s,{i:["("]}); + case ">>": return d(s,{i:["<<"]}); + case "end": return d(s,{i:["begin","case","fun","if","receive","try"]}); + case ",": return d(s,{e:["begin","try","when","->", + ",","(","[","{","<<"]}); + case "->": return d(s,{r:["when"], + m:["try","if","case","receive"]}); + case ";": return d(s,{E:["case","fun","if","receive","try","when"]}); + case "catch":return d(s,{e:["try"]}); + case "of": return d(s,{e:["case"]}); + case "after":return d(s,{e:["receive","try"]}); + default: return s; + } + } + + function d(stack,tt) { + // stack is a stack of Token objects. + // tt is an object; {type:tokens} + // type is a char, tokens is a list of token strings. + // The function returns (possibly truncated) stack. + // It will descend the stack, looking for a Token such that Token.token + // is a member of tokens. If it does not find that, it will normally (but + // see "E" below) return stack. If it does find a match, it will remove + // all the Tokens between the top and the matched Token. + // If type is "m", that is all it does. + // If type is "i", it will also remove the matched Token and the top Token. + // If type is "g", like "i", but add a fake "group" token at the top. + // If type is "r", it will remove the matched Token, but not the top Token. + // If type is "e", it will keep the matched Token but not the top Token. + // If type is "E", it behaves as for type "e", except if there is no match, + // in which case it will return an empty stack. + + for (var type in tt) { + var len = stack.length-1; + var tokens = tt[type]; + for (var i = len-1; -1 < i ; i--) { + if (is_member(stack[i].token,tokens)) { + var ss = stack.slice(0,i); + switch (type) { + case "m": return ss.concat(stack[i]).concat(stack[len]); + case "r": return ss.concat(stack[len]); + case "i": return ss; + case "g": return ss.concat(fakeToken("group")); + case "E": return ss.concat(stack[i]); + case "e": return ss.concat(stack[i]); + } + } + } + } + return (type == "E" ? [] : stack); + } + +///////////////////////////////////////////////////////////////////////////// +// indenter + + function indenter(state,textAfter) { + var t; + var unit = cmCfg.indentUnit; + var wordAfter = wordafter(textAfter); + var currT = peekToken(state,1); + var prevT = peekToken(state,2); + + if (state.in_string || state.in_atom) { + return CodeMirror.Pass; + }else if (!prevT) { + return 0; + }else if (currT.token == "when") { + return currT.column+unit; + }else if (wordAfter === "when" && prevT.type === "function") { + return prevT.indent+unit; + }else if (wordAfter === "(" && currT.token === "fun") { + return currT.column+3; + }else if (wordAfter === "catch" && (t = getToken(state,["try"]))) { + return t.column; + }else if (is_member(wordAfter,["end","after","of"])) { + t = getToken(state,["begin","case","fun","if","receive","try"]); + return t ? t.column : CodeMirror.Pass; + }else if (is_member(wordAfter,closeParenWords)) { + t = getToken(state,openParenWords); + return t ? t.column : CodeMirror.Pass; + }else if (is_member(currT.token,[",","|","||"]) || + is_member(wordAfter,[",","|","||"])) { + t = postcommaToken(state); + return t ? t.column+t.token.length : unit; + }else if (currT.token == "->") { + if (is_member(prevT.token, ["receive","case","if","try"])) { + return prevT.column+unit+unit; + }else{ + return prevT.column+unit; + } + }else if (is_member(currT.token,openParenWords)) { + return currT.column+currT.token.length; + }else{ + t = defaultToken(state); + return truthy(t) ? t.column+unit : 0; + } + } + + function wordafter(str) { + var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/); + + return truthy(m) && (m.index === 0) ? m[0] : ""; + } + + function postcommaToken(state) { + var objs = state.tokenStack.slice(0,-1); + var i = getTokenIndex(objs,"type",["open_paren"]); + + return truthy(objs[i]) ? objs[i] : false; + } + + function defaultToken(state) { + var objs = state.tokenStack; + var stop = getTokenIndex(objs,"type",["open_paren","separator","keyword"]); + var oper = getTokenIndex(objs,"type",["operator"]); + + if (truthy(stop) && truthy(oper) && stop < oper) { + return objs[stop+1]; + } else if (truthy(stop)) { + return objs[stop]; + } else { + return false; + } + } + + function getToken(state,tokens) { + var objs = state.tokenStack; + var i = getTokenIndex(objs,"token",tokens); + + return truthy(objs[i]) ? objs[i] : false; + } + + function getTokenIndex(objs,propname,propvals) { + + for (var i = objs.length-1; -1 < i ; i--) { + if (is_member(objs[i][propname],propvals)) { + return i; + } + } + return false; + } + + function truthy(x) { + return (x !== false) && (x != null); + } + +///////////////////////////////////////////////////////////////////////////// +// this object defines the mode + + return { + startState: + function() { + return {tokenStack: [], + in_string: false, + in_atom: false}; + }, + + token: + function(stream, state) { + return tokenizer(stream, state); + }, + + indent: + function(state, textAfter) { + return indenter(state,textAfter); + }, + + lineComment: "%" + }; +}); + +}); diff --git a/rhodecode/public/js/mode/factor/factor.js b/rhodecode/public/js/mode/factor/factor.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/factor/factor.js @@ -0,0 +1,83 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Factor syntax highlight - simple mode +// +// by Dimage Sapelkin (https://github.com/kerabromsmu) + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../addon/mode/simple")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../addon/mode/simple"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineSimpleMode("factor", { + // The start state contains the rules that are intially used + start: [ + // comments + {regex: /#?!.*/, token: "comment"}, + // strings """, multiline --> state + {regex: /"""/, token: "string", next: "string3"}, + {regex: /"/, token: "string", next: "string"}, + // numbers: dec, hex, unicode, bin, fractional, complex + {regex: /(?:[+-]?)(?:0x[\d,a-f]+)|(?:0o[0-7]+)|(?:0b[0,1]+)|(?:\d+.?\d*)/, token: "number"}, + //{regex: /[+-]?/} //fractional + // definition: defining word, defined word, etc + {regex: /(\:)(\s+)(\S+)(\s+)(\()/, token: ["keyword", null, "def", null, "keyword"], next: "stack"}, + // vocabulary using --> state + {regex: /USING\:/, token: "keyword", next: "vocabulary"}, + // vocabulary definition/use + {regex: /(USE\:|IN\:)(\s+)(\S+)/, token: ["keyword", null, "variable-2"]}, + // <constructors> + {regex: /<\S+>/, token: "builtin"}, + // "keywords", incl. ; t f . [ ] { } defining words + {regex: /;|t|f|if|\.|\[|\]|\{|\}|MAIN:/, token: "keyword"}, + // any id (?) + {regex: /\S+/, token: "variable"}, + + { + regex: /./, + token: null + } + ], + vocabulary: [ + {regex: /;/, token: "keyword", next: "start"}, + {regex: /\S+/, token: "variable-2"}, + { + regex: /./, + token: null + } + ], + string: [ + {regex: /(?:[^\\]|\\.)*?"/, token: "string", next: "start"}, + {regex: /.*/, token: "string"} + ], + string3: [ + {regex: /(?:[^\\]|\\.)*?"""/, token: "string", next: "start"}, + {regex: /.*/, token: "string"} + ], + stack: [ + {regex: /\)/, token: "meta", next: "start"}, + {regex: /--/, token: "meta"}, + {regex: /\S+/, token: "variable-3"}, + { + regex: /./, + token: null + } + ], + // The meta property contains global information about the mode. It + // can contain properties like lineComment, which are supported by + // all modes, and also directives like dontIndentStates, which are + // specific to simple modes. + meta: { + dontIndentStates: ["start", "vocabulary", "string", "string3", "stack"], + lineComment: [ "!", "#!" ] + } + }); + + CodeMirror.defineMIME("text/x-factor", "factor"); +}); diff --git a/rhodecode/public/js/mode/forth/forth.js b/rhodecode/public/js/mode/forth/forth.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/forth/forth.js @@ -0,0 +1,180 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Author: Aliaksei Chapyzhenka + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function toWordList(words) { + var ret = []; + words.split(' ').forEach(function(e){ + ret.push({name: e}); + }); + return ret; + } + + var coreWordList = toWordList( +'INVERT AND OR XOR\ + 2* 2/ LSHIFT RSHIFT\ + 0= = 0< < > U< MIN MAX\ + 2DROP 2DUP 2OVER 2SWAP ?DUP DEPTH DROP DUP OVER ROT SWAP\ + >R R> R@\ + + - 1+ 1- ABS NEGATE\ + S>D * M* UM*\ + FM/MOD SM/REM UM/MOD */ */MOD / /MOD MOD\ + HERE , @ ! CELL+ CELLS C, C@ C! CHARS 2@ 2!\ + ALIGN ALIGNED +! ALLOT\ + CHAR [CHAR] [ ] BL\ + FIND EXECUTE IMMEDIATE COUNT LITERAL STATE\ + ; DOES> >BODY\ + EVALUATE\ + SOURCE >IN\ + <# # #S #> HOLD SIGN BASE >NUMBER HEX DECIMAL\ + FILL MOVE\ + . CR EMIT SPACE SPACES TYPE U. .R U.R\ + ACCEPT\ + TRUE FALSE\ + <> U> 0<> 0>\ + NIP TUCK ROLL PICK\ + 2>R 2R@ 2R>\ + WITHIN UNUSED MARKER\ + I J\ + TO\ + COMPILE, [COMPILE]\ + SAVE-INPUT RESTORE-INPUT\ + PAD ERASE\ + 2LITERAL DNEGATE\ + D- D+ D0< D0= D2* D2/ D< D= DMAX DMIN D>S DABS\ + M+ M*/ D. D.R 2ROT DU<\ + CATCH THROW\ + FREE RESIZE ALLOCATE\ + CS-PICK CS-ROLL\ + GET-CURRENT SET-CURRENT FORTH-WORDLIST GET-ORDER SET-ORDER\ + PREVIOUS SEARCH-WORDLIST WORDLIST FIND ALSO ONLY FORTH DEFINITIONS ORDER\ + -TRAILING /STRING SEARCH COMPARE CMOVE CMOVE> BLANK SLITERAL'); + + var immediateWordList = toWordList('IF ELSE THEN BEGIN WHILE REPEAT UNTIL RECURSE [IF] [ELSE] [THEN] ?DO DO LOOP +LOOP UNLOOP LEAVE EXIT AGAIN CASE OF ENDOF ENDCASE'); + + CodeMirror.defineMode('forth', function() { + function searchWordList (wordList, word) { + var i; + for (i = wordList.length - 1; i >= 0; i--) { + if (wordList[i].name === word.toUpperCase()) { + return wordList[i]; + } + } + return undefined; + } + return { + startState: function() { + return { + state: '', + base: 10, + coreWordList: coreWordList, + immediateWordList: immediateWordList, + wordList: [] + }; + }, + token: function (stream, stt) { + var mat; + if (stream.eatSpace()) { + return null; + } + if (stt.state === '') { // interpretation + if (stream.match(/^(\]|:NONAME)(\s|$)/i)) { + stt.state = ' compilation'; + return 'builtin compilation'; + } + mat = stream.match(/^(\:)\s+(\S+)(\s|$)+/); + if (mat) { + stt.wordList.push({name: mat[2].toUpperCase()}); + stt.state = ' compilation'; + return 'def' + stt.state; + } + mat = stream.match(/^(VARIABLE|2VARIABLE|CONSTANT|2CONSTANT|CREATE|POSTPONE|VALUE|WORD)\s+(\S+)(\s|$)+/i); + if (mat) { + stt.wordList.push({name: mat[2].toUpperCase()}); + return 'def' + stt.state; + } + mat = stream.match(/^(\'|\[\'\])\s+(\S+)(\s|$)+/); + if (mat) { + return 'builtin' + stt.state; + } + } else { // compilation + // ; [ + if (stream.match(/^(\;|\[)(\s)/)) { + stt.state = ''; + stream.backUp(1); + return 'builtin compilation'; + } + if (stream.match(/^(\;|\[)($)/)) { + stt.state = ''; + return 'builtin compilation'; + } + if (stream.match(/^(POSTPONE)\s+\S+(\s|$)+/)) { + return 'builtin'; + } + } + + // dynamic wordlist + mat = stream.match(/^(\S+)(\s+|$)/); + if (mat) { + if (searchWordList(stt.wordList, mat[1]) !== undefined) { + return 'variable' + stt.state; + } + + // comments + if (mat[1] === '\\') { + stream.skipToEnd(); + return 'comment' + stt.state; + } + + // core words + if (searchWordList(stt.coreWordList, mat[1]) !== undefined) { + return 'builtin' + stt.state; + } + if (searchWordList(stt.immediateWordList, mat[1]) !== undefined) { + return 'keyword' + stt.state; + } + + if (mat[1] === '(') { + stream.eatWhile(function (s) { return s !== ')'; }); + stream.eat(')'); + return 'comment' + stt.state; + } + + // // strings + if (mat[1] === '.(') { + stream.eatWhile(function (s) { return s !== ')'; }); + stream.eat(')'); + return 'string' + stt.state; + } + if (mat[1] === 'S"' || mat[1] === '."' || mat[1] === 'C"') { + stream.eatWhile(function (s) { return s !== '"'; }); + stream.eat('"'); + return 'string' + stt.state; + } + + // numbers + if (mat[1] - 0xfffffffff) { + return 'number' + stt.state; + } + // if (mat[1].match(/^[-+]?[0-9]+\.[0-9]*/)) { + // return 'number' + stt.state; + // } + + return 'atom' + stt.state; + } + } + }; + }); + CodeMirror.defineMIME("text/x-forth", "forth"); +}); diff --git a/rhodecode/public/js/mode/fortran/fortran.js b/rhodecode/public/js/mode/fortran/fortran.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/fortran/fortran.js @@ -0,0 +1,188 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("fortran", function() { + function words(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var keywords = words([ + "abstract", "accept", "allocatable", "allocate", + "array", "assign", "asynchronous", "backspace", + "bind", "block", "byte", "call", "case", + "class", "close", "common", "contains", + "continue", "cycle", "data", "deallocate", + "decode", "deferred", "dimension", "do", + "elemental", "else", "encode", "end", + "endif", "entry", "enumerator", "equivalence", + "exit", "external", "extrinsic", "final", + "forall", "format", "function", "generic", + "go", "goto", "if", "implicit", "import", "include", + "inquire", "intent", "interface", "intrinsic", + "module", "namelist", "non_intrinsic", + "non_overridable", "none", "nopass", + "nullify", "open", "optional", "options", + "parameter", "pass", "pause", "pointer", + "print", "private", "program", "protected", + "public", "pure", "read", "recursive", "result", + "return", "rewind", "save", "select", "sequence", + "stop", "subroutine", "target", "then", "to", "type", + "use", "value", "volatile", "where", "while", + "write"]); + var builtins = words(["abort", "abs", "access", "achar", "acos", + "adjustl", "adjustr", "aimag", "aint", "alarm", + "all", "allocated", "alog", "amax", "amin", + "amod", "and", "anint", "any", "asin", + "associated", "atan", "besj", "besjn", "besy", + "besyn", "bit_size", "btest", "cabs", "ccos", + "ceiling", "cexp", "char", "chdir", "chmod", + "clog", "cmplx", "command_argument_count", + "complex", "conjg", "cos", "cosh", "count", + "cpu_time", "cshift", "csin", "csqrt", "ctime", + "c_funloc", "c_loc", "c_associated", "c_null_ptr", + "c_null_funptr", "c_f_pointer", "c_null_char", + "c_alert", "c_backspace", "c_form_feed", + "c_new_line", "c_carriage_return", + "c_horizontal_tab", "c_vertical_tab", "dabs", + "dacos", "dasin", "datan", "date_and_time", + "dbesj", "dbesj", "dbesjn", "dbesy", "dbesy", + "dbesyn", "dble", "dcos", "dcosh", "ddim", "derf", + "derfc", "dexp", "digits", "dim", "dint", "dlog", + "dlog", "dmax", "dmin", "dmod", "dnint", + "dot_product", "dprod", "dsign", "dsinh", + "dsin", "dsqrt", "dtanh", "dtan", "dtime", + "eoshift", "epsilon", "erf", "erfc", "etime", + "exit", "exp", "exponent", "extends_type_of", + "fdate", "fget", "fgetc", "float", "floor", + "flush", "fnum", "fputc", "fput", "fraction", + "fseek", "fstat", "ftell", "gerror", "getarg", + "get_command", "get_command_argument", + "get_environment_variable", "getcwd", + "getenv", "getgid", "getlog", "getpid", + "getuid", "gmtime", "hostnm", "huge", "iabs", + "iachar", "iand", "iargc", "ibclr", "ibits", + "ibset", "ichar", "idate", "idim", "idint", + "idnint", "ieor", "ierrno", "ifix", "imag", + "imagpart", "index", "int", "ior", "irand", + "isatty", "ishft", "ishftc", "isign", + "iso_c_binding", "is_iostat_end", "is_iostat_eor", + "itime", "kill", "kind", "lbound", "len", "len_trim", + "lge", "lgt", "link", "lle", "llt", "lnblnk", "loc", + "log", "logical", "long", "lshift", "lstat", "ltime", + "matmul", "max", "maxexponent", "maxloc", "maxval", + "mclock", "merge", "move_alloc", "min", "minexponent", + "minloc", "minval", "mod", "modulo", "mvbits", + "nearest", "new_line", "nint", "not", "or", "pack", + "perror", "precision", "present", "product", "radix", + "rand", "random_number", "random_seed", "range", + "real", "realpart", "rename", "repeat", "reshape", + "rrspacing", "rshift", "same_type_as", "scale", + "scan", "second", "selected_int_kind", + "selected_real_kind", "set_exponent", "shape", + "short", "sign", "signal", "sinh", "sin", "sleep", + "sngl", "spacing", "spread", "sqrt", "srand", "stat", + "sum", "symlnk", "system", "system_clock", "tan", + "tanh", "time", "tiny", "transfer", "transpose", + "trim", "ttynam", "ubound", "umask", "unlink", + "unpack", "verify", "xor", "zabs", "zcos", "zexp", + "zlog", "zsin", "zsqrt"]); + + var dataTypes = words(["c_bool", "c_char", "c_double", "c_double_complex", + "c_float", "c_float_complex", "c_funptr", "c_int", + "c_int16_t", "c_int32_t", "c_int64_t", "c_int8_t", + "c_int_fast16_t", "c_int_fast32_t", "c_int_fast64_t", + "c_int_fast8_t", "c_int_least16_t", "c_int_least32_t", + "c_int_least64_t", "c_int_least8_t", "c_intmax_t", + "c_intptr_t", "c_long", "c_long_double", + "c_long_double_complex", "c_long_long", "c_ptr", + "c_short", "c_signed_char", "c_size_t", "character", + "complex", "double", "integer", "logical", "real"]); + var isOperatorChar = /[+\-*&=<>\/\:]/; + var litOperator = new RegExp("(\.and\.|\.or\.|\.eq\.|\.lt\.|\.le\.|\.gt\.|\.ge\.|\.ne\.|\.not\.|\.eqv\.|\.neqv\.)", "i"); + + function tokenBase(stream, state) { + + if (stream.match(litOperator)){ + return 'operator'; + } + + var ch = stream.next(); + if (ch == "!") { + stream.skipToEnd(); + return "comment"; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]\(\),]/.test(ch)) { + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var word = stream.current().toLowerCase(); + + if (keywords.hasOwnProperty(word)){ + return 'keyword'; + } + if (builtins.hasOwnProperty(word) || dataTypes.hasOwnProperty(word)) { + return 'builtin'; + } + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end || !escaped) state.tokenize = null; + return "string"; + }; + } + + // Interface + + return { + startState: function() { + return {tokenize: null}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-fortran", "fortran"); + +}); diff --git a/rhodecode/public/js/mode/gas/gas.js b/rhodecode/public/js/mode/gas/gas.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/gas/gas.js @@ -0,0 +1,345 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("gas", function(_config, parserConfig) { + 'use strict'; + + // If an architecture is specified, its initialization function may + // populate this array with custom parsing functions which will be + // tried in the event that the standard functions do not find a match. + var custom = []; + + // The symbol used to start a line comment changes based on the target + // architecture. + // If no architecture is pased in "parserConfig" then only multiline + // comments will have syntax support. + var lineCommentStartSymbol = ""; + + // These directives are architecture independent. + // Machine specific directives should go in their respective + // architecture initialization function. + // Reference: + // http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops + var directives = { + ".abort" : "builtin", + ".align" : "builtin", + ".altmacro" : "builtin", + ".ascii" : "builtin", + ".asciz" : "builtin", + ".balign" : "builtin", + ".balignw" : "builtin", + ".balignl" : "builtin", + ".bundle_align_mode" : "builtin", + ".bundle_lock" : "builtin", + ".bundle_unlock" : "builtin", + ".byte" : "builtin", + ".cfi_startproc" : "builtin", + ".comm" : "builtin", + ".data" : "builtin", + ".def" : "builtin", + ".desc" : "builtin", + ".dim" : "builtin", + ".double" : "builtin", + ".eject" : "builtin", + ".else" : "builtin", + ".elseif" : "builtin", + ".end" : "builtin", + ".endef" : "builtin", + ".endfunc" : "builtin", + ".endif" : "builtin", + ".equ" : "builtin", + ".equiv" : "builtin", + ".eqv" : "builtin", + ".err" : "builtin", + ".error" : "builtin", + ".exitm" : "builtin", + ".extern" : "builtin", + ".fail" : "builtin", + ".file" : "builtin", + ".fill" : "builtin", + ".float" : "builtin", + ".func" : "builtin", + ".global" : "builtin", + ".gnu_attribute" : "builtin", + ".hidden" : "builtin", + ".hword" : "builtin", + ".ident" : "builtin", + ".if" : "builtin", + ".incbin" : "builtin", + ".include" : "builtin", + ".int" : "builtin", + ".internal" : "builtin", + ".irp" : "builtin", + ".irpc" : "builtin", + ".lcomm" : "builtin", + ".lflags" : "builtin", + ".line" : "builtin", + ".linkonce" : "builtin", + ".list" : "builtin", + ".ln" : "builtin", + ".loc" : "builtin", + ".loc_mark_labels" : "builtin", + ".local" : "builtin", + ".long" : "builtin", + ".macro" : "builtin", + ".mri" : "builtin", + ".noaltmacro" : "builtin", + ".nolist" : "builtin", + ".octa" : "builtin", + ".offset" : "builtin", + ".org" : "builtin", + ".p2align" : "builtin", + ".popsection" : "builtin", + ".previous" : "builtin", + ".print" : "builtin", + ".protected" : "builtin", + ".psize" : "builtin", + ".purgem" : "builtin", + ".pushsection" : "builtin", + ".quad" : "builtin", + ".reloc" : "builtin", + ".rept" : "builtin", + ".sbttl" : "builtin", + ".scl" : "builtin", + ".section" : "builtin", + ".set" : "builtin", + ".short" : "builtin", + ".single" : "builtin", + ".size" : "builtin", + ".skip" : "builtin", + ".sleb128" : "builtin", + ".space" : "builtin", + ".stab" : "builtin", + ".string" : "builtin", + ".struct" : "builtin", + ".subsection" : "builtin", + ".symver" : "builtin", + ".tag" : "builtin", + ".text" : "builtin", + ".title" : "builtin", + ".type" : "builtin", + ".uleb128" : "builtin", + ".val" : "builtin", + ".version" : "builtin", + ".vtable_entry" : "builtin", + ".vtable_inherit" : "builtin", + ".warning" : "builtin", + ".weak" : "builtin", + ".weakref" : "builtin", + ".word" : "builtin" + }; + + var registers = {}; + + function x86(_parserConfig) { + lineCommentStartSymbol = "#"; + + registers.ax = "variable"; + registers.eax = "variable-2"; + registers.rax = "variable-3"; + + registers.bx = "variable"; + registers.ebx = "variable-2"; + registers.rbx = "variable-3"; + + registers.cx = "variable"; + registers.ecx = "variable-2"; + registers.rcx = "variable-3"; + + registers.dx = "variable"; + registers.edx = "variable-2"; + registers.rdx = "variable-3"; + + registers.si = "variable"; + registers.esi = "variable-2"; + registers.rsi = "variable-3"; + + registers.di = "variable"; + registers.edi = "variable-2"; + registers.rdi = "variable-3"; + + registers.sp = "variable"; + registers.esp = "variable-2"; + registers.rsp = "variable-3"; + + registers.bp = "variable"; + registers.ebp = "variable-2"; + registers.rbp = "variable-3"; + + registers.ip = "variable"; + registers.eip = "variable-2"; + registers.rip = "variable-3"; + + registers.cs = "keyword"; + registers.ds = "keyword"; + registers.ss = "keyword"; + registers.es = "keyword"; + registers.fs = "keyword"; + registers.gs = "keyword"; + } + + function armv6(_parserConfig) { + // Reference: + // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf + lineCommentStartSymbol = "@"; + directives.syntax = "builtin"; + + registers.r0 = "variable"; + registers.r1 = "variable"; + registers.r2 = "variable"; + registers.r3 = "variable"; + registers.r4 = "variable"; + registers.r5 = "variable"; + registers.r6 = "variable"; + registers.r7 = "variable"; + registers.r8 = "variable"; + registers.r9 = "variable"; + registers.r10 = "variable"; + registers.r11 = "variable"; + registers.r12 = "variable"; + + registers.sp = "variable-2"; + registers.lr = "variable-2"; + registers.pc = "variable-2"; + registers.r13 = registers.sp; + registers.r14 = registers.lr; + registers.r15 = registers.pc; + + custom.push(function(ch, stream) { + if (ch === '#') { + stream.eatWhile(/\w/); + return "number"; + } + }); + } + + var arch = (parserConfig.architecture || "x86").toLowerCase(); + if (arch === "x86") { + x86(parserConfig); + } else if (arch === "arm" || arch === "armv6") { + armv6(parserConfig); + } + + function nextUntilUnescaped(stream, end) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next === end && !escaped) { + return false; + } + escaped = !escaped && next === "\\"; + } + return escaped; + } + + function clikeComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (ch === "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch === "*"); + } + return "comment"; + } + + return { + startState: function() { + return { + tokenize: null + }; + }, + + token: function(stream, state) { + if (state.tokenize) { + return state.tokenize(stream, state); + } + + if (stream.eatSpace()) { + return null; + } + + var style, cur, ch = stream.next(); + + if (ch === "/") { + if (stream.eat("*")) { + state.tokenize = clikeComment; + return clikeComment(stream, state); + } + } + + if (ch === lineCommentStartSymbol) { + stream.skipToEnd(); + return "comment"; + } + + if (ch === '"') { + nextUntilUnescaped(stream, '"'); + return "string"; + } + + if (ch === '.') { + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + style = directives[cur]; + return style || null; + } + + if (ch === '=') { + stream.eatWhile(/\w/); + return "tag"; + } + + if (ch === '{') { + return "braket"; + } + + if (ch === '}') { + return "braket"; + } + + if (/\d/.test(ch)) { + if (ch === "0" && stream.eat("x")) { + stream.eatWhile(/[0-9a-fA-F]/); + return "number"; + } + stream.eatWhile(/\d/); + return "number"; + } + + if (/\w/.test(ch)) { + stream.eatWhile(/\w/); + if (stream.eat(":")) { + return 'tag'; + } + cur = stream.current().toLowerCase(); + style = registers[cur]; + return style || null; + } + + for (var i = 0; i < custom.length; i++) { + style = custom[i](ch, stream, state); + if (style) { + return style; + } + } + }, + + lineComment: lineCommentStartSymbol, + blockCommentStart: "/*", + blockCommentEnd: "*/" + }; +}); + +}); diff --git a/rhodecode/public/js/mode/gfm/gfm.js b/rhodecode/public/js/mode/gfm/gfm.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/gfm/gfm.js @@ -0,0 +1,123 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("gfm", function(config, modeConfig) { + var codeDepth = 0; + function blankLine(state) { + state.code = false; + return null; + } + var gfmOverlay = { + startState: function() { + return { + code: false, + codeBlock: false, + ateSpace: false + }; + }, + copyState: function(s) { + return { + code: s.code, + codeBlock: s.codeBlock, + ateSpace: s.ateSpace + }; + }, + token: function(stream, state) { + state.combineTokens = null; + + // Hack to prevent formatting override inside code blocks (block and inline) + if (state.codeBlock) { + if (stream.match(/^```/)) { + state.codeBlock = false; + return null; + } + stream.skipToEnd(); + return null; + } + if (stream.sol()) { + state.code = false; + } + if (stream.sol() && stream.match(/^```/)) { + stream.skipToEnd(); + state.codeBlock = true; + return null; + } + // If this block is changed, it may need to be updated in Markdown mode + if (stream.peek() === '`') { + stream.next(); + var before = stream.pos; + stream.eatWhile('`'); + var difference = 1 + stream.pos - before; + if (!state.code) { + codeDepth = difference; + state.code = true; + } else { + if (difference === codeDepth) { // Must be exact + state.code = false; + } + } + return null; + } else if (state.code) { + stream.next(); + return null; + } + // Check if space. If so, links can be formatted later on + if (stream.eatSpace()) { + state.ateSpace = true; + return null; + } + if (stream.sol() || state.ateSpace) { + state.ateSpace = false; + if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) { + // User/Project@SHA + // User@SHA + // SHA + state.combineTokens = true; + return "link"; + } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) { + // User/Project#Num + // User#Num + // #Num + state.combineTokens = true; + return "link"; + } + } + if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i) && + stream.string.slice(stream.start - 2, stream.start) != "](") { + // URLs + // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls + // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine + state.combineTokens = true; + return "link"; + } + stream.next(); + return null; + }, + blankLine: blankLine + }; + + var markdownConfig = { + underscoresBreakWords: false, + taskLists: true, + fencedCodeBlocks: true, + strikethrough: true + }; + for (var attr in modeConfig) { + markdownConfig[attr] = modeConfig[attr]; + } + markdownConfig.name = "markdown"; + CodeMirror.defineMIME("gfmBase", markdownConfig); + return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay); +}, "markdown"); + +}); diff --git a/rhodecode/public/js/mode/gherkin/gherkin.js b/rhodecode/public/js/mode/gherkin/gherkin.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/gherkin/gherkin.js @@ -0,0 +1,178 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* +Gherkin mode - http://www.cukes.info/ +Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues +*/ + +// Following Objs from Brackets implementation: https://github.com/tregusti/brackets-gherkin/blob/master/main.js +//var Quotes = { +// SINGLE: 1, +// DOUBLE: 2 +//}; + +//var regex = { +// keywords: /(Feature| {2}(Scenario|In order to|As|I)| {4}(Given|When|Then|And))/ +//}; + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("gherkin", function () { + return { + startState: function () { + return { + lineNumber: 0, + tableHeaderLine: false, + allowFeature: true, + allowBackground: false, + allowScenario: false, + allowSteps: false, + allowPlaceholders: false, + allowMultilineArgument: false, + inMultilineString: false, + inMultilineTable: false, + inKeywordLine: false + }; + }, + token: function (stream, state) { + if (stream.sol()) { + state.lineNumber++; + state.inKeywordLine = false; + if (state.inMultilineTable) { + state.tableHeaderLine = false; + if (!stream.match(/\s*\|/, false)) { + state.allowMultilineArgument = false; + state.inMultilineTable = false; + } + } + } + + stream.eatSpace(); + + if (state.allowMultilineArgument) { + + // STRING + if (state.inMultilineString) { + if (stream.match('"""')) { + state.inMultilineString = false; + state.allowMultilineArgument = false; + } else { + stream.match(/.*/); + } + return "string"; + } + + // TABLE + if (state.inMultilineTable) { + if (stream.match(/\|\s*/)) { + return "bracket"; + } else { + stream.match(/[^\|]*/); + return state.tableHeaderLine ? "header" : "string"; + } + } + + // DETECT START + if (stream.match('"""')) { + // String + state.inMultilineString = true; + return "string"; + } else if (stream.match("|")) { + // Table + state.inMultilineTable = true; + state.tableHeaderLine = true; + return "bracket"; + } + + } + + // LINE COMMENT + if (stream.match(/#.*/)) { + return "comment"; + + // TAG + } else if (!state.inKeywordLine && stream.match(/@\S+/)) { + return "tag"; + + // FEATURE + } else if (!state.inKeywordLine && state.allowFeature && stream.match(/(機能|功能|フィーチャ|기능|โครงหลัก|ความสามารถ|ความต้องการทางธุรกิจ|ಹೆಚ್ಚಳ|గుణము|ਮੁਹਾਂਦਰਾ|ਨਕਸ਼ ਨੁਹਾਰ|ਖਾਸੀਅਤ|रूप लेख|وِیژگی|خاصية|תכונה|Функціонал|Функция|Функционалност|Функционал|Үзенчәлеклелек|Свойство|Особина|Мөмкинлек|Могућност|Λειτουργία|Δυνατότητα|Właściwość|Vlastnosť|Trajto|Tính năng|Savybė|Pretty much|Požiadavka|Požadavek|Potrzeba biznesowa|Özellik|Osobina|Ominaisuus|Omadus|OH HAI|Mogućnost|Mogucnost|Jellemző|Hwæt|Hwaet|Funzionalità|Funktionalitéit|Funktionalität|Funkcja|Funkcionalnost|Funkcionalitāte|Funkcia|Fungsi|Functionaliteit|Funcționalitate|Funcţionalitate|Functionalitate|Funcionalitat|Funcionalidade|Fonctionnalité|Fitur|Fīča|Feature|Eiginleiki|Egenskap|Egenskab|Característica|Caracteristica|Business Need|Aspekt|Arwedd|Ahoy matey!|Ability):/)) { + state.allowScenario = true; + state.allowBackground = true; + state.allowPlaceholders = false; + state.allowSteps = false; + state.allowMultilineArgument = false; + state.inKeywordLine = true; + return "keyword"; + + // BACKGROUND + } else if (!state.inKeywordLine && state.allowBackground && stream.match(/(背景|배경|แนวคิด|ಹಿನ್ನೆಲೆ|నేపథ్యం|ਪਿਛੋਕੜ|पृष्ठभूमि|زمینه|الخلفية|רקע|Тарих|Предыстория|Предистория|Позадина|Передумова|Основа|Контекст|Кереш|Υπόβαθρο|Założenia|Yo\-ho\-ho|Tausta|Taust|Situācija|Rerefons|Pozadina|Pozadie|Pozadí|Osnova|Latar Belakang|Kontext|Konteksts|Kontekstas|Kontekst|Háttér|Hannergrond|Grundlage|Geçmiş|Fundo|Fono|First off|Dis is what went down|Dasar|Contexto|Contexte|Context|Contesto|Cenário de Fundo|Cenario de Fundo|Cefndir|Bối cảnh|Bakgrunnur|Bakgrunn|Bakgrund|Baggrund|Background|B4|Antecedents|Antecedentes|Ær|Aer|Achtergrond):/)) { + state.allowPlaceholders = false; + state.allowSteps = true; + state.allowBackground = false; + state.allowMultilineArgument = false; + state.inKeywordLine = true; + return "keyword"; + + // SCENARIO OUTLINE + } else if (!state.inKeywordLine && state.allowScenario && stream.match(/(場景大綱|场景大纲|劇本大綱|剧本大纲|テンプレ|シナリオテンプレート|シナリオテンプレ|シナリオアウトライン|시나리오 개요|สรุปเหตุการณ์|โครงสร้างของเหตุการณ์|ವಿವರಣೆ|కథనం|ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਟਕਥਾ ਢਾਂਚਾ|परिदृश्य रूपरेखा|سيناريو مخطط|الگوی سناریو|תבנית תרחיש|Сценарийның төзелеше|Сценарий структураси|Структура сценарію|Структура сценария|Структура сценарија|Скица|Рамка на сценарий|Концепт|Περιγραφή Σεναρίου|Wharrimean is|Template Situai|Template Senario|Template Keadaan|Tapausaihio|Szenariogrundriss|Szablon scenariusza|Swa hwær swa|Swa hwaer swa|Struktura scenarija|Structură scenariu|Structura scenariu|Skica|Skenario konsep|Shiver me timbers|Senaryo taslağı|Schema dello scenario|Scenariomall|Scenariomal|Scenario Template|Scenario Outline|Scenario Amlinellol|Scenārijs pēc parauga|Scenarijaus šablonas|Reckon it's like|Raamstsenaarium|Plang vum Szenario|Plan du Scénario|Plan du scénario|Osnova scénáře|Osnova Scenára|Náčrt Scenáru|Náčrt Scénáře|Náčrt Scenára|MISHUN SRSLY|Menggariskan Senario|Lýsing Dæma|Lýsing Atburðarásar|Konturo de la scenaro|Koncept|Khung tình huống|Khung kịch bản|Forgatókönyv vázlat|Esquema do Cenário|Esquema do Cenario|Esquema del escenario|Esquema de l'escenari|Esbozo do escenario|Delineação do Cenário|Delineacao do Cenario|All y'all|Abstrakt Scenario|Abstract Scenario):/)) { + state.allowPlaceholders = true; + state.allowSteps = true; + state.allowMultilineArgument = false; + state.inKeywordLine = true; + return "keyword"; + + // EXAMPLES + } else if (state.allowScenario && stream.match(/(例子|例|サンプル|예|ชุดของเหตุการณ์|ชุดของตัวอย่าง|ಉದಾಹರಣೆಗಳು|ఉదాహరణలు|ਉਦਾਹਰਨਾਂ|उदाहरण|نمونه ها|امثلة|דוגמאות|Үрнәкләр|Сценарији|Примеры|Примери|Приклади|Мисоллар|Мисаллар|Σενάρια|Παραδείγματα|You'll wanna|Voorbeelden|Variantai|Tapaukset|Se þe|Se the|Se ðe|Scenarios|Scenariji|Scenarijai|Przykłady|Primjeri|Primeri|Příklady|Príklady|Piemēri|Példák|Pavyzdžiai|Paraugs|Örnekler|Juhtumid|Exemplos|Exemples|Exemple|Exempel|EXAMPLZ|Examples|Esempi|Enghreifftiau|Ekzemploj|Eksempler|Ejemplos|Dữ liệu|Dead men tell no tales|Dæmi|Contoh|Cenários|Cenarios|Beispiller|Beispiele|Atburðarásir):/)) { + state.allowPlaceholders = false; + state.allowSteps = true; + state.allowBackground = false; + state.allowMultilineArgument = true; + return "keyword"; + + // SCENARIO + } else if (!state.inKeywordLine && state.allowScenario && stream.match(/(場景|场景|劇本|剧本|シナリオ|시나리오|เหตุการณ์|ಕಥಾಸಾರಾಂಶ|సన్నివేశం|ਪਟਕਥਾ|परिदृश्य|سيناريو|سناریو|תרחיש|Сценарій|Сценарио|Сценарий|Пример|Σενάριο|Tình huống|The thing of it is|Tapaus|Szenario|Swa|Stsenaarium|Skenario|Situai|Senaryo|Senario|Scenaro|Scenariusz|Scenariu|Scénario|Scenario|Scenarijus|Scenārijs|Scenarij|Scenarie|Scénář|Scenár|Primer|MISHUN|Kịch bản|Keadaan|Heave to|Forgatókönyv|Escenario|Escenari|Cenário|Cenario|Awww, look mate|Atburðarás):/)) { + state.allowPlaceholders = false; + state.allowSteps = true; + state.allowBackground = false; + state.allowMultilineArgument = false; + state.inKeywordLine = true; + return "keyword"; + + // STEPS + } else if (!state.inKeywordLine && state.allowSteps && stream.match(/(那麼|那么|而且|當|当|并且|同時|同时|前提|假设|假設|假定|假如|但是|但し|並且|もし|ならば|ただし|しかし|かつ|하지만|조건|먼저|만일|만약|단|그리고|그러면|และ |เมื่อ |แต่ |ดังนั้น |กำหนดให้ |ಸ್ಥಿತಿಯನ್ನು |ಮತ್ತು |ನೀಡಿದ |ನಂತರ |ಆದರೆ |మరియు |చెప్పబడినది |కాని |ఈ పరిస్థితిలో |అప్పుడు |ਪਰ |ਤਦ |ਜੇਕਰ |ਜਿਵੇਂ ਕਿ |ਜਦੋਂ |ਅਤੇ |यदि |परन्तु |पर |तब |तदा |तथा |जब |चूंकि |किन्तु |कदा |और |अगर |و |هنگامی |متى |لكن |عندما |ثم |بفرض |با فرض |اما |اذاً |آنگاه |כאשר |וגם |בהינתן |אזי |אז |אבל |Якщо |Һәм |Унда |Тоді |Тогда |То |Также |Та |Пусть |Припустимо, що |Припустимо |Онда |Но |Нехай |Нәтиҗәдә |Лекин |Ләкин |Коли |Когда |Когато |Када |Кад |К тому же |І |И |Задато |Задати |Задате |Если |Допустим |Дано |Дадено |Вә |Ва |Бирок |Әмма |Әйтик |Әгәр |Аммо |Али |Але |Агар |А також |А |Τότε |Όταν |Και |Δεδομένου |Αλλά |Þurh |Þegar |Þa þe |Þá |Þa |Zatati |Zakładając |Zadato |Zadate |Zadano |Zadani |Zadan |Za předpokladu |Za predpokladu |Youse know when youse got |Youse know like when |Yna |Yeah nah |Y'know |Y |Wun |Wtedy |When y'all |When |Wenn |WEN |wann |Ve |Và |Und |Un |ugeholl |Too right |Thurh |Thì |Then y'all |Then |Tha the |Tha |Tetapi |Tapi |Tak |Tada |Tad |Stel |Soit |Siis |Și |Şi |Si |Sed |Se |Så |Quando |Quand |Quan |Pryd |Potom |Pokud |Pokiaľ |Però |Pero |Pak |Oraz |Onda |Ond |Oletetaan |Og |Och |O zaman |Niin |Nhưng |När |Når |Mutta |Men |Mas |Maka |Majd |Mając |Mais |Maar |mä |Ma |Lorsque |Lorsqu'|Logo |Let go and haul |Kun |Kuid |Kui |Kiedy |Khi |Ketika |Kemudian |Keď |Když |Kaj |Kai |Kada |Kad |Jeżeli |Jeśli |Ja |It's just unbelievable |Ir |I CAN HAZ |I |Ha |Givun |Givet |Given y'all |Given |Gitt |Gegeven |Gegeben seien |Gegeben sei |Gdy |Gangway! |Fakat |Étant donnés |Etant donnés |Étant données |Etant données |Étant donnée |Etant donnée |Étant donné |Etant donné |Et |És |Entonces |Entón |Então |Entao |En |Eğer ki |Ef |Eeldades |E |Ðurh |Duota |Dun |Donitaĵo |Donat |Donada |Do |Diyelim ki |Diberi |Dengan |Den youse gotta |DEN |De |Dato |Dați fiind |Daţi fiind |Dati fiind |Dati |Date fiind |Date |Data |Dat fiind |Dar |Dann |dann |Dan |Dados |Dado |Dadas |Dada |Ða ðe |Ða |Cuando |Cho |Cando |Când |Cand |Cal |But y'all |But at the end of the day I reckon |BUT |But |Buh |Blimey! |Biết |Bet |Bagi |Aye |awer |Avast! |Atunci |Atesa |Atès |Apabila |Anrhegedig a |Angenommen |And y'all |And |AN |An |an |Amikor |Amennyiben |Ama |Als |Alors |Allora |Ali |Aleshores |Ale |Akkor |Ak |Adott |Ac |Aber |A zároveň |A tiež |A taktiež |A také |A |a |7 |\* )/)) { + state.inStep = true; + state.allowPlaceholders = true; + state.allowMultilineArgument = true; + state.inKeywordLine = true; + return "keyword"; + + // INLINE STRING + } else if (stream.match(/"[^"]*"?/)) { + return "string"; + + // PLACEHOLDER + } else if (state.allowPlaceholders && stream.match(/<[^>]*>?/)) { + return "variable"; + + // Fall through + } else { + stream.next(); + stream.eatWhile(/[^@"<#]/); + return null; + } + } + }; +}); + +CodeMirror.defineMIME("text/x-feature", "gherkin"); + +}); diff --git a/rhodecode/public/js/mode/go/go.js b/rhodecode/public/js/mode/go/go.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/go/go.js @@ -0,0 +1,185 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("go", function(config) { + var indentUnit = config.indentUnit; + + var keywords = { + "break":true, "case":true, "chan":true, "const":true, "continue":true, + "default":true, "defer":true, "else":true, "fallthrough":true, "for":true, + "func":true, "go":true, "goto":true, "if":true, "import":true, + "interface":true, "map":true, "package":true, "range":true, "return":true, + "select":true, "struct":true, "switch":true, "type":true, "var":true, + "bool":true, "byte":true, "complex64":true, "complex128":true, + "float32":true, "float64":true, "int8":true, "int16":true, "int32":true, + "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true, + "uint64":true, "int":true, "uint":true, "uintptr":true + }; + + var atoms = { + "true":true, "false":true, "iota":true, "nil":true, "append":true, + "cap":true, "close":true, "complex":true, "copy":true, "imag":true, + "len":true, "make":true, "new":true, "panic":true, "print":true, + "println":true, "real":true, "recover":true + }; + + var isOperatorChar = /[+\-*&^%:=<>!|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\d\.]/.test(ch)) { + if (ch == ".") { + stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); + } else if (ch == "0") { + stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); + } else { + stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); + } + return "number"; + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (cur == "case" || cur == "default") curPunc = "case"; + return "keyword"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || quote == "`")) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + if (!state.context.prev) return; + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + if (ctx.type == "case") ctx.type = "}"; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "case") ctx.type = "case"; + else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state); + else if (curPunc == ctx.type) popContext(state); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return 0; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) { + state.context.type = "}"; + return ctx.indented; + } + var closing = firstChar == ctx.type; + if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}):", + fold: "brace", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + +CodeMirror.defineMIME("text/x-go", "go"); + +}); diff --git a/rhodecode/public/js/mode/groovy/groovy.js b/rhodecode/public/js/mode/groovy/groovy.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/groovy/groovy.js @@ -0,0 +1,230 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("groovy", function(config) { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = words( + "abstract as assert boolean break byte case catch char class const continue def default " + + "do double else enum extends final finally float for goto if implements import in " + + "instanceof int interface long native new package private protected public return " + + "short static strictfp super switch synchronized threadsafe throw throws transient " + + "try void volatile while"); + var blockKeywords = words("catch class do else finally for if switch try while enum interface def"); + var standaloneKeywords = words("return break continue"); + var atoms = words("null true false this"); + + var curPunc; + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + return startString(ch, stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + if (stream.eat(/eE/)) { stream.eat(/\+\-/); stream.eatWhile(/\d/); } + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize.push(tokenComment); + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + if (expectExpression(state.lastToken, false)) { + return startString(ch, stream, state); + } + } + if (ch == "-" && stream.eat(">")) { + curPunc = "->"; + return null; + } + if (/[+\-*&%=<>!?|\/~]/.test(ch)) { + stream.eatWhile(/[+\-*&%=<>|~]/); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + if (ch == "@") { stream.eatWhile(/[\w\$_\.]/); return "meta"; } + if (state.lastToken == ".") return "property"; + if (stream.eat(":")) { curPunc = "proplabel"; return "property"; } + var cur = stream.current(); + if (atoms.propertyIsEnumerable(cur)) { return "atom"; } + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + else if (standaloneKeywords.propertyIsEnumerable(cur)) curPunc = "standalone"; + return "keyword"; + } + return "variable"; + } + tokenBase.isBase = true; + + function startString(quote, stream, state) { + var tripleQuoted = false; + if (quote != "/" && stream.eat(quote)) { + if (stream.eat(quote)) tripleQuoted = true; + else return "string"; + } + function t(stream, state) { + var escaped = false, next, end = !tripleQuoted; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + if (!tripleQuoted) { break; } + if (stream.match(quote + quote)) { end = true; break; } + } + if (quote == '"' && next == "$" && !escaped && stream.eat("{")) { + state.tokenize.push(tokenBaseUntilBrace()); + return "string"; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize.pop(); + return "string"; + } + state.tokenize.push(t); + return t(stream, state); + } + + function tokenBaseUntilBrace() { + var depth = 1; + function t(stream, state) { + if (stream.peek() == "}") { + depth--; + if (depth == 0) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } + } else if (stream.peek() == "{") { + depth++; + } + return tokenBase(stream, state); + } + t.isBase = true; + return t; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize.pop(); + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function expectExpression(last, newline) { + return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) || + last == "newstatement" || last == "keyword" || last == "proplabel" || + (last == "standalone" && !newline); + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: [tokenBase], + context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false), + indented: 0, + startOfLine: true, + lastToken: null + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + // Automatic semicolon insertion + if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) { + popContext(state); ctx = state.context; + } + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = state.tokenize[state.tokenize.length-1](stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); + // Handle indentation for {x -> \n ... } + else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") { + popContext(state); + state.context.align = false; + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + state.lastToken = curPunc || style; + return style; + }, + + indent: function(state, textAfter) { + if (!state.tokenize[state.tokenize.length-1].isBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.context; + if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : config.indentUnit); + }, + + electricChars: "{}", + closeBrackets: {triples: "'\""}, + fold: "brace" + }; +}); + +CodeMirror.defineMIME("text/x-groovy", "groovy"); + +}); diff --git a/rhodecode/public/js/mode/haml/haml.js b/rhodecode/public/js/mode/haml/haml.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/haml/haml.js @@ -0,0 +1,159 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + + // full haml mode. This handled embeded ruby and html fragments too + CodeMirror.defineMode("haml", function(config) { + var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); + var rubyMode = CodeMirror.getMode(config, "ruby"); + + function rubyInQuote(endQuote) { + return function(stream, state) { + var ch = stream.peek(); + if (ch == endQuote && state.rubyState.tokenize.length == 1) { + // step out of ruby context as it seems to complete processing all the braces + stream.next(); + state.tokenize = html; + return "closeAttributeTag"; + } else { + return ruby(stream, state); + } + }; + } + + function ruby(stream, state) { + if (stream.match("-#")) { + stream.skipToEnd(); + return "comment"; + } + return rubyMode.token(stream, state.rubyState); + } + + function html(stream, state) { + var ch = stream.peek(); + + // handle haml declarations. All declarations that cant be handled here + // will be passed to html mode + if (state.previousToken.style == "comment" ) { + if (state.indented > state.previousToken.indented) { + stream.skipToEnd(); + return "commentLine"; + } + } + + if (state.startOfLine) { + if (ch == "!" && stream.match("!!")) { + stream.skipToEnd(); + return "tag"; + } else if (stream.match(/^%[\w:#\.]+=/)) { + state.tokenize = ruby; + return "hamlTag"; + } else if (stream.match(/^%[\w:]+/)) { + return "hamlTag"; + } else if (ch == "/" ) { + stream.skipToEnd(); + return "comment"; + } + } + + if (state.startOfLine || state.previousToken.style == "hamlTag") { + if ( ch == "#" || ch == ".") { + stream.match(/[\w-#\.]*/); + return "hamlAttribute"; + } + } + + // donot handle --> as valid ruby, make it HTML close comment instead + if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { + state.tokenize = ruby; + return state.tokenize(stream, state); + } + + if (state.previousToken.style == "hamlTag" || + state.previousToken.style == "closeAttributeTag" || + state.previousToken.style == "hamlAttribute") { + if (ch == "(") { + state.tokenize = rubyInQuote(")"); + return state.tokenize(stream, state); + } else if (ch == "{") { + state.tokenize = rubyInQuote("}"); + return state.tokenize(stream, state); + } + } + + return htmlMode.token(stream, state.htmlState); + } + + return { + // default to html mode + startState: function() { + var htmlState = htmlMode.startState(); + var rubyState = rubyMode.startState(); + return { + htmlState: htmlState, + rubyState: rubyState, + indented: 0, + previousToken: { style: null, indented: 0}, + tokenize: html + }; + }, + + copyState: function(state) { + return { + htmlState : CodeMirror.copyState(htmlMode, state.htmlState), + rubyState: CodeMirror.copyState(rubyMode, state.rubyState), + indented: state.indented, + previousToken: state.previousToken, + tokenize: state.tokenize + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + state.startOfLine = false; + // dont record comment line as we only want to measure comment line with + // the opening comment block + if (style && style != "commentLine") { + state.previousToken = { style: style, indented: state.indented }; + } + // if current state is ruby and the previous token is not `,` reset the + // tokenize to html + if (stream.eol() && state.tokenize == ruby) { + stream.backUp(1); + var ch = stream.peek(); + stream.next(); + if (ch && ch != ",") { + state.tokenize = html; + } + } + // reprocess some of the specific style tag when finish setting previousToken + if (style == "hamlTag") { + style = "tag"; + } else if (style == "commentLine") { + style = "comment"; + } else if (style == "hamlAttribute") { + style = "attribute"; + } else if (style == "closeAttributeTag") { + style = null; + } + return style; + } + }; + }, "htmlmixed", "ruby"); + + CodeMirror.defineMIME("text/x-haml", "haml"); +}); diff --git a/rhodecode/public/js/mode/handlebars/handlebars.js b/rhodecode/public/js/mode/handlebars/handlebars.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/handlebars/handlebars.js @@ -0,0 +1,53 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../addon/mode/simple")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../addon/mode/simple"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineSimpleMode("handlebars", { + start: [ + { regex: /\{\{!--/, push: "dash_comment", token: "comment" }, + { regex: /\{\{!/, push: "comment", token: "comment" }, + { regex: /\{\{/, push: "handlebars", token: "tag" } + ], + handlebars: [ + { regex: /\}\}/, pop: true, token: "tag" }, + + // Double and single quotes + { regex: /"(?:[^\\]|\\.)*?"/, token: "string" }, + { regex: /'(?:[^\\]|\\.)*?'/, token: "string" }, + + // Handlebars keywords + { regex: />|[#\/]([A-Za-z_]\w*)/, token: "keyword" }, + { regex: /(?:else|this)\b/, token: "keyword" }, + + // Numeral + { regex: /\d+/i, token: "number" }, + + // Atoms like = and . + { regex: /=|~|@|true|false/, token: "atom" }, + + // Paths + { regex: /(?:\.\.\/)*(?:[A-Za-z_][\w\.]*)+/, token: "variable-2" } + ], + dash_comment: [ + { regex: /--\}\}/, pop: true, token: "comment" }, + + // Commented code + { regex: /./, token: "comment"} + ], + comment: [ + { regex: /\}\}/, pop: true, token: "comment" }, + { regex: /./, token: "comment" } + ] + }); + + CodeMirror.defineMIME("text/x-handlebars-template", "handlebars"); +}); diff --git a/rhodecode/public/js/mode/haskell-literate/haskell-literate.js b/rhodecode/public/js/mode/haskell-literate/haskell-literate.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/haskell-literate/haskell-literate.js @@ -0,0 +1,43 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function (mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../haskell/haskell")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../haskell/haskell"], mod) + else // Plain browser env + mod(CodeMirror) +})(function (CodeMirror) { + "use strict" + + CodeMirror.defineMode("haskell-literate", function (config, parserConfig) { + var baseMode = CodeMirror.getMode(config, (parserConfig && parserConfig.base) || "haskell") + + return { + startState: function () { + return { + inCode: false, + baseState: CodeMirror.startState(baseMode) + } + }, + token: function (stream, state) { + if (stream.sol()) { + if (state.inCode = stream.eat(">")) + return "meta" + } + if (state.inCode) { + return baseMode.token(stream, state.baseState) + } else { + stream.skipToEnd() + return "comment" + } + }, + innerMode: function (state) { + return state.inCode ? {state: state.baseState, mode: baseMode} : null + } + } + }, "haskell") + + CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate") +}) diff --git a/rhodecode/public/js/mode/haskell/haskell.js b/rhodecode/public/js/mode/haskell/haskell.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/haskell/haskell.js @@ -0,0 +1,267 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("haskell", function(_config, modeConfig) { + + function switchState(source, setState, f) { + setState(f); + return f(source, setState); + } + + // These should all be Unicode extended, as per the Haskell 2010 report + var smallRE = /[a-z_]/; + var largeRE = /[A-Z]/; + var digitRE = /\d/; + var hexitRE = /[0-9A-Fa-f]/; + var octitRE = /[0-7]/; + var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/; + var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/; + var specialRE = /[(),;[\]`{}]/; + var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer + + function normal(source, setState) { + if (source.eatWhile(whiteCharRE)) { + return null; + } + + var ch = source.next(); + if (specialRE.test(ch)) { + if (ch == '{' && source.eat('-')) { + var t = "comment"; + if (source.eat('#')) { + t = "meta"; + } + return switchState(source, setState, ncomment(t, 1)); + } + return null; + } + + if (ch == '\'') { + if (source.eat('\\')) { + source.next(); // should handle other escapes here + } + else { + source.next(); + } + if (source.eat('\'')) { + return "string"; + } + return "error"; + } + + if (ch == '"') { + return switchState(source, setState, stringLiteral); + } + + if (largeRE.test(ch)) { + source.eatWhile(idRE); + if (source.eat('.')) { + return "qualifier"; + } + return "variable-2"; + } + + if (smallRE.test(ch)) { + source.eatWhile(idRE); + return "variable"; + } + + if (digitRE.test(ch)) { + if (ch == '0') { + if (source.eat(/[xX]/)) { + source.eatWhile(hexitRE); // should require at least 1 + return "integer"; + } + if (source.eat(/[oO]/)) { + source.eatWhile(octitRE); // should require at least 1 + return "number"; + } + } + source.eatWhile(digitRE); + var t = "number"; + if (source.match(/^\.\d+/)) { + t = "number"; + } + if (source.eat(/[eE]/)) { + t = "number"; + source.eat(/[-+]/); + source.eatWhile(digitRE); // should require at least 1 + } + return t; + } + + if (ch == "." && source.eat(".")) + return "keyword"; + + if (symbolRE.test(ch)) { + if (ch == '-' && source.eat(/-/)) { + source.eatWhile(/-/); + if (!source.eat(symbolRE)) { + source.skipToEnd(); + return "comment"; + } + } + var t = "variable"; + if (ch == ':') { + t = "variable-2"; + } + source.eatWhile(symbolRE); + return t; + } + + return "error"; + } + + function ncomment(type, nest) { + if (nest == 0) { + return normal; + } + return function(source, setState) { + var currNest = nest; + while (!source.eol()) { + var ch = source.next(); + if (ch == '{' && source.eat('-')) { + ++currNest; + } + else if (ch == '-' && source.eat('}')) { + --currNest; + if (currNest == 0) { + setState(normal); + return type; + } + } + } + setState(ncomment(type, currNest)); + return type; + }; + } + + function stringLiteral(source, setState) { + while (!source.eol()) { + var ch = source.next(); + if (ch == '"') { + setState(normal); + return "string"; + } + if (ch == '\\') { + if (source.eol() || source.eat(whiteCharRE)) { + setState(stringGap); + return "string"; + } + if (source.eat('&')) { + } + else { + source.next(); // should handle other escapes here + } + } + } + setState(normal); + return "error"; + } + + function stringGap(source, setState) { + if (source.eat('\\')) { + return switchState(source, setState, stringLiteral); + } + source.next(); + setState(normal); + return "error"; + } + + + var wellKnownWords = (function() { + var wkw = {}; + function setType(t) { + return function () { + for (var i = 0; i < arguments.length; i++) + wkw[arguments[i]] = t; + }; + } + + setType("keyword")( + "case", "class", "data", "default", "deriving", "do", "else", "foreign", + "if", "import", "in", "infix", "infixl", "infixr", "instance", "let", + "module", "newtype", "of", "then", "type", "where", "_"); + + setType("keyword")( + "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>"); + + setType("builtin")( + "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<", + "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**"); + + setType("builtin")( + "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq", + "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT", + "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left", + "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read", + "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS", + "String", "True"); + + setType("builtin")( + "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf", + "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling", + "compare", "concat", "concatMap", "const", "cos", "cosh", "curry", + "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either", + "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo", + "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter", + "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap", + "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger", + "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents", + "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized", + "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last", + "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map", + "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound", + "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or", + "otherwise", "pi", "pred", "print", "product", "properFraction", + "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile", + "readIO", "readList", "readLn", "readParen", "reads", "readsPrec", + "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse", + "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq", + "sequence", "sequence_", "show", "showChar", "showList", "showParen", + "showString", "shows", "showsPrec", "significand", "signum", "sin", + "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum", + "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger", + "toRational", "truncate", "uncurry", "undefined", "unlines", "until", + "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip", + "zip3", "zipWith", "zipWith3"); + + var override = modeConfig.overrideKeywords; + if (override) for (var word in override) if (override.hasOwnProperty(word)) + wkw[word] = override[word]; + + return wkw; + })(); + + + + return { + startState: function () { return { f: normal }; }, + copyState: function (s) { return { f: s.f }; }, + + token: function(stream, state) { + var t = state.f(stream, function(s) { state.f = s; }); + var w = stream.current(); + return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t; + }, + + blockCommentStart: "{-", + blockCommentEnd: "-}", + lineComment: "--" + }; + +}); + +CodeMirror.defineMIME("text/x-haskell", "haskell"); + +}); diff --git a/rhodecode/public/js/mode/haxe/haxe.js b/rhodecode/public/js/mode/haxe/haxe.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/haxe/haxe.js @@ -0,0 +1,518 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("haxe", function(config, parserConfig) { + var indentUnit = config.indentUnit; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}, attribute = {type:"attribute", style: "attribute"}; + var type = kw("typedef"); + return { + "if": A, "while": A, "else": B, "do": B, "try": B, + "return": C, "break": C, "continue": C, "new": C, "throw": C, + "var": kw("var"), "inline":attribute, "static": attribute, "using":kw("import"), + "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"), + "function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "never": kw("property_access"), "trace":kw("trace"), + "class": type, "abstract":type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type, + "true": atom, "false": atom, "null": atom + }; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function nextUntilUnescaped(stream, end) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next == end && !escaped) + return false; + escaped = !escaped && next == "\\"; + } + return escaped; + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + + function haxeTokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") + return chain(stream, state, haxeTokenString(ch)); + else if (/[\[\]{}\(\),;\:\.]/.test(ch)) + return ret(ch); + else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } + else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } + else if (state.reAllowed && (ch == "~" && stream.eat(/\//))) { + nextUntilUnescaped(stream, "/"); + stream.eatWhile(/[gimsu]/); + return ret("regexp", "string-2"); + } + else if (ch == "/") { + if (stream.eat("*")) { + return chain(stream, state, haxeTokenComment); + } + else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", null, stream.current()); + } + } + else if (ch == "#") { + stream.skipToEnd(); + return ret("conditional", "meta"); + } + else if (ch == "@") { + stream.eat(/:/); + stream.eatWhile(/[\w_]/); + return ret ("metadata", "meta"); + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", null, stream.current()); + } + else { + var word; + if(/[A-Z]/.test(ch)) + { + stream.eatWhile(/[\w_<>]/); + word = stream.current(); + return ret("type", "variable-3", word); + } + else + { + stream.eatWhile(/[\w_]/); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.kwAllowed) ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + } + + function haxeTokenString(quote) { + return function(stream, state) { + if (!nextUntilUnescaped(stream, quote)) + state.tokenize = haxeTokenBase; + return ret("string", "string"); + }; + } + + function haxeTokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = haxeTokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true}; + + function HaxeLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + } + + function parseHaxe(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + if (type == "variable" && imported(state, content)) return "variable-3"; + return style; + } + } + } + + function imported(state, typename) + { + if (/[a-z]/.test(typename.charAt(0))) + return false; + var len = state.importedtypes.length; + for (var i = 0; i<len; i++) + if(state.importedtypes[i]==typename) return true; + } + + + function registerimport(importname) { + var state = cx.state; + for (var t = state.importedtypes; t; t = t.next) + if(t.name == importname) return; + state.importedtypes = { name: importname, next: state.importedtypes }; + } + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + var state = cx.state; + if (state.context) { + cx.marked = "def"; + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return; + state.localVars = {name: varname, next: state.localVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: null}; + function pushcontext() { + if (!cx.state.context) cx.state.localVars = defaultVars; + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state; + state.lexical = new HaxeLexical(state.indented, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function f(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(f); + }; + return f; + } + + function statement(type) { + if (type == "@") return cont(metadef); + if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), pushcontext, block, poplex, popcontext); + if (type == ";") return cont(); + if (type == "attribute") return cont(maybeattribute); + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), + poplex, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "import") return cont(importdef, expect(";")); + if (type == "typedef") return cont(typedef); + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator); + if (type == "function") return cont(functiondef); + if (type == "keyword c") return cont(maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator); + if (type == "operator") return cont(expression); + if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator); + if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + + function maybeoperator(type, value) { + if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator); + if (type == "operator" || type == ":") return cont(expression); + if (type == ";") return; + if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator); + if (type == ".") return cont(property, maybeoperator); + if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator); + } + + function maybeattribute(type) { + if (type == "attribute") return cont(maybeattribute); + if (type == "function") return cont(functiondef); + if (type == "var") return cont(vardef1); + } + + function metadef(type) { + if(type == ":") return cont(metadef); + if(type == "variable") return cont(metadef); + if(type == "(") return cont(pushlex(")"), commasep(metaargs, ")"), poplex, statement); + } + function metaargs(type) { + if(type == "variable") return cont(); + } + + function importdef (type, value) { + if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); } + else if(type == "variable" || type == "property" || type == "." || value == "*") return cont(importdef); + } + + function typedef (type, value) + { + if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); } + else if (type == "type" && /[A-Z]/.test(value.charAt(0))) { return cont(); } + } + + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperator, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type) { + if (type == "variable") cx.marked = "property"; + if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression); + } + function commasep(what, end) { + function proceed(type) { + if (type == ",") return cont(what, proceed); + if (type == end) return cont(); + return cont(expect(end)); + } + return function(type) { + if (type == end) return cont(); + else return pass(what, proceed); + }; + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function vardef1(type, value) { + if (type == "variable"){register(value); return cont(typeuse, vardef2);} + return cont(); + } + function vardef2(type, value) { + if (value == "=") return cont(expression, vardef2); + if (type == ",") return cont(vardef1); + } + function forspec1(type, value) { + if (type == "variable") { + register(value); + } + return cont(pushlex(")"), pushcontext, forin, expression, poplex, statement, popcontext); + } + function forin(_type, value) { + if (value == "in") return cont(); + } + function functiondef(type, value) { + if (type == "variable") {register(value); return cont(functiondef);} + if (value == "new") return cont(functiondef); + if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, typeuse, statement, popcontext); + } + function typeuse(type) { + if(type == ":") return cont(typestring); + } + function typestring(type) { + if(type == "type") return cont(); + if(type == "variable") return cont(); + if(type == "{") return cont(pushlex("}"), commasep(typeprop, "}"), poplex); + } + function typeprop(type) { + if(type == "variable") return cont(typeuse); + } + function funarg(type, value) { + if (type == "variable") {register(value); return cont(typeuse);} + } + + // Interface + + return { + startState: function(basecolumn) { + var defaulttypes = ["Int", "Float", "String", "Void", "Std", "Bool", "Dynamic", "Array"]; + return { + tokenize: haxeTokenBase, + reAllowed: true, + kwAllowed: true, + cc: [], + lexical: new HaxeLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + importedtypes: defaulttypes, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: 0 + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/)); + state.kwAllowed = type != '.'; + return parseHaxe(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize != haxeTokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + if (type == "vardef") return lexical.indented + 4; + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "stat" || type == "form") return lexical.indented + indentUnit; + else if (lexical.info == "switch" && !closing) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + +CodeMirror.defineMIME("text/x-haxe", "haxe"); + +CodeMirror.defineMode("hxml", function () { + + return { + startState: function () { + return { + define: false, + inString: false + }; + }, + token: function (stream, state) { + var ch = stream.peek(); + var sol = stream.sol(); + + ///* comments */ + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + if (sol && ch == "-") { + var style = "variable-2"; + + stream.eat(/-/); + + if (stream.peek() == "-") { + stream.eat(/-/); + style = "keyword a"; + } + + if (stream.peek() == "D") { + stream.eat(/[D]/); + style = "keyword c"; + state.define = true; + } + + stream.eatWhile(/[A-Z]/i); + return style; + } + + var ch = stream.peek(); + + if (state.inString == false && ch == "'") { + state.inString = true; + ch = stream.next(); + } + + if (state.inString == true) { + if (stream.skipTo("'")) { + + } else { + stream.skipToEnd(); + } + + if (stream.peek() == "'") { + stream.next(); + state.inString = false; + } + + return "string"; + } + + stream.next(); + return null; + }, + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/x-hxml", "hxml"); + +}); diff --git a/rhodecode/public/js/mode/htmlembedded/htmlembedded.js b/rhodecode/public/js/mode/htmlembedded/htmlembedded.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/htmlembedded/htmlembedded.js @@ -0,0 +1,28 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/multiplex")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/multiplex"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { + return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), { + open: parserConfig.open || parserConfig.scriptStartRegex || "<%", + close: parserConfig.close || parserConfig.scriptEndRegex || "%>", + mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec) + }); + }, "htmlmixed"); + + CodeMirror.defineMIME("application/x-ejs", {name: "htmlembedded", scriptingModeSpec:"javascript"}); + CodeMirror.defineMIME("application/x-aspx", {name: "htmlembedded", scriptingModeSpec:"text/x-csharp"}); + CodeMirror.defineMIME("application/x-jsp", {name: "htmlembedded", scriptingModeSpec:"text/x-java"}); + CodeMirror.defineMIME("application/x-erb", {name: "htmlembedded", scriptingModeSpec:"ruby"}); +}); diff --git a/rhodecode/public/js/mode/htmlmixed/htmlmixed.js b/rhodecode/public/js/mode/htmlmixed/htmlmixed.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/htmlmixed/htmlmixed.js @@ -0,0 +1,121 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, {name: "xml", + htmlMode: true, + multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag}); + var cssMode = CodeMirror.getMode(config, "css"); + + var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes; + scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, + mode: CodeMirror.getMode(config, "javascript")}); + if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) { + var conf = scriptTypesConf[i]; + scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)}); + } + scriptTypes.push({matches: /./, + mode: CodeMirror.getMode(config, "text/plain")}); + + function html(stream, state) { + var tagName = state.htmlState.tagName; + if (tagName) tagName = tagName.toLowerCase(); + var style = htmlMode.token(stream, state.htmlState); + if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") { + // Script block: mode to change to depends on type attribute + var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); + scriptType = scriptType ? scriptType[1] : ""; + if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); + for (var i = 0; i < scriptTypes.length; ++i) { + var tp = scriptTypes[i]; + if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { + if (tp.mode) { + state.token = script; + state.localMode = tp.mode; + state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); + } + break; + } + } + } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") { + state.token = css; + state.localMode = cssMode; + state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); + } + return style; + } + function maybeBackup(stream, pat, style) { + var cur = stream.current(); + var close = cur.search(pat); + if (close > -1) stream.backUp(cur.length - close); + else if (cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur); + } + return style; + } + function script(stream, state) { + if (stream.match(/^<\/\s*script\s*>/i, false)) { + state.token = html; + state.localState = state.localMode = null; + return null; + } + return maybeBackup(stream, /<\/\s*script\s*>/, + state.localMode.token(stream, state.localState)); + } + function css(stream, state) { + if (stream.match(/^<\/\s*style\s*>/i, false)) { + state.token = html; + state.localState = state.localMode = null; + return null; + } + return maybeBackup(stream, /<\/\s*style\s*>/, + cssMode.token(stream, state.localState)); + } + + return { + startState: function() { + var state = htmlMode.startState(); + return {token: html, localMode: null, localState: null, htmlState: state}; + }, + + copyState: function(state) { + if (state.localState) + var local = CodeMirror.copyState(state.localMode, state.localState); + return {token: state.token, localMode: state.localMode, localState: local, + htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; + }, + + token: function(stream, state) { + return state.token(stream, state); + }, + + indent: function(state, textAfter) { + if (!state.localMode || /^\s*<\//.test(textAfter)) + return htmlMode.indent(state.htmlState, textAfter); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter); + else + return CodeMirror.Pass; + }, + + innerMode: function(state) { + return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; + } + }; +}, "xml", "javascript", "css"); + +CodeMirror.defineMIME("text/html", "htmlmixed"); + +}); diff --git a/rhodecode/public/js/mode/http/http.js b/rhodecode/public/js/mode/http/http.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/http/http.js @@ -0,0 +1,113 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("http", function() { + function failFirstLine(stream, state) { + stream.skipToEnd(); + state.cur = header; + return "error"; + } + + function start(stream, state) { + if (stream.match(/^HTTP\/\d\.\d/)) { + state.cur = responseStatusCode; + return "keyword"; + } else if (stream.match(/^[A-Z]+/) && /[ \t]/.test(stream.peek())) { + state.cur = requestPath; + return "keyword"; + } else { + return failFirstLine(stream, state); + } + } + + function responseStatusCode(stream, state) { + var code = stream.match(/^\d+/); + if (!code) return failFirstLine(stream, state); + + state.cur = responseStatusText; + var status = Number(code[0]); + if (status >= 100 && status < 200) { + return "positive informational"; + } else if (status >= 200 && status < 300) { + return "positive success"; + } else if (status >= 300 && status < 400) { + return "positive redirect"; + } else if (status >= 400 && status < 500) { + return "negative client-error"; + } else if (status >= 500 && status < 600) { + return "negative server-error"; + } else { + return "error"; + } + } + + function responseStatusText(stream, state) { + stream.skipToEnd(); + state.cur = header; + return null; + } + + function requestPath(stream, state) { + stream.eatWhile(/\S/); + state.cur = requestProtocol; + return "string-2"; + } + + function requestProtocol(stream, state) { + if (stream.match(/^HTTP\/\d\.\d$/)) { + state.cur = header; + return "keyword"; + } else { + return failFirstLine(stream, state); + } + } + + function header(stream) { + if (stream.sol() && !stream.eat(/[ \t]/)) { + if (stream.match(/^.*?:/)) { + return "atom"; + } else { + stream.skipToEnd(); + return "error"; + } + } else { + stream.skipToEnd(); + return "string"; + } + } + + function body(stream) { + stream.skipToEnd(); + return null; + } + + return { + token: function(stream, state) { + var cur = state.cur; + if (cur != header && cur != body && stream.eatSpace()) return null; + return cur(stream, state); + }, + + blankLine: function(state) { + state.cur = body; + }, + + startState: function() { + return {cur: start}; + } + }; +}); + +CodeMirror.defineMIME("message/http", "http"); + +}); diff --git a/rhodecode/public/js/mode/idl/idl.js b/rhodecode/public/js/mode/idl/idl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/idl/idl.js @@ -0,0 +1,290 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function wordRegexp(words) { + return new RegExp('^((' + words.join(')|(') + '))\\b', 'i'); + }; + + var builtinArray = [ + 'a_correlate', 'abs', 'acos', 'adapt_hist_equal', 'alog', + 'alog2', 'alog10', 'amoeba', 'annotate', 'app_user_dir', + 'app_user_dir_query', 'arg_present', 'array_equal', 'array_indices', + 'arrow', 'ascii_template', 'asin', 'assoc', 'atan', + 'axis', 'axis', 'bandpass_filter', 'bandreject_filter', 'barplot', + 'bar_plot', 'beseli', 'beselj', 'beselk', 'besely', + 'beta', 'biginteger', 'bilinear', 'bin_date', 'binary_template', + 'bindgen', 'binomial', 'bit_ffs', 'bit_population', 'blas_axpy', + 'blk_con', 'boolarr', 'boolean', 'boxplot', 'box_cursor', + 'breakpoint', 'broyden', 'bubbleplot', 'butterworth', 'bytarr', + 'byte', 'byteorder', 'bytscl', 'c_correlate', 'calendar', + 'caldat', 'call_external', 'call_function', 'call_method', + 'call_procedure', 'canny', 'catch', 'cd', 'cdf', 'ceil', + 'chebyshev', 'check_math', 'chisqr_cvf', 'chisqr_pdf', 'choldc', + 'cholsol', 'cindgen', 'cir_3pnt', 'clipboard', 'close', + 'clust_wts', 'cluster', 'cluster_tree', 'cmyk_convert', 'code_coverage', + 'color_convert', 'color_exchange', 'color_quan', 'color_range_map', + 'colorbar', 'colorize_sample', 'colormap_applicable', + 'colormap_gradient', 'colormap_rotation', 'colortable', + 'comfit', 'command_line_args', 'common', 'compile_opt', 'complex', + 'complexarr', 'complexround', 'compute_mesh_normals', 'cond', 'congrid', + 'conj', 'constrained_min', 'contour', 'contour', 'convert_coord', + 'convol', 'convol_fft', 'coord2to3', 'copy_lun', 'correlate', + 'cos', 'cosh', 'cpu', 'cramer', 'createboxplotdata', + 'create_cursor', 'create_struct', 'create_view', 'crossp', 'crvlength', + 'ct_luminance', 'cti_test', 'cursor', 'curvefit', 'cv_coord', + 'cvttobm', 'cw_animate', 'cw_animate_getp', 'cw_animate_load', + 'cw_animate_run', 'cw_arcball', 'cw_bgroup', 'cw_clr_index', + 'cw_colorsel', 'cw_defroi', 'cw_field', 'cw_filesel', 'cw_form', + 'cw_fslider', 'cw_light_editor', 'cw_light_editor_get', + 'cw_light_editor_set', 'cw_orient', 'cw_palette_editor', + 'cw_palette_editor_get', 'cw_palette_editor_set', 'cw_pdmenu', + 'cw_rgbslider', 'cw_tmpl', 'cw_zoom', 'db_exists', + 'dblarr', 'dcindgen', 'dcomplex', 'dcomplexarr', 'define_key', + 'define_msgblk', 'define_msgblk_from_file', 'defroi', 'defsysv', + 'delvar', 'dendro_plot', 'dendrogram', 'deriv', 'derivsig', + 'determ', 'device', 'dfpmin', 'diag_matrix', 'dialog_dbconnect', + 'dialog_message', 'dialog_pickfile', 'dialog_printersetup', + 'dialog_printjob', 'dialog_read_image', + 'dialog_write_image', 'dictionary', 'digital_filter', 'dilate', 'dindgen', + 'dissolve', 'dist', 'distance_measure', 'dlm_load', 'dlm_register', + 'doc_library', 'double', 'draw_roi', 'edge_dog', 'efont', + 'eigenql', 'eigenvec', 'ellipse', 'elmhes', 'emboss', + 'empty', 'enable_sysrtn', 'eof', 'eos', 'erase', + 'erf', 'erfc', 'erfcx', 'erode', 'errorplot', + 'errplot', 'estimator_filter', 'execute', 'exit', 'exp', + 'expand', 'expand_path', 'expint', 'extrac', 'extract_slice', + 'f_cvf', 'f_pdf', 'factorial', 'fft', 'file_basename', + 'file_chmod', 'file_copy', 'file_delete', 'file_dirname', + 'file_expand_path', 'file_gunzip', 'file_gzip', 'file_info', + 'file_lines', 'file_link', 'file_mkdir', 'file_move', + 'file_poll_input', 'file_readlink', 'file_same', + 'file_search', 'file_tar', 'file_test', 'file_untar', 'file_unzip', + 'file_which', 'file_zip', 'filepath', 'findgen', 'finite', + 'fix', 'flick', 'float', 'floor', 'flow3', + 'fltarr', 'flush', 'format_axis_values', 'forward_function', 'free_lun', + 'fstat', 'fulstr', 'funct', 'function', 'fv_test', + 'fx_root', 'fz_roots', 'gamma', 'gamma_ct', 'gauss_cvf', + 'gauss_pdf', 'gauss_smooth', 'gauss2dfit', 'gaussfit', + 'gaussian_function', 'gaussint', 'get_drive_list', 'get_dxf_objects', + 'get_kbrd', 'get_login_info', + 'get_lun', 'get_screen_size', 'getenv', 'getwindows', 'greg2jul', + 'grib', 'grid_input', 'grid_tps', 'grid3', 'griddata', + 'gs_iter', 'h_eq_ct', 'h_eq_int', 'hanning', 'hash', + 'hdf', 'hdf5', 'heap_free', 'heap_gc', 'heap_nosave', + 'heap_refcount', 'heap_save', 'help', 'hilbert', 'hist_2d', + 'hist_equal', 'histogram', 'hls', 'hough', 'hqr', + 'hsv', 'i18n_multibytetoutf8', + 'i18n_multibytetowidechar', 'i18n_utf8tomultibyte', + 'i18n_widechartomultibyte', + 'ibeta', 'icontour', 'iconvertcoord', 'idelete', 'identity', + 'idl_base64', 'idl_container', 'idl_validname', + 'idlexbr_assistant', 'idlitsys_createtool', + 'idlunit', 'iellipse', 'igamma', 'igetcurrent', 'igetdata', + 'igetid', 'igetproperty', 'iimage', 'image', 'image_cont', + 'image_statistics', 'image_threshold', 'imaginary', 'imap', 'indgen', + 'int_2d', 'int_3d', 'int_tabulated', 'intarr', 'interpol', + 'interpolate', 'interval_volume', 'invert', 'ioctl', 'iopen', + 'ir_filter', 'iplot', 'ipolygon', 'ipolyline', 'iputdata', + 'iregister', 'ireset', 'iresolve', 'irotate', 'isa', + 'isave', 'iscale', 'isetcurrent', 'isetproperty', 'ishft', + 'isocontour', 'isosurface', 'isurface', 'itext', 'itranslate', + 'ivector', 'ivolume', 'izoom', 'journal', 'json_parse', + 'json_serialize', 'jul2greg', 'julday', 'keyword_set', 'krig2d', + 'kurtosis', 'kw_test', 'l64indgen', 'la_choldc', 'la_cholmprove', + 'la_cholsol', 'la_determ', 'la_eigenproblem', 'la_eigenql', 'la_eigenvec', + 'la_elmhes', 'la_gm_linear_model', 'la_hqr', 'la_invert', + 'la_least_square_equality', 'la_least_squares', 'la_linear_equation', + 'la_ludc', 'la_lumprove', 'la_lusol', + 'la_svd', 'la_tridc', 'la_trimprove', 'la_triql', 'la_trired', + 'la_trisol', 'label_date', 'label_region', 'ladfit', 'laguerre', + 'lambda', 'lambdap', 'lambertw', 'laplacian', 'least_squares_filter', + 'leefilt', 'legend', 'legendre', 'linbcg', 'lindgen', + 'linfit', 'linkimage', 'list', 'll_arc_distance', 'lmfit', + 'lmgr', 'lngamma', 'lnp_test', 'loadct', 'locale_get', + 'logical_and', 'logical_or', 'logical_true', 'lon64arr', 'lonarr', + 'long', 'long64', 'lsode', 'lu_complex', 'ludc', + 'lumprove', 'lusol', 'm_correlate', 'machar', 'make_array', + 'make_dll', 'make_rt', 'map', 'mapcontinents', 'mapgrid', + 'map_2points', 'map_continents', 'map_grid', 'map_image', 'map_patch', + 'map_proj_forward', 'map_proj_image', 'map_proj_info', + 'map_proj_init', 'map_proj_inverse', + 'map_set', 'matrix_multiply', 'matrix_power', 'max', 'md_test', + 'mean', 'meanabsdev', 'mean_filter', 'median', 'memory', + 'mesh_clip', 'mesh_decimate', 'mesh_issolid', + 'mesh_merge', 'mesh_numtriangles', + 'mesh_obj', 'mesh_smooth', 'mesh_surfacearea', + 'mesh_validate', 'mesh_volume', + 'message', 'min', 'min_curve_surf', 'mk_html_help', 'modifyct', + 'moment', 'morph_close', 'morph_distance', + 'morph_gradient', 'morph_hitormiss', + 'morph_open', 'morph_thin', 'morph_tophat', 'multi', 'n_elements', + 'n_params', 'n_tags', 'ncdf', 'newton', 'noise_hurl', + 'noise_pick', 'noise_scatter', 'noise_slur', 'norm', 'obj_class', + 'obj_destroy', 'obj_hasmethod', 'obj_isa', 'obj_new', 'obj_valid', + 'objarr', 'on_error', 'on_ioerror', 'online_help', 'openr', + 'openu', 'openw', 'oplot', 'oploterr', 'orderedhash', + 'p_correlate', 'parse_url', 'particle_trace', 'path_cache', 'path_sep', + 'pcomp', 'plot', 'plot3d', 'plot', 'plot_3dbox', + 'plot_field', 'ploterr', 'plots', 'polar_contour', 'polar_surface', + 'polyfill', 'polyshade', 'pnt_line', 'point_lun', 'polarplot', + 'poly', 'poly_2d', 'poly_area', 'poly_fit', 'polyfillv', + 'polygon', 'polyline', 'polywarp', 'popd', 'powell', + 'pref_commit', 'pref_get', 'pref_set', 'prewitt', 'primes', + 'print', 'printf', 'printd', 'pro', 'product', + 'profile', 'profiler', 'profiles', 'project_vol', 'ps_show_fonts', + 'psafm', 'pseudo', 'ptr_free', 'ptr_new', 'ptr_valid', + 'ptrarr', 'pushd', 'qgrid3', 'qhull', 'qromb', + 'qromo', 'qsimp', 'query_*', 'query_ascii', 'query_bmp', + 'query_csv', 'query_dicom', 'query_gif', 'query_image', 'query_jpeg', + 'query_jpeg2000', 'query_mrsid', 'query_pict', 'query_png', 'query_ppm', + 'query_srf', 'query_tiff', 'query_video', 'query_wav', 'r_correlate', + 'r_test', 'radon', 'randomn', 'randomu', 'ranks', + 'rdpix', 'read', 'readf', 'read_ascii', 'read_binary', + 'read_bmp', 'read_csv', 'read_dicom', 'read_gif', 'read_image', + 'read_interfile', 'read_jpeg', 'read_jpeg2000', 'read_mrsid', 'read_pict', + 'read_png', 'read_ppm', 'read_spr', 'read_srf', 'read_sylk', + 'read_tiff', 'read_video', 'read_wav', 'read_wave', 'read_x11_bitmap', + 'read_xwd', 'reads', 'readu', 'real_part', 'rebin', + 'recall_commands', 'recon3', 'reduce_colors', 'reform', 'region_grow', + 'register_cursor', 'regress', 'replicate', + 'replicate_inplace', 'resolve_all', + 'resolve_routine', 'restore', 'retall', 'return', 'reverse', + 'rk4', 'roberts', 'rot', 'rotate', 'round', + 'routine_filepath', 'routine_info', 'rs_test', 's_test', 'save', + 'savgol', 'scale3', 'scale3d', 'scatterplot', 'scatterplot3d', + 'scope_level', 'scope_traceback', 'scope_varfetch', + 'scope_varname', 'search2d', + 'search3d', 'sem_create', 'sem_delete', 'sem_lock', 'sem_release', + 'set_plot', 'set_shading', 'setenv', 'sfit', 'shade_surf', + 'shade_surf_irr', 'shade_volume', 'shift', 'shift_diff', 'shmdebug', + 'shmmap', 'shmunmap', 'shmvar', 'show3', 'showfont', + 'signum', 'simplex', 'sin', 'sindgen', 'sinh', + 'size', 'skewness', 'skip_lun', 'slicer3', 'slide_image', + 'smooth', 'sobel', 'socket', 'sort', 'spawn', + 'sph_4pnt', 'sph_scat', 'spher_harm', 'spl_init', 'spl_interp', + 'spline', 'spline_p', 'sprsab', 'sprsax', 'sprsin', + 'sprstp', 'sqrt', 'standardize', 'stddev', 'stop', + 'strarr', 'strcmp', 'strcompress', 'streamline', 'streamline', + 'stregex', 'stretch', 'string', 'strjoin', 'strlen', + 'strlowcase', 'strmatch', 'strmessage', 'strmid', 'strpos', + 'strput', 'strsplit', 'strtrim', 'struct_assign', 'struct_hide', + 'strupcase', 'surface', 'surface', 'surfr', 'svdc', + 'svdfit', 'svsol', 'swap_endian', 'swap_endian_inplace', 'symbol', + 'systime', 't_cvf', 't_pdf', 't3d', 'tag_names', + 'tan', 'tanh', 'tek_color', 'temporary', 'terminal_size', + 'tetra_clip', 'tetra_surface', 'tetra_volume', 'text', 'thin', + 'thread', 'threed', 'tic', 'time_test2', 'timegen', + 'timer', 'timestamp', 'timestamptovalues', 'tm_test', 'toc', + 'total', 'trace', 'transpose', 'tri_surf', 'triangulate', + 'trigrid', 'triql', 'trired', 'trisol', 'truncate_lun', + 'ts_coef', 'ts_diff', 'ts_fcast', 'ts_smooth', 'tv', + 'tvcrs', 'tvlct', 'tvrd', 'tvscl', 'typename', + 'uindgen', 'uint', 'uintarr', 'ul64indgen', 'ulindgen', + 'ulon64arr', 'ulonarr', 'ulong', 'ulong64', 'uniq', + 'unsharp_mask', 'usersym', 'value_locate', 'variance', 'vector', + 'vector_field', 'vel', 'velovect', 'vert_t3d', 'voigt', + 'volume', 'voronoi', 'voxel_proj', 'wait', 'warp_tri', + 'watershed', 'wdelete', 'wf_draw', 'where', 'widget_base', + 'widget_button', 'widget_combobox', 'widget_control', + 'widget_displaycontextmenu', 'widget_draw', + 'widget_droplist', 'widget_event', 'widget_info', + 'widget_label', 'widget_list', + 'widget_propertysheet', 'widget_slider', 'widget_tab', + 'widget_table', 'widget_text', + 'widget_tree', 'widget_tree_move', 'widget_window', + 'wiener_filter', 'window', + 'window', 'write_bmp', 'write_csv', 'write_gif', 'write_image', + 'write_jpeg', 'write_jpeg2000', 'write_nrif', 'write_pict', 'write_png', + 'write_ppm', 'write_spr', 'write_srf', 'write_sylk', 'write_tiff', + 'write_video', 'write_wav', 'write_wave', 'writeu', 'wset', + 'wshow', 'wtn', 'wv_applet', 'wv_cwt', 'wv_cw_wavelet', + 'wv_denoise', 'wv_dwt', 'wv_fn_coiflet', + 'wv_fn_daubechies', 'wv_fn_gaussian', + 'wv_fn_haar', 'wv_fn_morlet', 'wv_fn_paul', + 'wv_fn_symlet', 'wv_import_data', + 'wv_import_wavelet', 'wv_plot3d_wps', 'wv_plot_multires', + 'wv_pwt', 'wv_tool_denoise', + 'xbm_edit', 'xdisplayfile', 'xdxf', 'xfont', 'xinteranimate', + 'xloadct', 'xmanager', 'xmng_tmpl', 'xmtool', 'xobjview', + 'xobjview_rotate', 'xobjview_write_image', + 'xpalette', 'xpcolor', 'xplot3d', + 'xregistered', 'xroi', 'xsq_test', 'xsurface', 'xvaredit', + 'xvolume', 'xvolume_rotate', 'xvolume_write_image', + 'xyouts', 'zlib_compress', 'zlib_uncompress', 'zoom', 'zoom_24' + ]; + var builtins = wordRegexp(builtinArray); + + var keywordArray = [ + 'begin', 'end', 'endcase', 'endfor', + 'endwhile', 'endif', 'endrep', 'endforeach', + 'break', 'case', 'continue', 'for', + 'foreach', 'goto', 'if', 'then', 'else', + 'repeat', 'until', 'switch', 'while', + 'do', 'pro', 'function' + ]; + var keywords = wordRegexp(keywordArray); + + CodeMirror.registerHelper("hintWords", "idl", builtinArray.concat(keywordArray)); + + var identifiers = new RegExp('^[_a-z\xa1-\uffff][_a-z0-9\xa1-\uffff]*', 'i'); + + var singleOperators = /[+\-*&=<>\/@#~$]/; + var boolOperators = new RegExp('(and|or|eq|lt|le|gt|ge|ne|not)', 'i'); + + function tokenBase(stream) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match(';')) { + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+/)) + return 'number'; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?/)) + return 'number'; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?/)) + return 'number'; + } + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } + if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } + + // Handle words + if (stream.match(keywords)) { return 'keyword'; } + if (stream.match(builtins)) { return 'builtin'; } + if (stream.match(identifiers)) { return 'variable'; } + + if (stream.match(singleOperators) || stream.match(boolOperators)) { + return 'operator'; } + + // Handle non-detected items + stream.next(); + return null; + }; + + CodeMirror.defineMode('idl', function() { + return { + token: function(stream) { + return tokenBase(stream); + } + }; + }); + + CodeMirror.defineMIME('text/x-idl', 'idl'); +}); diff --git a/rhodecode/public/js/mode/jade/jade.js b/rhodecode/public/js/mode/jade/jade.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/jade/jade.js @@ -0,0 +1,590 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../javascript/javascript"), require("../css/css"), require("../htmlmixed/htmlmixed")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../javascript/javascript", "../css/css", "../htmlmixed/htmlmixed"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('jade', function (config) { + // token types + var KEYWORD = 'keyword'; + var DOCTYPE = 'meta'; + var ID = 'builtin'; + var CLASS = 'qualifier'; + + var ATTRS_NEST = { + '{': '}', + '(': ')', + '[': ']' + }; + + var jsMode = CodeMirror.getMode(config, 'javascript'); + + function State() { + this.javaScriptLine = false; + this.javaScriptLineExcludesColon = false; + + this.javaScriptArguments = false; + this.javaScriptArgumentsDepth = 0; + + this.isInterpolating = false; + this.interpolationNesting = 0; + + this.jsState = jsMode.startState(); + + this.restOfLine = ''; + + this.isIncludeFiltered = false; + this.isEach = false; + + this.lastTag = ''; + this.scriptType = ''; + + // Attributes Mode + this.isAttrs = false; + this.attrsNest = []; + this.inAttributeName = true; + this.attributeIsType = false; + this.attrValue = ''; + + // Indented Mode + this.indentOf = Infinity; + this.indentToken = ''; + + this.innerMode = null; + this.innerState = null; + + this.innerModeForLine = false; + } + /** + * Safely copy a state + * + * @return {State} + */ + State.prototype.copy = function () { + var res = new State(); + res.javaScriptLine = this.javaScriptLine; + res.javaScriptLineExcludesColon = this.javaScriptLineExcludesColon; + res.javaScriptArguments = this.javaScriptArguments; + res.javaScriptArgumentsDepth = this.javaScriptArgumentsDepth; + res.isInterpolating = this.isInterpolating; + res.interpolationNesting = this.intpolationNesting; + + res.jsState = CodeMirror.copyState(jsMode, this.jsState); + + res.innerMode = this.innerMode; + if (this.innerMode && this.innerState) { + res.innerState = CodeMirror.copyState(this.innerMode, this.innerState); + } + + res.restOfLine = this.restOfLine; + + res.isIncludeFiltered = this.isIncludeFiltered; + res.isEach = this.isEach; + res.lastTag = this.lastTag; + res.scriptType = this.scriptType; + res.isAttrs = this.isAttrs; + res.attrsNest = this.attrsNest.slice(); + res.inAttributeName = this.inAttributeName; + res.attributeIsType = this.attributeIsType; + res.attrValue = this.attrValue; + res.indentOf = this.indentOf; + res.indentToken = this.indentToken; + + res.innerModeForLine = this.innerModeForLine; + + return res; + }; + + function javaScript(stream, state) { + if (stream.sol()) { + // if javaScriptLine was set at end of line, ignore it + state.javaScriptLine = false; + state.javaScriptLineExcludesColon = false; + } + if (state.javaScriptLine) { + if (state.javaScriptLineExcludesColon && stream.peek() === ':') { + state.javaScriptLine = false; + state.javaScriptLineExcludesColon = false; + return; + } + var tok = jsMode.token(stream, state.jsState); + if (stream.eol()) state.javaScriptLine = false; + return tok || true; + } + } + function javaScriptArguments(stream, state) { + if (state.javaScriptArguments) { + if (state.javaScriptArgumentsDepth === 0 && stream.peek() !== '(') { + state.javaScriptArguments = false; + return; + } + if (stream.peek() === '(') { + state.javaScriptArgumentsDepth++; + } else if (stream.peek() === ')') { + state.javaScriptArgumentsDepth--; + } + if (state.javaScriptArgumentsDepth === 0) { + state.javaScriptArguments = false; + return; + } + + var tok = jsMode.token(stream, state.jsState); + return tok || true; + } + } + + function yieldStatement(stream) { + if (stream.match(/^yield\b/)) { + return 'keyword'; + } + } + + function doctype(stream) { + if (stream.match(/^(?:doctype) *([^\n]+)?/)) { + return DOCTYPE; + } + } + + function interpolation(stream, state) { + if (stream.match('#{')) { + state.isInterpolating = true; + state.interpolationNesting = 0; + return 'punctuation'; + } + } + + function interpolationContinued(stream, state) { + if (state.isInterpolating) { + if (stream.peek() === '}') { + state.interpolationNesting--; + if (state.interpolationNesting < 0) { + stream.next(); + state.isInterpolating = false; + return 'puncutation'; + } + } else if (stream.peek() === '{') { + state.interpolationNesting++; + } + return jsMode.token(stream, state.jsState) || true; + } + } + + function caseStatement(stream, state) { + if (stream.match(/^case\b/)) { + state.javaScriptLine = true; + return KEYWORD; + } + } + + function when(stream, state) { + if (stream.match(/^when\b/)) { + state.javaScriptLine = true; + state.javaScriptLineExcludesColon = true; + return KEYWORD; + } + } + + function defaultStatement(stream) { + if (stream.match(/^default\b/)) { + return KEYWORD; + } + } + + function extendsStatement(stream, state) { + if (stream.match(/^extends?\b/)) { + state.restOfLine = 'string'; + return KEYWORD; + } + } + + function append(stream, state) { + if (stream.match(/^append\b/)) { + state.restOfLine = 'variable'; + return KEYWORD; + } + } + function prepend(stream, state) { + if (stream.match(/^prepend\b/)) { + state.restOfLine = 'variable'; + return KEYWORD; + } + } + function block(stream, state) { + if (stream.match(/^block\b *(?:(prepend|append)\b)?/)) { + state.restOfLine = 'variable'; + return KEYWORD; + } + } + + function include(stream, state) { + if (stream.match(/^include\b/)) { + state.restOfLine = 'string'; + return KEYWORD; + } + } + + function includeFiltered(stream, state) { + if (stream.match(/^include:([a-zA-Z0-9\-]+)/, false) && stream.match('include')) { + state.isIncludeFiltered = true; + return KEYWORD; + } + } + + function includeFilteredContinued(stream, state) { + if (state.isIncludeFiltered) { + var tok = filter(stream, state); + state.isIncludeFiltered = false; + state.restOfLine = 'string'; + return tok; + } + } + + function mixin(stream, state) { + if (stream.match(/^mixin\b/)) { + state.javaScriptLine = true; + return KEYWORD; + } + } + + function call(stream, state) { + if (stream.match(/^\+([-\w]+)/)) { + if (!stream.match(/^\( *[-\w]+ *=/, false)) { + state.javaScriptArguments = true; + state.javaScriptArgumentsDepth = 0; + } + return 'variable'; + } + if (stream.match(/^\+#{/, false)) { + stream.next(); + state.mixinCallAfter = true; + return interpolation(stream, state); + } + } + function callArguments(stream, state) { + if (state.mixinCallAfter) { + state.mixinCallAfter = false; + if (!stream.match(/^\( *[-\w]+ *=/, false)) { + state.javaScriptArguments = true; + state.javaScriptArgumentsDepth = 0; + } + return true; + } + } + + function conditional(stream, state) { + if (stream.match(/^(if|unless|else if|else)\b/)) { + state.javaScriptLine = true; + return KEYWORD; + } + } + + function each(stream, state) { + if (stream.match(/^(- *)?(each|for)\b/)) { + state.isEach = true; + return KEYWORD; + } + } + function eachContinued(stream, state) { + if (state.isEach) { + if (stream.match(/^ in\b/)) { + state.javaScriptLine = true; + state.isEach = false; + return KEYWORD; + } else if (stream.sol() || stream.eol()) { + state.isEach = false; + } else if (stream.next()) { + while (!stream.match(/^ in\b/, false) && stream.next()); + return 'variable'; + } + } + } + + function whileStatement(stream, state) { + if (stream.match(/^while\b/)) { + state.javaScriptLine = true; + return KEYWORD; + } + } + + function tag(stream, state) { + var captures; + if (captures = stream.match(/^(\w(?:[-:\w]*\w)?)\/?/)) { + state.lastTag = captures[1].toLowerCase(); + if (state.lastTag === 'script') { + state.scriptType = 'application/javascript'; + } + return 'tag'; + } + } + + function filter(stream, state) { + if (stream.match(/^:([\w\-]+)/)) { + var innerMode; + if (config && config.innerModes) { + innerMode = config.innerModes(stream.current().substring(1)); + } + if (!innerMode) { + innerMode = stream.current().substring(1); + } + if (typeof innerMode === 'string') { + innerMode = CodeMirror.getMode(config, innerMode); + } + setInnerMode(stream, state, innerMode); + return 'atom'; + } + } + + function code(stream, state) { + if (stream.match(/^(!?=|-)/)) { + state.javaScriptLine = true; + return 'punctuation'; + } + } + + function id(stream) { + if (stream.match(/^#([\w-]+)/)) { + return ID; + } + } + + function className(stream) { + if (stream.match(/^\.([\w-]+)/)) { + return CLASS; + } + } + + function attrs(stream, state) { + if (stream.peek() == '(') { + stream.next(); + state.isAttrs = true; + state.attrsNest = []; + state.inAttributeName = true; + state.attrValue = ''; + state.attributeIsType = false; + return 'punctuation'; + } + } + + function attrsContinued(stream, state) { + if (state.isAttrs) { + if (ATTRS_NEST[stream.peek()]) { + state.attrsNest.push(ATTRS_NEST[stream.peek()]); + } + if (state.attrsNest[state.attrsNest.length - 1] === stream.peek()) { + state.attrsNest.pop(); + } else if (stream.eat(')')) { + state.isAttrs = false; + return 'punctuation'; + } + if (state.inAttributeName && stream.match(/^[^=,\)!]+/)) { + if (stream.peek() === '=' || stream.peek() === '!') { + state.inAttributeName = false; + state.jsState = jsMode.startState(); + if (state.lastTag === 'script' && stream.current().trim().toLowerCase() === 'type') { + state.attributeIsType = true; + } else { + state.attributeIsType = false; + } + } + return 'attribute'; + } + + var tok = jsMode.token(stream, state.jsState); + if (state.attributeIsType && tok === 'string') { + state.scriptType = stream.current().toString(); + } + if (state.attrsNest.length === 0 && (tok === 'string' || tok === 'variable' || tok === 'keyword')) { + try { + Function('', 'var x ' + state.attrValue.replace(/,\s*$/, '').replace(/^!/, '')); + state.inAttributeName = true; + state.attrValue = ''; + stream.backUp(stream.current().length); + return attrsContinued(stream, state); + } catch (ex) { + //not the end of an attribute + } + } + state.attrValue += stream.current(); + return tok || true; + } + } + + function attributesBlock(stream, state) { + if (stream.match(/^&attributes\b/)) { + state.javaScriptArguments = true; + state.javaScriptArgumentsDepth = 0; + return 'keyword'; + } + } + + function indent(stream) { + if (stream.sol() && stream.eatSpace()) { + return 'indent'; + } + } + + function comment(stream, state) { + if (stream.match(/^ *\/\/(-)?([^\n]*)/)) { + state.indentOf = stream.indentation(); + state.indentToken = 'comment'; + return 'comment'; + } + } + + function colon(stream) { + if (stream.match(/^: */)) { + return 'colon'; + } + } + + function text(stream, state) { + if (stream.match(/^(?:\| ?| )([^\n]+)/)) { + return 'string'; + } + if (stream.match(/^(<[^\n]*)/, false)) { + // html string + setInnerMode(stream, state, 'htmlmixed'); + state.innerModeForLine = true; + return innerMode(stream, state, true); + } + } + + function dot(stream, state) { + if (stream.eat('.')) { + var innerMode = null; + if (state.lastTag === 'script' && state.scriptType.toLowerCase().indexOf('javascript') != -1) { + innerMode = state.scriptType.toLowerCase().replace(/"|'/g, ''); + } else if (state.lastTag === 'style') { + innerMode = 'css'; + } + setInnerMode(stream, state, innerMode); + return 'dot'; + } + } + + function fail(stream) { + stream.next(); + return null; + } + + + function setInnerMode(stream, state, mode) { + mode = CodeMirror.mimeModes[mode] || mode; + mode = config.innerModes ? config.innerModes(mode) || mode : mode; + mode = CodeMirror.mimeModes[mode] || mode; + mode = CodeMirror.getMode(config, mode); + state.indentOf = stream.indentation(); + + if (mode && mode.name !== 'null') { + state.innerMode = mode; + } else { + state.indentToken = 'string'; + } + } + function innerMode(stream, state, force) { + if (stream.indentation() > state.indentOf || (state.innerModeForLine && !stream.sol()) || force) { + if (state.innerMode) { + if (!state.innerState) { + state.innerState = state.innerMode.startState ? state.innerMode.startState(stream.indentation()) : {}; + } + return stream.hideFirstChars(state.indentOf + 2, function () { + return state.innerMode.token(stream, state.innerState) || true; + }); + } else { + stream.skipToEnd(); + return state.indentToken; + } + } else if (stream.sol()) { + state.indentOf = Infinity; + state.indentToken = null; + state.innerMode = null; + state.innerState = null; + } + } + function restOfLine(stream, state) { + if (stream.sol()) { + // if restOfLine was set at end of line, ignore it + state.restOfLine = ''; + } + if (state.restOfLine) { + stream.skipToEnd(); + var tok = state.restOfLine; + state.restOfLine = ''; + return tok; + } + } + + + function startState() { + return new State(); + } + function copyState(state) { + return state.copy(); + } + /** + * Get the next token in the stream + * + * @param {Stream} stream + * @param {State} state + */ + function nextToken(stream, state) { + var tok = innerMode(stream, state) + || restOfLine(stream, state) + || interpolationContinued(stream, state) + || includeFilteredContinued(stream, state) + || eachContinued(stream, state) + || attrsContinued(stream, state) + || javaScript(stream, state) + || javaScriptArguments(stream, state) + || callArguments(stream, state) + + || yieldStatement(stream, state) + || doctype(stream, state) + || interpolation(stream, state) + || caseStatement(stream, state) + || when(stream, state) + || defaultStatement(stream, state) + || extendsStatement(stream, state) + || append(stream, state) + || prepend(stream, state) + || block(stream, state) + || include(stream, state) + || includeFiltered(stream, state) + || mixin(stream, state) + || call(stream, state) + || conditional(stream, state) + || each(stream, state) + || whileStatement(stream, state) + || tag(stream, state) + || filter(stream, state) + || code(stream, state) + || id(stream, state) + || className(stream, state) + || attrs(stream, state) + || attributesBlock(stream, state) + || indent(stream, state) + || text(stream, state) + || comment(stream, state) + || colon(stream, state) + || dot(stream, state) + || fail(stream, state); + + return tok === true ? null : tok; + } + return { + startState: startState, + copyState: copyState, + token: nextToken + }; +}); + +CodeMirror.defineMIME('text/x-jade', 'jade'); + +}); diff --git a/rhodecode/public/js/mode/javascript/javascript.js b/rhodecode/public/js/mode/javascript/javascript.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/javascript/javascript.js @@ -0,0 +1,704 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// TODO actually recognize syntax of TypeScript constructs + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + + var jsKeywords = { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C + }; + + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = {type: "variable", style: "variable-3"}; + var tsKeywords = { + // object-like things + "interface": kw("interface"), + "extends": kw("extends"), + "constructor": kw("constructor"), + + // scope modifiers + "public": kw("public"), + "private": kw("private"), + "protected": kw("protected"), + "static": kw("static"), + + // types + "string": type, "number": type, "bool": type, "any": type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; + } + } + + return jsKeywords; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (state.lastType == "operator" || state.lastType == "keyword c" || + state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { + readRegexp(stream); + stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); + return ret("regexp", "string-2"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.lastType != ".") ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) break; + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/]/.test(ch)) { + return; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + function inList(list) { + for (var v = list; v; v = v.next) + if (v.name == varname) return true; + return false; + } + var state = cx.state; + if (state.context) { + cx.marked = "def"; + if (inList(state.localVars)) return; + state.localVars = {name: varname, next: state.localVars}; + } else { + if (inList(state.globalVars)) return; + if (parserConfig.globalVars) + state.globalVars = {name: varname, next: state.globalVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: {name: "arguments"}}; + function pushcontext() { + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + cx.state.localVars = defaultVars; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), expression, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); + if (type == "class") return cont(pushlex("form"), className, poplex); + if (type == "export") return cont(pushlex("form"), afterExport, poplex); + if (type == "import") return cont(pushlex("form"), afterImport, poplex); + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + return expressionInner(type, false); + } + function expressionNoComma(type) { + return expressionInner(type, true); + } + function expressionInner(type, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") { return pass(quasi, maybeop); } + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value)) return cont(me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expressionNoComma); + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (type == "[") { + return cont(expression, expect("]"), afterprop); + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end) { + function proceed(type) { + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(what, proceed); + } + if (type == end) return cont(); + return cont(expect(end)); + } + return function(type) { + if (type == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type) { + if (isTS && type == ":") return cont(typedef); + } + function maybedefault(_, value) { + if (value == "=") return cont(expressionNoComma); + } + function typedef(type) { + if (type == "variable") {cx.marked = "variable-3"; return cont();} + } + function vardef() { + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (type == "variable") { register(value); return cont(); } + if (type == "[") return contCommasep(pattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + return cont(expect(":"), pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type) { + if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, expect(";"), forspec2); + if (type == ";") return cont(forspec2); + if (type == "variable") return cont(formaybeinof); + return pass(expression, expect(";"), forspec2); + } + function formaybeinof(_type, value) { + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return pass(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); + } + function funarg(type) { + if (type == "spread") return cont(funarg); + return pass(pattern, maybetype, maybedefault); + } + function className(type, value) { + if (type == "variable") {register(value); return cont(classNameAfter);} + } + function classNameAfter(type, value) { + if (value == "extends") return cont(expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + if (value == "static") { + cx.marked = "keyword"; + return cont(classBody); + } + cx.marked = "property"; + if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); + return cont(functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); + } + function classGetterSetter(type) { + if (type != "variable") return pass(); + cx.marked = "property"; + return cont(); + } + function afterModule(type, value) { + if (type == "string") return cont(statement); + if (type == "variable") { register(value); return cont(maybeFrom); } + } + function afterExport(_type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + return pass(statement); + } + function afterImport(type) { + if (type == "string") return cont(); + return pass(importSpec, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + if (value == "*") cx.marked = "keyword"; + return cont(maybeAs); + } + function maybeAs(_type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(expressionNoComma, maybeArrayComprehension); + } + function maybeArrayComprehension(type) { + if (type == "for") return pass(comprehension, expect("]")); + if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); + return pass(commasep(expressionNoComma, "]")); + } + function comprehension(type) { + if (type == "for") return cont(forspec, comprehension); + if (type == "if") return cont(expression, comprehension); + } + + function isContinuedStatement(state, textAfter) { + return state.lastType == "operator" || state.lastType == "," || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)); + } + + // Interface + + return { + startState: function(basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", + fold: "brace", + closeBrackets: "()[]{}''\"\"``", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode + }; +}); + +CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +}); diff --git a/rhodecode/public/js/mode/jinja2/jinja2.js b/rhodecode/public/js/mode/jinja2/jinja2.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/jinja2/jinja2.js @@ -0,0 +1,142 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("jinja2", function() { + var keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", + "extends", "filter", "endfilter", "firstof", "for", + "endfor", "if", "endif", "ifchanged", "endifchanged", + "ifequal", "endifequal", "ifnotequal", + "endifnotequal", "in", "include", "load", "not", "now", "or", + "parsed", "regroup", "reversed", "spaceless", + "endspaceless", "ssi", "templatetag", "openblock", + "closeblock", "openvariable", "closevariable", + "openbrace", "closebrace", "opencomment", + "closecomment", "widthratio", "url", "with", "endwith", + "get_current_language", "trans", "endtrans", "noop", "blocktrans", + "endblocktrans", "get_available_languages", + "get_current_language_bidi", "plural"], + operator = /^[+\-*&%=<>!?|~^]/, + sign = /^[:\[\(\{]/, + atom = ["true", "false"], + number = /^(\d[+\-\*\/])?\d+(\.\d+)?/; + + keywords = new RegExp("((" + keywords.join(")|(") + "))\\b"); + atom = new RegExp("((" + atom.join(")|(") + "))\\b"); + + function tokenBase (stream, state) { + var ch = stream.peek(); + + //Comment + if (state.incomment) { + if(!stream.skipTo("#}")) { + stream.skipToEnd(); + } else { + stream.eatWhile(/\#|}/); + state.incomment = false; + } + return "comment"; + //Tag + } else if (state.intag) { + //After operator + if(state.operator) { + state.operator = false; + if(stream.match(atom)) { + return "atom"; + } + if(stream.match(number)) { + return "number"; + } + } + //After sign + if(state.sign) { + state.sign = false; + if(stream.match(atom)) { + return "atom"; + } + if(stream.match(number)) { + return "number"; + } + } + + if(state.instring) { + if(ch == state.instring) { + state.instring = false; + } + stream.next(); + return "string"; + } else if(ch == "'" || ch == '"') { + state.instring = ch; + stream.next(); + return "string"; + } else if(stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) { + state.intag = false; + return "tag"; + } else if(stream.match(operator)) { + state.operator = true; + return "operator"; + } else if(stream.match(sign)) { + state.sign = true; + } else { + if(stream.eat(" ") || stream.sol()) { + if(stream.match(keywords)) { + return "keyword"; + } + if(stream.match(atom)) { + return "atom"; + } + if(stream.match(number)) { + return "number"; + } + if(stream.sol()) { + stream.next(); + } + } else { + stream.next(); + } + + } + return "variable"; + } else if (stream.eat("{")) { + if (ch = stream.eat("#")) { + state.incomment = true; + if(!stream.skipTo("#}")) { + stream.skipToEnd(); + } else { + stream.eatWhile(/\#|}/); + state.incomment = false; + } + return "comment"; + //Open tag + } else if (ch = stream.eat(/\{|%/)) { + //Cache close tag + state.intag = ch; + if(ch == "{") { + state.intag = "}"; + } + stream.eat("-"); + return "tag"; + } + } + stream.next(); + }; + + return { + startState: function () { + return {tokenize: tokenBase}; + }, + token: function (stream, state) { + return state.tokenize(stream, state); + } + }; + }); +}); diff --git a/rhodecode/public/js/mode/jsx/jsx.js b/rhodecode/public/js/mode/jsx/jsx.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/jsx/jsx.js @@ -0,0 +1,147 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + + // Depth means the amount of open braces in JS context, in XML + // context 0 means not in tag, 1 means in tag, and 2 means in tag + // and js block comment. + function Context(state, mode, depth, prev) { + this.state = state; this.mode = mode; this.depth = depth; this.prev = prev + } + + function copyContext(context) { + return new Context(CodeMirror.copyState(context.mode, context.state), + context.mode, + context.depth, + context.prev && copyContext(context.prev)) + } + + CodeMirror.defineMode("jsx", function(config) { + var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false}) + var jsMode = CodeMirror.getMode(config, "javascript") + + function flatXMLIndent(state) { + var tagName = state.tagName + state.tagName = null + var result = xmlMode.indent(state, "") + state.tagName = tagName + return result + } + + function token(stream, state) { + if (state.context.mode == xmlMode) + return xmlToken(stream, state, state.context) + else + return jsToken(stream, state, state.context) + } + + function xmlToken(stream, state, cx) { + if (cx.depth == 2) { // Inside a JS /* */ comment + if (stream.match(/^.*?\*\//)) cx.depth = 1 + else stream.skipToEnd() + return "comment" + } + + if (stream.peek() == "{") { + xmlMode.skipAttribute(cx.state) + + var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context + // If JS starts on same line as tag + if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) { + while (xmlContext.prev && !xmlContext.startOfLine) + xmlContext = xmlContext.prev + // If tag starts the line, use XML indentation level + if (xmlContext.startOfLine) indent -= config.indentUnit + // Else use JS indentation level + else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented + // Else if inside of tag + } else if (cx.depth == 1) { + indent += config.indentUnit + } + + state.context = new Context(CodeMirror.startState(jsMode, indent), + jsMode, 0, state.context) + return null + } + + if (cx.depth == 1) { // Inside of tag + if (stream.peek() == "<") { // Tag inside of tag + xmlMode.skipAttribute(cx.state) + state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)), + xmlMode, 0, state.context) + return null + } else if (stream.match("//")) { + stream.skipToEnd() + return "comment" + } else if (stream.match("/*")) { + cx.depth = 2 + return token(stream, state) + } + } + + var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop + if (/\btag\b/.test(style)) { + if (/>$/.test(cur)) { + if (cx.state.context) cx.depth = 0 + else state.context = state.context.prev + } else if (/^</.test(cur)) { + cx.depth = 1 + } + } else if (!style && (stop = cur.indexOf("{")) > -1) { + stream.backUp(cur.length - stop) + } + return style + } + + function jsToken(stream, state, cx) { + if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) { + jsMode.skipExpression(cx.state) + state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")), + xmlMode, 0, state.context) + return null + } + + var style = jsMode.token(stream, cx.state) + if (!style && cx.depth != null) { + var cur = stream.current() + if (cur == "{") { + cx.depth++ + } else if (cur == "}") { + if (--cx.depth == 0) state.context = state.context.prev + } + } + return style + } + + return { + startState: function() { + return {context: new Context(CodeMirror.startState(jsMode), jsMode)} + }, + + copyState: function(state) { + return {context: copyContext(state.context)} + }, + + token: token, + + indent: function(state, textAfter, fullLine) { + return state.context.mode.indent(state.context.state, textAfter, fullLine) + }, + + innerMode: function(state) { + return state.context + } + } + }, "xml", "javascript") + + CodeMirror.defineMIME("text/jsx", "jsx") +}) diff --git a/rhodecode/public/js/mode/julia/julia.js b/rhodecode/public/js/mode/julia/julia.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/julia/julia.js @@ -0,0 +1,299 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("julia", function(_conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b/; + var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; + var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*!*/; + var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"]; + var blockClosers = ["end", "else", "elseif", "catch", "finally"]; + var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall']; + var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf']; + + //var stringPrefixes = new RegExp("^[br]?('|\")") + var stringPrefixes = /^(`|'|"{3}|([br]?"))/; + var keywords = wordRegexp(keywordList); + var builtins = wordRegexp(builtinList); + var openers = wordRegexp(blockOpeners); + var closers = wordRegexp(blockClosers); + var macro = /^@[_A-Za-z][_A-Za-z0-9]*/; + var symbol = /^:[_A-Za-z][_A-Za-z0-9]*/; + + function in_array(state) { + var ch = cur_scope(state); + if(ch=="[" || ch=="{") { + return true; + } + else { + return false; + } + } + + function cur_scope(state) { + if(state.scopes.length==0) { + return null; + } + return state.scopes[state.scopes.length - 1]; + } + + // tokenizers + function tokenBase(stream, state) { + // Handle scope changes + var leaving_expr = state.leaving_expr; + if(stream.sol()) { + leaving_expr = false; + } + state.leaving_expr = false; + if(leaving_expr) { + if(stream.match(/^'+/)) { + return 'operator'; + } + + } + + if(stream.match(/^\.{2,3}/)) { + return 'operator'; + } + + if (stream.eatSpace()) { + return null; + } + + var ch = stream.peek(); + // Handle Comments + if (ch === '#') { + stream.skipToEnd(); + return 'comment'; + } + if(ch==='[') { + state.scopes.push("["); + } + + if(ch==='{') { + state.scopes.push("{"); + } + + var scope=cur_scope(state); + + if(scope==='[' && ch===']') { + state.scopes.pop(); + state.leaving_expr=true; + } + + if(scope==='{' && ch==='}') { + state.scopes.pop(); + state.leaving_expr=true; + } + + if(ch===')') { + state.leaving_expr = true; + } + + var match; + if(!in_array(state) && (match=stream.match(openers, false))) { + state.scopes.push(match); + } + + if(!in_array(state) && stream.match(closers, false)) { + state.scopes.pop(); + } + + if(in_array(state)) { + if(stream.match(/^end/)) { + return 'number'; + } + + } + + if(stream.match(/^=>/)) { + return 'operator'; + } + + + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var imMatcher = RegExp(/^im\b/); + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.(?!\.)\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d+\.(?!\.)\d*/)) { floatLiteral = true; } + if (stream.match(/^\.\d+/)) { floatLiteral = true; } + if (floatLiteral) { + // Float literals may be "imaginary" + stream.match(imMatcher); + state.leaving_expr = true; + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; } + // Binary + if (stream.match(/^0b[01]+/i)) { intLiteral = true; } + // Octal + if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; } + // Decimal + if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.match(imMatcher); + state.leaving_expr = true; + return 'number'; + } + } + + if(stream.match(/^(::)|(<:)/)) { + return 'operator'; + } + + // Handle symbols + if(!leaving_expr && stream.match(symbol)) { + return 'string'; + } + + // Handle operators and Delimiters + if (stream.match(operators)) { + return 'operator'; + } + + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + if (stream.match(macro)) { + return 'meta'; + } + + + if (stream.match(delimiters)) { + return null; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(builtins)) { + return 'builtin'; + } + + + if (stream.match(identifiers)) { + state.leaving_expr=true; + return 'variable'; + } + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { + delimiter = delimiter.substr(1); + } + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + function tokenString(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\\]/); + if (stream.eat('\\')) { + stream.next(); + if (singleline && stream.eol()) { + return OUTCLASS; + } + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + } + tokenString.isString = true; + return tokenString; + } + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = stream.match(identifiers, false) ? null : ERRORCLASS; + if (style === null && state.lastStyle === 'meta') { + // Apply 'meta' style to '.' connected identifiers when + // appropriate. + style = 'meta'; + } + return style; + } + + return style; + } + + var external = { + startState: function() { + return { + tokenize: tokenBase, + scopes: [], + leaving_expr: false + }; + }, + + token: function(stream, state) { + var style = tokenLexer(stream, state); + state.lastStyle = style; + return style; + }, + + indent: function(state, textAfter) { + var delta = 0; + if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif" || textAfter=="catch" || textAfter=="finally") { + delta = -1; + } + return (state.scopes.length + delta) * 4; + }, + + lineComment: "#", + fold: "indent", + electricChars: "edlsifyh]}" + }; + return external; +}); + + +CodeMirror.defineMIME("text/x-julia", "julia"); + +}); diff --git a/rhodecode/public/js/mode/kotlin/kotlin.js b/rhodecode/public/js/mode/kotlin/kotlin.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/kotlin/kotlin.js @@ -0,0 +1,284 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("kotlin", function (config, parserConfig) { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var multiLineStrings = parserConfig.multiLineStrings; + + var keywords = words( + "package continue return object while break class data trait interface throw super" + + " when type this else This try val var fun for is in if do as true false null get set"); + var softKeywords = words("import" + + " where by get set abstract enum open annotation override private public internal" + + " protected catch out vararg inline finally final ref"); + var blockKeywords = words("catch class do else finally for if where try while enum"); + var atoms = words("null true false this"); + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + return startString(ch, stream, state); + } + // Wildcard import w/o trailing semicolon (import smth.*) + if (ch == "." && stream.eat("*")) { + return "word"; + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + if (stream.eat(/eE/)) { + stream.eat(/\+\-/); + stream.eatWhile(/\d/); + } + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize.push(tokenComment); + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + if (expectExpression(state.lastToken)) { + return startString(ch, stream, state); + } + } + // Commented + if (ch == "-" && stream.eat(">")) { + curPunc = "->"; + return null; + } + if (/[\-+*&%=<>!?|\/~]/.test(ch)) { + stream.eatWhile(/[\-+*&%=<>|~]/); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + + var cur = stream.current(); + if (atoms.propertyIsEnumerable(cur)) { + return "atom"; + } + if (softKeywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "softKeyword"; + } + + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + return "word"; + } + + tokenBase.isBase = true; + + function startString(quote, stream, state) { + var tripleQuoted = false; + if (quote != "/" && stream.eat(quote)) { + if (stream.eat(quote)) tripleQuoted = true; + else return "string"; + } + function t(stream, state) { + var escaped = false, next, end = !tripleQuoted; + + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + if (!tripleQuoted) { + break; + } + if (stream.match(quote + quote)) { + end = true; + break; + } + } + + if (quote == '"' && next == "$" && !escaped && stream.eat("{")) { + state.tokenize.push(tokenBaseUntilBrace()); + return "string"; + } + + if (next == "$" && !escaped && !stream.eat(" ")) { + state.tokenize.push(tokenBaseUntilSpace()); + return "string"; + } + escaped = !escaped && next == "\\"; + } + if (multiLineStrings) + state.tokenize.push(t); + if (end) state.tokenize.pop(); + return "string"; + } + + state.tokenize.push(t); + return t(stream, state); + } + + function tokenBaseUntilBrace() { + var depth = 1; + + function t(stream, state) { + if (stream.peek() == "}") { + depth--; + if (depth == 0) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length - 1](stream, state); + } + } else if (stream.peek() == "{") { + depth++; + } + return tokenBase(stream, state); + } + + t.isBase = true; + return t; + } + + function tokenBaseUntilSpace() { + function t(stream, state) { + if (stream.eat(/[\w]/)) { + var isWord = stream.eatWhile(/[\w]/); + if (isWord) { + state.tokenize.pop(); + return "word"; + } + } + state.tokenize.pop(); + return "string"; + } + + t.isBase = true; + return t; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize.pop(); + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function expectExpression(last) { + return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) || + last == "newstatement" || last == "keyword" || last == "proplabel"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function (basecolumn) { + return { + tokenize: [tokenBase], + context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false), + indented: 0, + startOfLine: true, + lastToken: null + }; + }, + + token: function (stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + // Automatic semicolon insertion + if (ctx.type == "statement" && !expectExpression(state.lastToken)) { + popContext(state); + ctx = state.context; + } + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = state.tokenize[state.tokenize.length - 1](stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); + // Handle indentation for {x -> \n ... } + else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") { + popContext(state); + state.context.align = false; + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + state.lastToken = curPunc || style; + return style; + }, + + indent: function (state, textAfter) { + if (!state.tokenize[state.tokenize.length - 1].isBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.context; + if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") { + return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit); + } + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : config.indentUnit); + }, + + closeBrackets: {triples: "'\""}, + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + +CodeMirror.defineMIME("text/x-kotlin", "kotlin"); + +}); diff --git a/rhodecode/public/js/mode/livescript/livescript.js b/rhodecode/public/js/mode/livescript/livescript.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/livescript/livescript.js @@ -0,0 +1,280 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Link to the project's GitHub page: + * https://github.com/duralog/CodeMirror + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode('livescript', function(){ + var tokenBase = function(stream, state) { + var next_rule = state.next || "start"; + if (next_rule) { + state.next = state.next; + var nr = Rules[next_rule]; + if (nr.splice) { + for (var i$ = 0; i$ < nr.length; ++i$) { + var r = nr[i$]; + if (r.regex && stream.match(r.regex)) { + state.next = r.next || state.next; + return r.token; + } + } + stream.next(); + return 'error'; + } + if (stream.match(r = Rules[next_rule])) { + if (r.regex && stream.match(r.regex)) { + state.next = r.next; + return r.token; + } else { + stream.next(); + return 'error'; + } + } + } + stream.next(); + return 'error'; + }; + var external = { + startState: function(){ + return { + next: 'start', + lastToken: null + }; + }, + token: function(stream, state){ + while (stream.pos == stream.start) + var style = tokenBase(stream, state); + state.lastToken = { + style: style, + indent: stream.indentation(), + content: stream.current() + }; + return style.replace(/\./g, ' '); + }, + indent: function(state){ + var indentation = state.lastToken.indent; + if (state.lastToken.content.match(indenter)) { + indentation += 2; + } + return indentation; + } + }; + return external; + }); + + var identifier = '(?![\\d\\s])[$\\w\\xAA-\\uFFDC](?:(?!\\s)[$\\w\\xAA-\\uFFDC]|-[A-Za-z])*'; + var indenter = RegExp('(?:[({[=:]|[-~]>|\\b(?:e(?:lse|xport)|d(?:o|efault)|t(?:ry|hen)|finally|import(?:\\s*all)?|const|var|let|new|catch(?:\\s*' + identifier + ')?))\\s*$'); + var keywordend = '(?![$\\w]|-[A-Za-z]|\\s*:(?![:=]))'; + var stringfill = { + token: 'string', + regex: '.+' + }; + var Rules = { + start: [ + { + token: 'comment.doc', + regex: '/\\*', + next: 'comment' + }, { + token: 'comment', + regex: '#.*' + }, { + token: 'keyword', + regex: '(?:t(?:h(?:is|row|en)|ry|ypeof!?)|c(?:on(?:tinue|st)|a(?:se|tch)|lass)|i(?:n(?:stanceof)?|mp(?:ort(?:\\s+all)?|lements)|[fs])|d(?:e(?:fault|lete|bugger)|o)|f(?:or(?:\\s+own)?|inally|unction)|s(?:uper|witch)|e(?:lse|x(?:tends|port)|val)|a(?:nd|rguments)|n(?:ew|ot)|un(?:less|til)|w(?:hile|ith)|o[fr]|return|break|let|var|loop)' + keywordend + }, { + token: 'constant.language', + regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend + }, { + token: 'invalid.illegal', + regex: '(?:p(?:ackage|r(?:ivate|otected)|ublic)|i(?:mplements|nterface)|enum|static|yield)' + keywordend + }, { + token: 'language.support.class', + regex: '(?:R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|Array|Boolean|Date|Function|Number|Object|TypeError|URIError)' + keywordend + }, { + token: 'language.support.function', + regex: '(?:is(?:NaN|Finite)|parse(?:Int|Float)|Math|JSON|(?:en|de)codeURI(?:Component)?)' + keywordend + }, { + token: 'variable.language', + regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend + }, { + token: 'identifier', + regex: identifier + '\\s*:(?![:=])' + }, { + token: 'variable', + regex: identifier + }, { + token: 'keyword.operator', + regex: '(?:\\.{3}|\\s+\\?)' + }, { + token: 'keyword.variable', + regex: '(?:@+|::|\\.\\.)', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\.\\s*', + next: 'key' + }, { + token: 'string', + regex: '\\\\\\S[^\\s,;)}\\]]*' + }, { + token: 'string.doc', + regex: '\'\'\'', + next: 'qdoc' + }, { + token: 'string.doc', + regex: '"""', + next: 'qqdoc' + }, { + token: 'string', + regex: '\'', + next: 'qstring' + }, { + token: 'string', + regex: '"', + next: 'qqstring' + }, { + token: 'string', + regex: '`', + next: 'js' + }, { + token: 'string', + regex: '<\\[', + next: 'words' + }, { + token: 'string.regex', + regex: '//', + next: 'heregex' + }, { + token: 'string.regex', + regex: '\\/(?:[^[\\/\\n\\\\]*(?:(?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[\\/\\n\\\\]*)*)\\/[gimy$]{0,4}', + next: 'key' + }, { + token: 'constant.numeric', + regex: '(?:0x[\\da-fA-F][\\da-fA-F_]*|(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]*|(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[\\w$]*)' + }, { + token: 'lparen', + regex: '[({[]' + }, { + token: 'rparen', + regex: '[)}\\]]', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\S+' + }, { + token: 'text', + regex: '\\s+' + } + ], + heregex: [ + { + token: 'string.regex', + regex: '.*?//[gimy$?]{0,4}', + next: 'start' + }, { + token: 'string.regex', + regex: '\\s*#{' + }, { + token: 'comment.regex', + regex: '\\s+(?:#.*)?' + }, { + token: 'string.regex', + regex: '\\S+' + } + ], + key: [ + { + token: 'keyword.operator', + regex: '[.?@!]+' + }, { + token: 'identifier', + regex: identifier, + next: 'start' + }, { + token: 'text', + regex: '', + next: 'start' + } + ], + comment: [ + { + token: 'comment.doc', + regex: '.*?\\*/', + next: 'start' + }, { + token: 'comment.doc', + regex: '.+' + } + ], + qdoc: [ + { + token: 'string', + regex: ".*?'''", + next: 'key' + }, stringfill + ], + qqdoc: [ + { + token: 'string', + regex: '.*?"""', + next: 'key' + }, stringfill + ], + qstring: [ + { + token: 'string', + regex: '[^\\\\\']*(?:\\\\.[^\\\\\']*)*\'', + next: 'key' + }, stringfill + ], + qqstring: [ + { + token: 'string', + regex: '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"', + next: 'key' + }, stringfill + ], + js: [ + { + token: 'string', + regex: '[^\\\\`]*(?:\\\\.[^\\\\`]*)*`', + next: 'key' + }, stringfill + ], + words: [ + { + token: 'string', + regex: '.*?\\]>', + next: 'key' + }, stringfill + ] + }; + for (var idx in Rules) { + var r = Rules[idx]; + if (r.splice) { + for (var i = 0, len = r.length; i < len; ++i) { + var rr = r[i]; + if (typeof rr.regex === 'string') { + Rules[idx][i].regex = new RegExp('^' + rr.regex); + } + } + } else if (typeof rr.regex === 'string') { + Rules[idx].regex = new RegExp('^' + r.regex); + } + } + + CodeMirror.defineMIME('text/x-livescript', 'livescript'); + +}); diff --git a/rhodecode/public/js/mode/lua/lua.js b/rhodecode/public/js/mode/lua/lua.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/lua/lua.js @@ -0,0 +1,159 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's +// CodeMirror 1 mode. +// highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("lua", function(config, parserConfig) { + var indentUnit = config.indentUnit; + + function prefixRE(words) { + return new RegExp("^(?:" + words.join("|") + ")", "i"); + } + function wordRE(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var specials = wordRE(parserConfig.specials || []); + + // long list of standard functions from lua manual + var builtins = wordRE([ + "_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load", + "loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require", + "select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall", + + "coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield", + + "debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable", + "debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable", + "debug.setupvalue","debug.traceback", + + "close","flush","lines","read","seek","setvbuf","write", + + "io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin", + "io.stdout","io.tmpfile","io.type","io.write", + + "math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg", + "math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max", + "math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh", + "math.sqrt","math.tan","math.tanh", + + "os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale", + "os.time","os.tmpname", + + "package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload", + "package.seeall", + + "string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub", + "string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper", + + "table.concat","table.insert","table.maxn","table.remove","table.sort" + ]); + var keywords = wordRE(["and","break","elseif","false","nil","not","or","return", + "true","function", "end", "if", "then", "else", "do", + "while", "repeat", "until", "for", "in", "local" ]); + + var indentTokens = wordRE(["function", "if","repeat","do", "\\(", "{"]); + var dedentTokens = wordRE(["end", "until", "\\)", "}"]); + var dedentPartial = prefixRE(["end", "until", "\\)", "}", "else", "elseif"]); + + function readBracket(stream) { + var level = 0; + while (stream.eat("=")) ++level; + stream.eat("["); + return level; + } + + function normal(stream, state) { + var ch = stream.next(); + if (ch == "-" && stream.eat("-")) { + if (stream.eat("[") && stream.eat("[")) + return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state); + stream.skipToEnd(); + return "comment"; + } + if (ch == "\"" || ch == "'") + return (state.cur = string(ch))(stream, state); + if (ch == "[" && /[\[=]/.test(stream.peek())) + return (state.cur = bracketed(readBracket(stream), "string"))(stream, state); + if (/\d/.test(ch)) { + stream.eatWhile(/[\w.%]/); + return "number"; + } + if (/[\w_]/.test(ch)) { + stream.eatWhile(/[\w\\\-_.]/); + return "variable"; + } + return null; + } + + function bracketed(level, style) { + return function(stream, state) { + var curlev = null, ch; + while ((ch = stream.next()) != null) { + if (curlev == null) {if (ch == "]") curlev = 0;} + else if (ch == "=") ++curlev; + else if (ch == "]" && curlev == level) { state.cur = normal; break; } + else curlev = null; + } + return style; + }; + } + + function string(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.cur = normal; + return "string"; + }; + } + + return { + startState: function(basecol) { + return {basecol: basecol || 0, indentDepth: 0, cur: normal}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.cur(stream, state); + var word = stream.current(); + if (style == "variable") { + if (keywords.test(word)) style = "keyword"; + else if (builtins.test(word)) style = "builtin"; + else if (specials.test(word)) style = "variable-2"; + } + if ((style != "comment") && (style != "string")){ + if (indentTokens.test(word)) ++state.indentDepth; + else if (dedentTokens.test(word)) --state.indentDepth; + } + return style; + }, + + indent: function(state, textAfter) { + var closing = dedentPartial.test(textAfter); + return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0)); + }, + + lineComment: "--", + blockCommentStart: "--[[", + blockCommentEnd: "]]" + }; +}); + +CodeMirror.defineMIME("text/x-lua", "lua"); + +}); diff --git a/rhodecode/public/js/mode/markdown/markdown.js b/rhodecode/public/js/mode/markdown/markdown.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/markdown/markdown.js @@ -0,0 +1,781 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../meta"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { + + var htmlFound = CodeMirror.modes.hasOwnProperty("xml"); + var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain"); + + function getMode(name) { + if (CodeMirror.findModeByName) { + var found = CodeMirror.findModeByName(name); + if (found) name = found.mime || found.mimes[0]; + } + var mode = CodeMirror.getMode(cmCfg, name); + return mode.name == "null" ? null : mode; + } + + // Should characters that affect highlighting be highlighted separate? + // Does not include characters that will be output (such as `1.` and `-` for lists) + if (modeCfg.highlightFormatting === undefined) + modeCfg.highlightFormatting = false; + + // Maximum number of nested blockquotes. Set to 0 for infinite nesting. + // Excess `>` will emit `error` token. + if (modeCfg.maxBlockquoteDepth === undefined) + modeCfg.maxBlockquoteDepth = 0; + + // Should underscores in words open/close em/strong? + if (modeCfg.underscoresBreakWords === undefined) + modeCfg.underscoresBreakWords = true; + + // Turn on fenced code blocks? ("```" to start/end) + if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false; + + // Turn on task lists? ("- [ ] " and "- [x] ") + if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; + + // Turn on strikethrough syntax + if (modeCfg.strikethrough === undefined) + modeCfg.strikethrough = false; + + var codeDepth = 0; + + var header = 'header' + , code = 'comment' + , quote = 'quote' + , list1 = 'variable-2' + , list2 = 'variable-3' + , list3 = 'keyword' + , hr = 'hr' + , image = 'tag' + , formatting = 'formatting' + , linkinline = 'link' + , linkemail = 'link' + , linktext = 'link' + , linkhref = 'string' + , em = 'em' + , strong = 'strong' + , strikethrough = 'strikethrough'; + + var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ + , ulRE = /^[*\-+]\s+/ + , olRE = /^[0-9]+([.)])\s+/ + , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE + , atxHeaderRE = /^(#+)(?: |$)/ + , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ + , textRE = /^[^#!\[\]*_\\<>` "'(~]+/; + + function switchInline(stream, state, f) { + state.f = state.inline = f; + return f(stream, state); + } + + function switchBlock(stream, state, f) { + state.f = state.block = f; + return f(stream, state); + } + + + // Blocks + + function blankLine(state) { + // Reset linkTitle state + state.linkTitle = false; + // Reset EM state + state.em = false; + // Reset STRONG state + state.strong = false; + // Reset strikethrough state + state.strikethrough = false; + // Reset state.quote + state.quote = 0; + // Reset state.indentedCode + state.indentedCode = false; + if (!htmlFound && state.f == htmlBlock) { + state.f = inlineNormal; + state.block = blockNormal; + } + // Reset state.trailingSpace + state.trailingSpace = 0; + state.trailingSpaceNewLine = false; + // Mark this line as blank + state.thisLineHasContent = false; + return null; + } + + function blockNormal(stream, state) { + + var sol = stream.sol(); + + var prevLineIsList = state.list !== false, + prevLineIsIndentedCode = state.indentedCode; + + state.indentedCode = false; + + if (prevLineIsList) { + if (state.indentationDiff >= 0) { // Continued list + if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block + state.indentation -= state.indentationDiff; + } + state.list = null; + } else if (state.indentation > 0) { + state.list = null; + state.listDepth = Math.floor(state.indentation / 4); + } else { // No longer a list + state.list = false; + state.listDepth = 0; + } + } + + var match = null; + if (state.indentationDiff >= 4) { + stream.skipToEnd(); + if (prevLineIsIndentedCode || !state.prevLineHasContent) { + state.indentation -= 4; + state.indentedCode = true; + return code; + } else { + return null; + } + } else if (stream.eatSpace()) { + return null; + } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) { + state.header = match[1].length; + if (modeCfg.highlightFormatting) state.formatting = "header"; + state.f = state.inline; + return getType(state); + } else if (state.prevLineHasContent && !state.quote && !prevLineIsList && !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) { + state.header = match[0].charAt(0) == '=' ? 1 : 2; + if (modeCfg.highlightFormatting) state.formatting = "header"; + state.f = state.inline; + return getType(state); + } else if (stream.eat('>')) { + state.quote = sol ? 1 : state.quote + 1; + if (modeCfg.highlightFormatting) state.formatting = "quote"; + stream.eatSpace(); + return getType(state); + } else if (stream.peek() === '[') { + return switchInline(stream, state, footnoteLink); + } else if (stream.match(hrRE, true)) { + state.hr = true; + return hr; + } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { + var listType = null; + if (stream.match(ulRE, true)) { + listType = 'ul'; + } else { + stream.match(olRE, true); + listType = 'ol'; + } + state.indentation += 4; + state.list = true; + state.listDepth++; + if (modeCfg.taskLists && stream.match(taskListRE, false)) { + state.taskList = true; + } + state.f = state.inline; + if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; + return getType(state); + } else if (modeCfg.fencedCodeBlocks && stream.match(/^```[ \t]*([\w+#]*)/, true)) { + // try switching mode + state.localMode = getMode(RegExp.$1); + if (state.localMode) state.localState = state.localMode.startState(); + state.f = state.block = local; + if (modeCfg.highlightFormatting) state.formatting = "code-block"; + state.code = true; + return getType(state); + } + + return switchInline(stream, state, state.inline); + } + + function htmlBlock(stream, state) { + var style = htmlMode.token(stream, state.htmlState); + if ((htmlFound && state.htmlState.tagStart === null && !state.htmlState.context) || + (state.md_inside && stream.current().indexOf(">") > -1)) { + state.f = inlineNormal; + state.block = blockNormal; + state.htmlState = null; + } + return style; + } + + function local(stream, state) { + if (stream.sol() && stream.match("```", false)) { + state.localMode = state.localState = null; + state.f = state.block = leavingLocal; + return null; + } else if (state.localMode) { + return state.localMode.token(stream, state.localState); + } else { + stream.skipToEnd(); + return code; + } + } + + function leavingLocal(stream, state) { + stream.match("```"); + state.block = blockNormal; + state.f = inlineNormal; + if (modeCfg.highlightFormatting) state.formatting = "code-block"; + state.code = true; + var returnType = getType(state); + state.code = false; + return returnType; + } + + // Inline + function getType(state) { + var styles = []; + + if (state.formatting) { + styles.push(formatting); + + if (typeof state.formatting === "string") state.formatting = [state.formatting]; + + for (var i = 0; i < state.formatting.length; i++) { + styles.push(formatting + "-" + state.formatting[i]); + + if (state.formatting[i] === "header") { + styles.push(formatting + "-" + state.formatting[i] + "-" + state.header); + } + + // Add `formatting-quote` and `formatting-quote-#` for blockquotes + // Add `error` instead if the maximum blockquote nesting depth is passed + if (state.formatting[i] === "quote") { + if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { + styles.push(formatting + "-" + state.formatting[i] + "-" + state.quote); + } else { + styles.push("error"); + } + } + } + } + + if (state.taskOpen) { + styles.push("meta"); + return styles.length ? styles.join(' ') : null; + } + if (state.taskClosed) { + styles.push("property"); + return styles.length ? styles.join(' ') : null; + } + + if (state.linkHref) { + styles.push(linkhref, "url"); + } else { // Only apply inline styles to non-url text + if (state.strong) { styles.push(strong); } + if (state.em) { styles.push(em); } + if (state.strikethrough) { styles.push(strikethrough); } + + if (state.linkText) { styles.push(linktext); } + + if (state.code) { styles.push(code); } + } + + if (state.header) { styles.push(header); styles.push(header + "-" + state.header); } + + if (state.quote) { + styles.push(quote); + + // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth + if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { + styles.push(quote + "-" + state.quote); + } else { + styles.push(quote + "-" + modeCfg.maxBlockquoteDepth); + } + } + + if (state.list !== false) { + var listMod = (state.listDepth - 1) % 3; + if (!listMod) { + styles.push(list1); + } else if (listMod === 1) { + styles.push(list2); + } else { + styles.push(list3); + } + } + + if (state.trailingSpaceNewLine) { + styles.push("trailing-space-new-line"); + } else if (state.trailingSpace) { + styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b")); + } + + return styles.length ? styles.join(' ') : null; + } + + function handleText(stream, state) { + if (stream.match(textRE, true)) { + return getType(state); + } + return undefined; + } + + function inlineNormal(stream, state) { + var style = state.text(stream, state); + if (typeof style !== 'undefined') + return style; + + if (state.list) { // List marker (*, +, -, 1., etc) + state.list = null; + return getType(state); + } + + if (state.taskList) { + var taskOpen = stream.match(taskListRE, true)[1] !== "x"; + if (taskOpen) state.taskOpen = true; + else state.taskClosed = true; + if (modeCfg.highlightFormatting) state.formatting = "task"; + state.taskList = false; + return getType(state); + } + + state.taskOpen = false; + state.taskClosed = false; + + if (state.header && stream.match(/^#+$/, true)) { + if (modeCfg.highlightFormatting) state.formatting = "header"; + return getType(state); + } + + // Get sol() value now, before character is consumed + var sol = stream.sol(); + + var ch = stream.next(); + + if (ch === '\\') { + stream.next(); + if (modeCfg.highlightFormatting) { + var type = getType(state); + return type ? type + " formatting-escape" : "formatting-escape"; + } + } + + // Matches link titles present on next line + if (state.linkTitle) { + state.linkTitle = false; + var matchCh = ch; + if (ch === '(') { + matchCh = ')'; + } + matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; + if (stream.match(new RegExp(regex), true)) { + return linkhref; + } + } + + // If this block is changed, it may need to be updated in GFM mode + if (ch === '`') { + var previousFormatting = state.formatting; + if (modeCfg.highlightFormatting) state.formatting = "code"; + var t = getType(state); + var before = stream.pos; + stream.eatWhile('`'); + var difference = 1 + stream.pos - before; + if (!state.code) { + codeDepth = difference; + state.code = true; + return getType(state); + } else { + if (difference === codeDepth) { // Must be exact + state.code = false; + return t; + } + state.formatting = previousFormatting; + return getType(state); + } + } else if (state.code) { + return getType(state); + } + + if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { + stream.match(/\[[^\]]*\]/); + state.inline = state.f = linkHref; + return image; + } + + if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) { + state.linkText = true; + if (modeCfg.highlightFormatting) state.formatting = "link"; + return getType(state); + } + + if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) { + if (modeCfg.highlightFormatting) state.formatting = "link"; + var type = getType(state); + state.linkText = false; + state.inline = state.f = linkHref; + return type; + } + + if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) { + state.f = state.inline = linkInline; + if (modeCfg.highlightFormatting) state.formatting = "link"; + var type = getType(state); + if (type){ + type += " "; + } else { + type = ""; + } + return type + linkinline; + } + + if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) { + state.f = state.inline = linkInline; + if (modeCfg.highlightFormatting) state.formatting = "link"; + var type = getType(state); + if (type){ + type += " "; + } else { + type = ""; + } + return type + linkemail; + } + + if (ch === '<' && stream.match(/^\w/, false)) { + if (stream.string.indexOf(">") != -1) { + var atts = stream.string.substring(1,stream.string.indexOf(">")); + if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) { + state.md_inside = true; + } + } + stream.backUp(1); + state.htmlState = CodeMirror.startState(htmlMode); + return switchBlock(stream, state, htmlBlock); + } + + if (ch === '<' && stream.match(/^\/\w*?>/)) { + state.md_inside = false; + return "tag"; + } + + var ignoreUnderscore = false; + if (!modeCfg.underscoresBreakWords) { + if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { + var prevPos = stream.pos - 2; + if (prevPos >= 0) { + var prevCh = stream.string.charAt(prevPos); + if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { + ignoreUnderscore = true; + } + } + } + } + if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { + if (sol && stream.peek() === ' ') { + // Do nothing, surrounded by newline and space + } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG + if (modeCfg.highlightFormatting) state.formatting = "strong"; + var t = getType(state); + state.strong = false; + return t; + } else if (!state.strong && stream.eat(ch)) { // Add STRONG + state.strong = ch; + if (modeCfg.highlightFormatting) state.formatting = "strong"; + return getType(state); + } else if (state.em === ch) { // Remove EM + if (modeCfg.highlightFormatting) state.formatting = "em"; + var t = getType(state); + state.em = false; + return t; + } else if (!state.em) { // Add EM + state.em = ch; + if (modeCfg.highlightFormatting) state.formatting = "em"; + return getType(state); + } + } else if (ch === ' ') { + if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces + if (stream.peek() === ' ') { // Surrounded by spaces, ignore + return getType(state); + } else { // Not surrounded by spaces, back up pointer + stream.backUp(1); + } + } + } + + if (modeCfg.strikethrough) { + if (ch === '~' && stream.eatWhile(ch)) { + if (state.strikethrough) {// Remove strikethrough + if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; + var t = getType(state); + state.strikethrough = false; + return t; + } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough + state.strikethrough = true; + if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; + return getType(state); + } + } else if (ch === ' ') { + if (stream.match(/^~~/, true)) { // Probably surrounded by space + if (stream.peek() === ' ') { // Surrounded by spaces, ignore + return getType(state); + } else { // Not surrounded by spaces, back up pointer + stream.backUp(2); + } + } + } + } + + if (ch === ' ') { + if (stream.match(/ +$/, false)) { + state.trailingSpace++; + } else if (state.trailingSpace) { + state.trailingSpaceNewLine = true; + } + } + + return getType(state); + } + + function linkInline(stream, state) { + var ch = stream.next(); + + if (ch === ">") { + state.f = state.inline = inlineNormal; + if (modeCfg.highlightFormatting) state.formatting = "link"; + var type = getType(state); + if (type){ + type += " "; + } else { + type = ""; + } + return type + linkinline; + } + + stream.match(/^[^>]+/, true); + + return linkinline; + } + + function linkHref(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + var ch = stream.next(); + if (ch === '(' || ch === '[') { + state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]"); + if (modeCfg.highlightFormatting) state.formatting = "link-string"; + state.linkHref = true; + return getType(state); + } + return 'error'; + } + + function getLinkHrefInside(endChar) { + return function(stream, state) { + var ch = stream.next(); + + if (ch === endChar) { + state.f = state.inline = inlineNormal; + if (modeCfg.highlightFormatting) state.formatting = "link-string"; + var returnState = getType(state); + state.linkHref = false; + return returnState; + } + + if (stream.match(inlineRE(endChar), true)) { + stream.backUp(1); + } + + state.linkHref = true; + return getType(state); + }; + } + + function footnoteLink(stream, state) { + if (stream.match(/^[^\]]*\]:/, false)) { + state.f = footnoteLinkInside; + stream.next(); // Consume [ + if (modeCfg.highlightFormatting) state.formatting = "link"; + state.linkText = true; + return getType(state); + } + return switchInline(stream, state, inlineNormal); + } + + function footnoteLinkInside(stream, state) { + if (stream.match(/^\]:/, true)) { + state.f = state.inline = footnoteUrl; + if (modeCfg.highlightFormatting) state.formatting = "link"; + var returnType = getType(state); + state.linkText = false; + return returnType; + } + + stream.match(/^[^\]]+/, true); + + return linktext; + } + + function footnoteUrl(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + // Match URL + stream.match(/^[^\s]+/, true); + // Check for link title + if (stream.peek() === undefined) { // End of line, set flag to check next line + state.linkTitle = true; + } else { // More content on line, check if link title + stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); + } + state.f = state.inline = inlineNormal; + return linkhref + " url"; + } + + var savedInlineRE = []; + function inlineRE(endChar) { + if (!savedInlineRE[endChar]) { + // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) + endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + // Match any non-endChar, escaped character, as well as the closing + // endChar. + savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); + } + return savedInlineRE[endChar]; + } + + var mode = { + startState: function() { + return { + f: blockNormal, + + prevLineHasContent: false, + thisLineHasContent: false, + + block: blockNormal, + htmlState: null, + indentation: 0, + + inline: inlineNormal, + text: handleText, + + formatting: false, + linkText: false, + linkHref: false, + linkTitle: false, + em: false, + strong: false, + header: 0, + hr: false, + taskList: false, + list: false, + listDepth: 0, + quote: 0, + trailingSpace: 0, + trailingSpaceNewLine: false, + strikethrough: false + }; + }, + + copyState: function(s) { + return { + f: s.f, + + prevLineHasContent: s.prevLineHasContent, + thisLineHasContent: s.thisLineHasContent, + + block: s.block, + htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState), + indentation: s.indentation, + + localMode: s.localMode, + localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, + + inline: s.inline, + text: s.text, + formatting: false, + linkTitle: s.linkTitle, + em: s.em, + strong: s.strong, + strikethrough: s.strikethrough, + header: s.header, + hr: s.hr, + taskList: s.taskList, + list: s.list, + listDepth: s.listDepth, + quote: s.quote, + indentedCode: s.indentedCode, + trailingSpace: s.trailingSpace, + trailingSpaceNewLine: s.trailingSpaceNewLine, + md_inside: s.md_inside + }; + }, + + token: function(stream, state) { + + // Reset state.formatting + state.formatting = false; + + if (stream.sol()) { + var forceBlankLine = !!state.header || state.hr; + + // Reset state.header and state.hr + state.header = 0; + state.hr = false; + + if (stream.match(/^\s*$/, true) || forceBlankLine) { + state.prevLineHasContent = false; + blankLine(state); + return forceBlankLine ? this.token(stream, state) : null; + } else { + state.prevLineHasContent = state.thisLineHasContent; + state.thisLineHasContent = true; + } + + // Reset state.taskList + state.taskList = false; + + // Reset state.code + state.code = false; + + // Reset state.trailingSpace + state.trailingSpace = 0; + state.trailingSpaceNewLine = false; + + state.f = state.block; + var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; + var difference = Math.floor((indentation - state.indentation) / 4) * 4; + if (difference > 4) difference = 4; + var adjustedIndentation = state.indentation + difference; + state.indentationDiff = adjustedIndentation - state.indentation; + state.indentation = adjustedIndentation; + if (indentation > 0) return null; + } + return state.f(stream, state); + }, + + innerMode: function(state) { + if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode}; + if (state.localState) return {state: state.localState, mode: state.localMode}; + return {state: state, mode: mode}; + }, + + blankLine: blankLine, + + getType: getType, + + fold: "markdown" + }; + return mode; +}, "xml"); + +CodeMirror.defineMIME("text/x-markdown", "markdown"); + +}); diff --git a/rhodecode/public/js/mode/mathematica/mathematica.js b/rhodecode/public/js/mode/mathematica/mathematica.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mathematica/mathematica.js @@ -0,0 +1,175 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Mathematica mode copyright (c) 2015 by Calin Barbat +// Based on code by Patrick Scheibe (halirutan) +// See: https://github.com/halirutan/Mathematica-Source-Highlighting/tree/master/src/lang-mma.js + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('mathematica', function(_config, _parserConfig) { + + // used pattern building blocks + var Identifier = '[a-zA-Z\\$][a-zA-Z0-9\\$]*'; + var pBase = "(?:\\d+)"; + var pFloat = "(?:\\.\\d+|\\d+\\.\\d*|\\d+)"; + var pFloatBase = "(?:\\.\\w+|\\w+\\.\\w*|\\w+)"; + var pPrecision = "(?:`(?:`?"+pFloat+")?)"; + + // regular expressions + var reBaseForm = new RegExp('(?:'+pBase+'(?:\\^\\^'+pFloatBase+pPrecision+'?(?:\\*\\^[+-]?\\d+)?))'); + var reFloatForm = new RegExp('(?:' + pFloat + pPrecision + '?(?:\\*\\^[+-]?\\d+)?)'); + var reIdInContext = new RegExp('(?:`?)(?:' + Identifier + ')(?:`(?:' + Identifier + '))*(?:`?)'); + + function tokenBase(stream, state) { + var ch; + + // get next character + ch = stream.next(); + + // string + if (ch === '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + + // comment + if (ch === '(') { + if (stream.eat('*')) { + state.commentLevel++; + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } + } + + // go back one character + stream.backUp(1); + + // look for numbers + // Numbers in a baseform + if (stream.match(reBaseForm, true, false)) { + return 'number'; + } + + // Mathematica numbers. Floats (1.2, .2, 1.) can have optionally a precision (`float) or an accuracy definition + // (``float). Note: while 1.2` is possible 1.2`` is not. At the end an exponent (float*^+12) can follow. + if (stream.match(reFloatForm, true, false)) { + return 'number'; + } + + /* In[23] and Out[34] */ + if (stream.match(/(?:In|Out)\[[0-9]*\]/, true, false)) { + return 'atom'; + } + + // usage + if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::usage)/, true, false)) { + return 'meta'; + } + + // message + if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) { + return 'string-2'; + } + + // this makes a look-ahead match for something like variable:{_Integer} + // the match is then forwarded to the mma-patterns tokenizer. + if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*\s*:)(?:(?:[a-zA-Z\$][a-zA-Z0-9\$]*)|(?:[^:=>~@\^\&\*\)\[\]'\?,\|])).*/, true, false)) { + return 'variable-2'; + } + + // catch variables which are used together with Blank (_), BlankSequence (__) or BlankNullSequence (___) + // Cannot start with a number, but can have numbers at any other position. Examples + // blub__Integer, a1_, b34_Integer32 + if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) { + return 'variable-2'; + } + if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+/, true, false)) { + return 'variable-2'; + } + if (stream.match(/_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) { + return 'variable-2'; + } + + // Named characters in Mathematica, like \[Gamma]. + if (stream.match(/\\\[[a-zA-Z\$][a-zA-Z0-9\$]*\]/, true, false)) { + return 'variable-3'; + } + + // Match all braces separately + if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { + return 'bracket'; + } + + // Catch Slots (#, ##, #3, ##9 and the V10 named slots #name). I have never seen someone using more than one digit after #, so we match + // only one. + if (stream.match(/(?:#[a-zA-Z\$][a-zA-Z0-9\$]*|#+[0-9]?)/, true, false)) { + return 'variable-2'; + } + + // Literals like variables, keywords, functions + if (stream.match(reIdInContext, true, false)) { + return 'keyword'; + } + + // operators. Note that operators like @@ or /; are matched separately for each symbol. + if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%)/, true, false)) { + return 'operator'; + } + + // everything else is an error + return 'error'; + } + + function tokenString(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === '"' && !escaped) { + end = true; + break; + } + escaped = !escaped && next === '\\'; + } + if (end && !escaped) { + state.tokenize = tokenBase; + } + return 'string'; + }; + + function tokenComment(stream, state) { + var prev, next; + while(state.commentLevel > 0 && (next = stream.next()) != null) { + if (prev === '(' && next === '*') state.commentLevel++; + if (prev === '*' && next === ')') state.commentLevel--; + prev = next; + } + if (state.commentLevel <= 0) { + state.tokenize = tokenBase; + } + return 'comment'; + } + + return { + startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + blockCommentStart: "(*", + blockCommentEnd: "*)" + }; +}); + +CodeMirror.defineMIME('text/x-mathematica', { + name: 'mathematica' +}); + +}); diff --git a/rhodecode/public/js/mode/meta.js b/rhodecode/public/js/mode/meta.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/meta.js @@ -0,0 +1,188 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.modeInfo = [ + {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]}, + {name: "PGP", mimes: ["application/pgp", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["pgp"]}, + {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn, asn1"]}, + {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, + {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]}, + {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, + {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, + {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, + {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]}, + {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, + {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, + {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, + {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]}, + {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]}, + {name: "CSS", mime: "text/css", mode: "css", ext: ["css"]}, + {name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]}, + {name: "D", mime: "text/x-d", mode: "d", ext: ["d"]}, + {name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]}, + {name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]}, + {name: "Django", mime: "text/x-django", mode: "django"}, + {name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/}, + {name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]}, + {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]}, + {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"}, + {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]}, + {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, + {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]}, + {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, + {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, + {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, + {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]}, + {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]}, + {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]}, + {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, + {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]}, + {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]}, + {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i}, + {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]}, + {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]}, + {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]}, + {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]}, + {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]}, + {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]}, + {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]}, + {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]}, + {name: "HTTP", mime: "message/http", mode: "http"}, + {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]}, + {name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]}, + {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]}, + {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]}, + {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"], + mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]}, + {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]}, + {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]}, + {name: "Jinja2", mime: "null", mode: "jinja2"}, + {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]}, + {name: "Kotlin", mime: "text/x-kotlin", mode: "kotlin", ext: ["kt"]}, + {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]}, + {name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]}, + {name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]}, + {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]}, + {name: "mIRC", mime: "text/mirc", mode: "mirc"}, + {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"}, + {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]}, + {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]}, + {name: "MUMPS", mime: "text/x-mumps", mode: "mumps"}, + {name: "MS SQL", mime: "text/x-mssql", mode: "sql"}, + {name: "MySQL", mime: "text/x-mysql", mode: "sql"}, + {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i}, + {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]}, + {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]}, + {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, + {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, + {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, + {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, + {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, + {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]}, + {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, + {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, + {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, + {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, + {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]}, + {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, + {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, + {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]}, + {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]}, + {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"}, + {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, + {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]}, + {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]}, + {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]}, + {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, + {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, + {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]}, + {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"]}, + {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]}, + {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]}, + {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, + {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]}, + {name: "Solr", mime: "text/x-solr", mode: "solr"}, + {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]}, + {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]}, + {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, + {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]}, + {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]}, + {name: "MariaDB", mime: "text/x-mariadb", mode: "sql"}, + {name: "sTeX", mime: "text/x-stex", mode: "stex"}, + {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]}, + {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]}, + {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]}, + {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]}, + {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"}, + {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, + {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]}, + {name: "Tornado", mime: "text/x-tornado", mode: "tornado"}, + {name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]}, + {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]}, + {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]}, + {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, + {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]}, + {name: "Twig", mime: "text/x-twig", mode: "twig"}, + {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]}, + {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]}, + {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, + {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, + {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, + {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, + {name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, + {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]} + ]; + // Ensure all modes have a mime property for backwards compatibility + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mimes) info.mime = info.mimes[0]; + } + + CodeMirror.findModeByMIME = function(mime) { + mime = mime.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mime == mime) return info; + if (info.mimes) for (var j = 0; j < info.mimes.length; j++) + if (info.mimes[j] == mime) return info; + } + }; + + CodeMirror.findModeByExtension = function(ext) { + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.ext) for (var j = 0; j < info.ext.length; j++) + if (info.ext[j] == ext) return info; + } + }; + + CodeMirror.findModeByFileName = function(filename) { + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.file && info.file.test(filename)) return info; + } + var dot = filename.lastIndexOf("."); + var ext = dot > -1 && filename.substring(dot + 1, filename.length); + if (ext) return CodeMirror.findModeByExtension(ext); + }; + + CodeMirror.findModeByName = function(name) { + name = name.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.name.toLowerCase() == name) return info; + if (info.alias) for (var j = 0; j < info.alias.length; j++) + if (info.alias[j].toLowerCase() == name) return info; + } + }; +}); diff --git a/rhodecode/public/js/mode/meta_ext.js b/rhodecode/public/js/mode/meta_ext.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/meta_ext.js @@ -0,0 +1,336 @@ +var _EMPTY_EXT = {'exts': [], 'mode': 'plain'}; + +MIME_TO_EXT = { +"application/json": {"exts": ["*.json","*.map"], "mode": "javascript"}, +"application/postscript": {"exts": ["*.ps","*.eps"], "mode": ""}, +"application/sieve": {"exts": ["*.siv","*.sieve"], "mode": "sieve"}, +"application/typescript": {"exts": ["*.ts"], "mode": "javascript"}, +"application/x-actionscript": {"exts": ["*.as"], "mode": ""}, +"application/x-actionscript3": {"exts": ["*.as"], "mode": ""}, +"application/x-aspx": {"exts": ["*.aspx"], "mode": "htmlembedded"}, +"application/x-awk": {"exts": ["*.awk"], "mode": ""}, +"application/x-befunge": {"exts": ["*.befunge"], "mode": ""}, +"application/x-brainfuck": {"exts": ["*.bf","*.b"], "mode": ""}, +"application/x-cheetah": {"exts": ["*.tmpl","*.spt"], "mode": ""}, +"application/x-coldfusion": {"exts": ["*.cfm","*.cfml","*.cfc"], "mode": ""}, +"application/x-csh": {"exts": ["*.tcsh","*.csh"], "mode": ""}, +"application/x-dos-batch": {"exts": ["*.bat","*.cmd"], "mode": ""}, +"application/x-ecl": {"exts": ["*.ecl"], "mode": ""}, +"application/x-ejs": {"exts": ["*.ejs"], "mode": "htmlembedded"}, +"application/x-evoque": {"exts": ["*.evoque"], "mode": ""}, +"application/x-fantom": {"exts": ["*.fan"], "mode": ""}, +"application/x-genshi": {"exts": ["*.kid"], "mode": ""}, +"application/x-gettext": {"exts": ["*.pot","*.po"], "mode": ""}, +"application/x-json": {"exts": ["*.json"], "mode": ""}, +"application/x-jsp": {"exts": ["*.jsp"], "mode": "htmlembedded"}, +"application/x-mako": {"exts": ["*.mako"], "mode": ""}, +"application/x-mason": {"exts": ["*.m","*.mhtml","*.mc","*.mi","autohandler","dhandler"], "mode": ""}, +"application/x-myghty": {"exts": ["*.myt","autodelegate"], "mode": ""}, +"application/x-php": {"exts": ["*.phtml"], "mode": ""}, +"application/x-pypylog": {"exts": ["*.pypylog"], "mode": ""}, +"application/x-qml": {"exts": ["*.qml"], "mode": ""}, +"application/x-sh-session": {"exts": ["*.shell-session"], "mode": ""}, +"application/x-shell-session": {"exts": ["*.sh-session"], "mode": ""}, +"application/x-smarty": {"exts": ["*.tpl"], "mode": ""}, +"application/x-sparql-query": {"exts": [], "mode": "sparql"}, +"application/x-ssp": {"exts": ["*.ssp"], "mode": ""}, +"application/x-troff": {"exts": ["*.[1234567]","*.man"], "mode": ""}, +"application/x-urbiscript": {"exts": ["*.u"], "mode": ""}, +"application/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl"], "mode": "xml"}, +"application/xml+evoque": {"exts": ["*.xml"], "mode": ""}, +"application/xml-dtd": {"exts": ["*.dtd"], "mode": "dtd"}, +"application/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm","*.xy"], "mode": "xquery"}, +"application/xsl+xml": {"exts": ["*.xsl","*.xslt","*.xpl"], "mode": ""}, +"jinja2": {"exts": [".jinja2"], "mode": "jinja2"}, +"message/http": {"exts": [], "mode": "http"}, +"text/S-plus": {"exts": ["*.S","*.R",".Rhistory",".Rprofile"], "mode": ""}, +"text/apl": {"exts": ["*.dyalog","*.pgp","*.apl"], "mode": "apl"}, +"text/coffeescript": {"exts": ["*.coffee"], "mode": ""}, +"text/css": {"exts": ["*.css"], "mode": "css"}, +"text/haxe": {"exts": ["*.hx"], "mode": ""}, +"text/html": {"exts": ["*.html","*.htm","*.xhtml","*.xslt"], "mode": "htmlmixed"}, +"text/html+evoque": {"exts": ["*.html"], "mode": ""}, +"text/html+ruby": {"exts": ["*.rhtml"], "mode": ""}, +"text/idl": {"exts": ["*.pro"], "mode": ""}, +"text/javascript": {"exts": ["*.js"], "mode": "javascript"}, +"text/livescript": {"exts": ["*.ls"], "mode": ""}, +"text/matlab": {"exts": ["*.m"], "mode": ""}, +"text/mirc": {"exts": [], "mode": "mirc"}, +"text/n-triples": {"exts": ["*.nt"], "mode": "ntriples"}, +"text/octave": {"exts": ["*.m"], "mode": ""}, +"text/plain": {"exts": ["*.txt","*.text","*.conf","*.def","*.list","*.log"], "mode": "null"}, +"text/scilab": {"exts": ["*.sci","*.sce","*.tst"], "mode": ""}, +"text/smali": {"exts": ["*.smali"], "mode": ""}, +"text/tiki": {"exts": [], "mode": "tiki"}, +"text/vbscript": {"exts": ["*.vb","*.vbs"], "mode": "vbscript"}, +"text/velocity": {"exts": ["*.vtl"], "mode": "velocity"}, +"text/x-abap": {"exts": ["*.abap"], "mode": ""}, +"text/x-ada": {"exts": ["*.adb","*.ads","*.ada"], "mode": ""}, +"text/x-apacheconf": {"exts": [".htaccess","apache.conf","apache2.conf"], "mode": ""}, +"text/x-aspectj": {"exts": ["*.aj"], "mode": ""}, +"text/x-asterisk": {"exts": [], "mode": "asterisk"}, +"text/x-asymptote": {"exts": ["*.asy"], "mode": ""}, +"text/x-autohotkey": {"exts": ["*.ahk","*.ahkl"], "mode": ""}, +"text/x-autoit": {"exts": ["*.au3"], "mode": ""}, +"text/x-bmx": {"exts": ["*.bmx"], "mode": ""}, +"text/x-boo": {"exts": ["*.boo"], "mode": ""}, +"text/x-c": {"exts": ["*.c"], "mode": "clike"}, +"text/x-c++hdr": {"exts": ["*.cpp","*.hpp","*.c++","*.h++","*.cc","*.hh","*.cxx","*.hxx","*.C","*.H","*.cp","*.CPP"], "mode": "clike"}, +"text/x-c++src": {"exts": ["*.cpp","*.c++","*.cc","*.cxx","*.hpp","*.h++","*.hh","*.hxx"], "mode": "clike"}, +"text/x-c-objdump": {"exts": ["*.c-objdump"], "mode": ""}, +"text/x-ceylon": {"exts": ["*.ceylon"], "mode": ""}, +"text/x-chdr": {"exts": ["*.c","*.h","*.idc"], "mode": "clike"}, +"text/x-clojure": {"exts": ["*.clj"], "mode": "clojure"}, +"text/x-cmake": {"exts": ["*.cmake","CMakeLists.txt","*.cmake.in"], "mode": "cmake"}, +"text/x-cobol": {"exts": ["*.cob","*.COB","*.cpy","*.CPY"], "mode": "cobol"}, +"text/x-coffeescript": {"exts": ["*.coffee"], "mode": "coffeescript"}, +"text/x-common-lisp": {"exts": ["*.cl","*.lisp","*.el"], "mode": "commonlisp"}, +"text/x-coq": {"exts": ["*.v"], "mode": ""}, +"text/x-cpp-objdump": {"exts": ["*.cpp-objdump","*.c++-objdump","*.cxx-objdump"], "mode": ""}, +"text/x-crocsrc": {"exts": ["*.croc"], "mode": ""}, +"text/x-csharp": {"exts": ["*.cs"], "mode": "clike"}, +"text/x-csrc": {"exts": ["*.c","*.h"], "mode": "clike"}, +"text/x-cuda": {"exts": ["*.cu","*.cuh"], "mode": ""}, +"text/x-cython": {"exts": ["*.pyx","*.pxd","*.pxi"], "mode": "python"}, +"text/x-d": {"exts": ["*.d"], "mode": "d"}, +"text/x-d-objdump": {"exts": ["*.d-objdump"], "mode": ""}, +"text/x-dart": {"exts": ["*.dart"], "mode": ""}, +"text/x-dg": {"exts": ["*.dg"], "mode": ""}, +"text/x-diff": {"exts": ["*.diff","*.patch"], "mode": "diff"}, +"text/x-dsrc": {"exts": ["*.d","*.di"], "mode": ""}, +"text/x-duel": {"exts": ["*.duel","*.jbst"], "mode": ""}, +"text/x-dylan": {"exts": ["*.dylan","*.dyl","*.intr"], "mode": "dylan"}, +"text/x-dylan-console": {"exts": ["*.dylan-console"], "mode": ""}, +"text/x-dylan-lid": {"exts": ["*.lid","*.hdp"], "mode": ""}, +"text/x-echdr": {"exts": ["*.ec","*.eh"], "mode": ""}, +"text/x-ecl": {"exts": ["*.ecl"], "mode": "ecl"}, +"text/x-elixir": {"exts": ["*.ex","*.exs"], "mode": ""}, +"text/x-erl-shellsession": {"exts": ["*.erl-sh"], "mode": ""}, +"text/x-erlang": {"exts": ["*.erl","*.hrl","*.es","*.escript"], "mode": "erlang"}, +"text/x-factor": {"exts": ["*.factor"], "mode": "factor"}, +"text/x-fancysrc": {"exts": ["*.fy","*.fancypack"], "mode": ""}, +"text/x-felix": {"exts": ["*.flx","*.flxh"], "mode": ""}, +"text/x-fortran": {"exts": ["*.f","*.f90","*.F","*.F90","*.for","*.f77"], "mode": "fortran"}, +"text/x-fsharp": {"exts": ["*.fs","*.fsi"], "mode": "mllike"}, +"text/x-gas": {"exts": ["*.s","*.S"], "mode": "gas"}, +"text/x-gfm": {"exts": ["*.md","*.MD"], "mode": "markdown"}, +"text/x-gherkin": {"exts": ["*.feature"], "mode": ""}, +"text/x-glslsrc": {"exts": ["*.vert","*.frag","*.geo"], "mode": ""}, +"text/x-gnuplot": {"exts": ["*.plot","*.plt"], "mode": ""}, +"text/x-go": {"exts": ["*.go"], "mode": "go"}, +"text/x-gooddata-cl": {"exts": ["*.gdc"], "mode": ""}, +"text/x-gooddata-maql": {"exts": ["*.maql"], "mode": ""}, +"text/x-gosrc": {"exts": ["*.go"], "mode": ""}, +"text/x-gosu": {"exts": ["*.gs","*.gsx","*.gsp","*.vark"], "mode": ""}, +"text/x-gosu-template": {"exts": ["*.gst"], "mode": ""}, +"text/x-groovy": {"exts": ["*.groovy"], "mode": "groovy"}, +"text/x-haml": {"exts": ["*.haml"], "mode": "haml"}, +"text/x-haskell": {"exts": ["*.hs"], "mode": "haskell"}, +"text/x-haxe": {"exts": ["*.hx"], "mode": "haxe"}, +"text/x-hybris": {"exts": ["*.hy","*.hyb"], "mode": ""}, +"text/x-ini": {"exts": ["*.ini","*.cfg"], "mode": ""}, +"text/x-iokesrc": {"exts": ["*.ik"], "mode": ""}, +"text/x-iosrc": {"exts": ["*.io"], "mode": ""}, +"text/x-irclog": {"exts": ["*.weechatlog"], "mode": ""}, +"text/x-jade": {"exts": ["*.jade"], "mode": "jade"}, +"text/x-java": {"exts": ["*.java"], "mode": "clike"}, +"text/x-julia": {"exts": ["*.jl"], "mode": "julia"}, +"text/x-kconfig": {"exts": ["Kconfig","*Config.in*","external.in*","standard-modules.in"], "mode": ""}, +"text/x-koka": {"exts": ["*.kk","*.kki"], "mode": ""}, +"text/x-kotlin": {"exts": ["*.kt"], "mode": "kotlin"}, +"text/x-lasso": {"exts": ["*.lasso","*.lasso[89]"], "mode": ""}, +"text/x-latex": {"exts": ["*.ltx","*.text"], "mode": "stex"}, +"text/x-less": {"exts": ["*.less"], "mode": "css"}, +"text/x-literate-haskell": {"exts": ["*.lhs"], "mode": ""}, +"text/x-livescript": {"exts": ["*.ls"], "mode": "livescript"}, +"text/x-llvm": {"exts": ["*.ll"], "mode": ""}, +"text/x-logos": {"exts": ["*.x","*.xi","*.xm","*.xmi"], "mode": ""}, +"text/x-logtalk": {"exts": ["*.lgt"], "mode": ""}, +"text/x-lua": {"exts": ["*.lua","*.wlua"], "mode": "lua"}, +"text/x-makefile": {"exts": ["*.mak","Makefile","makefile","Makefile.*","GNUmakefile"], "mode": ""}, +"text/x-mariadb": {"exts": ["*.sql"], "mode": "sql"}, +"text/x-markdown": {"exts": ["*.md","*.markdown","*.mdown","*.mkd"], "mode": "gfm"}, +"text/x-minidsrc": {"exts": ["*.md"], "mode": "gfm"}, +"text/x-modelica": {"exts": ["*.mo"], "mode": "modelica"}, +"text/x-modula2": {"exts": ["*.def","*.mod"], "mode": ""}, +"text/x-monkey": {"exts": ["*.monkey"], "mode": ""}, +"text/x-moocode": {"exts": ["*.moo"], "mode": ""}, +"text/x-moonscript": {"exts": ["*.moon"], "mode": ""}, +"text/x-nasm": {"exts": ["*.asm","*.ASM"], "mode": ""}, +"text/x-nemerle": {"exts": ["*.n"], "mode": ""}, +"text/x-newlisp": {"exts": ["*.lsp","*.nl"], "mode": ""}, +"text/x-newspeak": {"exts": ["*.ns2"], "mode": ""}, +"text/x-nginx-conf": {"exts": ["*.conf"], "mode": "nginx"}, +"text/x-nimrod": {"exts": ["*.nim","*.nimrod"], "mode": ""}, +"text/x-nsis": {"exts": ["*.nsi","*.nsh"], "mode": ""}, +"text/x-objdump": {"exts": ["*.objdump"], "mode": ""}, +"text/x-objective-c": {"exts": ["*.m","*.h"], "mode": ""}, +"text/x-objective-c++": {"exts": ["*.mm","*.hh"], "mode": ""}, +"text/x-objective-j": {"exts": ["*.j"], "mode": ""}, +"text/x-ocaml": {"exts": ["*.ml","*.mli","*.mll","*.mly"], "mode": "mllike"}, +"text/x-ooc": {"exts": ["*.ooc"], "mode": ""}, +"text/x-opa": {"exts": ["*.opa"], "mode": ""}, +"text/x-openedge": {"exts": ["*.p","*.cls"], "mode": ""}, +"text/x-pascal": {"exts": ["*.pas","*.p"], "mode": "pascal"}, +"text/x-perl": {"exts": ["*.pl","*.pm"], "mode": "perl"}, +"text/x-php": {"exts": ["*.php","*.php[345]","*.inc"], "mode": "php"}, +"text/x-pig": {"exts": ["*.pig"], "mode": "pig"}, +"text/x-povray": {"exts": ["*.pov","*.inc"], "mode": ""}, +"text/x-powershell": {"exts": ["*.ps1"], "mode": ""}, +"text/x-prolog": {"exts": ["*.prolog","*.pro","*.pl"], "mode": ""}, +"text/x-properties": {"exts": ["*.properties","*.ini","*.in"], "mode": "properties"}, +"text/x-python": {"exts": ["*.py","*.pyw","*.sc","SConstruct","SConscript","*.tac","*.sage"], "mode": "python"}, +"text/x-python-traceback": {"exts": ["*.pytb"], "mode": ""}, +"text/x-python3-traceback": {"exts": ["*.py3tb"], "mode": ""}, +"text/x-r-doc": {"exts": ["*.Rd"], "mode": ""}, +"text/x-racket": {"exts": ["*.rkt","*.rktl"], "mode": ""}, +"text/x-rebol": {"exts": ["*.r","*.r3"], "mode": ""}, +"text/x-robotframework": {"exts": ["*.txt","*.robot"], "mode": ""}, +"text/x-rpm-spec": {"exts": ["*.spec"], "mode": "rpm"}, +"text/x-rsrc": {"exts": ["*.r"], "mode": "r"}, +"text/x-rst": {"exts": ["*.rst","*.rest"], "mode": "rst"}, +"text/x-ruby": {"exts": ["*.rb","*.rbw","Rakefile","*.rake","*.gemspec","*.rbx","*.duby"], "mode": "ruby"}, +"text/x-rustsrc": {"exts": ["*.rs","*.rc"], "mode": "rust"}, +"text/x-sass": {"exts": ["*.sass"], "mode": "sass"}, +"text/x-scala": {"exts": ["*.scala"], "mode": "clike"}, +"text/x-scaml": {"exts": ["*.scaml"], "mode": ""}, +"text/x-scheme": {"exts": ["*.scm","*.ss"], "mode": "scheme"}, +"text/x-scss": {"exts": ["*.scss"], "mode": "css"}, +"text/x-sh": {"exts": ["*.sh","*.ksh","*.bash","*.ebuild","*.eclass",".bashrc","bashrc",".bash_*","bash_*"], "mode": "shell"}, +"text/x-smalltalk": {"exts": ["*.st"], "mode": ""}, +"text/x-smarty": {"exts": ["*.tpl"], "mode": "smarty"}, +"text/x-snobol": {"exts": ["*.snobol"], "mode": ""}, +"text/x-sourcepawn": {"exts": ["*.sp"], "mode": ""}, +"text/x-sql": {"exts": ["*.sql"], "mode": "sql"}, +"text/x-sqlite3-console": {"exts": ["*.sqlite3-console"], "mode": ""}, +"text/x-squidconf": {"exts": ["squid.conf"], "mode": ""}, +"text/x-standardml": {"exts": ["*.sml","*.sig","*.fun"], "mode": ""}, +"text/x-stex": {"exts": [], "mode": "stex"}, +"text/x-stsrc": {"exts": ["*.rs","*.rc","*.st"], "mode": "smalltalk"}, +"text/x-systemverilog": {"exts": ["*.sv","*.svh","*.v"], "mode": "verilog"}, +"text/x-tcl": {"exts": ["*.tcl"], "mode": "tcl"}, +"text/x-tea": {"exts": ["*.tea"], "mode": ""}, +"text/x-tex": {"exts": ["*.tex","*.aux","*.toc"], "mode": ""}, +"text/x-tiddlywiki": {"exts": [], "mode": "tiddlywiki"}, +"text/x-typescript": {"exts": ["*.ts"], "mode": ""}, +"text/x-vala": {"exts": ["*.vala","*.vapi"], "mode": ""}, +"text/x-vb": {"exts": ["*.vb"], "mode": "vb"}, +"text/x-vbnet": {"exts": ["*.vb","*.bas"], "mode": ""}, +"text/x-verilog": {"exts": ["*.v"], "mode": "verilog"}, +"text/x-vhdl": {"exts": ["*.vhdl","*.vhd"], "mode": ""}, +"text/x-vim": {"exts": ["*.vim",".vimrc",".exrc",".gvimrc","_vimrc","_exrc","_gvimrc","vimrc","gvimrc"], "mode": ""}, +"text/x-windows-registry": {"exts": ["*.reg"], "mode": ""}, +"text/x-xtend": {"exts": ["*.xtend"], "mode": ""}, +"text/x-yaml": {"exts": ["*.yaml","*.yml"], "mode": "yaml"}, +"text/x-z80": {"exts": ["*.z80"], "mode": "z80"}, +"text/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl"], "mode": ""}, +"text/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm"], "mode": ""} +}; + +/* Special case for overriding mode by file extensions +* key is extensions, value is codemirror mode +* */ +_SPECIAL_CASES = { + "md": "markdown", + "markdown": "markdown" +}; + +/** + * Get's proposed extension based on given mimetype + * + * @param mimetype + * @returns extensions (default .txt) + */ +var getExtFromMimeType = function(mimetype){ + + var proposed_exts = MIME_TO_EXT[mimetype] || _EMPTY_EXT; + if(proposed_exts.exts.length < 1){ + //fallback to text/plain + proposed_exts = {'exts': ['*.txt'], 'mode': '' } + } + // get the first + var ext = proposed_exts.exts[0]; + if(ext[0] == '*'){ + ext = ext.substr(1) + } + + return ext +}; + +var getMimeTypeFromExt = function(ext, multiple){ + mimetypes = []; + for (k in MIME_TO_EXT){ + var mode = MIME_TO_EXT[k]; + if ($.inArray("*."+ext, mode.exts) != -1){ + mimetypes.push(k) + } + } + if(multiple){ + return mimetypes + } + if(mimetypes.length > 0){ + return mimetypes[0] + } + +}; + +var getFilenameAndExt = function(filename){ + var parts = filename.split('.'); + var ext = null; + var filename = null; + + if (parts.length > 1){ + var ext = parts.pop(); + var filename = parts.join(""); + } + return {"filename": filename, "ext": ext} +} + +/** + * Detect mode from extension, this is mostly used to override the + * detection by mimetype + * + * @param filename + */ +var detectCodeMirrorModeFromExt = function(filename, fallback){ + var ext = filename.split('.'); + if (ext){ + var ext = ext[ext.length-1]; + } + // try to do a lookup by extension + var _special_mode = _SPECIAL_CASES[ext]; + if (_special_mode){ + return _special_mode + } + if(fallback !== undefined && fallback === true){ + var mimetype = getMimeTypeFromExt(ext); + if(mimetype){ + return MIME_TO_EXT[mimetype].mode; + } + + } +} + + +/** + * Try to detect a codemirror mode based on a filename and mimetype + * + * @param filename + * @param mimetype + * @returns mode or undefined + */ +var detectCodeMirrorMode = function(filename, mimetype, fallback){ + // just use _SPECIAL_CASES for detection here, as we usually got mimetype + // and it's faster to lookup by mimetype. + var do_fallback = fallback || false; + var _mode_from_ext = detectCodeMirrorModeFromExt(filename, do_fallback); + if(_mode_from_ext){ + return _mode_from_ext + } + + // first try to match by exact mimetype + var mode = MIME_TO_EXT[mimetype]; + if(mode && mode.mode){ + return mode.mode; + } +} diff --git a/rhodecode/public/js/mode/mirc/mirc.js b/rhodecode/public/js/mode/mirc/mirc.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mirc/mirc.js @@ -0,0 +1,193 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +//mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMIME("text/mirc", "mirc"); +CodeMirror.defineMode("mirc", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " + + "$activewid $address $addtok $agent $agentname $agentstat $agentver " + + "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + + "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + + "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + + "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + + "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + + "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + + "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + + "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + + "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + + "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + + "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + + "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + + "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + + "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + + "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + + "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + + "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + + "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + + "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + + "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + + "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + + "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + + "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + + "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + + "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + + "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + + "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + + "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + + "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + + "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + + "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + + "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + + "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + + "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); + var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " + + "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + + "channel clear clearall cline clipboard close cnick color comclose comopen " + + "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + + "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + + "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + + "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + + "events exit fclose filter findtext finger firewall flash flist flood flush " + + "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + + "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + + "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + + "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + + "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + + "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + + "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + + "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + + "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + + "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + + "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + + "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + + "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + + "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + + "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + + "elseif else goto menu nicklist status title icon size option text edit " + + "button check radio box scroll list combo link tab item"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if (/[\[\]{}\(\),\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "\\") { + stream.eat("\\"); + stream.eat(/./); + return "number"; + } + else if (ch == "/" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == ";" && stream.match(/ *\( *\(/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == ";" && !state.inParams) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.eat(/"/); + return "keyword"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.:]/); + if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { + return "keyword"; + } + else { + state.beforeParams = true; + return "builtin"; + } + } + else if (ch == "%") { + stream.eatWhile(/[^,^\s^\(^\)]/); + state.beforeParams = true; + return "string"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + stream.eatWhile(/[\w\$_{}]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == ";" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == ")") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); + +}); diff --git a/rhodecode/public/js/mode/mllike/mllike.js b/rhodecode/public/js/mode/mllike/mllike.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mllike/mllike.js @@ -0,0 +1,205 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('mllike', function(_config, parserConfig) { + var words = { + 'let': 'keyword', + 'rec': 'keyword', + 'in': 'keyword', + 'of': 'keyword', + 'and': 'keyword', + 'if': 'keyword', + 'then': 'keyword', + 'else': 'keyword', + 'for': 'keyword', + 'to': 'keyword', + 'while': 'keyword', + 'do': 'keyword', + 'done': 'keyword', + 'fun': 'keyword', + 'function': 'keyword', + 'val': 'keyword', + 'type': 'keyword', + 'mutable': 'keyword', + 'match': 'keyword', + 'with': 'keyword', + 'try': 'keyword', + 'open': 'builtin', + 'ignore': 'builtin', + 'begin': 'keyword', + 'end': 'keyword' + }; + + var extraWords = parserConfig.extraWords || {}; + for (var prop in extraWords) { + if (extraWords.hasOwnProperty(prop)) { + words[prop] = parserConfig.extraWords[prop]; + } + } + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch === '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + if (ch === '(') { + if (stream.eat('*')) { + state.commentLevel++; + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } + } + if (ch === '~') { + stream.eatWhile(/\w/); + return 'variable-2'; + } + if (ch === '`') { + stream.eatWhile(/\w/); + return 'quote'; + } + if (ch === '/' && parserConfig.slashComments && stream.eat('/')) { + stream.skipToEnd(); + return 'comment'; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\d]/); + if (stream.eat('.')) { + stream.eatWhile(/[\d]/); + } + return 'number'; + } + if ( /[+\-*&%=<>!?|]/.test(ch)) { + return 'operator'; + } + stream.eatWhile(/\w/); + var cur = stream.current(); + return words.hasOwnProperty(cur) ? words[cur] : 'variable'; + } + + function tokenString(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === '"' && !escaped) { + end = true; + break; + } + escaped = !escaped && next === '\\'; + } + if (end && !escaped) { + state.tokenize = tokenBase; + } + return 'string'; + }; + + function tokenComment(stream, state) { + var prev, next; + while(state.commentLevel > 0 && (next = stream.next()) != null) { + if (prev === '(' && next === '*') state.commentLevel++; + if (prev === '*' && next === ')') state.commentLevel--; + prev = next; + } + if (state.commentLevel <= 0) { + state.tokenize = tokenBase; + } + return 'comment'; + } + + return { + startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + + blockCommentStart: "(*", + blockCommentEnd: "*)", + lineComment: parserConfig.slashComments ? "//" : null + }; +}); + +CodeMirror.defineMIME('text/x-ocaml', { + name: 'mllike', + extraWords: { + 'succ': 'keyword', + 'trace': 'builtin', + 'exit': 'builtin', + 'print_string': 'builtin', + 'print_endline': 'builtin', + 'true': 'atom', + 'false': 'atom', + 'raise': 'keyword' + } +}); + +CodeMirror.defineMIME('text/x-fsharp', { + name: 'mllike', + extraWords: { + 'abstract': 'keyword', + 'as': 'keyword', + 'assert': 'keyword', + 'base': 'keyword', + 'class': 'keyword', + 'default': 'keyword', + 'delegate': 'keyword', + 'downcast': 'keyword', + 'downto': 'keyword', + 'elif': 'keyword', + 'exception': 'keyword', + 'extern': 'keyword', + 'finally': 'keyword', + 'global': 'keyword', + 'inherit': 'keyword', + 'inline': 'keyword', + 'interface': 'keyword', + 'internal': 'keyword', + 'lazy': 'keyword', + 'let!': 'keyword', + 'member' : 'keyword', + 'module': 'keyword', + 'namespace': 'keyword', + 'new': 'keyword', + 'null': 'keyword', + 'override': 'keyword', + 'private': 'keyword', + 'public': 'keyword', + 'return': 'keyword', + 'return!': 'keyword', + 'select': 'keyword', + 'static': 'keyword', + 'struct': 'keyword', + 'upcast': 'keyword', + 'use': 'keyword', + 'use!': 'keyword', + 'val': 'keyword', + 'when': 'keyword', + 'yield': 'keyword', + 'yield!': 'keyword', + + 'List': 'builtin', + 'Seq': 'builtin', + 'Map': 'builtin', + 'Set': 'builtin', + 'int': 'builtin', + 'string': 'builtin', + 'raise': 'builtin', + 'failwith': 'builtin', + 'not': 'builtin', + 'true': 'builtin', + 'false': 'builtin' + }, + slashComments: true +}); + +}); diff --git a/rhodecode/public/js/mode/modelica/modelica.js b/rhodecode/public/js/mode/modelica/modelica.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/modelica/modelica.js @@ -0,0 +1,245 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Modelica support for CodeMirror, copyright (c) by Lennart Ochel + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +}) + +(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("modelica", function(config, parserConfig) { + + var indentUnit = config.indentUnit; + var keywords = parserConfig.keywords || {}; + var builtin = parserConfig.builtin || {}; + var atoms = parserConfig.atoms || {}; + + var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/; + var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/; + var isDigit = /[0-9]/; + var isNonDigit = /[_a-zA-Z]/; + + function tokenLineComment(stream, state) { + stream.skipToEnd(); + state.tokenize = null; + return "comment"; + } + + function tokenBlockComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == '"' && !escaped) { + state.tokenize = null; + state.sol = false; + break; + } + escaped = !escaped && ch == "\\"; + } + + return "string"; + } + + function tokenIdent(stream, state) { + stream.eatWhile(isDigit); + while (stream.eat(isDigit) || stream.eat(isNonDigit)) { } + + + var cur = stream.current(); + + if(state.sol && (cur == "package" || cur == "model" || cur == "when" || cur == "connector")) state.level++; + else if(state.sol && cur == "end" && state.level > 0) state.level--; + + state.tokenize = null; + state.sol = false; + + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + else if (builtin.propertyIsEnumerable(cur)) return "builtin"; + else if (atoms.propertyIsEnumerable(cur)) return "atom"; + else return "variable"; + } + + function tokenQIdent(stream, state) { + while (stream.eat(/[^']/)) { } + + state.tokenize = null; + state.sol = false; + + if(stream.eat("'")) + return "variable"; + else + return "error"; + } + + function tokenUnsignedNuber(stream, state) { + stream.eatWhile(isDigit); + if (stream.eat('.')) { + stream.eatWhile(isDigit); + } + if (stream.eat('e') || stream.eat('E')) { + if (!stream.eat('-')) + stream.eat('+'); + stream.eatWhile(isDigit); + } + + state.tokenize = null; + state.sol = false; + return "number"; + } + + // Interface + return { + startState: function() { + return { + tokenize: null, + level: 0, + sol: true + }; + }, + + token: function(stream, state) { + if(state.tokenize != null) { + return state.tokenize(stream, state); + } + + if(stream.sol()) { + state.sol = true; + } + + // WHITESPACE + if(stream.eatSpace()) { + state.tokenize = null; + return null; + } + + var ch = stream.next(); + + // LINECOMMENT + if(ch == '/' && stream.eat('/')) { + state.tokenize = tokenLineComment; + } + // BLOCKCOMMENT + else if(ch == '/' && stream.eat('*')) { + state.tokenize = tokenBlockComment; + } + // TWO SYMBOL TOKENS + else if(isDoubleOperatorChar.test(ch+stream.peek())) { + stream.next(); + state.tokenize = null; + return "operator"; + } + // SINGLE SYMBOL TOKENS + else if(isSingleOperatorChar.test(ch)) { + state.tokenize = null; + return "operator"; + } + // IDENT + else if(isNonDigit.test(ch)) { + state.tokenize = tokenIdent; + } + // Q-IDENT + else if(ch == "'" && stream.peek() && stream.peek() != "'") { + state.tokenize = tokenQIdent; + } + // STRING + else if(ch == '"') { + state.tokenize = tokenString; + } + // UNSIGNED_NUBER + else if(isDigit.test(ch)) { + state.tokenize = tokenUnsignedNuber; + } + // ERROR + else { + state.tokenize = null; + return "error"; + } + + return state.tokenize(stream, state); + }, + + indent: function(state, textAfter) { + if (state.tokenize != null) return CodeMirror.Pass; + + var level = state.level; + if(/(algorithm)/.test(textAfter)) level--; + if(/(equation)/.test(textAfter)) level--; + if(/(initial algorithm)/.test(textAfter)) level--; + if(/(initial equation)/.test(textAfter)) level--; + if(/(end)/.test(textAfter)) level--; + + if(level > 0) + return indentUnit*level; + else + return 0; + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i=0; i<words.length; ++i) + obj[words[i]] = true; + return obj; + } + + var modelicaKeywords = "algorithm and annotation assert block break class connect connector constant constrainedby der discrete each else elseif elsewhen encapsulated end enumeration equation expandable extends external false final flow for function if import impure in initial inner input loop model not operator or outer output package parameter partial protected public pure record redeclare replaceable return stream then true type when while within"; + var modelicaBuiltin = "abs acos actualStream asin atan atan2 cardinality ceil cos cosh delay div edge exp floor getInstanceName homotopy inStream integer log log10 mod pre reinit rem semiLinear sign sin sinh spatialDistribution sqrt tan tanh"; + var modelicaAtoms = "Real Boolean Integer String"; + + function def(mimes, mode) { + if (typeof mimes == "string") + mimes = [mimes]; + + var words = []; + + function add(obj) { + if (obj) + for (var prop in obj) + if (obj.hasOwnProperty(prop)) + words.push(prop); + } + + add(mode.keywords); + add(mode.builtin); + add(mode.atoms); + + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i=0; i<mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def(["text/x-modelica"], { + name: "modelica", + keywords: words(modelicaKeywords), + builtin: words(modelicaBuiltin), + atoms: words(modelicaAtoms) + }); +}); diff --git a/rhodecode/public/js/mode/mscgen/mscgen.js b/rhodecode/public/js/mode/mscgen/mscgen.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mscgen/mscgen.js @@ -0,0 +1,169 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// mode(s) for the sequence chart dsl's mscgen, xù and msgenny +// For more information on mscgen, see the site of the original author: +// http://www.mcternan.me.uk/mscgen +// +// This mode for mscgen and the two derivative languages were +// originally made for use in the mscgen_js interpreter +// (https://sverweij.github.io/mscgen_js) + +(function(mod) { + if ( typeof exports == "object" && typeof module == "object")// CommonJS + mod(require("../../lib/codemirror")); + else if ( typeof define == "function" && define.amd)// AMD + define(["../../lib/codemirror"], mod); + else// Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var languages = { + mscgen: { + "keywords" : ["msc"], + "options" : ["hscale", "width", "arcgradient", "wordwraparcs"], + "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], + "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists + "arcsWords" : ["note", "abox", "rbox", "box"], + "arcsOthers" : ["\\|\\|\\|", "\\.\\.\\.", "---", "--", "<->", "==", "<<=>>", "<=>", "\\.\\.", "<<>>", "::", "<:>", "->", "=>>", "=>", ">>", ":>", "<-", "<<=", "<=", "<<", "<:", "x-", "-x"], + "singlecomment" : ["//", "#"], + "operators" : ["="] + }, + xu: { + "keywords" : ["msc"], + "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], + "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], + "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists + "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], + "arcsOthers" : ["\\|\\|\\|", "\\.\\.\\.", "---", "--", "<->", "==", "<<=>>", "<=>", "\\.\\.", "<<>>", "::", "<:>", "->", "=>>", "=>", ">>", ":>", "<-", "<<=", "<=", "<<", "<:", "x-", "-x"], + "singlecomment" : ["//", "#"], + "operators" : ["="] + }, + msgenny: { + "keywords" : null, + "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], + "attributes" : null, + "brackets" : ["\\{", "\\}"], + "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], + "arcsOthers" : ["\\|\\|\\|", "\\.\\.\\.", "---", "--", "<->", "==", "<<=>>", "<=>", "\\.\\.", "<<>>", "::", "<:>", "->", "=>>", "=>", ">>", ":>", "<-", "<<=", "<=", "<<", "<:", "x-", "-x"], + "singlecomment" : ["//", "#"], + "operators" : ["="] + } + } + + CodeMirror.defineMode("mscgen", function(_, modeConfig) { + var language = languages[modeConfig && modeConfig.language || "mscgen"] + return { + startState: startStateFn, + copyState: copyStateFn, + token: produceTokenFunction(language), + lineComment : "#", + blockCommentStart : "/*", + blockCommentEnd : "*/" + }; + }); + + CodeMirror.defineMIME("text/x-mscgen", "mscgen"); + CodeMirror.defineMIME("text/x-xu", {name: "mscgen", language: "xu"}); + CodeMirror.defineMIME("text/x-msgenny", {name: "mscgen", language: "msgenny"}); + + function wordRegexpBoundary(pWords) { + return new RegExp("\\b(" + pWords.join("|") + ")\\b", "i"); + } + + function wordRegexp(pWords) { + return new RegExp("(" + pWords.join("|") + ")", "i"); + } + + function startStateFn() { + return { + inComment : false, + inString : false, + inAttributeList : false, + inScript : false + }; + } + + function copyStateFn(pState) { + return { + inComment : pState.inComment, + inString : pState.inString, + inAttributeList : pState.inAttributeList, + inScript : pState.inScript + }; + } + + function produceTokenFunction(pConfig) { + + return function(pStream, pState) { + if (pStream.match(wordRegexp(pConfig.brackets), true, true)) { + return "bracket"; + } + /* comments */ + if (!pState.inComment) { + if (pStream.match(/\/\*[^\*\/]*/, true, true)) { + pState.inComment = true; + return "comment"; + } + if (pStream.match(wordRegexp(pConfig.singlecomment), true, true)) { + pStream.skipToEnd(); + return "comment"; + } + } + if (pState.inComment) { + if (pStream.match(/[^\*\/]*\*\//, true, true)) + pState.inComment = false; + else + pStream.skipToEnd(); + return "comment"; + } + /* strings */ + if (!pState.inString && pStream.match(/\"(\\\"|[^\"])*/, true, true)) { + pState.inString = true; + return "string"; + } + if (pState.inString) { + if (pStream.match(/[^\"]*\"/, true, true)) + pState.inString = false; + else + pStream.skipToEnd(); + return "string"; + } + /* keywords & operators */ + if (!!pConfig.keywords && pStream.match(wordRegexpBoundary(pConfig.keywords), true, true)) + return "keyword"; + + if (pStream.match(wordRegexpBoundary(pConfig.options), true, true)) + return "keyword"; + + if (pStream.match(wordRegexpBoundary(pConfig.arcsWords), true, true)) + return "keyword"; + + if (pStream.match(wordRegexp(pConfig.arcsOthers), true, true)) + return "keyword"; + + if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true)) + return "operator"; + + /* attribute lists */ + if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) { + pConfig.inAttributeList = true; + return "bracket"; + } + if (pConfig.inAttributeList) { + if (pConfig.attributes !== null && pStream.match(wordRegexpBoundary(pConfig.attributes), true, true)) { + return "attribute"; + } + if (pStream.match(/]/, true, true)) { + pConfig.inAttributeList = false; + return "bracket"; + } + } + + pStream.next(); + return "base"; + }; + } + +}); diff --git a/rhodecode/public/js/mode/mscgen/mscgen_test.js b/rhodecode/public/js/mode/mscgen/mscgen_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mscgen/mscgen_test.js @@ -0,0 +1,75 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "mscgen"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("empty chart", + "[keyword msc][bracket {]", + "[base ]", + "[bracket }]" + ); + + MT("comments", + "[comment // a single line comment]", + "[comment # another single line comment /* and */ ignored here]", + "[comment /* A multi-line comment even though it contains]", + "[comment msc keywords and \"quoted text\"*/]"); + + MT("strings", + "[string \"// a string\"]", + "[string \"a string running over]", + "[string two lines\"]", + "[string \"with \\\"escaped quote\"]" + ); + + MT("xù/ msgenny keywords classify as 'base'", + "[base watermark]", + "[base alt loop opt ref else break par seq assert]" + ); + + MT("mscgen options classify as keyword", + "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" + ); + + MT("mscgen arcs classify as keyword", + "[keyword note]","[keyword abox]","[keyword rbox]","[keyword box]", + "[keyword |||...---]", "[keyword ..--==::]", + "[keyword ->]", "[keyword <-]", "[keyword <->]", + "[keyword =>]", "[keyword <=]", "[keyword <=>]", + "[keyword =>>]", "[keyword <<=]", "[keyword <<=>>]", + "[keyword >>]", "[keyword <<]", "[keyword <<>>]", + "[keyword -x]", "[keyword x-]", "[keyword -X]", "[keyword X-]", + "[keyword :>]", "[keyword <:]", "[keyword <:>]" + ); + + MT("within an attribute list, attributes classify as attribute", + "[bracket [[][attribute label]", + "[attribute id]","[attribute url]","[attribute idurl]", + "[attribute linecolor]","[attribute linecolour]","[attribute textcolor]","[attribute textcolour]","[attribute textbgcolor]","[attribute textbgcolour]", + "[attribute arclinecolor]","[attribute arclinecolour]","[attribute arctextcolor]","[attribute arctextcolour]","[attribute arctextbgcolor]","[attribute arctextbgcolour]", + "[attribute arcskip][bracket ]]]" + ); + + MT("outside an attribute list, attributes classify as base", + "[base label]", + "[base id]","[base url]","[base idurl]", + "[base linecolor]","[base linecolour]","[base textcolor]","[base textcolour]","[base textbgcolor]","[base textbgcolour]", + "[base arclinecolor]","[base arclinecolour]","[base arctextcolor]","[base arctextcolour]","[base arctextbgcolor]","[base arctextbgcolour]", + "[base arcskip]" + ); + + MT("a typical program", + "[comment # typical mscgen program]", + "[keyword msc][base ][bracket {]", + "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", + "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", + "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", + "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", + "[base a ][keyword =>>][base b][bracket [[][attribute label][operator =][string \"Hello entity B\"][bracket ]]][base ;]", + "[base a ][keyword <<][base b][bracket [[][attribute label][operator =][string \"Here's an answer dude!\"][bracket ]]][base ;]", + "[base c ][keyword :>][base *][bracket [[][attribute label][operator =][string \"What about me?\"][base , ][attribute textcolor][operator =][base red][bracket ]]][base ;]", + "[bracket }]" + ); +})(); diff --git a/rhodecode/public/js/mode/mscgen/msgenny_test.js b/rhodecode/public/js/mode/mscgen/msgenny_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mscgen/msgenny_test.js @@ -0,0 +1,71 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-msgenny"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "msgenny"); } + + MT("comments", + "[comment // a single line comment]", + "[comment # another single line comment /* and */ ignored here]", + "[comment /* A multi-line comment even though it contains]", + "[comment msc keywords and \"quoted text\"*/]"); + + MT("strings", + "[string \"// a string\"]", + "[string \"a string running over]", + "[string two lines\"]", + "[string \"with \\\"escaped quote\"]" + ); + + MT("xù/ msgenny keywords classify as 'keyword'", + "[keyword watermark]", + "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" + ); + + MT("mscgen options classify as keyword", + "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" + ); + + MT("mscgen arcs classify as keyword", + "[keyword note]","[keyword abox]","[keyword rbox]","[keyword box]", + "[keyword |||...---]", "[keyword ..--==::]", + "[keyword ->]", "[keyword <-]", "[keyword <->]", + "[keyword =>]", "[keyword <=]", "[keyword <=>]", + "[keyword =>>]", "[keyword <<=]", "[keyword <<=>>]", + "[keyword >>]", "[keyword <<]", "[keyword <<>>]", + "[keyword -x]", "[keyword x-]", "[keyword -X]", "[keyword X-]", + "[keyword :>]", "[keyword <:]", "[keyword <:>]" + ); + + MT("within an attribute list, mscgen/ xù attributes classify as base", + "[base [[label]", + "[base idurl id url]", + "[base linecolor linecolour textcolor textcolour textbgcolor textbgcolour]", + "[base arclinecolor arclinecolour arctextcolor arctextcolour arctextbgcolor arctextbgcolour]", + "[base arcskip]]]" + ); + + MT("outside an attribute list, mscgen/ xù attributes classify as base", + "[base label]", + "[base idurl id url]", + "[base linecolor linecolour textcolor textcolour textbgcolor textbgcolour]", + "[base arclinecolor arclinecolour arctextcolor arctextcolour arctextbgcolor arctextbgcolour]", + "[base arcskip]" + ); + + MT("a typical program", + "[comment # typical msgenny program]", + "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]", + "[base a : ][string \"Entity A\"][base ,]", + "[base b : Entity B,]", + "[base c : Entity C;]", + "[base a ][keyword =>>][base b: ][string \"Hello entity B\"][base ;]", + "[base a ][keyword alt][base c][bracket {]", + "[base a ][keyword <<][base b: ][string \"Here's an answer dude!\"][base ;]", + "[keyword ---][base : ][string \"sorry, won't march - comm glitch\"]", + "[base a ][keyword x-][base b: ][string \"Here's an answer dude! (won't arrive...)\"][base ;]", + "[bracket }]", + "[base c ][keyword :>][base *: What about me?;]" + ); +})(); diff --git a/rhodecode/public/js/mode/mscgen/xu_test.js b/rhodecode/public/js/mode/mscgen/xu_test.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mscgen/xu_test.js @@ -0,0 +1,75 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-xu"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "xu"); } + + MT("empty chart", + "[keyword msc][bracket {]", + "[base ]", + "[bracket }]" + ); + + MT("comments", + "[comment // a single line comment]", + "[comment # another single line comment /* and */ ignored here]", + "[comment /* A multi-line comment even though it contains]", + "[comment msc keywords and \"quoted text\"*/]"); + + MT("strings", + "[string \"// a string\"]", + "[string \"a string running over]", + "[string two lines\"]", + "[string \"with \\\"escaped quote\"]" + ); + + MT("xù/ msgenny keywords classify as 'keyword'", + "[keyword watermark]", + "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" + ); + + MT("mscgen options classify as keyword", + "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" + ); + + MT("mscgen arcs classify as keyword", + "[keyword note]","[keyword abox]","[keyword rbox]","[keyword box]", + "[keyword |||...---]", "[keyword ..--==::]", + "[keyword ->]", "[keyword <-]", "[keyword <->]", + "[keyword =>]", "[keyword <=]", "[keyword <=>]", + "[keyword =>>]", "[keyword <<=]", "[keyword <<=>>]", + "[keyword >>]", "[keyword <<]", "[keyword <<>>]", + "[keyword -x]", "[keyword x-]", "[keyword -X]", "[keyword X-]", + "[keyword :>]", "[keyword <:]", "[keyword <:>]" + ); + + MT("within an attribute list, attributes classify as attribute", + "[bracket [[][attribute label]", + "[attribute id]","[attribute url]","[attribute idurl]", + "[attribute linecolor]","[attribute linecolour]","[attribute textcolor]","[attribute textcolour]","[attribute textbgcolor]","[attribute textbgcolour]", + "[attribute arclinecolor]","[attribute arclinecolour]","[attribute arctextcolor]","[attribute arctextcolour]","[attribute arctextbgcolor]","[attribute arctextbgcolour]", + "[attribute arcskip][bracket ]]]" + ); + + MT("outside an attribute list, attributes classify as base", + "[base label]", + "[base id]","[base url]","[base idurl]", + "[base linecolor]","[base linecolour]","[base textcolor]","[base textcolour]","[base textbgcolor]","[base textbgcolour]", + "[base arclinecolor]","[base arclinecolour]","[base arctextcolor]","[base arctextcolour]","[base arctextbgcolor]","[base arctextbgcolour]", + "[base arcskip]" + ); + + MT("a typical program", + "[comment # typical mscgen program]", + "[keyword msc][base ][bracket {]", + "[keyword wordwraparcs][operator =][string \"true\"][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", + "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", + "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", + "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", + "[base a ][keyword =>>][base b][bracket [[][attribute label][operator =][string \"Hello entity B\"][bracket ]]][base ;]", + "[base a ][keyword <<][base b][bracket [[][attribute label][operator =][string \"Here's an answer dude!\"][bracket ]]][base ;]", + "[base c ][keyword :>][base *][bracket [[][attribute label][operator =][string \"What about me?\"][base , ][attribute textcolor][operator =][base red][bracket ]]][base ;]", + "[bracket }]" + ); +})(); diff --git a/rhodecode/public/js/mode/mumps/mumps.js b/rhodecode/public/js/mode/mumps/mumps.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/mumps/mumps.js @@ -0,0 +1,148 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + This MUMPS Language script was constructed using vbscript.js as a template. +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("mumps", function() { + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&#!_?\\\\<>=\\'\\[\\]]"); + var doubleOperators = new RegExp("^(('=)|(<=)|(>=)|('>)|('<)|([[)|(]])|(^$))"); + var singleDelimiters = new RegExp("^[\\.,:]"); + var brackets = new RegExp("[()]"); + var identifiers = new RegExp("^[%A-Za-z][A-Za-z0-9]*"); + var commandKeywords = ["break","close","do","else","for","goto", "halt", "hang", "if", "job","kill","lock","merge","new","open", "quit", "read", "set", "tcommit", "trollback", "tstart", "use", "view", "write", "xecute", "b","c","d","e","f","g", "h", "i", "j","k","l","m","n","o", "q", "r", "s", "tc", "tro", "ts", "u", "v", "w", "x"]; + // The following list includes instrinsic functions _and_ special variables + var intrinsicFuncsWords = ["\\$ascii", "\\$char", "\\$data", "\\$ecode", "\\$estack", "\\$etrap", "\\$extract", "\\$find", "\\$fnumber", "\\$get", "\\$horolog", "\\$io", "\\$increment", "\\$job", "\\$justify", "\\$length", "\\$name", "\\$next", "\\$order", "\\$piece", "\\$qlength", "\\$qsubscript", "\\$query", "\\$quit", "\\$random", "\\$reverse", "\\$select", "\\$stack", "\\$test", "\\$text", "\\$translate", "\\$view", "\\$x", "\\$y", "\\$a", "\\$c", "\\$d", "\\$e", "\\$ec", "\\$es", "\\$et", "\\$f", "\\$fn", "\\$g", "\\$h", "\\$i", "\\$j", "\\$l", "\\$n", "\\$na", "\\$o", "\\$p", "\\$q", "\\$ql", "\\$qs", "\\$r", "\\$re", "\\$s", "\\$st", "\\$t", "\\$tr", "\\$v", "\\$z"]; + var intrinsicFuncs = wordRegexp(intrinsicFuncsWords); + var command = wordRegexp(commandKeywords); + + function tokenBase(stream, state) { + if (stream.sol()) { + state.label = true; + state.commandMode = 0; + } + + // The <space> character has meaning in MUMPS. Ignoring consecutive + // spaces would interfere with interpreting whether the next non-space + // character belongs to the command or argument context. + + // Examine each character and update a mode variable whose interpretation is: + // >0 => command 0 => argument <0 => command post-conditional + var ch = stream.peek(); + + if (ch == " " || ch == "\t") { // Pre-process <space> + state.label = false; + if (state.commandMode == 0) + state.commandMode = 1; + else if ((state.commandMode < 0) || (state.commandMode == 2)) + state.commandMode = 0; + } else if ((ch != ".") && (state.commandMode > 0)) { + if (ch == ":") + state.commandMode = -1; // SIS - Command post-conditional + else + state.commandMode = 2; + } + + // Do not color parameter list as line tag + if ((ch === "(") || (ch === "\u0009")) + state.label = false; + + // MUMPS comment starts with ";" + if (ch === ";") { + stream.skipToEnd(); + return "comment"; + } + + // Number Literals // SIS/RLM - MUMPS permits canonic number followed by concatenate operator + if (stream.match(/^[-+]?\d+(\.\d+)?([eE][-+]?\d+)?/)) + return "number"; + + // Handle Strings + if (ch == '"') { + if (stream.skipTo('"')) { + stream.next(); + return "string"; + } else { + stream.skipToEnd(); + return "error"; + } + } + + // Handle operators and Delimiters + if (stream.match(doubleOperators) || stream.match(singleOperators)) + return "operator"; + + // Prevents leading "." in DO block from falling through to error + if (stream.match(singleDelimiters)) + return null; + + if (brackets.test(ch)) { + stream.next(); + return "bracket"; + } + + if (state.commandMode > 0 && stream.match(command)) + return "variable-2"; + + if (stream.match(intrinsicFuncs)) + return "builtin"; + + if (stream.match(identifiers)) + return "variable"; + + // Detect dollar-sign when not a documented intrinsic function + // "^" may introduce a GVN or SSVN - Color same as function + if (ch === "$" || ch === "^") { + stream.next(); + return "builtin"; + } + + // MUMPS Indirection + if (ch === "@") { + stream.next(); + return "string-2"; + } + + if (/[\w%]/.test(ch)) { + stream.eatWhile(/[\w%]/); + return "variable"; + } + + // Handle non-detected items + stream.next(); + return "error"; + } + + return { + startState: function() { + return { + label: false, + commandMode: 0 + }; + }, + + token: function(stream, state) { + var style = tokenBase(stream, state); + if (state.label) return "tag"; + return style; + } + }; + }); + + CodeMirror.defineMIME("text/x-mumps", "mumps"); +}); diff --git a/rhodecode/public/js/mode/nginx/nginx.js b/rhodecode/public/js/mode/nginx/nginx.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/nginx/nginx.js @@ -0,0 +1,178 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("nginx", function(config) { + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = words( + /* ngxDirectiveControl */ "break return rewrite set" + + /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23" + ); + + var keywords_block = words( + /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map" + ); + + var keywords_important = words( + /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files" + ); + + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + function tokenBase(stream, state) { + + + stream.eatWhile(/[\w\$_]/); + + var cur = stream.current(); + + + if (keywords.propertyIsEnumerable(cur)) { + return "keyword"; + } + else if (keywords_block.propertyIsEnumerable(cur)) { + return "variable-2"; + } + else if (keywords_important.propertyIsEnumerable(cur)) { + return "string-2"; + } + /**/ + + var ch = stream.next(); + if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());} + else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + else if (ch == "<" && stream.eat("!")) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } + else if (ch == "=") ret(null, "compare"); + else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare"); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + else if (ch == "#") { + stream.skipToEnd(); + return ret("comment", "comment"); + } + else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } + else if (/[,.+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } + else if (/[;{}:\[\]]/.test(ch)) { + return ret(null, ch); + } + else { + stream.eatWhile(/[\w\\\-]/); + return ret("variable", "variable"); + } + } + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = tokenBase; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) + break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + stack: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + + var context = state.stack[state.stack.length-1]; + if (type == "hash" && context == "rule") style = "atom"; + else if (style == "variable") { + if (context == "rule") style = "number"; + else if (!context || context == "@media{") style = "tag"; + } + + if (context == "rule" && /^[\{\};]$/.test(type)) + state.stack.pop(); + if (type == "{") { + if (context == "@media") state.stack[state.stack.length-1] = "@media{"; + else state.stack.push("{"); + } + else if (type == "}") state.stack.pop(); + else if (type == "@media") state.stack.push("@media"); + else if (context == "{" && type != "comment") state.stack.push("rule"); + return style; + }, + + indent: function(state, textAfter) { + var n = state.stack.length; + if (/^\}/.test(textAfter)) + n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; + return state.baseIndent + n * indentUnit; + }, + + electricChars: "}" + }; +}); + +CodeMirror.defineMIME("text/nginx", "text/x-nginx-conf"); + +}); diff --git a/rhodecode/public/js/mode/nsis/nsis.js b/rhodecode/public/js/mode/nsis/nsis.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/nsis/nsis.js @@ -0,0 +1,95 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Author: Jan T. Sott (http://github.com/idleberg) + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../addon/mode/simple")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../addon/mode/simple"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineSimpleMode("nsis",{ + start:[ + // Numbers + {regex: /(?:[+-]?)(?:0x[\d,a-f]+)|(?:0o[0-7]+)|(?:0b[0,1]+)|(?:\d+.?\d*)/, token: "number"}, + + // Strings + { regex: /"(?:[^\\"]|\\.)*"?/, token: "string" }, + { regex: /'(?:[^\\']|\\.)*'?/, token: "string" }, + { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" }, + + // Compile Time Commands + {regex: /(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"}, + + // Conditional Compilation + {regex: /(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true}, + {regex: /(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true}, + + // Runtime Commands + {regex: /\b(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetPluginUnload|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, + {regex: /\b(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true}, + {regex: /\b(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true}, + + // Command Options + {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"}, + {regex: /\b(?:admin|all|auto|both|bottom|bzip2|components|current|custom|directory|force|hide|highest|ifdiff|ifnewer|instfiles|lastused|leave|left|license|listonly|lzma|nevershow|none|normal|notset|right|show|silent|silentlog|textonly|top|try|un\.components|un\.custom|un\.directory|un\.instfiles|un\.license|uninstConfirm|user|Win10|Win7|Win8|WinVista|zlib)\b/, token: "builtin"}, + + // LogicLib.nsh + {regex: /\$\{(?:And(?:If(?:Not)?|Unless)|Break|Case(?:Else)?|Continue|Default|Do(?:Until|While)?|Else(?:If(?:Not)?|Unless)?|End(?:If|Select|Switch)|Exit(?:Do|For|While)|For(?:Each)?|If(?:Cmd|Not(?:Then)?|Then)?|Loop(?:Until|While)?|Or(?:If(?:Not)?|Unless)|Select|Switch|Unless|While)\}/, token: "variable-2", indent: true}, + + // FileFunc.nsh + {regex: /\$\{(?:BannerTrimPath|DirState|DriveSpace|Get(BaseName|Drives|ExeName|ExePath|FileAttributes|FileExt|FileName|FileVersion|Options|OptionsS|Parameters|Parent|Root|Size|Time)|Locate|RefreshShellIcons)\}/, token: "variable-2", dedent: true}, + + // Memento.nsh + {regex: /\$\{(?:Memento(?:Section(?:Done|End|Restore|Save)?|UnselectedSection))\}/, token: "variable-2", dedent: true}, + + // TextFunc.nsh + {regex: /\$\{(?:Config(?:Read|ReadS|Write|WriteS)|File(?:Join|ReadFromEnd|Recode)|Line(?:Find|Read|Sum)|Text(?:Compare|CompareS)|TrimNewLines)\}/, token: "variable-2", dedent: true}, + + // WinVer.nsh + {regex: /\$\{(?:(?:At(?:Least|Most)|Is)(?:ServicePack|Win(?:7|8|10|95|98|200(?:0|3|8(?:R2)?)|ME|NT4|Vista|XP))|Is(?:NT|Server))\}/, token: "variable", dedent: true}, + + // WordFunc.nsh + {regex: /\$\{(?:StrFilterS?|Version(?:Compare|Convert)|Word(?:AddS?|Find(?:(?:2|3)X)?S?|InsertS?|ReplaceS?))\}/, token: "variable-2", dedent: true}, + + // x64.nsh + {regex: /\$\{(?:RunningX64)\}/, token: "variable", dedent: true}, + {regex: /\$\{(?:Disable|Enable)X64FSRedirection\}/, token: "variable-2", dedent: true}, + + // Line Comment + {regex: /(#|;).*/, token: "comment"}, + + // Block Comment + {regex: /\/\*/, token: "comment", next: "comment"}, + + // Operator + {regex: /[-+\/*=<>!]+/, token: "operator"}, + + // Variable + {regex: /\$[\w]+/, token: "variable"}, + + // Constant + {regex: /\${[\w]+}/,token: "variable-2"}, + + // Language String + {regex: /\$\([\w]+\)/,token: "variable-3"} + ], + comment: [ + {regex: /.*?\*\//, token: "comment", next: "start"}, + {regex: /.*/, token: "comment"} + ], + meta: { + electricInput: /^\s*((Function|PageEx|Section|Section(Group)?)End|(\!(endif|macroend))|\$\{(End(If|Unless|While)|Loop(Until)|Next)\})$/, + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: ["#", ";"] + } +}); + +CodeMirror.defineMIME("text/x-nsis", "nsis"); +}); diff --git a/rhodecode/public/js/mode/ntriples/ntriples.js b/rhodecode/public/js/mode/ntriples/ntriples.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ntriples/ntriples.js @@ -0,0 +1,186 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/********************************************************** +* This script provides syntax highlighting support for +* the Ntriples format. +* Ntriples format specification: +* http://www.w3.org/TR/rdf-testcases/#ntriples +***********************************************************/ + +/* + The following expression defines the defined ASF grammar transitions. + + pre_subject -> + { + ( writing_subject_uri | writing_bnode_uri ) + -> pre_predicate + -> writing_predicate_uri + -> pre_object + -> writing_object_uri | writing_object_bnode | + ( + writing_object_literal + -> writing_literal_lang | writing_literal_type + ) + -> post_object + -> BEGIN + } otherwise { + -> ERROR + } +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("ntriples", function() { + + var Location = { + PRE_SUBJECT : 0, + WRITING_SUB_URI : 1, + WRITING_BNODE_URI : 2, + PRE_PRED : 3, + WRITING_PRED_URI : 4, + PRE_OBJ : 5, + WRITING_OBJ_URI : 6, + WRITING_OBJ_BNODE : 7, + WRITING_OBJ_LITERAL : 8, + WRITING_LIT_LANG : 9, + WRITING_LIT_TYPE : 10, + POST_OBJ : 11, + ERROR : 12 + }; + function transitState(currState, c) { + var currLocation = currState.location; + var ret; + + // Opening. + if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI; + else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI; + else if(currLocation == Location.PRE_PRED && c == '<') ret = Location.WRITING_PRED_URI; + else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI; + else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE; + else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL; + + // Closing. + else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED; + else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED; + else if(currLocation == Location.WRITING_PRED_URI && c == '>') ret = Location.PRE_OBJ; + else if(currLocation == Location.WRITING_OBJ_URI && c == '>') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_OBJ_BNODE && c == ' ') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ; + + // Closing typed and language literal. + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG; + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE; + + // Spaces. + else if( c == ' ' && + ( + currLocation == Location.PRE_SUBJECT || + currLocation == Location.PRE_PRED || + currLocation == Location.PRE_OBJ || + currLocation == Location.POST_OBJ + ) + ) ret = currLocation; + + // Reset. + else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT; + + // Error + else ret = Location.ERROR; + + currState.location=ret; + } + + return { + startState: function() { + return { + location : Location.PRE_SUBJECT, + uris : [], + anchors : [], + bnodes : [], + langs : [], + types : [] + }; + }, + token: function(stream, state) { + var ch = stream.next(); + if(ch == '<') { + transitState(state, ch); + var parsedURI = ''; + stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} ); + state.uris.push(parsedURI); + if( stream.match('#', false) ) return 'variable'; + stream.next(); + transitState(state, '>'); + return 'variable'; + } + if(ch == '#') { + var parsedAnchor = ''; + stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false;}); + state.anchors.push(parsedAnchor); + return 'variable-2'; + } + if(ch == '>') { + transitState(state, '>'); + return 'variable'; + } + if(ch == '_') { + transitState(state, ch); + var parsedBNode = ''; + stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;}); + state.bnodes.push(parsedBNode); + stream.next(); + transitState(state, ' '); + return 'builtin'; + } + if(ch == '"') { + transitState(state, ch); + stream.eatWhile( function(c) { return c != '"'; } ); + stream.next(); + if( stream.peek() != '@' && stream.peek() != '^' ) { + transitState(state, '"'); + } + return 'string'; + } + if( ch == '@' ) { + transitState(state, '@'); + var parsedLang = ''; + stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;}); + state.langs.push(parsedLang); + stream.next(); + transitState(state, ' '); + return 'string-2'; + } + if( ch == '^' ) { + stream.next(); + transitState(state, '^'); + var parsedType = ''; + stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} ); + state.types.push(parsedType); + stream.next(); + transitState(state, '>'); + return 'variable'; + } + if( ch == ' ' ) { + transitState(state, ch); + } + if( ch == '.' ) { + transitState(state, ch); + } + } + }; +}); + +CodeMirror.defineMIME("text/n-triples", "ntriples"); + +}); diff --git a/rhodecode/public/js/mode/ocaml/ocaml.js b/rhodecode/public/js/mode/ocaml/ocaml.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ocaml/ocaml.js @@ -0,0 +1,116 @@ +CodeMirror.defineMode('ocaml', function() { + + var words = { + 'true': 'atom', + 'false': 'atom', + 'let': 'keyword', + 'rec': 'keyword', + 'in': 'keyword', + 'of': 'keyword', + 'and': 'keyword', + 'succ': 'keyword', + 'if': 'keyword', + 'then': 'keyword', + 'else': 'keyword', + 'for': 'keyword', + 'to': 'keyword', + 'while': 'keyword', + 'do': 'keyword', + 'done': 'keyword', + 'fun': 'keyword', + 'function': 'keyword', + 'val': 'keyword', + 'type': 'keyword', + 'mutable': 'keyword', + 'match': 'keyword', + 'with': 'keyword', + 'try': 'keyword', + 'raise': 'keyword', + 'begin': 'keyword', + 'end': 'keyword', + 'open': 'builtin', + 'trace': 'builtin', + 'ignore': 'builtin', + 'exit': 'builtin', + 'print_string': 'builtin', + 'print_endline': 'builtin' + }; + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch === '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + if (ch === '(') { + if (stream.eat('*')) { + state.commentLevel++; + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } + } + if (ch === '~') { + stream.eatWhile(/\w/); + return 'variable-2'; + } + if (ch === '`') { + stream.eatWhile(/\w/); + return 'quote'; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\d]/); + if (stream.eat('.')) { + stream.eatWhile(/[\d]/); + } + return 'number'; + } + if ( /[+\-*&%=<>!?|]/.test(ch)) { + return 'operator'; + } + stream.eatWhile(/\w/); + var cur = stream.current(); + return words[cur] || 'variable'; + } + + function tokenString(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === '"' && !escaped) { + end = true; + break; + } + escaped = !escaped && next === '\\'; + } + if (end && !escaped) { + state.tokenize = tokenBase; + } + return 'string'; + }; + + function tokenComment(stream, state) { + var prev, next; + while(state.commentLevel > 0 && (next = stream.next()) != null) { + if (prev === '(' && next === '*') state.commentLevel++; + if (prev === '*' && next === ')') state.commentLevel--; + prev = next; + } + if (state.commentLevel <= 0) { + state.tokenize = tokenBase; + } + return 'comment'; + } + + return { + startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + + blockCommentStart: "(*", + blockCommentEnd: "*)" + }; +}); + +CodeMirror.defineMIME('text/x-ocaml', 'ocaml'); diff --git a/rhodecode/public/js/mode/octave/octave.js b/rhodecode/public/js/mode/octave/octave.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/octave/octave.js @@ -0,0 +1,135 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("octave", function() { + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]"); + var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]'); + var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))"); + var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((>>=)|(<<=))"); + var expressionEnd = new RegExp("^[\\]\\)]"); + var identifiers = new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*"); + + var builtins = wordRegexp([ + 'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos', + 'cosh', 'exp', 'log', 'prod', 'sum', 'log10', 'max', 'min', 'sign', 'sin', 'sinh', + 'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones', + 'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov', + 'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot', + 'title', 'xlabel', 'ylabel', 'legend', 'text', 'grid', 'meshgrid', 'mesh', 'num2str', + 'fft', 'ifft', 'arrayfun', 'cellfun', 'input', 'fliplr', 'flipud', 'ismember' + ]); + + var keywords = wordRegexp([ + 'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction', + 'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events', + 'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'sprintf', 'disp', 'until', + 'continue', 'pkg' + ]); + + + // tokenizers + function tokenTranspose(stream, state) { + if (!stream.sol() && stream.peek() === '\'') { + stream.next(); + state.tokenize = tokenBase; + return 'operator'; + } + state.tokenize = tokenBase; + return tokenBase(stream, state); + } + + + function tokenComment(stream, state) { + if (stream.match(/^.*%}/)) { + state.tokenize = tokenBase; + return 'comment'; + }; + stream.skipToEnd(); + return 'comment'; + } + + function tokenBase(stream, state) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match('%{')){ + state.tokenize = tokenComment; + stream.skipToEnd(); + return 'comment'; + } + + if (stream.match(/^[%#]/)){ + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) { + stream.tokenize = tokenBase; + return 'number'; }; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + } + if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; }; + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ; + if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ; + + // Handle words + if (stream.match(keywords)) { return 'keyword'; } ; + if (stream.match(builtins)) { return 'builtin'; } ; + if (stream.match(identifiers)) { return 'variable'; } ; + + if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; }; + if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; }; + + if (stream.match(expressionEnd)) { + state.tokenize = tokenTranspose; + return null; + }; + + + // Handle non-detected items + stream.next(); + return 'error'; + }; + + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + var style = state.tokenize(stream, state); + if (style === 'number' || style === 'variable'){ + state.tokenize = tokenTranspose; + } + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-octave", "octave"); + +}); diff --git a/rhodecode/public/js/mode/oz/oz.js b/rhodecode/public/js/mode/oz/oz.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/oz/oz.js @@ -0,0 +1,252 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("oz", function (conf) { + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = /[\^@!\|<>#~\.\*\-\+\\/,=]/; + var doubleOperators = /(<-)|(:=)|(=<)|(>=)|(<=)|(<:)|(>:)|(=:)|(\\=)|(\\=:)|(!!)|(==)|(::)/; + var tripleOperators = /(:::)|(\.\.\.)|(=<:)|(>=:)/; + + var middle = ["in", "then", "else", "of", "elseof", "elsecase", "elseif", "catch", + "finally", "with", "require", "prepare", "import", "export", "define", "do"]; + var end = ["end"]; + + var atoms = wordRegexp(["true", "false", "nil", "unit"]); + var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex", + "mod", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]); + var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis", + "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]); + var middleKeywords = wordRegexp(middle); + var endKeywords = wordRegexp(end); + + // Tokenizers + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return null; + } + + // Brackets + if(stream.match(/[{}]/)) { + return "bracket"; + } + + // Special [] keyword + if (stream.match(/(\[])/)) { + return "keyword" + } + + // Operators + if (stream.match(tripleOperators) || stream.match(doubleOperators)) { + return "operator"; + } + + // Atoms + if(stream.match(atoms)) { + return 'atom'; + } + + // Opening keywords + var matched = stream.match(openingKeywords); + if (matched) { + if (!state.doInCurrentLine) + state.currentIndent++; + else + state.doInCurrentLine = false; + + // Special matching for signatures + if(matched[0] == "proc" || matched[0] == "fun") + state.tokenize = tokenFunProc; + else if(matched[0] == "class") + state.tokenize = tokenClass; + else if(matched[0] == "meth") + state.tokenize = tokenMeth; + + return 'keyword'; + } + + // Middle and other keywords + if (stream.match(middleKeywords) || stream.match(commonKeywords)) { + return "keyword" + } + + // End keywords + if (stream.match(endKeywords)) { + state.currentIndent--; + return 'keyword'; + } + + // Eat the next char for next comparisons + var ch = stream.next(); + + // Strings + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + + // Numbers + if (/[~\d]/.test(ch)) { + if (ch == "~") { + if(! /^[0-9]/.test(stream.peek())) + return null; + else if (( stream.next() == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/)) + return "number"; + } + + if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/)) + return "number"; + + return null; + } + + // Comments + if (ch == "%") { + stream.skipToEnd(); + return 'comment'; + } + else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + } + + // Single operators + if(singleOperators.test(ch)) { + return "operator"; + } + + // If nothing match, we skip the entire alphanumerical block + stream.eatWhile(/\w/); + + return "variable"; + } + + function tokenClass(stream, state) { + if (stream.eatSpace()) { + return null; + } + stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)/); + state.tokenize = tokenBase; + return "variable-3" + } + + function tokenMeth(stream, state) { + if (stream.eatSpace()) { + return null; + } + stream.match(/([a-zA-Z][A-Za-z0-9_]*)|(`.+`)/); + state.tokenize = tokenBase; + return "def" + } + + function tokenFunProc(stream, state) { + if (stream.eatSpace()) { + return null; + } + + if(!state.hasPassedFirstStage && stream.eat("{")) { + state.hasPassedFirstStage = true; + return "bracket"; + } + else if(state.hasPassedFirstStage) { + stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)|\$/); + state.hasPassedFirstStage = false; + state.tokenize = tokenBase; + return "def" + } + else { + state.tokenize = tokenBase; + return null; + } + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(quote) { + return function (stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end || !escaped) + state.tokenize = tokenBase; + return "string"; + }; + } + + function buildElectricInputRegEx() { + // Reindentation should occur on [] or on a match of any of + // the block closing keywords, at the end of a line. + var allClosings = middle.concat(end); + return new RegExp("[\\[\\]]|(" + allClosings.join("|") + ")$"); + } + + return { + + startState: function () { + return { + tokenize: tokenBase, + currentIndent: 0, + doInCurrentLine: false, + hasPassedFirstStage: false + }; + }, + + token: function (stream, state) { + if (stream.sol()) + state.doInCurrentLine = 0; + + return state.tokenize(stream, state); + }, + + indent: function (state, textAfter) { + var trueText = textAfter.replace(/^\s+|\s+$/g, ''); + + if (trueText.match(endKeywords) || trueText.match(middleKeywords) || trueText.match(/(\[])/)) + return conf.indentUnit * (state.currentIndent - 1); + + if (state.currentIndent < 0) + return 0; + + return state.currentIndent * conf.indentUnit; + }, + fold: "indent", + electricInput: buildElectricInputRegEx(), + lineComment: "%", + blockCommentStart: "/*", + blockCommentEnd: "*/" + }; +}); + +CodeMirror.defineMIME("text/x-oz", "oz"); + +}); diff --git a/rhodecode/public/js/mode/pascal/pascal.js b/rhodecode/public/js/mode/pascal/pascal.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/pascal/pascal.js @@ -0,0 +1,109 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pascal", function() { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = words("and array begin case const div do downto else end file for forward integer " + + "boolean char function goto if in label mod nil not of or packed procedure " + + "program record repeat set string then to type until var while with"); + var atoms = {"null": true}; + + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == "#" && state.startOfLine) { + stream.skipToEnd(); + return "meta"; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (ch == "(" && stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !escaped) state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == ")" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + // Interface + + return { + startState: function() { + return {tokenize: null}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + return style; + }, + + electricChars: "{}" + }; +}); + +CodeMirror.defineMIME("text/x-pascal", "pascal"); + +}); diff --git a/rhodecode/public/js/mode/pegjs/pegjs.js b/rhodecode/public/js/mode/pegjs/pegjs.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/pegjs/pegjs.js @@ -0,0 +1,114 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../javascript/javascript")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../javascript/javascript"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pegjs", function (config) { + var jsMode = CodeMirror.getMode(config, "javascript"); + + function identifier(stream) { + return stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/); + } + + return { + startState: function () { + return { + inString: false, + stringType: null, + inComment: false, + inChracterClass: false, + braced: 0, + lhs: true, + localState: null + }; + }, + token: function (stream, state) { + if (stream) + + //check for state changes + if (!state.inString && !state.inComment && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (!state.inString && !state.inComment && stream.match(/^\/\*/)) { + state.inComment = true; + } + + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inComment) { + while (state.inComment && !stream.eol()) { + if (stream.match(/\*\//)) { + state.inComment = false; // Clear flag + } else { + stream.match(/^.[^\*]*/); + } + } + return "comment"; + } else if (state.inChracterClass) { + while (state.inChracterClass && !stream.eol()) { + if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) { + state.inChracterClass = false; + } + } + } else if (stream.peek() === '[') { + stream.next(); + state.inChracterClass = true; + return 'bracket'; + } else if (stream.match(/^\/\//)) { + stream.skipToEnd(); + return "comment"; + } else if (state.braced || stream.peek() === '{') { + if (state.localState === null) { + state.localState = jsMode.startState(); + } + var token = jsMode.token(stream, state.localState); + var text = stream.current(); + if (!token) { + for (var i = 0; i < text.length; i++) { + if (text[i] === '{') { + state.braced++; + } else if (text[i] === '}') { + state.braced--; + } + }; + } + return token; + } else if (identifier(stream)) { + if (stream.peek() === ':') { + return 'variable'; + } + return 'variable-2'; + } else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) { + stream.next(); + return 'bracket'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}, "javascript"); + +}); diff --git a/rhodecode/public/js/mode/perl/perl.js b/rhodecode/public/js/mode/perl/perl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/perl/perl.js @@ -0,0 +1,837 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08) +// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com) + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("perl",function(){ + // http://perldoc.perl.org + var PERL={ // null - magic touch + // 1 - keyword + // 2 - def + // 3 - atom + // 4 - operator + // 5 - variable-2 (predefined) + // [x,y] - x=1,2,3; y=must be defined if x{...} + // PERL operators + '->' : 4, + '++' : 4, + '--' : 4, + '**' : 4, + // ! ~ \ and unary + and - + '=~' : 4, + '!~' : 4, + '*' : 4, + '/' : 4, + '%' : 4, + 'x' : 4, + '+' : 4, + '-' : 4, + '.' : 4, + '<<' : 4, + '>>' : 4, + // named unary operators + '<' : 4, + '>' : 4, + '<=' : 4, + '>=' : 4, + 'lt' : 4, + 'gt' : 4, + 'le' : 4, + 'ge' : 4, + '==' : 4, + '!=' : 4, + '<=>' : 4, + 'eq' : 4, + 'ne' : 4, + 'cmp' : 4, + '~~' : 4, + '&' : 4, + '|' : 4, + '^' : 4, + '&&' : 4, + '||' : 4, + '//' : 4, + '..' : 4, + '...' : 4, + '?' : 4, + ':' : 4, + '=' : 4, + '+=' : 4, + '-=' : 4, + '*=' : 4, // etc. ??? + ',' : 4, + '=>' : 4, + '::' : 4, + // list operators (rightward) + 'not' : 4, + 'and' : 4, + 'or' : 4, + 'xor' : 4, + // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;) + 'BEGIN' : [5,1], + 'END' : [5,1], + 'PRINT' : [5,1], + 'PRINTF' : [5,1], + 'GETC' : [5,1], + 'READ' : [5,1], + 'READLINE' : [5,1], + 'DESTROY' : [5,1], + 'TIE' : [5,1], + 'TIEHANDLE' : [5,1], + 'UNTIE' : [5,1], + 'STDIN' : 5, + 'STDIN_TOP' : 5, + 'STDOUT' : 5, + 'STDOUT_TOP' : 5, + 'STDERR' : 5, + 'STDERR_TOP' : 5, + '$ARG' : 5, + '$_' : 5, + '@ARG' : 5, + '@_' : 5, + '$LIST_SEPARATOR' : 5, + '$"' : 5, + '$PROCESS_ID' : 5, + '$PID' : 5, + '$$' : 5, + '$REAL_GROUP_ID' : 5, + '$GID' : 5, + '$(' : 5, + '$EFFECTIVE_GROUP_ID' : 5, + '$EGID' : 5, + '$)' : 5, + '$PROGRAM_NAME' : 5, + '$0' : 5, + '$SUBSCRIPT_SEPARATOR' : 5, + '$SUBSEP' : 5, + '$;' : 5, + '$REAL_USER_ID' : 5, + '$UID' : 5, + '$<' : 5, + '$EFFECTIVE_USER_ID' : 5, + '$EUID' : 5, + '$>' : 5, + '$a' : 5, + '$b' : 5, + '$COMPILING' : 5, + '$^C' : 5, + '$DEBUGGING' : 5, + '$^D' : 5, + '${^ENCODING}' : 5, + '$ENV' : 5, + '%ENV' : 5, + '$SYSTEM_FD_MAX' : 5, + '$^F' : 5, + '@F' : 5, + '${^GLOBAL_PHASE}' : 5, + '$^H' : 5, + '%^H' : 5, + '@INC' : 5, + '%INC' : 5, + '$INPLACE_EDIT' : 5, + '$^I' : 5, + '$^M' : 5, + '$OSNAME' : 5, + '$^O' : 5, + '${^OPEN}' : 5, + '$PERLDB' : 5, + '$^P' : 5, + '$SIG' : 5, + '%SIG' : 5, + '$BASETIME' : 5, + '$^T' : 5, + '${^TAINT}' : 5, + '${^UNICODE}' : 5, + '${^UTF8CACHE}' : 5, + '${^UTF8LOCALE}' : 5, + '$PERL_VERSION' : 5, + '$^V' : 5, + '${^WIN32_SLOPPY_STAT}' : 5, + '$EXECUTABLE_NAME' : 5, + '$^X' : 5, + '$1' : 5, // - regexp $1, $2... + '$MATCH' : 5, + '$&' : 5, + '${^MATCH}' : 5, + '$PREMATCH' : 5, + '$`' : 5, + '${^PREMATCH}' : 5, + '$POSTMATCH' : 5, + "$'" : 5, + '${^POSTMATCH}' : 5, + '$LAST_PAREN_MATCH' : 5, + '$+' : 5, + '$LAST_SUBMATCH_RESULT' : 5, + '$^N' : 5, + '@LAST_MATCH_END' : 5, + '@+' : 5, + '%LAST_PAREN_MATCH' : 5, + '%+' : 5, + '@LAST_MATCH_START' : 5, + '@-' : 5, + '%LAST_MATCH_START' : 5, + '%-' : 5, + '$LAST_REGEXP_CODE_RESULT' : 5, + '$^R' : 5, + '${^RE_DEBUG_FLAGS}' : 5, + '${^RE_TRIE_MAXBUF}' : 5, + '$ARGV' : 5, + '@ARGV' : 5, + 'ARGV' : 5, + 'ARGVOUT' : 5, + '$OUTPUT_FIELD_SEPARATOR' : 5, + '$OFS' : 5, + '$,' : 5, + '$INPUT_LINE_NUMBER' : 5, + '$NR' : 5, + '$.' : 5, + '$INPUT_RECORD_SEPARATOR' : 5, + '$RS' : 5, + '$/' : 5, + '$OUTPUT_RECORD_SEPARATOR' : 5, + '$ORS' : 5, + '$\\' : 5, + '$OUTPUT_AUTOFLUSH' : 5, + '$|' : 5, + '$ACCUMULATOR' : 5, + '$^A' : 5, + '$FORMAT_FORMFEED' : 5, + '$^L' : 5, + '$FORMAT_PAGE_NUMBER' : 5, + '$%' : 5, + '$FORMAT_LINES_LEFT' : 5, + '$-' : 5, + '$FORMAT_LINE_BREAK_CHARACTERS' : 5, + '$:' : 5, + '$FORMAT_LINES_PER_PAGE' : 5, + '$=' : 5, + '$FORMAT_TOP_NAME' : 5, + '$^' : 5, + '$FORMAT_NAME' : 5, + '$~' : 5, + '${^CHILD_ERROR_NATIVE}' : 5, + '$EXTENDED_OS_ERROR' : 5, + '$^E' : 5, + '$EXCEPTIONS_BEING_CAUGHT' : 5, + '$^S' : 5, + '$WARNING' : 5, + '$^W' : 5, + '${^WARNING_BITS}' : 5, + '$OS_ERROR' : 5, + '$ERRNO' : 5, + '$!' : 5, + '%OS_ERROR' : 5, + '%ERRNO' : 5, + '%!' : 5, + '$CHILD_ERROR' : 5, + '$?' : 5, + '$EVAL_ERROR' : 5, + '$@' : 5, + '$OFMT' : 5, + '$#' : 5, + '$*' : 5, + '$ARRAY_BASE' : 5, + '$[' : 5, + '$OLD_PERL_VERSION' : 5, + '$]' : 5, + // PERL blocks + 'if' :[1,1], + elsif :[1,1], + 'else' :[1,1], + 'while' :[1,1], + unless :[1,1], + 'for' :[1,1], + foreach :[1,1], + // PERL functions + 'abs' :1, // - absolute value function + accept :1, // - accept an incoming socket connect + alarm :1, // - schedule a SIGALRM + 'atan2' :1, // - arctangent of Y/X in the range -PI to PI + bind :1, // - binds an address to a socket + binmode :1, // - prepare binary files for I/O + bless :1, // - create an object + bootstrap :1, // + 'break' :1, // - break out of a "given" block + caller :1, // - get context of the current subroutine call + chdir :1, // - change your current working directory + chmod :1, // - changes the permissions on a list of files + chomp :1, // - remove a trailing record separator from a string + chop :1, // - remove the last character from a string + chown :1, // - change the owership on a list of files + chr :1, // - get character this number represents + chroot :1, // - make directory new root for path lookups + close :1, // - close file (or pipe or socket) handle + closedir :1, // - close directory handle + connect :1, // - connect to a remote socket + 'continue' :[1,1], // - optional trailing block in a while or foreach + 'cos' :1, // - cosine function + crypt :1, // - one-way passwd-style encryption + dbmclose :1, // - breaks binding on a tied dbm file + dbmopen :1, // - create binding on a tied dbm file + 'default' :1, // + defined :1, // - test whether a value, variable, or function is defined + 'delete' :1, // - deletes a value from a hash + die :1, // - raise an exception or bail out + 'do' :1, // - turn a BLOCK into a TERM + dump :1, // - create an immediate core dump + each :1, // - retrieve the next key/value pair from a hash + endgrent :1, // - be done using group file + endhostent :1, // - be done using hosts file + endnetent :1, // - be done using networks file + endprotoent :1, // - be done using protocols file + endpwent :1, // - be done using passwd file + endservent :1, // - be done using services file + eof :1, // - test a filehandle for its end + 'eval' :1, // - catch exceptions or compile and run code + 'exec' :1, // - abandon this program to run another + exists :1, // - test whether a hash key is present + exit :1, // - terminate this program + 'exp' :1, // - raise I to a power + fcntl :1, // - file control system call + fileno :1, // - return file descriptor from filehandle + flock :1, // - lock an entire file with an advisory lock + fork :1, // - create a new process just like this one + format :1, // - declare a picture format with use by the write() function + formline :1, // - internal function used for formats + getc :1, // - get the next character from the filehandle + getgrent :1, // - get next group record + getgrgid :1, // - get group record given group user ID + getgrnam :1, // - get group record given group name + gethostbyaddr :1, // - get host record given its address + gethostbyname :1, // - get host record given name + gethostent :1, // - get next hosts record + getlogin :1, // - return who logged in at this tty + getnetbyaddr :1, // - get network record given its address + getnetbyname :1, // - get networks record given name + getnetent :1, // - get next networks record + getpeername :1, // - find the other end of a socket connection + getpgrp :1, // - get process group + getppid :1, // - get parent process ID + getpriority :1, // - get current nice value + getprotobyname :1, // - get protocol record given name + getprotobynumber :1, // - get protocol record numeric protocol + getprotoent :1, // - get next protocols record + getpwent :1, // - get next passwd record + getpwnam :1, // - get passwd record given user login name + getpwuid :1, // - get passwd record given user ID + getservbyname :1, // - get services record given its name + getservbyport :1, // - get services record given numeric port + getservent :1, // - get next services record + getsockname :1, // - retrieve the sockaddr for a given socket + getsockopt :1, // - get socket options on a given socket + given :1, // + glob :1, // - expand filenames using wildcards + gmtime :1, // - convert UNIX time into record or string using Greenwich time + 'goto' :1, // - create spaghetti code + grep :1, // - locate elements in a list test true against a given criterion + hex :1, // - convert a string to a hexadecimal number + 'import' :1, // - patch a module's namespace into your own + index :1, // - find a substring within a string + 'int' :1, // - get the integer portion of a number + ioctl :1, // - system-dependent device control system call + 'join' :1, // - join a list into a string using a separator + keys :1, // - retrieve list of indices from a hash + kill :1, // - send a signal to a process or process group + last :1, // - exit a block prematurely + lc :1, // - return lower-case version of a string + lcfirst :1, // - return a string with just the next letter in lower case + length :1, // - return the number of bytes in a string + 'link' :1, // - create a hard link in the filesytem + listen :1, // - register your socket as a server + local : 2, // - create a temporary value for a global variable (dynamic scoping) + localtime :1, // - convert UNIX time into record or string using local time + lock :1, // - get a thread lock on a variable, subroutine, or method + 'log' :1, // - retrieve the natural logarithm for a number + lstat :1, // - stat a symbolic link + m :null, // - match a string with a regular expression pattern + map :1, // - apply a change to a list to get back a new list with the changes + mkdir :1, // - create a directory + msgctl :1, // - SysV IPC message control operations + msgget :1, // - get SysV IPC message queue + msgrcv :1, // - receive a SysV IPC message from a message queue + msgsnd :1, // - send a SysV IPC message to a message queue + my : 2, // - declare and assign a local variable (lexical scoping) + 'new' :1, // + next :1, // - iterate a block prematurely + no :1, // - unimport some module symbols or semantics at compile time + oct :1, // - convert a string to an octal number + open :1, // - open a file, pipe, or descriptor + opendir :1, // - open a directory + ord :1, // - find a character's numeric representation + our : 2, // - declare and assign a package variable (lexical scoping) + pack :1, // - convert a list into a binary representation + 'package' :1, // - declare a separate global namespace + pipe :1, // - open a pair of connected filehandles + pop :1, // - remove the last element from an array and return it + pos :1, // - find or set the offset for the last/next m//g search + print :1, // - output a list to a filehandle + printf :1, // - output a formatted list to a filehandle + prototype :1, // - get the prototype (if any) of a subroutine + push :1, // - append one or more elements to an array + q :null, // - singly quote a string + qq :null, // - doubly quote a string + qr :null, // - Compile pattern + quotemeta :null, // - quote regular expression magic characters + qw :null, // - quote a list of words + qx :null, // - backquote quote a string + rand :1, // - retrieve the next pseudorandom number + read :1, // - fixed-length buffered input from a filehandle + readdir :1, // - get a directory from a directory handle + readline :1, // - fetch a record from a file + readlink :1, // - determine where a symbolic link is pointing + readpipe :1, // - execute a system command and collect standard output + recv :1, // - receive a message over a Socket + redo :1, // - start this loop iteration over again + ref :1, // - find out the type of thing being referenced + rename :1, // - change a filename + require :1, // - load in external functions from a library at runtime + reset :1, // - clear all variables of a given name + 'return' :1, // - get out of a function early + reverse :1, // - flip a string or a list + rewinddir :1, // - reset directory handle + rindex :1, // - right-to-left substring search + rmdir :1, // - remove a directory + s :null, // - replace a pattern with a string + say :1, // - print with newline + scalar :1, // - force a scalar context + seek :1, // - reposition file pointer for random-access I/O + seekdir :1, // - reposition directory pointer + select :1, // - reset default output or do I/O multiplexing + semctl :1, // - SysV semaphore control operations + semget :1, // - get set of SysV semaphores + semop :1, // - SysV semaphore operations + send :1, // - send a message over a socket + setgrent :1, // - prepare group file for use + sethostent :1, // - prepare hosts file for use + setnetent :1, // - prepare networks file for use + setpgrp :1, // - set the process group of a process + setpriority :1, // - set a process's nice value + setprotoent :1, // - prepare protocols file for use + setpwent :1, // - prepare passwd file for use + setservent :1, // - prepare services file for use + setsockopt :1, // - set some socket options + shift :1, // - remove the first element of an array, and return it + shmctl :1, // - SysV shared memory operations + shmget :1, // - get SysV shared memory segment identifier + shmread :1, // - read SysV shared memory + shmwrite :1, // - write SysV shared memory + shutdown :1, // - close down just half of a socket connection + 'sin' :1, // - return the sine of a number + sleep :1, // - block for some number of seconds + socket :1, // - create a socket + socketpair :1, // - create a pair of sockets + 'sort' :1, // - sort a list of values + splice :1, // - add or remove elements anywhere in an array + 'split' :1, // - split up a string using a regexp delimiter + sprintf :1, // - formatted print into a string + 'sqrt' :1, // - square root function + srand :1, // - seed the random number generator + stat :1, // - get a file's status information + state :1, // - declare and assign a state variable (persistent lexical scoping) + study :1, // - optimize input data for repeated searches + 'sub' :1, // - declare a subroutine, possibly anonymously + 'substr' :1, // - get or alter a portion of a stirng + symlink :1, // - create a symbolic link to a file + syscall :1, // - execute an arbitrary system call + sysopen :1, // - open a file, pipe, or descriptor + sysread :1, // - fixed-length unbuffered input from a filehandle + sysseek :1, // - position I/O pointer on handle used with sysread and syswrite + system :1, // - run a separate program + syswrite :1, // - fixed-length unbuffered output to a filehandle + tell :1, // - get current seekpointer on a filehandle + telldir :1, // - get current seekpointer on a directory handle + tie :1, // - bind a variable to an object class + tied :1, // - get a reference to the object underlying a tied variable + time :1, // - return number of seconds since 1970 + times :1, // - return elapsed time for self and child processes + tr :null, // - transliterate a string + truncate :1, // - shorten a file + uc :1, // - return upper-case version of a string + ucfirst :1, // - return a string with just the next letter in upper case + umask :1, // - set file creation mode mask + undef :1, // - remove a variable or function definition + unlink :1, // - remove one link to a file + unpack :1, // - convert binary structure into normal perl variables + unshift :1, // - prepend more elements to the beginning of a list + untie :1, // - break a tie binding to a variable + use :1, // - load in a module at compile time + utime :1, // - set a file's last access and modify times + values :1, // - return a list of the values in a hash + vec :1, // - test or set particular bits in a string + wait :1, // - wait for any child process to die + waitpid :1, // - wait for a particular child process to die + wantarray :1, // - get void vs scalar vs list context of current subroutine call + warn :1, // - print debugging info + when :1, // + write :1, // - print a picture record + y :null}; // - transliterate a string + + var RXstyle="string-2"; + var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type + + function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;) + state.chain=null; // 12 3tail + state.style=null; + state.tail=null; + state.tokenize=function(stream,state){ + var e=false,c,i=0; + while(c=stream.next()){ + if(c===chain[i]&&!e){ + if(chain[++i]!==undefined){ + state.chain=chain[i]; + state.style=style; + state.tail=tail;} + else if(tail) + stream.eatWhile(tail); + state.tokenize=tokenPerl; + return style;} + e=!e&&c=="\\";} + return style;}; + return state.tokenize(stream,state);} + + function tokenSOMETHING(stream,state,string){ + state.tokenize=function(stream,state){ + if(stream.string==string) + state.tokenize=tokenPerl; + stream.skipToEnd(); + return "string";}; + return state.tokenize(stream,state);} + + function tokenPerl(stream,state){ + if(stream.eatSpace()) + return null; + if(state.chain) + return tokenChain(stream,state,state.chain,state.style,state.tail); + if(stream.match(/^\-?[\d\.]/,false)) + if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/)) + return 'number'; + if(stream.match(/^<<(?=\w)/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n + stream.eatWhile(/\w/); + return tokenSOMETHING(stream,state,stream.current().substr(2));} + if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n + return tokenSOMETHING(stream,state,'=cut');} + var ch=stream.next(); + if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n + if(prefix(stream, 3)=="<<"+ch){ + var p=stream.pos; + stream.eatWhile(/\w/); + var n=stream.current().substr(1); + if(n&&stream.eat(ch)) + return tokenSOMETHING(stream,state,n); + stream.pos=p;} + return tokenChain(stream,state,[ch],"string");} + if(ch=="q"){ + var c=look(stream, -2); + if(!(c&&/\w/.test(c))){ + c=look(stream, 0); + if(c=="x"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(c=="q"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],"string");}} + else if(c=="w"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],"bracket");} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],"bracket");} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],"bracket");} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],"bracket");} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],"bracket");}} + else if(c=="r"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(/[\^'"!~\/(\[{<]/.test(c)){ + if(c=="("){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + eatSuffix(stream, 1); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ + eatSuffix(stream, 1); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[stream.eat(c)],"string");}}}} + if(ch=="m"){ + var c=look(stream, -2); + if(!(c&&/\w/.test(c))){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[c],RXstyle,RXmodifiers);} + if(c=="("){ + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}} + if(ch=="s"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="y"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="t"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat("r");if(c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}} + if(ch=="`"){ + return tokenChain(stream,state,[ch],"variable-2");} + if(ch=="/"){ + if(!/~\s*$/.test(prefix(stream))) + return "operator"; + else + return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);} + if(ch=="$"){ + var p=stream.pos; + if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}")) + return "variable-2"; + else + stream.pos=p;} + if(/[$@%]/.test(ch)){ + var p=stream.pos; + if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(look(stream, -2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){ + var c=stream.current(); + if(PERL[c]) + return "variable-2";} + stream.pos=p;} + if(/[$@%&]/.test(ch)){ + if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){ + var c=stream.current(); + if(PERL[c]) + return "variable-2"; + else + return "variable";}} + if(ch=="#"){ + if(look(stream, -2)!="$"){ + stream.skipToEnd(); + return "comment";}} + if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){ + var p=stream.pos; + stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/); + if(PERL[stream.current()]) + return "operator"; + else + stream.pos=p;} + if(ch=="_"){ + if(stream.pos==1){ + if(suffix(stream, 6)=="_END__"){ + return tokenChain(stream,state,['\0'],"comment");} + else if(suffix(stream, 7)=="_DATA__"){ + return tokenChain(stream,state,['\0'],"variable-2");} + else if(suffix(stream, 7)=="_C__"){ + return tokenChain(stream,state,['\0'],"string");}}} + if(/\w/.test(ch)){ + var p=stream.pos; + if(look(stream, -2)=="{"&&(look(stream, 0)=="}"||stream.eatWhile(/\w/)&&look(stream, 0)=="}")) + return "string"; + else + stream.pos=p;} + if(/[A-Z]/.test(ch)){ + var l=look(stream, -2); + var p=stream.pos; + stream.eatWhile(/[A-Z_]/); + if(/[\da-z]/.test(look(stream, 0))){ + stream.pos=p;} + else{ + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";}} + if(/[a-zA-Z_]/.test(ch)){ + var l=look(stream, -2); + stream.eatWhile(/\w/); + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";} + return null;} + + return { + startState: function() { + return { + tokenize: tokenPerl, + chain: null, + style: null, + tail: null + }; + }, + token: function(stream, state) { + return (state.tokenize || tokenPerl)(stream, state); + }, + lineComment: '#' + }; +}); + +CodeMirror.registerHelper("wordChars", "perl", /[\w$]/); + +CodeMirror.defineMIME("text/x-perl", "perl"); + +// it's like "peek", but need for look-ahead or look-behind if index < 0 +function look(stream, c){ + return stream.string.charAt(stream.pos+(c||0)); +} + +// return a part of prefix of current stream from current position +function prefix(stream, c){ + if(c){ + var x=stream.pos-c; + return stream.string.substr((x>=0?x:0),c);} + else{ + return stream.string.substr(0,stream.pos-1); + } +} + +// return a part of suffix of current stream from current position +function suffix(stream, c){ + var y=stream.string.length; + var x=y-stream.pos+1; + return stream.string.substr(stream.pos,(c&&c<y?c:x)); +} + +// eating and vomiting a part of stream from current position +function eatSuffix(stream, c){ + var x=stream.pos+c; + var y; + if(x<=0) + stream.pos=0; + else if(x>=(y=stream.string.length-1)) + stream.pos=y; + else + stream.pos=x; +} + +}); diff --git a/rhodecode/public/js/mode/php/php.js b/rhodecode/public/js/mode/php/php.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/php/php.js @@ -0,0 +1,230 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // Helper for phpString + function matchSequence(list, end, escapes) { + if (list.length == 0) return phpString(end); + return function (stream, state) { + var patterns = list[0]; + for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) { + state.tokenize = matchSequence(list.slice(1), end); + return patterns[i][1]; + } + state.tokenize = phpString(end, escapes); + return "string"; + }; + } + function phpString(closing, escapes) { + return function(stream, state) { return phpString_(stream, state, closing, escapes); }; + } + function phpString_(stream, state, closing, escapes) { + // "Complex" syntax + if (escapes !== false && stream.match("${", false) || stream.match("{$", false)) { + state.tokenize = null; + return "string"; + } + + // Simple syntax + if (escapes !== false && stream.match(/^\$[a-zA-Z_][a-zA-Z0-9_]*/)) { + // After the variable name there may appear array or object operator. + if (stream.match("[", false)) { + // Match array operator + state.tokenize = matchSequence([ + [["[", null]], + [[/\d[\w\.]*/, "number"], + [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"], + [/[\w\$]+/, "variable"]], + [["]", null]] + ], closing, escapes); + } + if (stream.match(/\-\>\w/, false)) { + // Match object operator + state.tokenize = matchSequence([ + [["->", null]], + [[/[\w]+/, "variable"]] + ], closing, escapes); + } + return "variable-2"; + } + + var escaped = false; + // Normal string + while (!stream.eol() && + (escaped || escapes === false || + (!stream.match("{$", false) && + !stream.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false)))) { + if (!escaped && stream.match(closing)) { + state.tokenize = null; + state.tokStack.pop(); state.tokStack.pop(); + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + var phpKeywords = "abstract and array as break case catch class clone const continue declare default " + + "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " + + "for foreach function global goto if implements interface instanceof namespace " + + "new or private protected public static switch throw trait try use var while xor " + + "die echo empty exit eval include include_once isset list require require_once return " + + "print unset __halt_compiler self static parent yield insteadof finally"; + var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"; + var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"; + CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" ")); + CodeMirror.registerHelper("wordChars", "php", /[\w$]/); + + var phpConfig = { + name: "clike", + helperType: "php", + keywords: keywords(phpKeywords), + blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"), + defKeywords: keywords("class function interface namespace trait"), + atoms: keywords(phpAtoms), + builtin: keywords(phpBuiltin), + multiLineStrings: true, + hooks: { + "$": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "variable-2"; + }, + "<": function(stream, state) { + if (stream.match(/<</)) { + var nowDoc = stream.eat("'"); + stream.eatWhile(/[\w\.]/); + var delim = stream.current().slice(3 + (nowDoc ? 1 : 0)); + if (nowDoc) stream.eat("'"); + if (delim) { + (state.tokStack || (state.tokStack = [])).push(delim, 0); + state.tokenize = phpString(delim, nowDoc ? false : true); + return "string"; + } + } + return false; + }, + "#": function(stream) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + }, + "/": function(stream) { + if (stream.eat("/")) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + } + return false; + }, + '"': function(_stream, state) { + (state.tokStack || (state.tokStack = [])).push('"', 0); + state.tokenize = phpString('"'); + return "string"; + }, + "{": function(_stream, state) { + if (state.tokStack && state.tokStack.length) + state.tokStack[state.tokStack.length - 1]++; + return false; + }, + "}": function(_stream, state) { + if (state.tokStack && state.tokStack.length > 0 && + !--state.tokStack[state.tokStack.length - 1]) { + state.tokenize = phpString(state.tokStack[state.tokStack.length - 2]); + } + return false; + } + } + }; + + CodeMirror.defineMode("php", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, "text/html"); + var phpMode = CodeMirror.getMode(config, phpConfig); + + function dispatch(stream, state) { + var isPHP = state.curMode == phpMode; + if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null; + if (!isPHP) { + if (stream.match(/^<\?\w*/)) { + state.curMode = phpMode; + state.curState = state.php; + return "meta"; + } + if (state.pending == '"' || state.pending == "'") { + while (!stream.eol() && stream.next() != state.pending) {} + var style = "string"; + } else if (state.pending && stream.pos < state.pending.end) { + stream.pos = state.pending.end; + var style = state.pending.style; + } else { + var style = htmlMode.token(stream, state.curState); + } + if (state.pending) state.pending = null; + var cur = stream.current(), openPHP = cur.search(/<\?/), m; + if (openPHP != -1) { + if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0]; + else state.pending = {end: stream.pos, style: style}; + stream.backUp(cur.length - openPHP); + } + return style; + } else if (isPHP && state.php.tokenize == null && stream.match("?>")) { + state.curMode = htmlMode; + state.curState = state.html; + return "meta"; + } else { + return phpMode.token(stream, state.curState); + } + } + + return { + startState: function() { + var html = CodeMirror.startState(htmlMode), php = CodeMirror.startState(phpMode); + return {html: html, + php: php, + curMode: parserConfig.startOpen ? phpMode : htmlMode, + curState: parserConfig.startOpen ? php : html, + pending: null}; + }, + + copyState: function(state) { + var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html), + php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur; + if (state.curMode == htmlMode) cur = htmlNew; + else cur = phpNew; + return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, + pending: state.pending}; + }, + + token: dispatch, + + indent: function(state, textAfter) { + if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) || + (state.curMode == phpMode && /^\?>/.test(textAfter))) + return htmlMode.indent(state.html, textAfter); + return state.curMode.indent(state.curState, textAfter); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + + innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } + }; + }, "htmlmixed", "clike"); + + CodeMirror.defineMIME("application/x-httpd-php", "php"); + CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true}); + CodeMirror.defineMIME("text/x-php", phpConfig); +}); diff --git a/rhodecode/public/js/mode/pig/pig.js b/rhodecode/public/js/mode/pig/pig.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/pig/pig.js @@ -0,0 +1,178 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + * Pig Latin Mode for CodeMirror 2 + * @author Prasanth Jayachandran + * @link https://github.com/prasanthj/pig-codemirror-2 + * This implementation is adapted from PL/SQL mode in CodeMirror 2. + */ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pig", function(_config, parserConfig) { + var keywords = parserConfig.keywords, + builtins = parserConfig.builtins, + types = parserConfig.types, + multiLineStrings = parserConfig.multiLineStrings; + + var isOperatorChar = /[*+\-%<>=&?:\/!|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function tokenComment(stream, state) { + var isEnd = false; + var ch; + while(ch = stream.next()) { + if(ch == "/" && isEnd) { + state.tokenize = tokenBase; + break; + } + isEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return "error"; + }; + } + + + function tokenBase(stream, state) { + var ch = stream.next(); + + // is a start of string? + if (ch == '"' || ch == "'") + return chain(stream, state, tokenString(ch)); + // is it one of the special chars + else if(/[\[\]{}\(\),;\.]/.test(ch)) + return null; + // is it a number? + else if(/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + // multi line comment or operator + else if (ch == "/") { + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else { + stream.eatWhile(isOperatorChar); + return "operator"; + } + } + // single line comment or operator + else if (ch=="-") { + if(stream.eat("-")){ + stream.skipToEnd(); + return "comment"; + } + else { + stream.eatWhile(isOperatorChar); + return "operator"; + } + } + // is it an operator + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + // get the while word + stream.eatWhile(/[\w\$_]/); + // is it one of the listed keywords? + if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { + //keywords can be used as variables like flatten(group), group.$0 etc.. + if (!stream.eat(")") && !stream.eat(".")) + return "keyword"; + } + // is it one of the builtin functions? + if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) + return "variable-2"; + // is it one of the listed types? + if (types && types.propertyIsEnumerable(stream.current().toUpperCase())) + return "variable-3"; + // default is a 'variable' + return "variable"; + } + } + + // Interface + return { + startState: function() { + return { + tokenize: tokenBase, + startOfLine: true + }; + }, + + token: function(stream, state) { + if(stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + } + }; +}); + +(function() { + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // builtin funcs taken from trunk revision 1303237 + var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " + + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS " + + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG " + + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN " + + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER " + + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS " + + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA " + + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE " + + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG " + + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER "; + + // taken from QueryLexer.g + var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " + + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " + + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " + + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " + + "NEQ MATCHES TRUE FALSE DUMP"; + + // data types + var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "; + + CodeMirror.defineMIME("text/x-pig", { + name: "pig", + builtins: keywords(pBuiltins), + keywords: keywords(pKeywords), + types: keywords(pTypes) + }); + + CodeMirror.registerHelper("hintWords", "pig", (pBuiltins + pTypes + pKeywords).split(" ")); +}()); + +}); diff --git a/rhodecode/public/js/mode/properties/properties.js b/rhodecode/public/js/mode/properties/properties.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/properties/properties.js @@ -0,0 +1,78 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("properties", function() { + return { + token: function(stream, state) { + var sol = stream.sol() || state.afterSection; + var eol = stream.eol(); + + state.afterSection = false; + + if (sol) { + if (state.nextMultiline) { + state.inMultiline = true; + state.nextMultiline = false; + } else { + state.position = "def"; + } + } + + if (eol && ! state.nextMultiline) { + state.inMultiline = false; + state.position = "def"; + } + + if (sol) { + while(stream.eatSpace()); + } + + var ch = stream.next(); + + if (sol && (ch === "#" || ch === "!" || ch === ";")) { + state.position = "comment"; + stream.skipToEnd(); + return "comment"; + } else if (sol && ch === "[") { + state.afterSection = true; + stream.skipTo("]"); stream.eat("]"); + return "header"; + } else if (ch === "=" || ch === ":") { + state.position = "quote"; + return null; + } else if (ch === "\\" && state.position === "quote") { + if (stream.eol()) { // end of line? + // Multiline value + state.nextMultiline = true; + } + } + + return state.position; + }, + + startState: function() { + return { + position : "def", // Current position, "def", "quote" or "comment" + nextMultiline : false, // Is the next line multiline value + inMultiline : false, // Is the current line a multiline value + afterSection : false // Did we just open a section + }; + } + + }; +}); + +CodeMirror.defineMIME("text/x-properties", "properties"); +CodeMirror.defineMIME("text/x-ini", "properties"); + +}); diff --git a/rhodecode/public/js/mode/puppet/puppet.js b/rhodecode/public/js/mode/puppet/puppet.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/puppet/puppet.js @@ -0,0 +1,220 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("puppet", function () { + // Stores the words from the define method + var words = {}; + // Taken, mostly, from the Puppet official variable standards regex + var variable_regex = /({)?([a-z][a-z0-9_]*)?((::[a-z][a-z0-9_]*)*::)?[a-zA-Z0-9_]+(})?/; + + // Takes a string of words separated by spaces and adds them as + // keys with the value of the first argument 'style' + function define(style, string) { + var split = string.split(' '); + for (var i = 0; i < split.length; i++) { + words[split[i]] = style; + } + } + + // Takes commonly known puppet types/words and classifies them to a style + define('keyword', 'class define site node include import inherits'); + define('keyword', 'case if else in and elsif default or'); + define('atom', 'false true running present absent file directory undef'); + define('builtin', 'action augeas burst chain computer cron destination dport exec ' + + 'file filebucket group host icmp iniface interface jump k5login limit log_level ' + + 'log_prefix macauthorization mailalias maillist mcx mount nagios_command ' + + 'nagios_contact nagios_contactgroup nagios_host nagios_hostdependency ' + + 'nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service ' + + 'nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo ' + + 'nagios_servicegroup nagios_timeperiod name notify outiface package proto reject ' + + 'resources router schedule scheduled_task selboolean selmodule service source ' + + 'sport ssh_authorized_key sshkey stage state table tidy todest toports tosource ' + + 'user vlan yumrepo zfs zone zpool'); + + // After finding a start of a string ('|") this function attempts to find the end; + // If a variable is encountered along the way, we display it differently when it + // is encapsulated in a double-quoted string. + function tokenString(stream, state) { + var current, prev, found_var = false; + while (!stream.eol() && (current = stream.next()) != state.pending) { + if (current === '$' && prev != '\\' && state.pending == '"') { + found_var = true; + break; + } + prev = current; + } + if (found_var) { + stream.backUp(1); + } + if (current == state.pending) { + state.continueString = false; + } else { + state.continueString = true; + } + return "string"; + } + + // Main function + function tokenize(stream, state) { + // Matches one whole word + var word = stream.match(/[\w]+/, false); + // Matches attributes (i.e. ensure => present ; 'ensure' would be matched) + var attribute = stream.match(/(\s+)?\w+\s+=>.*/, false); + // Matches non-builtin resource declarations + // (i.e. "apache::vhost {" or "mycustomclasss {" would be matched) + var resource = stream.match(/(\s+)?[\w:_]+(\s+)?{/, false); + // Matches virtual and exported resources (i.e. @@user { ; and the like) + var special_resource = stream.match(/(\s+)?[@]{1,2}[\w:_]+(\s+)?{/, false); + + // Finally advance the stream + var ch = stream.next(); + + // Have we found a variable? + if (ch === '$') { + if (stream.match(variable_regex)) { + // If so, and its in a string, assign it a different color + return state.continueString ? 'variable-2' : 'variable'; + } + // Otherwise return an invalid variable + return "error"; + } + // Should we still be looking for the end of a string? + if (state.continueString) { + // If so, go through the loop again + stream.backUp(1); + return tokenString(stream, state); + } + // Are we in a definition (class, node, define)? + if (state.inDefinition) { + // If so, return def (i.e. for 'class myclass {' ; 'myclass' would be matched) + if (stream.match(/(\s+)?[\w:_]+(\s+)?/)) { + return 'def'; + } + // Match the rest it the next time around + stream.match(/\s+{/); + state.inDefinition = false; + } + // Are we in an 'include' statement? + if (state.inInclude) { + // Match and return the included class + stream.match(/(\s+)?\S+(\s+)?/); + state.inInclude = false; + return 'def'; + } + // Do we just have a function on our hands? + // In 'ensure_resource("myclass")', 'ensure_resource' is matched + if (stream.match(/(\s+)?\w+\(/)) { + stream.backUp(1); + return 'def'; + } + // Have we matched the prior attribute regex? + if (attribute) { + stream.match(/(\s+)?\w+/); + return 'tag'; + } + // Do we have Puppet specific words? + if (word && words.hasOwnProperty(word)) { + // Negates the initial next() + stream.backUp(1); + // Acutally move the stream + stream.match(/[\w]+/); + // We want to process these words differently + // do to the importance they have in Puppet + if (stream.match(/\s+\S+\s+{/, false)) { + state.inDefinition = true; + } + if (word == 'include') { + state.inInclude = true; + } + // Returns their value as state in the prior define methods + return words[word]; + } + // Is there a match on a reference? + if (/(^|\s+)[A-Z][\w:_]+/.test(word)) { + // Negate the next() + stream.backUp(1); + // Match the full reference + stream.match(/(^|\s+)[A-Z][\w:_]+/); + return 'def'; + } + // Have we matched the prior resource regex? + if (resource) { + stream.match(/(\s+)?[\w:_]+/); + return 'def'; + } + // Have we matched the prior special_resource regex? + if (special_resource) { + stream.match(/(\s+)?[@]{1,2}/); + return 'special'; + } + // Match all the comments. All of them. + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + // Have we found a string? + if (ch == "'" || ch == '"') { + // Store the type (single or double) + state.pending = ch; + // Perform the looping function to find the end + return tokenString(stream, state); + } + // Match all the brackets + if (ch == '{' || ch == '}') { + return 'bracket'; + } + // Match characters that we are going to assume + // are trying to be regex + if (ch == '/') { + stream.match(/.*?\//); + return 'variable-3'; + } + // Match all the numbers + if (ch.match(/[0-9]/)) { + stream.eatWhile(/[0-9]+/); + return 'number'; + } + // Match the '=' and '=>' operators + if (ch == '=') { + if (stream.peek() == '>') { + stream.next(); + } + return "operator"; + } + // Keep advancing through all the rest + stream.eatWhile(/[\w-]/); + // Return a blank line for everything else + return null; + } + // Start it all + return { + startState: function () { + var state = {}; + state.inDefinition = false; + state.inInclude = false; + state.continueString = false; + state.pending = false; + return state; + }, + token: function (stream, state) { + // Strip the spaces, but regex will account for them eitherway + if (stream.eatSpace()) return null; + // Go through the main process + return tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME("text/x-puppet", "puppet"); + +}); diff --git a/rhodecode/public/js/mode/python/python.js b/rhodecode/public/js/mode/python/python.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/python/python.js @@ -0,0 +1,358 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var wordOperators = wordRegexp(["and", "or", "not", "is"]); + var commonKeywords = ["as", "assert", "break", "class", "continue", + "def", "del", "elif", "else", "except", "finally", + "for", "from", "global", "if", "import", + "lambda", "pass", "raise", "return", + "try", "while", "with", "yield", "in"]; + var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", + "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod", + "enumerate", "eval", "filter", "float", "format", "frozenset", + "getattr", "globals", "hasattr", "hash", "help", "hex", "id", + "input", "int", "isinstance", "issubclass", "iter", "len", + "list", "locals", "map", "max", "memoryview", "min", "next", + "object", "oct", "open", "ord", "pow", "property", "range", + "repr", "reversed", "round", "set", "setattr", "slice", + "sorted", "staticmethod", "str", "sum", "super", "tuple", + "type", "vars", "zip", "__import__", "NotImplemented", + "Ellipsis", "__debug__"]; + var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile", + "file", "intern", "long", "raw_input", "reduce", "reload", + "unichr", "unicode", "xrange", "False", "True", "None"], + keywords: ["exec", "print"]}; + var py3 = {builtins: ["ascii", "bytes", "exec", "print"], + keywords: ["nonlocal", "False", "True", "None", "async", "await"]}; + + CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins)); + + function top(state) { + return state.scopes[state.scopes.length - 1]; + } + + CodeMirror.defineMode("python", function(conf, parserConf) { + var ERRORCLASS = "error"; + + var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"); + var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); + var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); + + if (parserConf.version && parseInt(parserConf.version, 10) == 3){ + // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]"); + var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*"); + } else { + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"); + var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + } + + var hangingIndent = parserConf.hangingIndent || conf.indentUnit; + + var myKeywords = commonKeywords, myBuiltins = commonBuiltins; + if(parserConf.extra_keywords != undefined){ + myKeywords = myKeywords.concat(parserConf.extra_keywords); + } + if(parserConf.extra_builtins != undefined){ + myBuiltins = myBuiltins.concat(parserConf.extra_builtins); + } + if (parserConf.version && parseInt(parserConf.version, 10) == 3) { + myKeywords = myKeywords.concat(py3.keywords); + myBuiltins = myBuiltins.concat(py3.builtins); + var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i"); + } else { + myKeywords = myKeywords.concat(py2.keywords); + myBuiltins = myBuiltins.concat(py2.builtins); + var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i"); + } + var keywords = wordRegexp(myKeywords); + var builtins = wordRegexp(myBuiltins); + + // tokenizers + function tokenBase(stream, state) { + // Handle scope changes + if (stream.sol() && top(state).type == "py") { + var scopeOffset = top(state).offset; + if (stream.eatSpace()) { + var lineOffset = stream.indentation(); + if (lineOffset > scopeOffset) + pushScope(stream, state, "py"); + else if (lineOffset < scopeOffset && dedent(stream, state)) + state.errorToken = true; + return null; + } else { + var style = tokenBaseInner(stream, state); + if (scopeOffset > 0 && dedent(stream, state)) + style += " " + ERRORCLASS; + return style; + } + } + return tokenBaseInner(stream, state); + } + + function tokenBaseInner(stream, state) { + if (stream.eatSpace()) return null; + + var ch = stream.peek(); + + // Handle Comments + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + if (stream.match(/^\.\d+/)) { floatLiteral = true; } + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return "number"; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true; + // Binary + if (stream.match(/^0b[01]+/i)) intLiteral = true; + // Octal + if (stream.match(/^0o[0-7]+/i)) intLiteral = true; + // Decimal + if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^0(?![\dx])/i)) intLiteral = true; + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return "number"; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) + return null; + + if (stream.match(doubleOperators) || stream.match(singleOperators)) + return "operator"; + + if (stream.match(singleDelimiters)) + return null; + + if (stream.match(keywords) || stream.match(wordOperators)) + return "keyword"; + + if (stream.match(builtins)) + return "builtin"; + + if (stream.match(/^(self|cls)\b/)) + return "variable-2"; + + if (stream.match(identifiers)) { + if (state.lastToken == "def" || state.lastToken == "class") + return "def"; + return "variable"; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0) + delimiter = delimiter.substr(1); + + var singleline = delimiter.length == 1; + var OUTCLASS = "string"; + + function tokenString(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\\]/); + if (stream.eat("\\")) { + stream.next(); + if (singleline && stream.eol()) + return OUTCLASS; + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) + return ERRORCLASS; + else + state.tokenize = tokenBase; + } + return OUTCLASS; + } + tokenString.isString = true; + return tokenString; + } + + function pushScope(stream, state, type) { + var offset = 0, align = null; + if (type == "py") { + while (top(state).type != "py") + state.scopes.pop(); + } + offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent); + if (type != "py" && !stream.match(/^(\s|#.*)*$/, false)) + align = stream.column() + 1; + state.scopes.push({offset: offset, type: type, align: align}); + } + + function dedent(stream, state) { + var indented = stream.indentation(); + while (top(state).offset > indented) { + if (top(state).type != "py") return true; + state.scopes.pop(); + } + return top(state).offset != indented; + } + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current == ".") { + style = stream.match(identifiers, false) ? null : ERRORCLASS; + if (style == null && state.lastStyle == "meta") { + // Apply 'meta' style to '.' connected identifiers when + // appropriate. + style = "meta"; + } + return style; + } + + // Handle decorators + if (current == "@"){ + if(parserConf.version && parseInt(parserConf.version, 10) == 3){ + return stream.match(identifiers, false) ? "meta" : "operator"; + } else { + return stream.match(identifiers, false) ? "meta" : ERRORCLASS; + } + } + + if ((style == "variable" || style == "builtin") + && state.lastStyle == "meta") + style = "meta"; + + // Handle scope changes. + if (current == "pass" || current == "return") + state.dedent += 1; + + if (current == "lambda") state.lambda = true; + if (current == ":" && !state.lambda && top(state).type == "py") + pushScope(stream, state, "py"); + + var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; + if (delimiter_index != -1) + pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1)); + + delimiter_index = "])}".indexOf(current); + if (delimiter_index != -1) { + if (top(state).type == current) state.scopes.pop(); + else return ERRORCLASS; + } + if (state.dedent > 0 && stream.eol() && top(state).type == "py") { + if (state.scopes.length > 1) state.scopes.pop(); + state.dedent -= 1; + } + + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scopes: [{offset: basecolumn || 0, type: "py", align: null}], + lastStyle: null, + lastToken: null, + lambda: false, + dedent: 0 + }; + }, + + token: function(stream, state) { + var addErr = state.errorToken; + if (addErr) state.errorToken = false; + var style = tokenLexer(stream, state); + + state.lastStyle = style; + + var current = stream.current(); + if (current && style) + state.lastToken = current; + + if (stream.eol() && state.lambda) + state.lambda = false; + return addErr ? style + " " + ERRORCLASS : style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) + return state.tokenize.isString ? CodeMirror.Pass : 0; + + var scope = top(state); + var closing = textAfter && textAfter.charAt(0) == scope.type; + if (scope.align != null) + return scope.align - (closing ? 1 : 0); + else if (closing && state.scopes.length > 1) + return state.scopes[state.scopes.length - 2].offset; + else + return scope.offset; + }, + + closeBrackets: {triples: "'\""}, + lineComment: "#", + fold: "indent" + }; + return external; + }); + + CodeMirror.defineMIME("text/x-python", "python"); + + var words = function(str) { return str.split(" "); }; + + CodeMirror.defineMIME("text/x-cython", { + name: "python", + extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ + "extern gil include nogil property public"+ + "readonly struct union DEF IF ELIF ELSE") + }); + +}); diff --git a/rhodecode/public/js/mode/q/q.js b/rhodecode/public/js/mode/q/q.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/q/q.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("q",function(config){ + var indentUnit=config.indentUnit, + curPunc, + keywords=buildRE(["abs","acos","aj","aj0","all","and","any","asc","asin","asof","atan","attr","avg","avgs","bin","by","ceiling","cols","cor","cos","count","cov","cross","csv","cut","delete","deltas","desc","dev","differ","distinct","div","do","each","ej","enlist","eval","except","exec","exit","exp","fby","fills","first","fkeys","flip","floor","from","get","getenv","group","gtime","hclose","hcount","hdel","hopen","hsym","iasc","idesc","if","ij","in","insert","inter","inv","key","keys","last","like","list","lj","load","log","lower","lsq","ltime","ltrim","mavg","max","maxs","mcount","md5","mdev","med","meta","min","mins","mmax","mmin","mmu","mod","msum","neg","next","not","null","or","over","parse","peach","pj","plist","prd","prds","prev","prior","rand","rank","ratios","raze","read0","read1","reciprocal","reverse","rload","rotate","rsave","rtrim","save","scan","select","set","setenv","show","signum","sin","sqrt","ss","ssr","string","sublist","sum","sums","sv","system","tables","tan","til","trim","txf","type","uj","ungroup","union","update","upper","upsert","value","var","view","views","vs","wavg","where","where","while","within","wj","wj1","wsum","xasc","xbar","xcol","xcols","xdesc","xexp","xgroup","xkey","xlog","xprev","xrank"]), + E=/[|/&^!+:\\\-*%$=~#;@><,?_\'\"\[\(\]\)\s{}]/; + function buildRE(w){return new RegExp("^("+w.join("|")+")$");} + function tokenBase(stream,state){ + var sol=stream.sol(),c=stream.next(); + curPunc=null; + if(sol) + if(c=="/") + return(state.tokenize=tokenLineComment)(stream,state); + else if(c=="\\"){ + if(stream.eol()||/\s/.test(stream.peek())) + return stream.skipToEnd(),/^\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream, state):state.tokenize=tokenBase,"comment"; + else + return state.tokenize=tokenBase,"builtin"; + } + if(/\s/.test(c)) + return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace"; + if(c=='"') + return(state.tokenize=tokenString)(stream,state); + if(c=='`') + return stream.eatWhile(/[A-Z|a-z|\d|_|:|\/|\.]/),"symbol"; + if(("."==c&&/\d/.test(stream.peek()))||/\d/.test(c)){ + var t=null; + stream.backUp(1); + if(stream.match(/^\d{4}\.\d{2}(m|\.\d{2}([D|T](\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)?)?)/) + || stream.match(/^\d+D(\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)/) + || stream.match(/^\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?/) + || stream.match(/^\d+[ptuv]{1}/)) + t="temporal"; + else if(stream.match(/^0[NwW]{1}/) + || stream.match(/^0x[\d|a-f|A-F]*/) + || stream.match(/^[0|1]+[b]{1}/) + || stream.match(/^\d+[chijn]{1}/) + || stream.match(/-?\d*(\.\d*)?(e[+\-]?\d+)?(e|f)?/)) + t="number"; + return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),"error"); + } + if(/[A-Z|a-z]|\./.test(c)) + return stream.eatWhile(/[A-Z|a-z|\.|_|\d]/),keywords.test(stream.current())?"keyword":"variable"; + if(/[|/&^!+:\\\-*%$=~#;@><\.,?_\']/.test(c)) + return null; + if(/[{}\(\[\]\)]/.test(c)) + return null; + return"error"; + } + function tokenLineComment(stream,state){ + return stream.skipToEnd(),/\/\s*$/.test(stream.current())?(state.tokenize=tokenBlockComment)(stream,state):(state.tokenize=tokenBase),"comment"; + } + function tokenBlockComment(stream,state){ + var f=stream.sol()&&stream.peek()=="\\"; + stream.skipToEnd(); + if(f&&/^\\\s*$/.test(stream.current())) + state.tokenize=tokenBase; + return"comment"; + } + function tokenCommentToEOF(stream){return stream.skipToEnd(),"comment";} + function tokenString(stream,state){ + var escaped=false,next,end=false; + while((next=stream.next())){ + if(next=="\""&&!escaped){end=true;break;} + escaped=!escaped&&next=="\\"; + } + if(end)state.tokenize=tokenBase; + return"string"; + } + function pushContext(state,type,col){state.context={prev:state.context,indent:state.indent,col:col,type:type};} + function popContext(state){state.indent=state.context.indent;state.context=state.context.prev;} + return{ + startState:function(){ + return{tokenize:tokenBase, + context:null, + indent:0, + col:0}; + }, + token:function(stream,state){ + if(stream.sol()){ + if(state.context&&state.context.align==null) + state.context.align=false; + state.indent=stream.indentation(); + } + //if (stream.eatSpace()) return null; + var style=state.tokenize(stream,state); + if(style!="comment"&&state.context&&state.context.align==null&&state.context.type!="pattern"){ + state.context.align=true; + } + if(curPunc=="(")pushContext(state,")",stream.column()); + else if(curPunc=="[")pushContext(state,"]",stream.column()); + else if(curPunc=="{")pushContext(state,"}",stream.column()); + else if(/[\]\}\)]/.test(curPunc)){ + while(state.context&&state.context.type=="pattern")popContext(state); + if(state.context&&curPunc==state.context.type)popContext(state); + } + else if(curPunc=="."&&state.context&&state.context.type=="pattern")popContext(state); + else if(/atom|string|variable/.test(style)&&state.context){ + if(/[\}\]]/.test(state.context.type)) + pushContext(state,"pattern",stream.column()); + else if(state.context.type=="pattern"&&!state.context.align){ + state.context.align=true; + state.context.col=stream.column(); + } + } + return style; + }, + indent:function(state,textAfter){ + var firstChar=textAfter&&textAfter.charAt(0); + var context=state.context; + if(/[\]\}]/.test(firstChar)) + while (context&&context.type=="pattern")context=context.prev; + var closing=context&&firstChar==context.type; + if(!context) + return 0; + else if(context.type=="pattern") + return context.col; + else if(context.align) + return context.col+(closing?0:1); + else + return context.indent+(closing?0:indentUnit); + } + }; +}); +CodeMirror.defineMIME("text/x-q","q"); + +}); diff --git a/rhodecode/public/js/mode/r/r.js b/rhodecode/public/js/mode/r/r.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/r/r.js @@ -0,0 +1,162 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("r", function(config) { + function wordObj(str) { + var words = str.split(" "), res = {}; + for (var i = 0; i < words.length; ++i) res[words[i]] = true; + return res; + } + var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_"); + var builtins = wordObj("list quote bquote eval return call parse deparse"); + var keywords = wordObj("if else repeat while function for in next break"); + var blockkeywords = wordObj("if else repeat while function for"); + var opChars = /[+\-*\/^<>=!&|~$:]/; + var curPunc; + + function tokenBase(stream, state) { + curPunc = null; + var ch = stream.next(); + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "0" && stream.eat("x")) { + stream.eatWhile(/[\da-f]/i); + return "number"; + } else if (ch == "." && stream.eat(/\d/)) { + stream.match(/\d*(?:e[+\-]?\d+)?/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/\d*(?:\.\d+)?(?:e[+\-]\d+)?L?/); + return "number"; + } else if (ch == "'" || ch == '"') { + state.tokenize = tokenString(ch); + return "string"; + } else if (ch == "." && stream.match(/.[.\d]+/)) { + return "keyword"; + } else if (/[\w\.]/.test(ch) && ch != "_") { + stream.eatWhile(/[\w\.]/); + var word = stream.current(); + if (atoms.propertyIsEnumerable(word)) return "atom"; + if (keywords.propertyIsEnumerable(word)) { + // Block keywords start new blocks, except 'else if', which only starts + // one new block for the 'if', no block for the 'else'. + if (blockkeywords.propertyIsEnumerable(word) && + !stream.match(/\s*if(\s+|$)/, false)) + curPunc = "block"; + return "keyword"; + } + if (builtins.propertyIsEnumerable(word)) return "builtin"; + return "variable"; + } else if (ch == "%") { + if (stream.skipTo("%")) stream.next(); + return "variable-2"; + } else if (ch == "<" && stream.eat("-")) { + return "arrow"; + } else if (ch == "=" && state.ctx.argList) { + return "arg-is"; + } else if (opChars.test(ch)) { + if (ch == "$") return "dollar"; + stream.eatWhile(opChars); + return "operator"; + } else if (/[\(\){}\[\];]/.test(ch)) { + curPunc = ch; + if (ch == ";") return "semi"; + return null; + } else { + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + if (stream.eat("\\")) { + var ch = stream.next(); + if (ch == "x") stream.match(/^[a-f0-9]{2}/i); + else if ((ch == "u" || ch == "U") && stream.eat("{") && stream.skipTo("}")) stream.next(); + else if (ch == "u") stream.match(/^[a-f0-9]{4}/i); + else if (ch == "U") stream.match(/^[a-f0-9]{8}/i); + else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/); + return "string-2"; + } else { + var next; + while ((next = stream.next()) != null) { + if (next == quote) { state.tokenize = tokenBase; break; } + if (next == "\\") { stream.backUp(1); break; } + } + return "string"; + } + }; + } + + function push(state, type, stream) { + state.ctx = {type: type, + indent: state.indent, + align: null, + column: stream.column(), + prev: state.ctx}; + } + function pop(state) { + state.indent = state.ctx.indent; + state.ctx = state.ctx.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + ctx: {type: "top", + indent: -config.indentUnit, + align: false}, + indent: 0, + afterIdent: false}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.ctx.align == null) state.ctx.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (style != "comment" && state.ctx.align == null) state.ctx.align = true; + + var ctype = state.ctx.type; + if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state); + if (curPunc == "{") push(state, "}", stream); + else if (curPunc == "(") { + push(state, ")", stream); + if (state.afterIdent) state.ctx.argList = true; + } + else if (curPunc == "[") push(state, "]", stream); + else if (curPunc == "block") push(state, "block", stream); + else if (curPunc == ctype) pop(state); + state.afterIdent = style == "variable" || style == "keyword"; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx, + closing = firstChar == ctx.type; + if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indent + (closing ? 0 : config.indentUnit); + }, + + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/x-rsrc", "r"); + +}); diff --git a/rhodecode/public/js/mode/rpm/rpm.js b/rhodecode/public/js/mode/rpm/rpm.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/rpm/rpm.js @@ -0,0 +1,101 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("rpm-changes", function() { + var headerSeperator = /^-+$/; + var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /; + var simpleEmail = /^[\w+.-]+@[\w.-]+/; + + return { + token: function(stream) { + if (stream.sol()) { + if (stream.match(headerSeperator)) { return 'tag'; } + if (stream.match(headerLine)) { return 'tag'; } + } + if (stream.match(simpleEmail)) { return 'string'; } + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-changes", "rpm-changes"); + +// Quick and dirty spec file highlighting + +CodeMirror.defineMode("rpm-spec", function() { + var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/; + + var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/; + var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preinstall|preun|postinstall|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/; + var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros + var control_flow_simple = /^%(else|endif)/; // rpm control flow macros + var operators = /^(\!|\?|\<\=|\<|\>\=|\>|\=\=|\&\&|\|\|)/; // operators in control flow macros + + return { + startState: function () { + return { + controlFlow: false, + macroParameters: false, + section: false + }; + }, + token: function (stream, state) { + var ch = stream.peek(); + if (ch == "#") { stream.skipToEnd(); return "comment"; } + + if (stream.sol()) { + if (stream.match(preamble)) { return "preamble"; } + if (stream.match(section)) { return "section"; } + } + + if (stream.match(/^\$\w+/)) { return "def"; } // Variables like '$RPM_BUILD_ROOT' + if (stream.match(/^\$\{\w+\}/)) { return "def"; } // Variables like '${RPM_BUILD_ROOT}' + + if (stream.match(control_flow_simple)) { return "keyword"; } + if (stream.match(control_flow_complex)) { + state.controlFlow = true; + return "keyword"; + } + if (state.controlFlow) { + if (stream.match(operators)) { return "operator"; } + if (stream.match(/^(\d+)/)) { return "number"; } + if (stream.eol()) { state.controlFlow = false; } + } + + if (stream.match(arch)) { return "number"; } + + // Macros like '%make_install' or '%attr(0775,root,root)' + if (stream.match(/^%[\w]+/)) { + if (stream.match(/^\(/)) { state.macroParameters = true; } + return "macro"; + } + if (state.macroParameters) { + if (stream.match(/^\d+/)) { return "number";} + if (stream.match(/^\)/)) { + state.macroParameters = false; + return "macro"; + } + } + if (stream.match(/^%\{\??[\w \-]+\}/)) { return "macro"; } // Macros like '%{defined fedora}' + + //TODO: Include bash script sub-parser (CodeMirror supports that) + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-spec", "rpm-spec"); + +}); diff --git a/rhodecode/public/js/mode/rpm/spec/spec.js b/rhodecode/public/js/mode/rpm/spec/spec.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/rpm/spec/spec.js @@ -0,0 +1,66 @@ +// Quick and dirty spec file highlighting + +CodeMirror.defineMode("spec", function() { + var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/; + + var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/; + var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preinstall|preun|postinstall|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/; + var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros + var control_flow_simple = /^%(else|endif)/; // rpm control flow macros + var operators = /^(\!|\?|\<\=|\<|\>\=|\>|\=\=|\&\&|\|\|)/; // operators in control flow macros + + return { + startState: function () { + return { + controlFlow: false, + macroParameters: false, + section: false + }; + }, + token: function (stream, state) { + var ch = stream.peek(); + if (ch == "#") { stream.skipToEnd(); return "comment"; } + + if (stream.sol()) { + if (stream.match(preamble)) { return "preamble"; } + if (stream.match(section)) { return "section"; } + } + + if (stream.match(/^\$\w+/)) { return "def"; } // Variables like '$RPM_BUILD_ROOT' + if (stream.match(/^\$\{\w+\}/)) { return "def"; } // Variables like '${RPM_BUILD_ROOT}' + + if (stream.match(control_flow_simple)) { return "keyword"; } + if (stream.match(control_flow_complex)) { + state.controlFlow = true; + return "keyword"; + } + if (state.controlFlow) { + if (stream.match(operators)) { return "operator"; } + if (stream.match(/^(\d+)/)) { return "number"; } + if (stream.eol()) { state.controlFlow = false; } + } + + if (stream.match(arch)) { return "number"; } + + // Macros like '%make_install' or '%attr(0775,root,root)' + if (stream.match(/^%[\w]+/)) { + if (stream.match(/^\(/)) { state.macroParameters = true; } + return "macro"; + } + if (state.macroParameters) { + if (stream.match(/^\d+/)) { return "number";} + if (stream.match(/^\)/)) { + state.macroParameters = false; + return "macro"; + } + } + if (stream.match(/^%\{\??[\w \-]+\}/)) { return "macro"; } // Macros like '%{defined fedora}' + + //TODO: Include bash script sub-parser (CodeMirror supports that) + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-spec", "spec"); diff --git a/rhodecode/public/js/mode/rst/rst.js b/rhodecode/public/js/mode/rst/rst.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/rst/rst.js @@ -0,0 +1,557 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../python/python"), require("../stex/stex"), require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../python/python", "../stex/stex", "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('rst', function (config, options) { + + var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/; + var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/; + var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/; + + var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/; + var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/; + var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/; + + var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://"; + var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})"; + var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*"; + var rx_uri = new RegExp("^" + rx_uri_protocol + rx_uri_domain + rx_uri_path); + + var overlay = { + token: function (stream) { + + if (stream.match(rx_strong) && stream.match (/\W+|$/, false)) + return 'strong'; + if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false)) + return 'em'; + if (stream.match(rx_literal) && stream.match (/\W+|$/, false)) + return 'string-2'; + if (stream.match(rx_number)) + return 'number'; + if (stream.match(rx_positive)) + return 'positive'; + if (stream.match(rx_negative)) + return 'negative'; + if (stream.match(rx_uri)) + return 'link'; + + while (stream.next() != null) { + if (stream.match(rx_strong, false)) break; + if (stream.match(rx_emphasis, false)) break; + if (stream.match(rx_literal, false)) break; + if (stream.match(rx_number, false)) break; + if (stream.match(rx_positive, false)) break; + if (stream.match(rx_negative, false)) break; + if (stream.match(rx_uri, false)) break; + } + + return null; + } + }; + + var mode = CodeMirror.getMode( + config, options.backdrop || 'rst-base' + ); + + return CodeMirror.overlayMode(mode, overlay, true); // combine +}, 'python', 'stex'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +CodeMirror.defineMode('rst-base', function (config) { + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function format(string) { + var args = Array.prototype.slice.call(arguments, 1); + return string.replace(/{(\d+)}/g, function (match, n) { + return typeof args[n] != 'undefined' ? args[n] : match; + }); + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + var mode_python = CodeMirror.getMode(config, 'python'); + var mode_stex = CodeMirror.getMode(config, 'stex'); + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + var SEPA = "\\s+"; + var TAIL = "(?:\\s*|\\W|$)", + rx_TAIL = new RegExp(format('^{0}', TAIL)); + + var NAME = + "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)", + rx_NAME = new RegExp(format('^{0}', NAME)); + var NAME_WWS = + "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)"; + var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS); + + var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)"; + var TEXT2 = "(?:[^\\`]+)", + rx_TEXT2 = new RegExp(format('^{0}', TEXT2)); + + var rx_section = new RegExp( + "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$"); + var rx_explicit = new RegExp( + format('^\\.\\.{0}', SEPA)); + var rx_link = new RegExp( + format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL)); + var rx_directive = new RegExp( + format('^{0}::{1}', REF_NAME, TAIL)); + var rx_substitution = new RegExp( + format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL)); + var rx_footnote = new RegExp( + format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL)); + var rx_citation = new RegExp( + format('^\\[{0}\\]{1}', REF_NAME, TAIL)); + + var rx_substitution_ref = new RegExp( + format('^\\|{0}\\|', TEXT1)); + var rx_footnote_ref = new RegExp( + format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME)); + var rx_citation_ref = new RegExp( + format('^\\[{0}\\]_', REF_NAME)); + var rx_link_ref1 = new RegExp( + format('^{0}__?', REF_NAME)); + var rx_link_ref2 = new RegExp( + format('^`{0}`_', TEXT2)); + + var rx_role_pre = new RegExp( + format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL)); + var rx_role_suf = new RegExp( + format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL)); + var rx_role = new RegExp( + format('^:{0}:{1}', NAME, TAIL)); + + var rx_directive_name = new RegExp(format('^{0}', REF_NAME)); + var rx_directive_tail = new RegExp(format('^::{0}', TAIL)); + var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1)); + var rx_substitution_sepa = new RegExp(format('^{0}', SEPA)); + var rx_substitution_name = new RegExp(format('^{0}', REF_NAME)); + var rx_substitution_tail = new RegExp(format('^::{0}', TAIL)); + var rx_link_head = new RegExp("^_"); + var rx_link_name = new RegExp(format('^{0}|_', REF_NAME)); + var rx_link_tail = new RegExp(format('^:{0}', TAIL)); + + var rx_verbatim = new RegExp('^::\\s*$'); + var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s'); + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_normal(stream, state) { + var token = null; + + if (stream.sol() && stream.match(rx_examples, false)) { + change(state, to_mode, { + mode: mode_python, local: CodeMirror.startState(mode_python) + }); + } else if (stream.sol() && stream.match(rx_explicit)) { + change(state, to_explicit); + token = 'meta'; + } else if (stream.sol() && stream.match(rx_section)) { + change(state, to_normal); + token = 'header'; + } else if (phase(state) == rx_role_pre || + stream.match(rx_role_pre, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role_pre, 1)); + stream.match(/^:/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role_pre, 2)); + stream.match(rx_NAME); + token = 'keyword'; + + if (stream.current().match(/^(?:math|latex)/)) { + state.tmp_stex = true; + } + break; + case 2: + change(state, to_normal, context(rx_role_pre, 3)); + stream.match(/^:`/); + token = 'meta'; + break; + case 3: + if (state.tmp_stex) { + state.tmp_stex = undefined; state.tmp = { + mode: mode_stex, local: CodeMirror.startState(mode_stex) + }; + } + + if (state.tmp) { + if (stream.peek() == '`') { + change(state, to_normal, context(rx_role_pre, 4)); + state.tmp = undefined; + break; + } + + token = state.tmp.mode.token(stream, state.tmp.local); + break; + } + + change(state, to_normal, context(rx_role_pre, 4)); + stream.match(rx_TEXT2); + token = 'string'; + break; + case 4: + change(state, to_normal, context(rx_role_pre, 5)); + stream.match(/^`/); + token = 'meta'; + break; + case 5: + change(state, to_normal, context(rx_role_pre, 6)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_role_suf || + stream.match(rx_role_suf, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role_suf, 1)); + stream.match(/^`/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role_suf, 2)); + stream.match(rx_TEXT2); + token = 'string'; + break; + case 2: + change(state, to_normal, context(rx_role_suf, 3)); + stream.match(/^`:/); + token = 'meta'; + break; + case 3: + change(state, to_normal, context(rx_role_suf, 4)); + stream.match(rx_NAME); + token = 'keyword'; + break; + case 4: + change(state, to_normal, context(rx_role_suf, 5)); + stream.match(/^:/); + token = 'meta'; + break; + case 5: + change(state, to_normal, context(rx_role_suf, 6)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_role || stream.match(rx_role, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role, 1)); + stream.match(/^:/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role, 2)); + stream.match(rx_NAME); + token = 'keyword'; + break; + case 2: + change(state, to_normal, context(rx_role, 3)); + stream.match(/^:/); + token = 'meta'; + break; + case 3: + change(state, to_normal, context(rx_role, 4)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_substitution_ref || + stream.match(rx_substitution_ref, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_substitution_ref, 1)); + stream.match(rx_substitution_text); + token = 'variable-2'; + break; + case 1: + change(state, to_normal, context(rx_substitution_ref, 2)); + if (stream.match(/^_?_?/)) token = 'link'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_footnote_ref)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_citation_ref)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_link_ref1)) { + change(state, to_normal); + if (!stream.peek() || stream.peek().match(/^\W$/)) { + token = 'link'; + } + } else if (phase(state) == rx_link_ref2 || + stream.match(rx_link_ref2, false)) { + + switch (stage(state)) { + case 0: + if (!stream.peek() || stream.peek().match(/^\W$/)) { + change(state, to_normal, context(rx_link_ref2, 1)); + } else { + stream.match(rx_link_ref2); + } + break; + case 1: + change(state, to_normal, context(rx_link_ref2, 2)); + stream.match(/^`/); + token = 'link'; + break; + case 2: + change(state, to_normal, context(rx_link_ref2, 3)); + stream.match(rx_TEXT2); + break; + case 3: + change(state, to_normal, context(rx_link_ref2, 4)); + stream.match(/^`_/); + token = 'link'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_verbatim)) { + change(state, to_verbatim); + } + + else { + if (stream.next()) change(state, to_normal); + } + + return token; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_explicit(stream, state) { + var token = null; + + if (phase(state) == rx_substitution || + stream.match(rx_substitution, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_substitution, 1)); + stream.match(rx_substitution_text); + token = 'variable-2'; + break; + case 1: + change(state, to_explicit, context(rx_substitution, 2)); + stream.match(rx_substitution_sepa); + break; + case 2: + change(state, to_explicit, context(rx_substitution, 3)); + stream.match(rx_substitution_name); + token = 'keyword'; + break; + case 3: + change(state, to_explicit, context(rx_substitution, 4)); + stream.match(rx_substitution_tail); + token = 'meta'; + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_directive || + stream.match(rx_directive, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_directive, 1)); + stream.match(rx_directive_name); + token = 'keyword'; + + if (stream.current().match(/^(?:math|latex)/)) + state.tmp_stex = true; + else if (stream.current().match(/^python/)) + state.tmp_py = true; + break; + case 1: + change(state, to_explicit, context(rx_directive, 2)); + stream.match(rx_directive_tail); + token = 'meta'; + + if (stream.match(/^latex\s*$/) || state.tmp_stex) { + state.tmp_stex = undefined; change(state, to_mode, { + mode: mode_stex, local: CodeMirror.startState(mode_stex) + }); + } + break; + case 2: + change(state, to_explicit, context(rx_directive, 3)); + if (stream.match(/^python\s*$/) || state.tmp_py) { + state.tmp_py = undefined; change(state, to_mode, { + mode: mode_python, local: CodeMirror.startState(mode_python) + }); + } + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_link || stream.match(rx_link, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_link, 1)); + stream.match(rx_link_head); + stream.match(rx_link_name); + token = 'link'; + break; + case 1: + change(state, to_explicit, context(rx_link, 2)); + stream.match(rx_link_tail); + token = 'meta'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_footnote)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_citation)) { + change(state, to_normal); + token = 'quote'; + } + + else { + stream.eatSpace(); + if (stream.eol()) { + change(state, to_normal); + } else { + stream.skipToEnd(); + change(state, to_comment); + token = 'comment'; + } + } + + return token; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_comment(stream, state) { + return as_block(stream, state, 'comment'); + } + + function to_verbatim(stream, state) { + return as_block(stream, state, 'meta'); + } + + function as_block(stream, state, token) { + if (stream.eol() || stream.eatSpace()) { + stream.skipToEnd(); + return token; + } else { + change(state, to_normal); + return null; + } + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_mode(stream, state) { + + if (state.ctx.mode && state.ctx.local) { + + if (stream.sol()) { + if (!stream.eatSpace()) change(state, to_normal); + return null; + } + + return state.ctx.mode.token(stream, state.ctx.local); + } + + change(state, to_normal); + return null; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function context(phase, stage, mode, local) { + return {phase: phase, stage: stage, mode: mode, local: local}; + } + + function change(state, tok, ctx) { + state.tok = tok; + state.ctx = ctx || {}; + } + + function stage(state) { + return state.ctx.stage || 0; + } + + function phase(state) { + return state.ctx.phase; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + return { + startState: function () { + return {tok: to_normal, ctx: context(undefined, 0)}; + }, + + copyState: function (state) { + var ctx = state.ctx, tmp = state.tmp; + if (ctx.local) + ctx = {mode: ctx.mode, local: CodeMirror.copyState(ctx.mode, ctx.local)}; + if (tmp) + tmp = {mode: tmp.mode, local: CodeMirror.copyState(tmp.mode, tmp.local)}; + return {tok: state.tok, ctx: ctx, tmp: tmp}; + }, + + innerMode: function (state) { + return state.tmp ? {state: state.tmp.local, mode: state.tmp.mode} + : state.ctx.mode ? {state: state.ctx.local, mode: state.ctx.mode} + : null; + }, + + token: function (stream, state) { + return state.tok(stream, state); + } + }; +}, 'python', 'stex'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +CodeMirror.defineMIME('text/x-rst', 'rst'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +}); diff --git a/rhodecode/public/js/mode/ruby/ruby.js b/rhodecode/public/js/mode/ruby/ruby.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ruby/ruby.js @@ -0,0 +1,285 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("ruby", function(config) { + function wordObj(words) { + var o = {}; + for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; + return o; + } + var keywords = wordObj([ + "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", + "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", + "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", + "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", + "caller", "lambda", "proc", "public", "protected", "private", "require", "load", + "require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__" + ]); + var indentWords = wordObj(["def", "class", "case", "for", "while", "module", "then", + "catch", "loop", "proc", "begin"]); + var dedentWords = wordObj(["end", "until"]); + var matching = {"[": "]", "{": "}", "(": ")"}; + var curPunc; + + function chain(newtok, stream, state) { + state.tokenize.push(newtok); + return newtok(stream, state); + } + + function tokenBase(stream, state) { + curPunc = null; + if (stream.sol() && stream.match("=begin") && stream.eol()) { + state.tokenize.push(readBlockComment); + return "comment"; + } + if (stream.eatSpace()) return null; + var ch = stream.next(), m; + if (ch == "`" || ch == "'" || ch == '"') { + return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); + } else if (ch == "/") { + var currentIndex = stream.current().length; + if (stream.skipTo("/")) { + var search_till = stream.current().length; + stream.backUp(stream.current().length - currentIndex); + var balance = 0; // balance brackets + while (stream.current().length < search_till) { + var chchr = stream.next(); + if (chchr == "(") balance += 1; + else if (chchr == ")") balance -= 1; + if (balance < 0) break; + } + stream.backUp(stream.current().length - currentIndex); + if (balance == 0) + return chain(readQuoted(ch, "string-2", true), stream, state); + } + return "operator"; + } else if (ch == "%") { + var style = "string", embed = true; + if (stream.eat("s")) style = "atom"; + else if (stream.eat(/[WQ]/)) style = "string"; + else if (stream.eat(/[r]/)) style = "string-2"; + else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; } + var delim = stream.eat(/[^\w\s=]/); + if (!delim) return "operator"; + if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; + return chain(readQuoted(delim, style, embed, true), stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) { + return chain(readHereDoc(m[1]), stream, state); + } else if (ch == "0") { + if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); + else if (stream.eat("b")) stream.eatWhile(/[01]/); + else stream.eatWhile(/[0-7]/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); + return "number"; + } else if (ch == "?") { + while (stream.match(/^\\[CM]-/)) {} + if (stream.eat("\\")) stream.eatWhile(/\w/); + else stream.next(); + return "string"; + } else if (ch == ":") { + if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state); + if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state); + + // :> :>> :< :<< are valid symbols + if (stream.eat(/[\<\>]/)) { + stream.eat(/[\<\>]/); + return "atom"; + } + + // :+ :- :/ :* :| :& :! are valid symbols + if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) { + return "atom"; + } + + // Symbols can't start by a digit + if (stream.eat(/[a-zA-Z$@_\xa1-\uffff]/)) { + stream.eatWhile(/[\w$\xa1-\uffff]/); + // Only one ? ! = is allowed and only as the last character + stream.eat(/[\?\!\=]/); + return "atom"; + } + return "operator"; + } else if (ch == "@" && stream.match(/^@?[a-zA-Z_\xa1-\uffff]/)) { + stream.eat("@"); + stream.eatWhile(/[\w\xa1-\uffff]/); + return "variable-2"; + } else if (ch == "$") { + if (stream.eat(/[a-zA-Z_]/)) { + stream.eatWhile(/[\w]/); + } else if (stream.eat(/\d/)) { + stream.eat(/\d/); + } else { + stream.next(); // Must be a special global like $: or $! + } + return "variable-3"; + } else if (/[a-zA-Z_\xa1-\uffff]/.test(ch)) { + stream.eatWhile(/[\w\xa1-\uffff]/); + stream.eat(/[\?\!]/); + if (stream.eat(":")) return "atom"; + return "ident"; + } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { + curPunc = "|"; + return null; + } else if (/[\(\)\[\]{}\\;]/.test(ch)) { + curPunc = ch; + return null; + } else if (ch == "-" && stream.eat(">")) { + return "arrow"; + } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { + var more = stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); + if (ch == "." && !more) curPunc = "."; + return "operator"; + } else { + return null; + } + } + + function tokenBaseUntilBrace(depth) { + if (!depth) depth = 1; + return function(stream, state) { + if (stream.peek() == "}") { + if (depth == 1) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } else { + state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth - 1); + } + } else if (stream.peek() == "{") { + state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth + 1); + } + return tokenBase(stream, state); + }; + } + function tokenBaseOnce() { + var alreadyCalled = false; + return function(stream, state) { + if (alreadyCalled) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } + alreadyCalled = true; + return tokenBase(stream, state); + }; + } + function readQuoted(quote, style, embed, unescaped) { + return function(stream, state) { + var escaped = false, ch; + + if (state.context.type === 'read-quoted-paused') { + state.context = state.context.prev; + stream.eat("}"); + } + + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize.pop(); + break; + } + if (embed && ch == "#" && !escaped) { + if (stream.eat("{")) { + if (quote == "}") { + state.context = {prev: state.context, type: 'read-quoted-paused'}; + } + state.tokenize.push(tokenBaseUntilBrace()); + break; + } else if (/[@\$]/.test(stream.peek())) { + state.tokenize.push(tokenBaseOnce()); + break; + } + } + escaped = !escaped && ch == "\\"; + } + return style; + }; + } + function readHereDoc(phrase) { + return function(stream, state) { + if (stream.match(phrase)) state.tokenize.pop(); + else stream.skipToEnd(); + return "string"; + }; + } + function readBlockComment(stream, state) { + if (stream.sol() && stream.match("=end") && stream.eol()) + state.tokenize.pop(); + stream.skipToEnd(); + return "comment"; + } + + return { + startState: function() { + return {tokenize: [tokenBase], + indented: 0, + context: {type: "top", indented: -config.indentUnit}, + continuedLine: false, + lastTok: null, + varList: false}; + }, + + token: function(stream, state) { + if (stream.sol()) state.indented = stream.indentation(); + var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype; + var thisTok = curPunc; + if (style == "ident") { + var word = stream.current(); + style = state.lastTok == "." ? "property" + : keywords.propertyIsEnumerable(stream.current()) ? "keyword" + : /^[A-Z]/.test(word) ? "tag" + : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" + : "variable"; + if (style == "keyword") { + thisTok = word; + if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; + else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; + else if ((word == "if" || word == "unless") && stream.column() == stream.indentation()) + kwtype = "indent"; + else if (word == "do" && state.context.indented < state.indented) + kwtype = "indent"; + } + } + if (curPunc || (style && style != "comment")) state.lastTok = thisTok; + if (curPunc == "|") state.varList = !state.varList; + + if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) + state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; + else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) + state.context = state.context.prev; + + if (stream.eol()) + state.continuedLine = (curPunc == "\\" || style == "operator"); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0); + var ct = state.context; + var closing = ct.type == matching[firstChar] || + ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter); + return ct.indented + (closing ? 0 : config.indentUnit) + + (state.continuedLine ? config.indentUnit : 0); + }, + + electricChars: "}de", // enD and rescuE + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/x-ruby", "ruby"); + +}); diff --git a/rhodecode/public/js/mode/rust/rust.js b/rhodecode/public/js/mode/rust/rust.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/rust/rust.js @@ -0,0 +1,451 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("rust", function() { + var indentUnit = 4, altIndentUnit = 2; + var valKeywords = { + "if": "if-style", "while": "if-style", "loop": "else-style", "else": "else-style", + "do": "else-style", "ret": "else-style", "fail": "else-style", + "break": "atom", "cont": "atom", "const": "let", "resource": "fn", + "let": "let", "fn": "fn", "for": "for", "alt": "alt", "iface": "iface", + "impl": "impl", "type": "type", "enum": "enum", "mod": "mod", + "as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op", + "claim": "op", "native": "ignore", "unsafe": "ignore", "import": "else-style", + "export": "else-style", "copy": "op", "log": "op", "log_err": "op", + "use": "op", "bind": "op", "self": "atom", "struct": "enum" + }; + var typeKeywords = function() { + var keywords = {"fn": "fn", "block": "fn", "obj": "obj"}; + var atoms = "bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char".split(" "); + for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = "atom"; + return keywords; + }(); + var operatorChar = /[+\-*&%=<>!?|\.@]/; + + // Tokenizer + + // Used as scratch variable to communicate multiple values without + // consing up tons of objects. + var tcat, content; + function r(tc, style) { + tcat = tc; + return style; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + if (ch == "'") { + tcat = "atom"; + if (stream.eat("\\")) { + if (stream.skipTo("'")) { stream.next(); return "string"; } + else { return "error"; } + } else { + stream.next(); + return stream.eat("'") ? "string" : "error"; + } + } + if (ch == "/") { + if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } + if (stream.eat("*")) { + state.tokenize = tokenComment(1); + return state.tokenize(stream, state); + } + } + if (ch == "#") { + if (stream.eat("[")) { tcat = "open-attr"; return null; } + stream.eatWhile(/\w/); + return r("macro", "meta"); + } + if (ch == ":" && stream.match(":<")) { + return r("op", null); + } + if (ch.match(/\d/) || (ch == "." && stream.eat(/\d/))) { + var flp = false; + if (!stream.match(/^x[\da-f]+/i) && !stream.match(/^b[01]+/)) { + stream.eatWhile(/\d/); + if (stream.eat(".")) { flp = true; stream.eatWhile(/\d/); } + if (stream.match(/^e[+\-]?\d+/i)) { flp = true; } + } + if (flp) stream.match(/^f(?:32|64)/); + else stream.match(/^[ui](?:8|16|32|64)/); + return r("atom", "number"); + } + if (ch.match(/[()\[\]{}:;,]/)) return r(ch, null); + if (ch == "-" && stream.eat(">")) return r("->", null); + if (ch.match(operatorChar)) { + stream.eatWhile(operatorChar); + return r("op", null); + } + stream.eatWhile(/\w/); + content = stream.current(); + if (stream.match(/^::\w/)) { + stream.backUp(1); + return r("prefix", "variable-2"); + } + if (state.keywords.propertyIsEnumerable(content)) + return r(state.keywords[content], content.match(/true|false/) ? "atom" : "keyword"); + return r("name", "variable"); + } + + function tokenString(stream, state) { + var ch, escaped = false; + while (ch = stream.next()) { + if (ch == '"' && !escaped) { + state.tokenize = tokenBase; + return r("atom", "string"); + } + escaped = !escaped && ch == "\\"; + } + // Hack to not confuse the parser when a string is split in + // pieces. + return r("op", "string"); + } + + function tokenComment(depth) { + return function(stream, state) { + var lastCh = null, ch; + while (ch = stream.next()) { + if (ch == "/" && lastCh == "*") { + if (depth == 1) { + state.tokenize = tokenBase; + break; + } else { + state.tokenize = tokenComment(depth - 1); + return state.tokenize(stream, state); + } + } + if (ch == "*" && lastCh == "/") { + state.tokenize = tokenComment(depth + 1); + return state.tokenize(stream, state); + } + lastCh = ch; + } + return "comment"; + }; + } + + // Parser + + var cx = {state: null, stream: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + + function pushlex(type, info) { + var result = function() { + var state = cx.state; + state.lexical = {indented: state.indented, column: cx.stream.column(), + type: type, prev: state.lexical, info: info}; + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + function typecx() { cx.state.keywords = typeKeywords; } + function valcx() { cx.state.keywords = valKeywords; } + poplex.lex = typecx.lex = valcx.lex = true; + + function commasep(comb, end) { + function more(type) { + if (type == ",") return cont(comb, more); + if (type == end) return cont(); + return cont(more); + } + return function(type) { + if (type == end) return cont(); + return pass(comb, more); + }; + } + + function stat_of(comb, tag) { + return cont(pushlex("stat", tag), comb, poplex, block); + } + function block(type) { + if (type == "}") return cont(); + if (type == "let") return stat_of(letdef1, "let"); + if (type == "fn") return stat_of(fndef); + if (type == "type") return cont(pushlex("stat"), tydef, endstatement, poplex, block); + if (type == "enum") return stat_of(enumdef); + if (type == "mod") return stat_of(mod); + if (type == "iface") return stat_of(iface); + if (type == "impl") return stat_of(impl); + if (type == "open-attr") return cont(pushlex("]"), commasep(expression, "]"), poplex); + if (type == "ignore" || type.match(/[\]\);,]/)) return cont(block); + return pass(pushlex("stat"), expression, poplex, endstatement, block); + } + function endstatement(type) { + if (type == ";") return cont(); + return pass(); + } + function expression(type) { + if (type == "atom" || type == "name") return cont(maybeop); + if (type == "{") return cont(pushlex("}"), exprbrace, poplex); + if (type.match(/[\[\(]/)) return matchBrackets(type, expression); + if (type.match(/[\]\)\};,]/)) return pass(); + if (type == "if-style") return cont(expression, expression); + if (type == "else-style" || type == "op") return cont(expression); + if (type == "for") return cont(pattern, maybetype, inop, expression, expression); + if (type == "alt") return cont(expression, altbody); + if (type == "fn") return cont(fndef); + if (type == "macro") return cont(macro); + return cont(); + } + function maybeop(type) { + if (content == ".") return cont(maybeprop); + if (content == "::<"){return cont(typarams, maybeop);} + if (type == "op" || content == ":") return cont(expression); + if (type == "(" || type == "[") return matchBrackets(type, expression); + return pass(); + } + function maybeprop() { + if (content.match(/^\w+$/)) {cx.marked = "variable"; return cont(maybeop);} + return pass(expression); + } + function exprbrace(type) { + if (type == "op") { + if (content == "|") return cont(blockvars, poplex, pushlex("}", "block"), block); + if (content == "||") return cont(poplex, pushlex("}", "block"), block); + } + if (content == "mutable" || (content.match(/^\w+$/) && cx.stream.peek() == ":" + && !cx.stream.match("::", false))) + return pass(record_of(expression)); + return pass(block); + } + function record_of(comb) { + function ro(type) { + if (content == "mutable" || content == "with") {cx.marked = "keyword"; return cont(ro);} + if (content.match(/^\w*$/)) {cx.marked = "variable"; return cont(ro);} + if (type == ":") return cont(comb, ro); + if (type == "}") return cont(); + return cont(ro); + } + return ro; + } + function blockvars(type) { + if (type == "name") {cx.marked = "def"; return cont(blockvars);} + if (type == "op" && content == "|") return cont(); + return cont(blockvars); + } + + function letdef1(type) { + if (type.match(/[\]\)\};]/)) return cont(); + if (content == "=") return cont(expression, letdef2); + if (type == ",") return cont(letdef1); + return pass(pattern, maybetype, letdef1); + } + function letdef2(type) { + if (type.match(/[\]\)\};,]/)) return pass(letdef1); + else return pass(expression, letdef2); + } + function maybetype(type) { + if (type == ":") return cont(typecx, rtype, valcx); + return pass(); + } + function inop(type) { + if (type == "name" && content == "in") {cx.marked = "keyword"; return cont();} + return pass(); + } + function fndef(type) { + if (content == "@" || content == "~") {cx.marked = "keyword"; return cont(fndef);} + if (type == "name") {cx.marked = "def"; return cont(fndef);} + if (content == "<") return cont(typarams, fndef); + if (type == "{") return pass(expression); + if (type == "(") return cont(pushlex(")"), commasep(argdef, ")"), poplex, fndef); + if (type == "->") return cont(typecx, rtype, valcx, fndef); + if (type == ";") return cont(); + return cont(fndef); + } + function tydef(type) { + if (type == "name") {cx.marked = "def"; return cont(tydef);} + if (content == "<") return cont(typarams, tydef); + if (content == "=") return cont(typecx, rtype, valcx); + return cont(tydef); + } + function enumdef(type) { + if (type == "name") {cx.marked = "def"; return cont(enumdef);} + if (content == "<") return cont(typarams, enumdef); + if (content == "=") return cont(typecx, rtype, valcx, endstatement); + if (type == "{") return cont(pushlex("}"), typecx, enumblock, valcx, poplex); + return cont(enumdef); + } + function enumblock(type) { + if (type == "}") return cont(); + if (type == "(") return cont(pushlex(")"), commasep(rtype, ")"), poplex, enumblock); + if (content.match(/^\w+$/)) cx.marked = "def"; + return cont(enumblock); + } + function mod(type) { + if (type == "name") {cx.marked = "def"; return cont(mod);} + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function iface(type) { + if (type == "name") {cx.marked = "def"; return cont(iface);} + if (content == "<") return cont(typarams, iface); + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function impl(type) { + if (content == "<") return cont(typarams, impl); + if (content == "of" || content == "for") {cx.marked = "keyword"; return cont(rtype, impl);} + if (type == "name") {cx.marked = "def"; return cont(impl);} + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function typarams() { + if (content == ">") return cont(); + if (content == ",") return cont(typarams); + if (content == ":") return cont(rtype, typarams); + return pass(rtype, typarams); + } + function argdef(type) { + if (type == "name") {cx.marked = "def"; return cont(argdef);} + if (type == ":") return cont(typecx, rtype, valcx); + return pass(); + } + function rtype(type) { + if (type == "name") {cx.marked = "variable-3"; return cont(rtypemaybeparam); } + if (content == "mutable") {cx.marked = "keyword"; return cont(rtype);} + if (type == "atom") return cont(rtypemaybeparam); + if (type == "op" || type == "obj") return cont(rtype); + if (type == "fn") return cont(fntype); + if (type == "{") return cont(pushlex("{"), record_of(rtype), poplex); + return matchBrackets(type, rtype); + } + function rtypemaybeparam() { + if (content == "<") return cont(typarams); + return pass(); + } + function fntype(type) { + if (type == "(") return cont(pushlex("("), commasep(rtype, ")"), poplex, fntype); + if (type == "->") return cont(rtype); + return pass(); + } + function pattern(type) { + if (type == "name") {cx.marked = "def"; return cont(patternmaybeop);} + if (type == "atom") return cont(patternmaybeop); + if (type == "op") return cont(pattern); + if (type.match(/[\]\)\};,]/)) return pass(); + return matchBrackets(type, pattern); + } + function patternmaybeop(type) { + if (type == "op" && content == ".") return cont(); + if (content == "to") {cx.marked = "keyword"; return cont(pattern);} + else return pass(); + } + function altbody(type) { + if (type == "{") return cont(pushlex("}", "alt"), altblock1, poplex); + return pass(); + } + function altblock1(type) { + if (type == "}") return cont(); + if (type == "|") return cont(altblock1); + if (content == "when") {cx.marked = "keyword"; return cont(expression, altblock2);} + if (type.match(/[\]\);,]/)) return cont(altblock1); + return pass(pattern, altblock2); + } + function altblock2(type) { + if (type == "{") return cont(pushlex("}", "alt"), block, poplex, altblock1); + else return pass(altblock1); + } + + function macro(type) { + if (type.match(/[\[\(\{]/)) return matchBrackets(type, expression); + return pass(); + } + function matchBrackets(type, comb) { + if (type == "[") return cont(pushlex("]"), commasep(comb, "]"), poplex); + if (type == "(") return cont(pushlex(")"), commasep(comb, ")"), poplex); + if (type == "{") return cont(pushlex("}"), commasep(comb, "}"), poplex); + return cont(); + } + + function parse(state, stream, style) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; + + while (true) { + var combinator = cc.length ? cc.pop() : block; + if (combinator(tcat)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + return cx.marked || style; + } + } + } + + return { + startState: function() { + return { + tokenize: tokenBase, + cc: [], + lexical: {indented: -indentUnit, column: 0, type: "top", align: false}, + keywords: valKeywords, + indented: 0 + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + tcat = content = null; + var style = state.tokenize(stream, state); + if (style == "comment") return style; + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + if (tcat == "prefix") return style; + if (!content) content = stream.current(); + return parse(state, stream, style); + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, + type = lexical.type, closing = firstChar == type; + if (type == "stat") return lexical.indented + indentUnit; + if (lexical.align) return lexical.column + (closing ? 0 : 1); + return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit)); + }, + + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + fold: "brace" + }; +}); + +CodeMirror.defineMIME("text/x-rustsrc", "rust"); + +}); diff --git a/rhodecode/public/js/mode/sass/sass.js b/rhodecode/public/js/mode/sass/sass.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/sass/sass.js @@ -0,0 +1,414 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sass", function(config) { + function tokenRegexp(words) { + return new RegExp("^" + words.join("|")); + } + + var keywords = ["true", "false", "null", "auto"]; + var keywordsRegexp = new RegExp("^" + keywords.join("|")); + + var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", + "\\!=", "/", "\\*", "%", "and", "or", "not", ";","\\{","\\}",":"]; + var opRegexp = tokenRegexp(operators); + + var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/; + + function urlTokens(stream, state) { + var ch = stream.peek(); + + if (ch === ")") { + stream.next(); + state.tokenizer = tokenBase; + return "operator"; + } else if (ch === "(") { + stream.next(); + stream.eatSpace(); + + return "operator"; + } else if (ch === "'" || ch === '"') { + state.tokenizer = buildStringTokenizer(stream.next()); + return "string"; + } else { + state.tokenizer = buildStringTokenizer(")", false); + return "string"; + } + } + function comment(indentation, multiLine) { + return function(stream, state) { + if (stream.sol() && stream.indentation() <= indentation) { + state.tokenizer = tokenBase; + return tokenBase(stream, state); + } + + if (multiLine && stream.skipTo("*/")) { + stream.next(); + stream.next(); + state.tokenizer = tokenBase; + } else { + stream.skipToEnd(); + } + + return "comment"; + }; + } + + function buildStringTokenizer(quote, greedy) { + if (greedy == null) { greedy = true; } + + function stringTokenizer(stream, state) { + var nextChar = stream.next(); + var peekChar = stream.peek(); + var previousChar = stream.string.charAt(stream.pos-2); + + var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\")); + + if (endingString) { + if (nextChar !== quote && greedy) { stream.next(); } + state.tokenizer = tokenBase; + return "string"; + } else if (nextChar === "#" && peekChar === "{") { + state.tokenizer = buildInterpolationTokenizer(stringTokenizer); + stream.next(); + return "operator"; + } else { + return "string"; + } + } + + return stringTokenizer; + } + + function buildInterpolationTokenizer(currentTokenizer) { + return function(stream, state) { + if (stream.peek() === "}") { + stream.next(); + state.tokenizer = currentTokenizer; + return "operator"; + } else { + return tokenBase(stream, state); + } + }; + } + + function indent(state) { + if (state.indentCount == 0) { + state.indentCount++; + var lastScopeOffset = state.scopes[0].offset; + var currentOffset = lastScopeOffset + config.indentUnit; + state.scopes.unshift({ offset:currentOffset }); + } + } + + function dedent(state) { + if (state.scopes.length == 1) return; + + state.scopes.shift(); + } + + function tokenBase(stream, state) { + var ch = stream.peek(); + + // Comment + if (stream.match("/*")) { + state.tokenizer = comment(stream.indentation(), true); + return state.tokenizer(stream, state); + } + if (stream.match("//")) { + state.tokenizer = comment(stream.indentation(), false); + return state.tokenizer(stream, state); + } + + // Interpolation + if (stream.match("#{")) { + state.tokenizer = buildInterpolationTokenizer(tokenBase); + return "operator"; + } + + // Strings + if (ch === '"' || ch === "'") { + stream.next(); + state.tokenizer = buildStringTokenizer(ch); + return "string"; + } + + if(!state.cursorHalf){// state.cursorHalf === 0 + // first half i.e. before : for key-value pairs + // including selectors + + if (ch === ".") { + stream.next(); + if (stream.match(/^[\w-]+/)) { + indent(state); + return "atom"; + } else if (stream.peek() === "#") { + indent(state); + return "atom"; + } + } + + if (ch === "#") { + stream.next(); + // ID selectors + if (stream.match(/^[\w-]+/)) { + indent(state); + return "atom"; + } + if (stream.peek() === "#") { + indent(state); + return "atom"; + } + } + + // Variables + if (ch === "$") { + stream.next(); + stream.eatWhile(/[\w-]/); + return "variable-2"; + } + + // Numbers + if (stream.match(/^-?[0-9\.]+/)) + return "number"; + + // Units + if (stream.match(/^(px|em|in)\b/)) + return "unit"; + + if (stream.match(keywordsRegexp)) + return "keyword"; + + if (stream.match(/^url/) && stream.peek() === "(") { + state.tokenizer = urlTokens; + return "atom"; + } + + if (ch === "=") { + // Match shortcut mixin definition + if (stream.match(/^=[\w-]+/)) { + indent(state); + return "meta"; + } + } + + if (ch === "+") { + // Match shortcut mixin definition + if (stream.match(/^\+[\w-]+/)){ + return "variable-3"; + } + } + + if(ch === "@"){ + if(stream.match(/@extend/)){ + if(!stream.match(/\s*[\w]/)) + dedent(state); + } + } + + + // Indent Directives + if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) { + indent(state); + return "meta"; + } + + // Other Directives + if (ch === "@") { + stream.next(); + stream.eatWhile(/[\w-]/); + return "meta"; + } + + if (stream.eatWhile(/[\w-]/)){ + if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){ + return "property"; + } + else if(stream.match(/ *:/,false)){ + indent(state); + state.cursorHalf = 1; + return "atom"; + } + else if(stream.match(/ *,/,false)){ + return "atom"; + } + else{ + indent(state); + return "atom"; + } + } + + if(ch === ":"){ + if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element + return "keyword"; + } + stream.next(); + state.cursorHalf=1; + return "operator"; + } + + } // cursorHalf===0 ends here + else{ + + if (ch === "#") { + stream.next(); + // Hex numbers + if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "number"; + } + } + + // Numbers + if (stream.match(/^-?[0-9\.]+/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "number"; + } + + // Units + if (stream.match(/^(px|em|in)\b/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "unit"; + } + + if (stream.match(keywordsRegexp)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "keyword"; + } + + if (stream.match(/^url/) && stream.peek() === "(") { + state.tokenizer = urlTokens; + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "atom"; + } + + // Variables + if (ch === "$") { + stream.next(); + stream.eatWhile(/[\w-]/); + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "variable-3"; + } + + // bang character for !important, !default, etc. + if (ch === "!") { + stream.next(); + if(!stream.peek()){ + state.cursorHalf = 0; + } + return stream.match(/^[\w]+/) ? "keyword": "operator"; + } + + if (stream.match(opRegexp)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "operator"; + } + + // attributes + if (stream.eatWhile(/[\w-]/)) { + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "attribute"; + } + + //stream.eatSpace(); + if(!stream.peek()){ + state.cursorHalf = 0; + return null; + } + + } // else ends here + + if (stream.match(opRegexp)) + return "operator"; + + // If we haven't returned by now, we move 1 character + // and return an error + stream.next(); + return null; + } + + function tokenLexer(stream, state) { + if (stream.sol()) state.indentCount = 0; + var style = state.tokenizer(stream, state); + var current = stream.current(); + + if (current === "@return" || current === "}"){ + dedent(state); + } + + if (style !== null) { + var startOfToken = stream.pos - current.length; + + var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount); + + var newScopes = []; + + for (var i = 0; i < state.scopes.length; i++) { + var scope = state.scopes[i]; + + if (scope.offset <= withCurrentIndent) + newScopes.push(scope); + } + + state.scopes = newScopes; + } + + + return style; + } + + return { + startState: function() { + return { + tokenizer: tokenBase, + scopes: [{offset: 0, type: "sass"}], + indentCount: 0, + cursorHalf: 0, // cursor half tells us if cursor lies after (1) + // or before (0) colon (well... more or less) + definedVars: [], + definedMixins: [] + }; + }, + token: function(stream, state) { + var style = tokenLexer(stream, state); + + state.lastToken = { style: style, content: stream.current() }; + + return style; + }, + + indent: function(state) { + return state.scopes[0].offset; + } + }; +}); + +CodeMirror.defineMIME("text/x-sass", "sass"); + +}); diff --git a/rhodecode/public/js/mode/scheme/scheme.js b/rhodecode/public/js/mode/scheme/scheme.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/scheme/scheme.js @@ -0,0 +1,249 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Author: Koh Zi Han, based on implementation by Koh Zi Chun + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("scheme", function () { + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", + ATOM = "atom", NUMBER = "number", BRACKET = "bracket"; + var INDENT_WORD_SKIP = 2; + + function makeKeywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); + var indentKeys = makeKeywords("define let letrec let* lambda"); + + function stateStack(indent, type, prev) { // represents a state stack object + this.indent = indent; + this.type = type; + this.prev = prev; + } + + function pushStack(state, indent, type) { + state.indentStack = new stateStack(indent, type, state.indentStack); + } + + function popStack(state) { + state.indentStack = state.indentStack.prev; + } + + var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i); + var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i); + var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i); + var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i); + + function isBinaryNumber (stream) { + return stream.match(binaryMatcher); + } + + function isOctalNumber (stream) { + return stream.match(octalMatcher); + } + + function isDecimalNumber (stream, backup) { + if (backup === true) { + stream.backUp(1); + } + return stream.match(decimalMatcher); + } + + function isHexNumber (stream) { + return stream.match(hexMatcher); + } + + return { + startState: function () { + return { + indentStack: null, + indentation: 0, + mode: false, + sExprComment: false + }; + }, + + token: function (stream, state) { + if (state.indentStack == null && stream.sol()) { + // update indentation, but only if indentStack is empty + state.indentation = stream.indentation(); + } + + // skip spaces + if (stream.eatSpace()) { + return null; + } + var returnType = null; + + switch(state.mode){ + case "string": // multi-line string parsing mode + var next, escaped = false; + while ((next = stream.next()) != null) { + if (next == "\"" && !escaped) { + + state.mode = false; + break; + } + escaped = !escaped && next == "\\"; + } + returnType = STRING; // continue on in scheme-string mode + break; + case "comment": // comment parsing mode + var next, maybeEnd = false; + while ((next = stream.next()) != null) { + if (next == "#" && maybeEnd) { + + state.mode = false; + break; + } + maybeEnd = (next == "|"); + } + returnType = COMMENT; + break; + case "s-expr-comment": // s-expr commenting mode + state.mode = false; + if(stream.peek() == "(" || stream.peek() == "["){ + // actually start scheme s-expr commenting mode + state.sExprComment = 0; + }else{ + // if not we just comment the entire of the next token + stream.eatWhile(/[^/s]/); // eat non spaces + returnType = COMMENT; + break; + } + default: // default parsing mode + var ch = stream.next(); + + if (ch == "\"") { + state.mode = "string"; + returnType = STRING; + + } else if (ch == "'") { + returnType = ATOM; + } else if (ch == '#') { + if (stream.eat("|")) { // Multi-line comment + state.mode = "comment"; // toggle to comment mode + returnType = COMMENT; + } else if (stream.eat(/[tf]/i)) { // #t/#f (atom) + returnType = ATOM; + } else if (stream.eat(';')) { // S-Expr comment + state.mode = "s-expr-comment"; + returnType = COMMENT; + } else { + var numTest = null, hasExactness = false, hasRadix = true; + if (stream.eat(/[ei]/i)) { + hasExactness = true; + } else { + stream.backUp(1); // must be radix specifier + } + if (stream.match(/^#b/i)) { + numTest = isBinaryNumber; + } else if (stream.match(/^#o/i)) { + numTest = isOctalNumber; + } else if (stream.match(/^#x/i)) { + numTest = isHexNumber; + } else if (stream.match(/^#d/i)) { + numTest = isDecimalNumber; + } else if (stream.match(/^[-+0-9.]/, false)) { + hasRadix = false; + numTest = isDecimalNumber; + // re-consume the intial # if all matches failed + } else if (!hasExactness) { + stream.eat('#'); + } + if (numTest != null) { + if (hasRadix && !hasExactness) { + // consume optional exactness after radix + stream.match(/^#[ei]/i); + } + if (numTest(stream)) + returnType = NUMBER; + } + } + } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal + returnType = NUMBER; + } else if (ch == ";") { // comment + stream.skipToEnd(); // rest of the line is a comment + returnType = COMMENT; + } else if (ch == "(" || ch == "[") { + var keyWord = ''; var indentTemp = stream.column(), letter; + /** + Either + (indent-word .. + (non-indent-word .. + (;something else, bracket, etc. + */ + + while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) { + keyWord += letter; + } + + if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word + + pushStack(state, indentTemp + INDENT_WORD_SKIP, ch); + } else { // non-indent word + // we continue eating the spaces + stream.eatSpace(); + if (stream.eol() || stream.peek() == ";") { + // nothing significant after + // we restart indentation 1 space after + pushStack(state, indentTemp + 1, ch); + } else { + pushStack(state, indentTemp + stream.current().length, ch); // else we match + } + } + stream.backUp(stream.current().length - 1); // undo all the eating + + if(typeof state.sExprComment == "number") state.sExprComment++; + + returnType = BRACKET; + } else if (ch == ")" || ch == "]") { + returnType = BRACKET; + if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) { + popStack(state); + + if(typeof state.sExprComment == "number"){ + if(--state.sExprComment == 0){ + returnType = COMMENT; // final closing bracket + state.sExprComment = false; // turn off s-expr commenting mode + } + } + } + } else { + stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/); + + if (keywords && keywords.propertyIsEnumerable(stream.current())) { + returnType = BUILTIN; + } else returnType = "variable"; + } + } + return (typeof state.sExprComment == "number") ? COMMENT : returnType; + }, + + indent: function (state) { + if (state.indentStack == null) return state.indentation; + return state.indentStack.indent; + }, + + closeBrackets: {pairs: "()[]{}\"\""}, + lineComment: ";;" + }; +}); + +CodeMirror.defineMIME("text/x-scheme", "scheme"); + +}); diff --git a/rhodecode/public/js/mode/shell/shell.js b/rhodecode/public/js/mode/shell/shell.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/shell/shell.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('shell', function() { + + var words = {}; + function define(style, string) { + var split = string.split(' '); + for(var i = 0; i < split.length; i++) { + words[split[i]] = style; + } + }; + + // Atoms + define('atom', 'true false'); + + // Keywords + define('keyword', 'if then do else elif while until for in esac fi fin ' + + 'fil done exit set unset export function'); + + // Commands + define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' + + 'curl cut diff echo find gawk gcc get git grep kill killall ln ls make ' + + 'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' + + 'shopt shred source sort sleep ssh start stop su sudo tee telnet top ' + + 'touch vi vim wall wc wget who write yes zsh'); + + function tokenBase(stream, state) { + if (stream.eatSpace()) return null; + + var sol = stream.sol(); + var ch = stream.next(); + + if (ch === '\\') { + stream.next(); + return null; + } + if (ch === '\'' || ch === '"' || ch === '`') { + state.tokens.unshift(tokenString(ch)); + return tokenize(stream, state); + } + if (ch === '#') { + if (sol && stream.eat('!')) { + stream.skipToEnd(); + return 'meta'; // 'comment'? + } + stream.skipToEnd(); + return 'comment'; + } + if (ch === '$') { + state.tokens.unshift(tokenDollar); + return tokenize(stream, state); + } + if (ch === '+' || ch === '=') { + return 'operator'; + } + if (ch === '-') { + stream.eat('-'); + stream.eatWhile(/\w/); + return 'attribute'; + } + if (/\d/.test(ch)) { + stream.eatWhile(/\d/); + if(stream.eol() || !/\w/.test(stream.peek())) { + return 'number'; + } + } + stream.eatWhile(/[\w-]/); + var cur = stream.current(); + if (stream.peek() === '=' && /\w+/.test(cur)) return 'def'; + return words.hasOwnProperty(cur) ? words[cur] : null; + } + + function tokenString(quote) { + return function(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === quote && !escaped) { + end = true; + break; + } + if (next === '$' && !escaped && quote !== '\'') { + escaped = true; + stream.backUp(1); + state.tokens.unshift(tokenDollar); + break; + } + escaped = !escaped && next === '\\'; + } + if (end || !escaped) { + state.tokens.shift(); + } + return (quote === '`' || quote === ')' ? 'quote' : 'string'); + }; + }; + + var tokenDollar = function(stream, state) { + if (state.tokens.length > 1) stream.eat('$'); + var ch = stream.next(), hungry = /\w/; + if (ch === '{') hungry = /[^}]/; + if (ch === '(') { + state.tokens[0] = tokenString(')'); + return tokenize(stream, state); + } + if (!/\d/.test(ch)) { + stream.eatWhile(hungry); + stream.eat('}'); + } + state.tokens.shift(); + return 'def'; + }; + + function tokenize(stream, state) { + return (state.tokens[0] || tokenBase) (stream, state); + }; + + return { + startState: function() {return {tokens:[]};}, + token: function(stream, state) { + return tokenize(stream, state); + }, + lineComment: '#', + fold: "brace" + }; +}); + +CodeMirror.defineMIME('text/x-sh', 'shell'); + +}); diff --git a/rhodecode/public/js/mode/sieve/sieve.js b/rhodecode/public/js/mode/sieve/sieve.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/sieve/sieve.js @@ -0,0 +1,193 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sieve", function(config) { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = words("if elsif else stop require"); + var atoms = words("true false not"); + var indentUnit = config.indentUnit; + + function tokenBase(stream, state) { + + var ch = stream.next(); + if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + + if (ch === '#') { + stream.skipToEnd(); + return "comment"; + } + + if (ch == "\"") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + + if (ch == "(") { + state._indent.push("("); + // add virtual angel wings so that editor behaves... + // ...more sane incase of broken brackets + state._indent.push("{"); + return null; + } + + if (ch === "{") { + state._indent.push("{"); + return null; + } + + if (ch == ")") { + state._indent.pop(); + state._indent.pop(); + } + + if (ch === "}") { + state._indent.pop(); + return null; + } + + if (ch == ",") + return null; + + if (ch == ";") + return null; + + + if (/[{}\(\),;]/.test(ch)) + return null; + + // 1*DIGIT "K" / "M" / "G" + if (/\d/.test(ch)) { + stream.eatWhile(/[\d]/); + stream.eat(/[KkMmGg]/); + return "number"; + } + + // ":" (ALPHA / "_") *(ALPHA / DIGIT / "_") + if (ch == ":") { + stream.eatWhile(/[a-zA-Z_]/); + stream.eatWhile(/[a-zA-Z0-9_]/); + + return "operator"; + } + + stream.eatWhile(/\w/); + var cur = stream.current(); + + // "text:" *(SP / HTAB) (hash-comment / CRLF) + // *(multiline-literal / multiline-dotstart) + // "." CRLF + if ((cur == "text") && stream.eat(":")) + { + state.tokenize = tokenMultiLineString; + return "string"; + } + + if (keywords.propertyIsEnumerable(cur)) + return "keyword"; + + if (atoms.propertyIsEnumerable(cur)) + return "atom"; + + return null; + } + + function tokenMultiLineString(stream, state) + { + state._multiLineString = true; + // the first line is special it may contain a comment + if (!stream.sol()) { + stream.eatSpace(); + + if (stream.peek() == "#") { + stream.skipToEnd(); + return "comment"; + } + + stream.skipToEnd(); + return "string"; + } + + if ((stream.next() == ".") && (stream.eol())) + { + state._multiLineString = false; + state.tokenize = tokenBase; + } + + return "string"; + } + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) + break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return "string"; + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + _indent: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) + return null; + + return (state.tokenize || tokenBase)(stream, state);; + }, + + indent: function(state, _textAfter) { + var length = state._indent.length; + if (_textAfter && (_textAfter[0] == "}")) + length--; + + if (length <0) + length = 0; + + return length * indentUnit; + }, + + electricChars: "}" + }; +}); + +CodeMirror.defineMIME("application/sieve", "sieve"); + +}); diff --git a/rhodecode/public/js/mode/slim/slim.js b/rhodecode/public/js/mode/slim/slim.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/slim/slim.js @@ -0,0 +1,575 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + + CodeMirror.defineMode("slim", function(config) { + var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); + var rubyMode = CodeMirror.getMode(config, "ruby"); + var modes = { html: htmlMode, ruby: rubyMode }; + var embedded = { + ruby: "ruby", + javascript: "javascript", + css: "text/css", + sass: "text/x-sass", + scss: "text/x-scss", + less: "text/x-less", + styl: "text/x-styl", // no highlighting so far + coffee: "coffeescript", + asciidoc: "text/x-asciidoc", + markdown: "text/x-markdown", + textile: "text/x-textile", // no highlighting so far + creole: "text/x-creole", // no highlighting so far + wiki: "text/x-wiki", // no highlighting so far + mediawiki: "text/x-mediawiki", // no highlighting so far + rdoc: "text/x-rdoc", // no highlighting so far + builder: "text/x-builder", // no highlighting so far + nokogiri: "text/x-nokogiri", // no highlighting so far + erb: "application/x-erb" + }; + var embeddedRegexp = function(map){ + var arr = []; + for(var key in map) arr.push(key); + return new RegExp("^("+arr.join('|')+"):"); + }(embedded); + + var styleMap = { + "commentLine": "comment", + "slimSwitch": "operator special", + "slimTag": "tag", + "slimId": "attribute def", + "slimClass": "attribute qualifier", + "slimAttribute": "attribute", + "slimSubmode": "keyword special", + "closeAttributeTag": null, + "slimDoctype": null, + "lineContinuation": null + }; + var closing = { + "{": "}", + "[": "]", + "(": ")" + }; + + var nameStartChar = "_a-zA-Z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; + var nameChar = nameStartChar + "\\-0-9\xB7\u0300-\u036F\u203F-\u2040"; + var nameRegexp = new RegExp("^[:"+nameStartChar+"](?::["+nameChar+"]|["+nameChar+"]*)"); + var attributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*(?=\\s*=)"); + var wrappedAttributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*"); + var classNameRegexp = /^\.-?[_a-zA-Z]+[\w\-]*/; + var classIdRegexp = /^#[_a-zA-Z]+[\w\-]*/; + + function backup(pos, tokenize, style) { + var restore = function(stream, state) { + state.tokenize = tokenize; + if (stream.pos < pos) { + stream.pos = pos; + return style; + } + return state.tokenize(stream, state); + }; + return function(stream, state) { + state.tokenize = restore; + return tokenize(stream, state); + }; + } + + function maybeBackup(stream, state, pat, offset, style) { + var cur = stream.current(); + var idx = cur.search(pat); + if (idx > -1) { + state.tokenize = backup(stream.pos, state.tokenize, style); + stream.backUp(cur.length - idx - offset); + } + return style; + } + + function continueLine(state, column) { + state.stack = { + parent: state.stack, + style: "continuation", + indented: column, + tokenize: state.line + }; + state.line = state.tokenize; + } + function finishContinue(state) { + if (state.line == state.tokenize) { + state.line = state.stack.tokenize; + state.stack = state.stack.parent; + } + } + + function lineContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + if (stream.match(/^\\$/)) { + continueLine(state, column); + return "lineContinuation"; + } + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/(?:^|[^\\])(?:\\\\)*\\$/)) { + stream.backUp(1); + } + return style; + }; + } + function commaContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/,$/)) { + continueLine(state, column); + } + return style; + }; + } + + function rubyInQuote(endQuote, tokenize) { + // TODO: add multi line support + return function(stream, state) { + var ch = stream.peek(); + if (ch == endQuote && state.rubyState.tokenize.length == 1) { + // step out of ruby context as it seems to complete processing all the braces + stream.next(); + state.tokenize = tokenize; + return "closeAttributeTag"; + } else { + return ruby(stream, state); + } + }; + } + function startRubySplat(tokenize) { + var rubyState; + var runSplat = function(stream, state) { + if (state.rubyState.tokenize.length == 1 && !state.rubyState.context.prev) { + stream.backUp(1); + if (stream.eatSpace()) { + state.rubyState = rubyState; + state.tokenize = tokenize; + return tokenize(stream, state); + } + stream.next(); + } + return ruby(stream, state); + }; + return function(stream, state) { + rubyState = state.rubyState; + state.rubyState = rubyMode.startState(); + state.tokenize = runSplat; + return ruby(stream, state); + }; + } + + function ruby(stream, state) { + return rubyMode.token(stream, state.rubyState); + } + + function htmlLine(stream, state) { + if (stream.match(/^\\$/)) { + return "lineContinuation"; + } + return html(stream, state); + } + function html(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + return maybeBackup(stream, state, /[^\\]#\{/, 1, htmlMode.token(stream, state.htmlState)); + } + + function startHtmlLine(lastTokenize) { + return function(stream, state) { + var style = htmlLine(stream, state); + if (stream.eol()) state.tokenize = lastTokenize; + return style; + }; + } + + function startHtmlMode(stream, state, offset) { + state.stack = { + parent: state.stack, + style: "html", + indented: stream.column() + offset, // pipe + space + tokenize: state.line + }; + state.line = state.tokenize = html; + return null; + } + + function comment(stream, state) { + stream.skipToEnd(); + return state.stack.style; + } + + function commentMode(stream, state) { + state.stack = { + parent: state.stack, + style: "comment", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = comment; + return comment(stream, state); + } + + function attributeWrapper(stream, state) { + if (stream.eat(state.stack.endQuote)) { + state.line = state.stack.line; + state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + return null; + } + if (stream.match(wrappedAttributeNameRegexp)) { + state.tokenize = attributeWrapperAssign; + return "slimAttribute"; + } + stream.next(); + return null; + } + function attributeWrapperAssign(stream, state) { + if (stream.match(/^==?/)) { + state.tokenize = attributeWrapperValue; + return null; + } + return attributeWrapper(stream, state); + } + function attributeWrapperValue(stream, state) { + var ch = stream.peek(); + if (ch == '"' || ch == "\'") { + state.tokenize = readQuoted(ch, "string", true, false, attributeWrapper); + stream.next(); + return state.tokenize(stream, state); + } + if (ch == '[') { + return startRubySplat(attributeWrapper)(stream, state); + } + if (stream.match(/^(true|false|nil)\b/)) { + state.tokenize = attributeWrapper; + return "keyword"; + } + return startRubySplat(attributeWrapper)(stream, state); + } + + function startAttributeWrapperMode(state, endQuote, tokenize) { + state.stack = { + parent: state.stack, + style: "wrapper", + indented: state.indented + 1, + tokenize: tokenize, + line: state.line, + endQuote: endQuote + }; + state.line = state.tokenize = attributeWrapper; + return null; + } + + function sub(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + var subStream = new CodeMirror.StringStream(stream.string.slice(state.stack.indented), stream.tabSize); + subStream.pos = stream.pos - state.stack.indented; + subStream.start = stream.start - state.stack.indented; + subStream.lastColumnPos = stream.lastColumnPos - state.stack.indented; + subStream.lastColumnValue = stream.lastColumnValue - state.stack.indented; + var style = state.subMode.token(subStream, state.subState); + stream.pos = subStream.pos + state.stack.indented; + return style; + } + function firstSub(stream, state) { + state.stack.indented = stream.column(); + state.line = state.tokenize = sub; + return state.tokenize(stream, state); + } + + function createMode(mode) { + var query = embedded[mode]; + var spec = CodeMirror.mimeModes[query]; + if (spec) { + return CodeMirror.getMode(config, spec); + } + var factory = CodeMirror.modes[query]; + if (factory) { + return factory(config, {name: query}); + } + return CodeMirror.getMode(config, "null"); + } + + function getMode(mode) { + if (!modes.hasOwnProperty(mode)) { + return modes[mode] = createMode(mode); + } + return modes[mode]; + } + + function startSubMode(mode, state) { + var subMode = getMode(mode); + var subState = subMode.startState && subMode.startState(); + + state.subMode = subMode; + state.subState = subState; + + state.stack = { + parent: state.stack, + style: "sub", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = state.tokenize = firstSub; + return "slimSubmode"; + } + + function doctypeLine(stream, _state) { + stream.skipToEnd(); + return "slimDoctype"; + } + + function startLine(stream, state) { + var ch = stream.peek(); + if (ch == '<') { + return (state.tokenize = startHtmlLine(state.tokenize))(stream, state); + } + if (stream.match(/^[|']/)) { + return startHtmlMode(stream, state, 1); + } + if (stream.match(/^\/(!|\[\w+])?/)) { + return commentMode(stream, state); + } + if (stream.match(/^(-|==?[<>]?)/)) { + state.tokenize = lineContinuable(stream.column(), commaContinuable(stream.column(), ruby)); + return "slimSwitch"; + } + if (stream.match(/^doctype\b/)) { + state.tokenize = doctypeLine; + return "keyword"; + } + + var m = stream.match(embeddedRegexp); + if (m) { + return startSubMode(m[1], state); + } + + return slimTag(stream, state); + } + + function slim(stream, state) { + if (state.startOfLine) { + return startLine(stream, state); + } + return slimTag(stream, state); + } + + function slimTag(stream, state) { + if (stream.eat('*')) { + state.tokenize = startRubySplat(slimTagExtras); + return null; + } + if (stream.match(nameRegexp)) { + state.tokenize = slimTagExtras; + return "slimTag"; + } + return slimClass(stream, state); + } + function slimTagExtras(stream, state) { + if (stream.match(/^(<>?|><?)/)) { + state.tokenize = slimClass; + return null; + } + return slimClass(stream, state); + } + function slimClass(stream, state) { + if (stream.match(classIdRegexp)) { + state.tokenize = slimClass; + return "slimId"; + } + if (stream.match(classNameRegexp)) { + state.tokenize = slimClass; + return "slimClass"; + } + return slimAttribute(stream, state); + } + function slimAttribute(stream, state) { + if (stream.match(/^([\[\{\(])/)) { + return startAttributeWrapperMode(state, closing[RegExp.$1], slimAttribute); + } + if (stream.match(attributeNameRegexp)) { + state.tokenize = slimAttributeAssign; + return "slimAttribute"; + } + if (stream.peek() == '*') { + stream.next(); + state.tokenize = startRubySplat(slimContent); + return null; + } + return slimContent(stream, state); + } + function slimAttributeAssign(stream, state) { + if (stream.match(/^==?/)) { + state.tokenize = slimAttributeValue; + return null; + } + // should never happen, because of forward lookup + return slimAttribute(stream, state); + } + + function slimAttributeValue(stream, state) { + var ch = stream.peek(); + if (ch == '"' || ch == "\'") { + state.tokenize = readQuoted(ch, "string", true, false, slimAttribute); + stream.next(); + return state.tokenize(stream, state); + } + if (ch == '[') { + return startRubySplat(slimAttribute)(stream, state); + } + if (ch == ':') { + return startRubySplat(slimAttributeSymbols)(stream, state); + } + if (stream.match(/^(true|false|nil)\b/)) { + state.tokenize = slimAttribute; + return "keyword"; + } + return startRubySplat(slimAttribute)(stream, state); + } + function slimAttributeSymbols(stream, state) { + stream.backUp(1); + if (stream.match(/^[^\s],(?=:)/)) { + state.tokenize = startRubySplat(slimAttributeSymbols); + return null; + } + stream.next(); + return slimAttribute(stream, state); + } + function readQuoted(quote, style, embed, unescaped, nextTokenize) { + return function(stream, state) { + finishContinue(state); + var fresh = stream.current().length == 0; + if (stream.match(/^\\$/, fresh)) { + if (!fresh) return style; + continueLine(state, state.indented); + return "lineContinuation"; + } + if (stream.match(/^#\{/, fresh)) { + if (!fresh) return style; + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize = nextTokenize; + break; + } + if (embed && ch == "#" && !escaped) { + if (stream.eat("{")) { + stream.backUp(2); + break; + } + } + escaped = !escaped && ch == "\\"; + } + if (stream.eol() && escaped) { + stream.backUp(1); + } + return style; + }; + } + function slimContent(stream, state) { + if (stream.match(/^==?/)) { + state.tokenize = ruby; + return "slimSwitch"; + } + if (stream.match(/^\/$/)) { // tag close hint + state.tokenize = slim; + return null; + } + if (stream.match(/^:/)) { // inline tag + state.tokenize = slimTag; + return "slimSwitch"; + } + startHtmlMode(stream, state, 0); + return state.tokenize(stream, state); + } + + var mode = { + // default to html mode + startState: function() { + var htmlState = htmlMode.startState(); + var rubyState = rubyMode.startState(); + return { + htmlState: htmlState, + rubyState: rubyState, + stack: null, + last: null, + tokenize: slim, + line: slim, + indented: 0 + }; + }, + + copyState: function(state) { + return { + htmlState : CodeMirror.copyState(htmlMode, state.htmlState), + rubyState: CodeMirror.copyState(rubyMode, state.rubyState), + subMode: state.subMode, + subState: state.subMode && CodeMirror.copyState(state.subMode, state.subState), + stack: state.stack, + last: state.last, + tokenize: state.tokenize, + line: state.line + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.indented = stream.indentation(); + state.startOfLine = true; + state.tokenize = state.line; + while (state.stack && state.stack.indented > state.indented && state.last != "slimSubmode") { + state.line = state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + state.subMode = null; + state.subState = null; + } + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + state.startOfLine = false; + if (style) state.last = style; + return styleMap.hasOwnProperty(style) ? styleMap[style] : style; + }, + + blankLine: function(state) { + if (state.subMode && state.subMode.blankLine) { + return state.subMode.blankLine(state.subState); + } + }, + + innerMode: function(state) { + if (state.subMode) return {state: state.subState, mode: state.subMode}; + return {state: state, mode: mode}; + } + + //indent: function(state) { + // return state.indented; + //} + }; + return mode; + }, "htmlmixed", "ruby"); + + CodeMirror.defineMIME("text/x-slim", "slim"); + CodeMirror.defineMIME("application/x-slim", "slim"); +}); diff --git a/rhodecode/public/js/mode/smalltalk/smalltalk.js b/rhodecode/public/js/mode/smalltalk/smalltalk.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/smalltalk/smalltalk.js @@ -0,0 +1,168 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('smalltalk', function(config) { + + var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/; + var keywords = /true|false|nil|self|super|thisContext/; + + var Context = function(tokenizer, parent) { + this.next = tokenizer; + this.parent = parent; + }; + + var Token = function(name, context, eos) { + this.name = name; + this.context = context; + this.eos = eos; + }; + + var State = function() { + this.context = new Context(next, null); + this.expectVariable = true; + this.indentation = 0; + this.userIndentationDelta = 0; + }; + + State.prototype.userIndent = function(indentation) { + this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0; + }; + + var next = function(stream, context, state) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '"') { + token = nextComment(stream, new Context(nextComment, context)); + + } else if (aChar === '\'') { + token = nextString(stream, new Context(nextString, context)); + + } else if (aChar === '#') { + if (stream.peek() === '\'') { + stream.next(); + token = nextSymbol(stream, new Context(nextSymbol, context)); + } else { + if (stream.eatWhile(/[^\s.{}\[\]()]/)) + token.name = 'string-2'; + else + token.name = 'meta'; + } + + } else if (aChar === '$') { + if (stream.next() === '<') { + stream.eatWhile(/[^\s>]/); + stream.next(); + } + token.name = 'string-2'; + + } else if (aChar === '|' && state.expectVariable) { + token.context = new Context(nextTemporaries, context); + + } else if (/[\[\]{}()]/.test(aChar)) { + token.name = 'bracket'; + token.eos = /[\[{(]/.test(aChar); + + if (aChar === '[') { + state.indentation++; + } else if (aChar === ']') { + state.indentation = Math.max(0, state.indentation - 1); + } + + } else if (specialChars.test(aChar)) { + stream.eatWhile(specialChars); + token.name = 'operator'; + token.eos = aChar !== ';'; // ; cascaded message expression + + } else if (/\d/.test(aChar)) { + stream.eatWhile(/[\w\d]/); + token.name = 'number'; + + } else if (/[\w_]/.test(aChar)) { + stream.eatWhile(/[\w\d_]/); + token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null; + + } else { + token.eos = state.expectVariable; + } + + return token; + }; + + var nextComment = function(stream, context) { + stream.eatWhile(/[^"]/); + return new Token('comment', stream.eat('"') ? context.parent : context, true); + }; + + var nextString = function(stream, context) { + stream.eatWhile(/[^']/); + return new Token('string', stream.eat('\'') ? context.parent : context, false); + }; + + var nextSymbol = function(stream, context) { + stream.eatWhile(/[^']/); + return new Token('string-2', stream.eat('\'') ? context.parent : context, false); + }; + + var nextTemporaries = function(stream, context) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '|') { + token.context = context.parent; + token.eos = true; + + } else { + stream.eatWhile(/[^|]/); + token.name = 'variable'; + } + + return token; + }; + + return { + startState: function() { + return new State; + }, + + token: function(stream, state) { + state.userIndent(stream.indentation()); + + if (stream.eatSpace()) { + return null; + } + + var token = state.context.next(stream, state.context, state); + state.context = token.context; + state.expectVariable = token.eos; + + return token.name; + }, + + blankLine: function(state) { + state.userIndent(0); + }, + + indent: function(state, textAfter) { + var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta; + return (state.indentation + i) * config.indentUnit; + }, + + electricChars: ']' + }; + +}); + +CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); + +}); diff --git a/rhodecode/public/js/mode/smarty/smarty.js b/rhodecode/public/js/mode/smarty/smarty.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/smarty/smarty.js @@ -0,0 +1,225 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Smarty 2 and 3 mode. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("smarty", function(config, parserConf) { + var rightDelimiter = parserConf.rightDelimiter || "}"; + var leftDelimiter = parserConf.leftDelimiter || "{"; + var version = parserConf.version || 2; + var baseMode = CodeMirror.getMode(config, parserConf.baseMode || "null"); + + var keyFunctions = ["debug", "extends", "function", "include", "literal"]; + var regs = { + operatorChars: /[+\-*&%=<>!?]/, + validIdentifier: /[a-zA-Z0-9_]/, + stringChar: /['"]/ + }; + + var last; + function cont(style, lastType) { + last = lastType; + return style; + } + + function chain(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + } + + // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode + function doesNotCount(stream, pos) { + if (pos == null) pos = stream.pos; + return version === 3 && leftDelimiter == "{" && + (pos == stream.string.length || /\s/.test(stream.string.charAt(pos))); + } + + function tokenTop(stream, state) { + var string = stream.string; + for (var scan = stream.pos;;) { + var nextMatch = string.indexOf(leftDelimiter, scan); + scan = nextMatch + leftDelimiter.length; + if (nextMatch == -1 || !doesNotCount(stream, nextMatch + leftDelimiter.length)) break; + } + if (nextMatch == stream.pos) { + stream.match(leftDelimiter); + if (stream.eat("*")) { + return chain(stream, state, tokenBlock("comment", "*" + rightDelimiter)); + } else { + state.depth++; + state.tokenize = tokenSmarty; + last = "startTag"; + return "tag"; + } + } + + if (nextMatch > -1) stream.string = string.slice(0, nextMatch); + var token = baseMode.token(stream, state.base); + if (nextMatch > -1) stream.string = string; + return token; + } + + // parsing Smarty content + function tokenSmarty(stream, state) { + if (stream.match(rightDelimiter, true)) { + if (version === 3) { + state.depth--; + if (state.depth <= 0) { + state.tokenize = tokenTop; + } + } else { + state.tokenize = tokenTop; + } + return cont("tag", null); + } + + if (stream.match(leftDelimiter, true)) { + state.depth++; + return cont("tag", "startTag"); + } + + var ch = stream.next(); + if (ch == "$") { + stream.eatWhile(regs.validIdentifier); + return cont("variable-2", "variable"); + } else if (ch == "|") { + return cont("operator", "pipe"); + } else if (ch == ".") { + return cont("operator", "property"); + } else if (regs.stringChar.test(ch)) { + state.tokenize = tokenAttribute(ch); + return cont("string", "string"); + } else if (regs.operatorChars.test(ch)) { + stream.eatWhile(regs.operatorChars); + return cont("operator", "operator"); + } else if (ch == "[" || ch == "]") { + return cont("bracket", "bracket"); + } else if (ch == "(" || ch == ")") { + return cont("bracket", "operator"); + } else if (/\d/.test(ch)) { + stream.eatWhile(/\d/); + return cont("number", "number"); + } else { + + if (state.last == "variable") { + if (ch == "@") { + stream.eatWhile(regs.validIdentifier); + return cont("property", "property"); + } else if (ch == "|") { + stream.eatWhile(regs.validIdentifier); + return cont("qualifier", "modifier"); + } + } else if (state.last == "pipe") { + stream.eatWhile(regs.validIdentifier); + return cont("qualifier", "modifier"); + } else if (state.last == "whitespace") { + stream.eatWhile(regs.validIdentifier); + return cont("attribute", "modifier"); + } if (state.last == "property") { + stream.eatWhile(regs.validIdentifier); + return cont("property", null); + } else if (/\s/.test(ch)) { + last = "whitespace"; + return null; + } + + var str = ""; + if (ch != "/") { + str += ch; + } + var c = null; + while (c = stream.eat(regs.validIdentifier)) { + str += c; + } + for (var i=0, j=keyFunctions.length; i<j; i++) { + if (keyFunctions[i] == str) { + return cont("keyword", "keyword"); + } + } + if (/\s/.test(ch)) { + return null; + } + return cont("tag", "tag"); + } + } + + function tokenAttribute(quote) { + return function(stream, state) { + var prevChar = null; + var currChar = null; + while (!stream.eol()) { + currChar = stream.peek(); + if (stream.next() == quote && prevChar !== '\\') { + state.tokenize = tokenSmarty; + break; + } + prevChar = currChar; + } + return "string"; + }; + } + + function tokenBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = tokenTop; + break; + } + stream.next(); + } + return style; + }; + } + + return { + startState: function() { + return { + base: CodeMirror.startState(baseMode), + tokenize: tokenTop, + last: null, + depth: 0 + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(baseMode, state.base), + tokenize: state.tokenize, + last: state.last, + depth: state.depth + }; + }, + innerMode: function(state) { + if (state.tokenize == tokenTop) + return {mode: baseMode, state: state.base}; + }, + token: function(stream, state) { + var style = state.tokenize(stream, state); + state.last = last; + return style; + }, + indent: function(state, text) { + if (state.tokenize == tokenTop && baseMode.indent) + return baseMode.indent(state.base, text); + else + return CodeMirror.Pass; + }, + blockCommentStart: leftDelimiter + "*", + blockCommentEnd: "*" + rightDelimiter + }; + }); + + CodeMirror.defineMIME("text/x-smarty", "smarty"); +}); diff --git a/rhodecode/public/js/mode/solr/solr.js b/rhodecode/public/js/mode/solr/solr.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/solr/solr.js @@ -0,0 +1,104 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("solr", function() { + "use strict"; + + var isStringChar = /[^\s\|\!\+\-\*\?\~\^\&\:\(\)\[\]\{\}\^\"\\]/; + var isOperatorChar = /[\|\!\+\-\*\?\~\^\&]/; + var isOperatorString = /^(OR|AND|NOT|TO)$/i; + + function isNumber(word) { + return parseFloat(word, 10).toString() === word; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + + if (!escaped) state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenOperator(operator) { + return function(stream, state) { + var style = "operator"; + if (operator == "+") + style += " positive"; + else if (operator == "-") + style += " negative"; + else if (operator == "|") + stream.eat(/\|/); + else if (operator == "&") + stream.eat(/\&/); + else if (operator == "^") + style += " boost"; + + state.tokenize = tokenBase; + return style; + }; + } + + function tokenWord(ch) { + return function(stream, state) { + var word = ch; + while ((ch = stream.peek()) && ch.match(isStringChar) != null) { + word += stream.next(); + } + + state.tokenize = tokenBase; + if (isOperatorString.test(word)) + return "operator"; + else if (isNumber(word)) + return "number"; + else if (stream.peek() == ":") + return "field"; + else + return "string"; + }; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"') + state.tokenize = tokenString(ch); + else if (isOperatorChar.test(ch)) + state.tokenize = tokenOperator(ch); + else if (isStringChar.test(ch)) + state.tokenize = tokenWord(ch); + + return (state.tokenize != tokenBase) ? state.tokenize(stream, state) : null; + } + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME("text/x-solr", "solr"); + +}); diff --git a/rhodecode/public/js/mode/soy/soy.js b/rhodecode/public/js/mode/soy/soy.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/soy/soy.js @@ -0,0 +1,198 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var indentingTags = ["template", "literal", "msg", "fallbackmsg", "let", "if", "elseif", + "else", "switch", "case", "default", "foreach", "ifempty", "for", + "call", "param", "deltemplate", "delcall", "log"]; + + CodeMirror.defineMode("soy", function(config) { + var textMode = CodeMirror.getMode(config, "text/plain"); + var modes = { + html: CodeMirror.getMode(config, {name: "text/html", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false}), + attributes: textMode, + text: textMode, + uri: textMode, + css: CodeMirror.getMode(config, "text/css"), + js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit}) + }; + + function last(array) { + return array[array.length - 1]; + } + + function tokenUntil(stream, state, untilRegExp) { + var oldString = stream.string; + var match = untilRegExp.exec(oldString.substr(stream.pos)); + if (match) { + // We don't use backUp because it backs up just the position, not the state. + // This uses an undocumented API. + stream.string = oldString.substr(0, stream.pos + match.index); + } + var result = stream.hideFirstChars(state.indent, function() { + return state.localMode.token(stream, state.localState); + }); + stream.string = oldString; + return result; + } + + return { + startState: function() { + return { + kind: [], + kindTag: [], + soyState: [], + indent: 0, + localMode: modes.html, + localState: CodeMirror.startState(modes.html) + }; + }, + + copyState: function(state) { + return { + tag: state.tag, // Last seen Soy tag. + kind: state.kind.concat([]), // Values of kind="" attributes. + kindTag: state.kindTag.concat([]), // Opened tags with kind="" attributes. + soyState: state.soyState.concat([]), + indent: state.indent, // Indentation of the following line. + localMode: state.localMode, + localState: CodeMirror.copyState(state.localMode, state.localState) + }; + }, + + token: function(stream, state) { + var match; + + switch (last(state.soyState)) { + case "comment": + if (stream.match(/^.*?\*\//)) { + state.soyState.pop(); + } else { + stream.skipToEnd(); + } + return "comment"; + + case "variable": + if (stream.match(/^}/)) { + state.indent -= 2 * config.indentUnit; + state.soyState.pop(); + return "variable-2"; + } + stream.next(); + return null; + + case "tag": + if (stream.match(/^\/?}/)) { + if (state.tag == "/template" || state.tag == "/deltemplate") state.indent = 0; + else state.indent -= (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit; + state.soyState.pop(); + return "keyword"; + } else if (stream.match(/^([\w?]+)(?==)/)) { + if (stream.current() == "kind" && (match = stream.match(/^="([^"]+)/, false))) { + var kind = match[1]; + state.kind.push(kind); + state.kindTag.push(state.tag); + state.localMode = modes[kind] || modes.html; + state.localState = CodeMirror.startState(state.localMode); + } + return "attribute"; + } else if (stream.match(/^"/)) { + state.soyState.push("string"); + return "string"; + } + stream.next(); + return null; + + case "literal": + if (stream.match(/^(?=\{\/literal})/)) { + state.indent -= config.indentUnit; + state.soyState.pop(); + return this.token(stream, state); + } + return tokenUntil(stream, state, /\{\/literal}/); + + case "string": + if (stream.match(/^.*?"/)) { + state.soyState.pop(); + } else { + stream.skipToEnd(); + } + return "string"; + } + + if (stream.match(/^\/\*/)) { + state.soyState.push("comment"); + return "comment"; + } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { + return "comment"; + } else if (stream.match(/^\{\$[\w?]*/)) { + state.indent += 2 * config.indentUnit; + state.soyState.push("variable"); + return "variable-2"; + } else if (stream.match(/^\{literal}/)) { + state.indent += config.indentUnit; + state.soyState.push("literal"); + return "keyword"; + } else if (match = stream.match(/^\{([\/@\\]?[\w?]*)/)) { + if (match[1] != "/switch") + state.indent += (/^(\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit; + state.tag = match[1]; + if (state.tag == "/" + last(state.kindTag)) { + // We found the tag that opened the current kind="". + state.kind.pop(); + state.kindTag.pop(); + state.localMode = modes[last(state.kind)] || modes.html; + state.localState = CodeMirror.startState(state.localMode); + } + state.soyState.push("tag"); + return "keyword"; + } + + return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/); + }, + + indent: function(state, textAfter) { + var indent = state.indent, top = last(state.soyState); + if (top == "comment") return CodeMirror.Pass; + + if (top == "literal") { + if (/^\{\/literal}/.test(textAfter)) indent -= config.indentUnit; + } else { + if (/^\s*\{\/(template|deltemplate)\b/.test(textAfter)) return 0; + if (/^\{(\/|(fallbackmsg|elseif|else|ifempty)\b)/.test(textAfter)) indent -= config.indentUnit; + if (state.tag != "switch" && /^\{(case|default)\b/.test(textAfter)) indent -= config.indentUnit; + if (/^\{\/switch\b/.test(textAfter)) indent -= config.indentUnit; + } + if (indent && state.localMode.indent) + indent += state.localMode.indent(state.localState, textAfter); + return indent; + }, + + innerMode: function(state) { + if (state.soyState.length && last(state.soyState) != "literal") return null; + else return {state: state.localState, mode: state.localMode}; + }, + + electricInput: /^\s*\{(\/|\/template|\/deltemplate|\/switch|fallbackmsg|elseif|else|case|default|ifempty|\/literal\})$/, + lineComment: "//", + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + fold: "indent" + }; + }, "htmlmixed"); + + CodeMirror.registerHelper("hintWords", "soy", indentingTags.concat( + ["delpackage", "namespace", "alias", "print", "css", "debugger"])); + + CodeMirror.defineMIME("text/x-soy", "soy"); +}); diff --git a/rhodecode/public/js/mode/sparql/sparql.js b/rhodecode/public/js/mode/sparql/sparql.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/sparql/sparql.js @@ -0,0 +1,174 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sparql", function(config) { + var indentUnit = config.indentUnit; + var curPunc; + + function wordRegexp(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri", + "iri", "uri", "bnode", "count", "sum", "min", "max", "avg", "sample", + "group_concat", "rand", "abs", "ceil", "floor", "round", "concat", "substr", "strlen", + "replace", "ucase", "lcase", "encode_for_uri", "contains", "strstarts", "strends", + "strbefore", "strafter", "year", "month", "day", "hours", "minutes", "seconds", + "timezone", "tz", "now", "uuid", "struuid", "md5", "sha1", "sha256", "sha384", + "sha512", "coalesce", "if", "strlang", "strdt", "isnumeric", "regex", "exists", + "isblank", "isliteral", "a"]); + var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe", + "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional", + "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group", + "minus", "in", "not", "service", "silent", "using", "insert", "delete", "union", + "true", "false", "with", + "data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]); + var operatorChars = /[*+\-<>=&|\^\/!\?]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + curPunc = null; + if (ch == "$" || ch == "?") { + if(ch == "?" && stream.match(/\s/, false)){ + return "operator"; + } + stream.match(/^[\w\d]*/); + return "variable-2"; + } + else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { + stream.match(/^[^\s\u00a0>]*>?/); + return "atom"; + } + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } + else if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return "bracket"; + } + else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return "operator"; + } + else if (ch == ":") { + stream.eatWhile(/[\w\d\._\-]/); + return "atom"; + } + else if (ch == "@") { + stream.eatWhile(/[a-z\d\-]/i); + return "meta"; + } + else { + stream.eatWhile(/[_\w\d]/); + if (stream.eat(":")) { + stream.eatWhile(/[\w\d_\-]/); + return "atom"; + } + var word = stream.current(); + if (ops.test(word)) + return "builtin"; + else if (keywords.test(word)) + return "keyword"; + else + return "variable"; + } + } + + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function pushContext(state, type, col) { + state.context = {prev: state.context, indent: state.indent, col: col, type: type}; + } + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + context: null, + indent: 0, + col: 0}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) state.context.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { + state.context.align = true; + } + + if (curPunc == "(") pushContext(state, ")", stream.column()); + else if (curPunc == "[") pushContext(state, "]", stream.column()); + else if (curPunc == "{") pushContext(state, "}", stream.column()); + else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type == "pattern") popContext(state); + if (state.context && curPunc == state.context.type) popContext(state); + } + else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); + else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) + pushContext(state, "pattern", stream.column()); + else if (state.context.type == "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + + return style; + }, + + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) + while (context && context.type == "pattern") context = context.prev; + + var closing = context && firstChar == context.type; + if (!context) + return 0; + else if (context.type == "pattern") + return context.col; + else if (context.align) + return context.col + (closing ? 0 : 1); + else + return context.indent + (closing ? 0 : indentUnit); + } + }; +}); + +CodeMirror.defineMIME("application/sparql-query", "sparql"); + +}); diff --git a/rhodecode/public/js/mode/spreadsheet/spreadsheet.js b/rhodecode/public/js/mode/spreadsheet/spreadsheet.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/spreadsheet/spreadsheet.js @@ -0,0 +1,109 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("spreadsheet", function () { + return { + startState: function () { + return { + stringType: null, + stack: [] + }; + }, + token: function (stream, state) { + if (!stream) return; + + //check for state changes + if (state.stack.length === 0) { + //strings + if ((stream.peek() == '"') || (stream.peek() == "'")) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.stack.unshift("string"); + } + } + + //return state + //stack has + switch (state.stack[0]) { + case "string": + while (state.stack[0] === "string" && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.stack.shift(); // Clear flag + } else if (stream.peek() === "\\") { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return "string"; + + case "characterClass": + while (state.stack[0] === "characterClass" && !stream.eol()) { + if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) + state.stack.shift(); + } + return "operator"; + } + + var peek = stream.peek(); + + //no stack + switch (peek) { + case "[": + stream.next(); + state.stack.unshift("characterClass"); + return "bracket"; + case ":": + stream.next(); + return "operator"; + case "\\": + if (stream.match(/\\[a-z]+/)) return "string-2"; + else return null; + case ".": + case ",": + case ";": + case "*": + case "-": + case "+": + case "^": + case "<": + case "/": + case "=": + stream.next(); + return "atom"; + case "$": + stream.next(); + return "builtin"; + } + + if (stream.match(/\d+/)) { + if (stream.match(/^\w+/)) return "error"; + return "number"; + } else if (stream.match(/^[a-zA-Z_]\w*/)) { + if (stream.match(/(?=[\(.])/, false)) return "keyword"; + return "variable-2"; + } else if (["[", "]", "(", ")", "{", "}"].indexOf(peek) != -1) { + stream.next(); + return "bracket"; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; + }); + + CodeMirror.defineMIME("text/x-spreadsheet", "spreadsheet"); +}); diff --git a/rhodecode/public/js/mode/sql/sql.js b/rhodecode/public/js/mode/sql/sql.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/sql/sql.js @@ -0,0 +1,391 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sql", function(config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords || {}, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (support.hexNumber == true && + ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) { + // hex + // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html + return "number"; + } else if (support.binaryNumber == true && + (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) + || (ch == "0" && stream.match(/^b[01]+/)))) { + // bitstring + // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html + return "number"; + } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { + // placeholders + return "variable-3"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if ((((support.nCharCast == true && (ch == "n" || ch == "N")) + || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) + && (stream.peek() == "'" || stream.peek() == '"'))) { + // charset casting: _utf8'str', N'str', n'str' + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + return "keyword"; + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) { + // 1-line comment + stream.skipToEnd(); + return "comment"; + } else if ((support.commentHash && ch == "#") + || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + // .table_name (ODBC) + // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) { + return "variable-2"; + } + } else if (operatorChars.test(ch)) { + // operators + stream.eatWhile(operatorChars); + return null; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + return "number"; + } else { + stream.eatWhile(/^[_\w\d]/); + var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev: state.context, + indent: stream.indentation(), + col: stream.column(), + type: type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent: function(state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null + }; +}); + +(function() { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + }; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where "; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME("text/x-sql", { + name: "sql", + keywords: set(sqlKeywords + "begin"), + builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); + + CodeMirror.defineMIME("text/x-mssql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare"), + builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"), + hooks: { + "@": hookVar + } + }); + + CodeMirror.defineMIME("text/x-mysql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group group_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + CodeMirror.defineMIME("text/x-mariadb", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + // the query language used by Apache Cassandra is called CQL, but this mime type + // is called Cassandra to avoid confusion with Contextual Query Language + CodeMirror.defineMIME("text/x-cassandra", { + name: "sql", + client: { }, + keywords: set("add all allow alter and any apply as asc authorize batch begin by clustering columnfamily compact consistency count create custom delete desc distinct drop each_quorum exists filtering from grant if in index insert into key keyspace keyspaces level limit local_one local_quorum modify nan norecursive nosuperuser not of on one order password permission permissions primary quorum rename revoke schema select set storage superuser table three to token truncate ttl two type unlogged update use user users using values where with writetime"), + builtin: set("ascii bigint blob boolean counter decimal double float frozen inet int list map static text timestamp timeuuid tuple uuid varchar varint"), + atoms: set("false true infinity NaN"), + operatorChars: /^[<>=]/, + dateSQL: { }, + support: set("commentSlashSlash decimallessFloat"), + hooks: { } + }); + + // this is based on Peter Raganitsch's 'plsql' mode + CodeMirror.defineMIME("text/x-plsql", { + name: "sql", + client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), + keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), + builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"), + operatorChars: /^[*+\-%<>!=~]/, + dateSQL: set("date time timestamp"), + support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") + }); + + // Created to support specific hive keywords + CodeMirror.defineMIME("text/x-hive", { + name: "sql", + keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with"), + builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); +}()); + +}); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. +*/ diff --git a/rhodecode/public/js/mode/stex/stex.js b/rhodecode/public/js/mode/stex/stex.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/stex/stex.js @@ -0,0 +1,251 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de) + * Licence: MIT + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("stex", function() { + "use strict"; + + function pushCommand(state, command) { + state.cmdState.push(command); + } + + function peekCommand(state) { + if (state.cmdState.length > 0) { + return state.cmdState[state.cmdState.length - 1]; + } else { + return null; + } + } + + function popCommand(state) { + var plug = state.cmdState.pop(); + if (plug) { + plug.closeBracket(); + } + } + + // returns the non-default plugin closest to the end of the list + function getMostPowerful(state) { + var context = state.cmdState; + for (var i = context.length - 1; i >= 0; i--) { + var plug = context[i]; + if (plug.name == "DEFAULT") { + continue; + } + return plug; + } + return { styleIdentifier: function() { return null; } }; + } + + function addPluginPattern(pluginName, cmdStyle, styles) { + return function () { + this.name = pluginName; + this.bracketNo = 0; + this.style = cmdStyle; + this.styles = styles; + this.argument = null; // \begin and \end have arguments that follow. These are stored in the plugin + + this.styleIdentifier = function() { + return this.styles[this.bracketNo - 1] || null; + }; + this.openBracket = function() { + this.bracketNo++; + return "bracket"; + }; + this.closeBracket = function() {}; + }; + } + + var plugins = {}; + + plugins["importmodule"] = addPluginPattern("importmodule", "tag", ["string", "builtin"]); + plugins["documentclass"] = addPluginPattern("documentclass", "tag", ["", "atom"]); + plugins["usepackage"] = addPluginPattern("usepackage", "tag", ["atom"]); + plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]); + plugins["end"] = addPluginPattern("end", "tag", ["atom"]); + + plugins["DEFAULT"] = function () { + this.name = "DEFAULT"; + this.style = "tag"; + + this.styleIdentifier = this.openBracket = this.closeBracket = function() {}; + }; + + function setState(state, f) { + state.f = f; + } + + // called when in a normal (no environment) context + function normal(source, state) { + var plug; + // Do we look like '\command' ? If so, attempt to apply the plugin 'command' + if (source.match(/^\\[a-zA-Z@]+/)) { + var cmdName = source.current().slice(1); + plug = plugins[cmdName] || plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + setState(state, beginParams); + return plug.style; + } + + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + + // white space control characters + if (source.match(/^\\[,;!\/\\]/)) { + return "tag"; + } + + // find if we're starting various math modes + if (source.match("\\[")) { + setState(state, function(source, state){ return inMathMode(source, state, "\\]"); }); + return "keyword"; + } + if (source.match("$$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$$"); }); + return "keyword"; + } + if (source.match("$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$"); }); + return "keyword"; + } + + var ch = source.next(); + if (ch == "%") { + source.skipToEnd(); + return "comment"; + } else if (ch == '}' || ch == ']') { + plug = peekCommand(state); + if (plug) { + plug.closeBracket(ch); + setState(state, beginParams); + } else { + return "error"; + } + return "bracket"; + } else if (ch == '{' || ch == '[') { + plug = plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + return "bracket"; + } else if (/\d/.test(ch)) { + source.eatWhile(/[\w.%]/); + return "atom"; + } else { + source.eatWhile(/[\w\-_]/); + plug = getMostPowerful(state); + if (plug.name == 'begin') { + plug.argument = source.current(); + } + return plug.styleIdentifier(); + } + } + + function inMathMode(source, state, endModeSeq) { + if (source.eatSpace()) { + return null; + } + if (source.match(endModeSeq)) { + setState(state, normal); + return "keyword"; + } + if (source.match(/^\\[a-zA-Z@]+/)) { + return "tag"; + } + if (source.match(/^[a-zA-Z]+/)) { + return "variable-2"; + } + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + // white space control characters + if (source.match(/^\\[,;!\/]/)) { + return "tag"; + } + // special math-mode characters + if (source.match(/^[\^_&]/)) { + return "tag"; + } + // non-special characters + if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) { + return null; + } + if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) { + return "number"; + } + var ch = source.next(); + if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") { + return "bracket"; + } + + if (ch == "%") { + source.skipToEnd(); + return "comment"; + } + return "error"; + } + + function beginParams(source, state) { + var ch = source.peek(), lastPlug; + if (ch == '{' || ch == '[') { + lastPlug = peekCommand(state); + lastPlug.openBracket(ch); + source.eat(ch); + setState(state, normal); + return "bracket"; + } + if (/[ \t\r]/.test(ch)) { + source.eat(ch); + return null; + } + setState(state, normal); + popCommand(state); + + return normal(source, state); + } + + return { + startState: function() { + return { + cmdState: [], + f: normal + }; + }, + copyState: function(s) { + return { + cmdState: s.cmdState.slice(), + f: s.f + }; + }, + token: function(stream, state) { + return state.f(stream, state); + }, + blankLine: function(state) { + state.f = normal; + state.cmdState.length = 0; + }, + lineComment: "%" + }; + }); + + CodeMirror.defineMIME("text/x-stex", "stex"); + CodeMirror.defineMIME("text/x-latex", "stex"); + +}); diff --git a/rhodecode/public/js/mode/stylus/stylus.js b/rhodecode/public/js/mode/stylus/stylus.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/stylus/stylus.js @@ -0,0 +1,768 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Stylus mode created by Dmitry Kiselyov http://git.io/AaRB + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("stylus", function(config) { + var indentUnit = config.indentUnit, + tagKeywords = keySet(tagKeywords_), + tagVariablesRegexp = /^(a|b|i|s|col|em)$/i, + propertyKeywords = keySet(propertyKeywords_), + nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_), + valueKeywords = keySet(valueKeywords_), + colorKeywords = keySet(colorKeywords_), + documentTypes = keySet(documentTypes_), + documentTypesRegexp = wordRegexp(documentTypes_), + mediaFeatures = keySet(mediaFeatures_), + mediaTypes = keySet(mediaTypes_), + fontProperties = keySet(fontProperties_), + operatorsRegexp = /^\s*([.]{2,3}|&&|\|\||\*\*|[?!=:]?=|[-+*\/%<>]=?|\?:|\~)/, + wordOperatorKeywordsRegexp = wordRegexp(wordOperatorKeywords_), + blockKeywords = keySet(blockKeywords_), + vendorPrefixesRegexp = new RegExp(/^\-(moz|ms|o|webkit)-/i), + commonAtoms = keySet(commonAtoms_), + firstWordMatch = "", + states = {}, + ch, + style, + type, + override; + + /** + * Tokenizers + */ + function tokenBase(stream, state) { + firstWordMatch = stream.string.match(/(^[\w-]+\s*=\s*$)|(^\s*[\w-]+\s*=\s*[\w-])|(^\s*(\.|#|@|\$|\&|\[|\d|\+|::?|\{|\>|~|\/)?\s*[\w-]*([a-z0-9-]|\*|\/\*)(\(|,)?)/); + state.context.line.firstWord = firstWordMatch ? firstWordMatch[0].replace(/^\s*/, "") : ""; + state.context.line.indent = stream.indentation(); + ch = stream.peek(); + + // Line comment + if (stream.match("//")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } + // Block comment + if (stream.match("/*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + // String + if (ch == "\"" || ch == "'") { + stream.next(); + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + // Def + if (ch == "@") { + stream.next(); + stream.eatWhile(/[\w\\-]/); + return ["def", stream.current()]; + } + // ID selector or Hex color + if (ch == "#") { + stream.next(); + // Hex color + if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) { + return ["atom", "atom"]; + } + // ID selector + if (stream.match(/^[a-z][\w-]*/i)) { + return ["builtin", "hash"]; + } + } + // Vendor prefixes + if (stream.match(vendorPrefixesRegexp)) { + return ["meta", "vendor-prefixes"]; + } + // Numbers + if (stream.match(/^-?[0-9]?\.?[0-9]/)) { + stream.eatWhile(/[a-z%]/i); + return ["number", "unit"]; + } + // !important|optional + if (ch == "!") { + stream.next(); + return [stream.match(/^(important|optional)/i) ? "keyword": "operator", "important"]; + } + // Class + if (ch == "." && stream.match(/^\.[a-z][\w-]*/i)) { + return ["qualifier", "qualifier"]; + } + // url url-prefix domain regexp + if (stream.match(documentTypesRegexp)) { + if (stream.peek() == "(") state.tokenize = tokenParenthesized; + return ["property", "word"]; + } + // Mixins / Functions + if (stream.match(/^[a-z][\w-]*\(/i)) { + stream.backUp(1); + return ["keyword", "mixin"]; + } + // Block mixins + if (stream.match(/^(\+|-)[a-z][\w-]*\(/i)) { + stream.backUp(1); + return ["keyword", "block-mixin"]; + } + // Parent Reference BEM naming + if (stream.string.match(/^\s*&/) && stream.match(/^[-_]+[a-z][\w-]*/)) { + return ["qualifier", "qualifier"]; + } + // / Root Reference & Parent Reference + if (stream.match(/^(\/|&)(-|_|:|\.|#|[a-z])/)) { + stream.backUp(1); + return ["variable-3", "reference"]; + } + if (stream.match(/^&{1}\s*$/)) { + return ["variable-3", "reference"]; + } + // Variable + if (ch == "$" && stream.match(/^\$[\w-]+/i)) { + return ["variable-2", "variable-name"]; + } + // Word operator + if (stream.match(wordOperatorKeywordsRegexp)) { + return ["operator", "operator"]; + } + // Word + if (stream.match(/^[-_]*[a-z0-9]+[\w-]*/i)) { + if (stream.match(/^(\.|\[)[\w-\'\"\]]+/i, false)) { + if (!wordIsTag(stream.current())) { + stream.match(/[\w-]+/); + return ["variable-2", "variable-name"]; + } + } + return ["variable-2", "word"]; + } + // Operators + if (stream.match(operatorsRegexp)) { + return ["operator", stream.current()]; + } + // Delimiters + if (/[:;,{}\[\]\(\)]/.test(ch)) { + stream.next(); + return [null, ch]; + } + // Non-detected items + stream.next(); + return [null, null]; + } + + /** + * Token comment + */ + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + /** + * Token string + */ + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ["string", "string"]; + }; + } + + /** + * Token parenthesized + */ + function tokenParenthesized(stream, state) { + stream.next(); // Must be "(" + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return [null, "("]; + } + + /** + * Context management + */ + function Context(type, indent, prev, line) { + this.type = type; + this.indent = indent; + this.prev = prev; + this.line = line || {firstWord: "", indent: 0}; + } + + function pushContext(state, stream, type, indent) { + indent = indent >= 0 ? indent : indentUnit; + state.context = new Context(type, stream.indentation() + indent, state.context); + return type; + } + + function popContext(state, currentIndent) { + var contextIndent = state.context.indent - indentUnit; + currentIndent = currentIndent || false; + state.context = state.context.prev; + if (currentIndent) state.context.indent = contextIndent; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + + /** + * Parser + */ + function wordIsTag(word) { + return word.toLowerCase() in tagKeywords; + } + + function wordIsProperty(word) { + word = word.toLowerCase(); + return word in propertyKeywords || word in fontProperties; + } + + function wordIsBlock(word) { + return word.toLowerCase() in blockKeywords; + } + + function wordIsVendorPrefix(word) { + return word.toLowerCase().match(vendorPrefixesRegexp); + } + + function wordAsValue(word) { + var wordLC = word.toLowerCase(); + var override = "variable-2"; + if (wordIsTag(word)) override = "tag"; + else if (wordIsBlock(word)) override = "block-keyword"; + else if (wordIsProperty(word)) override = "property"; + else if (wordLC in valueKeywords || wordLC in commonAtoms) override = "atom"; + else if (wordLC == "return" || wordLC in colorKeywords) override = "keyword"; + + // Font family + else if (word.match(/^[A-Z]/)) override = "string"; + return override; + } + + function typeIsBlock(type, stream) { + return ((endOfLine(stream) && (type == "{" || type == "]" || type == "hash" || type == "qualifier")) || type == "block-mixin"); + } + + function typeIsInterpolation(type, stream) { + return type == "{" && stream.match(/^\s*\$?[\w-]+/i, false); + } + + function typeIsPseudo(type, stream) { + return type == ":" && stream.match(/^[a-z-]+/, false); + } + + function startOfLine(stream) { + return stream.sol() || stream.string.match(new RegExp("^\\s*" + escapeRegExp(stream.current()))); + } + + function endOfLine(stream) { + return stream.eol() || stream.match(/^\s*$/, false); + } + + function firstWordOfLine(line) { + var re = /^\s*[-_]*[a-z0-9]+[\w-]*/i; + var result = typeof line == "string" ? line.match(re) : line.string.match(re); + return result ? result[0].replace(/^\s*/, "") : ""; + } + + + /** + * Block + */ + states.block = function(type, stream, state) { + if ((type == "comment" && startOfLine(stream)) || + (type == "," && endOfLine(stream)) || + type == "mixin") { + return pushContext(state, stream, "block", 0); + } + if (typeIsInterpolation(type, stream)) { + return pushContext(state, stream, "interpolation"); + } + if (endOfLine(stream) && type == "]") { + if (!/^\s*(\.|#|:|\[|\*|&)/.test(stream.string) && !wordIsTag(firstWordOfLine(stream))) { + return pushContext(state, stream, "block", 0); + } + } + if (typeIsBlock(type, stream, state)) { + return pushContext(state, stream, "block"); + } + if (type == "}" && endOfLine(stream)) { + return pushContext(state, stream, "block", 0); + } + if (type == "variable-name") { + if ((stream.indentation() == 0 && startOfLine(stream)) || wordIsBlock(firstWordOfLine(stream))) { + return pushContext(state, stream, "variableName"); + } + else { + return pushContext(state, stream, "variableName", 0); + } + } + if (type == "=") { + if (!endOfLine(stream) && !wordIsBlock(firstWordOfLine(stream))) { + return pushContext(state, stream, "block", 0); + } + return pushContext(state, stream, "block"); + } + if (type == "*") { + if (endOfLine(stream) || stream.match(/\s*(,|\.|#|\[|:|{)/,false)) { + override = "tag"; + return pushContext(state, stream, "block"); + } + } + if (typeIsPseudo(type, stream)) { + return pushContext(state, stream, "pseudo"); + } + if (/@(font-face|media|supports|(-moz-)?document)/.test(type)) { + return pushContext(state, stream, endOfLine(stream) ? "block" : "atBlock"); + } + if (/@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { + return pushContext(state, stream, "keyframes"); + } + if (/@extends?/.test(type)) { + return pushContext(state, stream, "extend", 0); + } + if (type && type.charAt(0) == "@") { + + // Property Lookup + if (stream.indentation() > 0 && wordIsProperty(stream.current().slice(1))) { + override = "variable-2"; + return "block"; + } + if (/(@import|@require|@charset)/.test(type)) { + return pushContext(state, stream, "block", 0); + } + return pushContext(state, stream, "block"); + } + if (type == "reference" && endOfLine(stream)) { + return pushContext(state, stream, "block"); + } + if (type == "(") { + return pushContext(state, stream, "parens"); + } + + if (type == "vendor-prefixes") { + return pushContext(state, stream, "vendorPrefixes"); + } + if (type == "word") { + var word = stream.current(); + override = wordAsValue(word); + + if (override == "property") { + if (startOfLine(stream)) { + return pushContext(state, stream, "block", 0); + } else { + override = "atom"; + return "block"; + } + } + + if (override == "tag") { + + // tag is a css value + if (/embed|menu|pre|progress|sub|table/.test(word)) { + if (wordIsProperty(firstWordOfLine(stream))) { + override = "atom"; + return "block"; + } + } + + // tag is an attribute + if (stream.string.match(new RegExp("\\[\\s*" + word + "|" + word +"\\s*\\]"))) { + override = "atom"; + return "block"; + } + + // tag is a variable + if (tagVariablesRegexp.test(word)) { + if ((startOfLine(stream) && stream.string.match(/=/)) || + (!startOfLine(stream) && + !stream.string.match(/^(\s*\.|#|\&|\[|\/|>|\*)/) && + !wordIsTag(firstWordOfLine(stream)))) { + override = "variable-2"; + if (wordIsBlock(firstWordOfLine(stream))) return "block"; + return pushContext(state, stream, "block", 0); + } + } + + if (endOfLine(stream)) return pushContext(state, stream, "block"); + } + if (override == "block-keyword") { + override = "keyword"; + + // Postfix conditionals + if (stream.current(/(if|unless)/) && !startOfLine(stream)) { + return "block"; + } + return pushContext(state, stream, "block"); + } + if (word == "return") return pushContext(state, stream, "block", 0); + } + return state.context.type; + }; + + + /** + * Parens + */ + states.parens = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "parens"); + if (type == ")") { + if (state.context.prev.type == "parens") { + return popContext(state); + } + if ((stream.string.match(/^[a-z][\w-]*\(/i) && endOfLine(stream)) || + wordIsBlock(firstWordOfLine(stream)) || + /(\.|#|:|\[|\*|&|>|~|\+|\/)/.test(firstWordOfLine(stream)) || + (!stream.string.match(/^-?[a-z][\w-\.\[\]\'\"]*\s*=/) && + wordIsTag(firstWordOfLine(stream)))) { + return pushContext(state, stream, "block"); + } + if (stream.string.match(/^[\$-]?[a-z][\w-\.\[\]\'\"]*\s*=/) || + stream.string.match(/^\s*(\(|\)|[0-9])/) || + stream.string.match(/^\s+[a-z][\w-]*\(/i) || + stream.string.match(/^\s+[\$-]?[a-z]/i)) { + return pushContext(state, stream, "block", 0); + } + if (endOfLine(stream)) return pushContext(state, stream, "block"); + else return pushContext(state, stream, "block", 0); + } + if (type && type.charAt(0) == "@" && wordIsProperty(stream.current().slice(1))) { + override = "variable-2"; + } + if (type == "word") { + var word = stream.current(); + override = wordAsValue(word); + if (override == "tag" && tagVariablesRegexp.test(word)) { + override = "variable-2"; + } + if (override == "property" || word == "to") override = "atom"; + } + if (type == "variable-name") { + return pushContext(state, stream, "variableName"); + } + if (typeIsPseudo(type, stream)) { + return pushContext(state, stream, "pseudo"); + } + return state.context.type; + }; + + + /** + * Vendor prefixes + */ + states.vendorPrefixes = function(type, stream, state) { + if (type == "word") { + override = "property"; + return pushContext(state, stream, "block", 0); + } + return popContext(state); + }; + + + /** + * Pseudo + */ + states.pseudo = function(type, stream, state) { + if (!wordIsProperty(firstWordOfLine(stream.string))) { + stream.match(/^[a-z-]+/); + override = "variable-3"; + if (endOfLine(stream)) return pushContext(state, stream, "block"); + return popContext(state); + } + return popAndPass(type, stream, state); + }; + + + /** + * atBlock + */ + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); + if (typeIsBlock(type, stream, state)) { + return pushContext(state, stream, "block"); + } + if (typeIsInterpolation(type, stream)) { + return pushContext(state, stream, "interpolation"); + } + if (type == "word") { + var word = stream.current().toLowerCase(); + if (/^(only|not|and|or)$/.test(word)) + override = "keyword"; + else if (documentTypes.hasOwnProperty(word)) + override = "tag"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else override = wordAsValue(stream.current()); + if (override == "tag" && endOfLine(stream)) { + return pushContext(state, stream, "block"); + } + } + if (type == "operator" && /^(not|and|or)$/.test(stream.current())) { + override = "keyword"; + } + return state.context.type; + }; + + states.atBlock_parens = function(type, stream, state) { + if (type == "{" || type == "}") return state.context.type; + if (type == ")") { + if (endOfLine(stream)) return pushContext(state, stream, "block"); + else return pushContext(state, stream, "atBlock"); + } + if (type == "word") { + var word = stream.current().toLowerCase(); + override = wordAsValue(word); + if (/^(max|min)/.test(word)) override = "property"; + if (override == "tag") { + tagVariablesRegexp.test(word) ? override = "variable-2" : override = "atom"; + } + return state.context.type; + } + return states.atBlock(type, stream, state); + }; + + + /** + * Keyframes + */ + states.keyframes = function(type, stream, state) { + if (stream.indentation() == "0" && ((type == "}" && startOfLine(stream)) || type == "]" || type == "hash" + || type == "qualifier" || wordIsTag(stream.current()))) { + return popAndPass(type, stream, state); + } + if (type == "{") return pushContext(state, stream, "keyframes"); + if (type == "}") { + if (startOfLine(stream)) return popContext(state, true); + else return pushContext(state, stream, "keyframes"); + } + if (type == "unit" && /^[0-9]+\%$/.test(stream.current())) { + return pushContext(state, stream, "keyframes"); + } + if (type == "word") { + override = wordAsValue(stream.current()); + if (override == "block-keyword") { + override = "keyword"; + return pushContext(state, stream, "keyframes"); + } + } + if (/@(font-face|media|supports|(-moz-)?document)/.test(type)) { + return pushContext(state, stream, endOfLine(stream) ? "block" : "atBlock"); + } + if (type == "mixin") { + return pushContext(state, stream, "block", 0); + } + return state.context.type; + }; + + + /** + * Interpolation + */ + states.interpolation = function(type, stream, state) { + if (type == "{") popContext(state) && pushContext(state, stream, "block"); + if (type == "}") { + if (stream.string.match(/^\s*(\.|#|:|\[|\*|&|>|~|\+|\/)/i) || + (stream.string.match(/^\s*[a-z]/i) && wordIsTag(firstWordOfLine(stream)))) { + return pushContext(state, stream, "block"); + } + if (!stream.string.match(/^(\{|\s*\&)/) || + stream.match(/\s*[\w-]/,false)) { + return pushContext(state, stream, "block", 0); + } + return pushContext(state, stream, "block"); + } + if (type == "variable-name") { + return pushContext(state, stream, "variableName", 0); + } + if (type == "word") { + override = wordAsValue(stream.current()); + if (override == "tag") override = "atom"; + } + return state.context.type; + }; + + + /** + * Extend/s + */ + states.extend = function(type, stream, state) { + if (type == "[" || type == "=") return "extend"; + if (type == "]") return popContext(state); + if (type == "word") { + override = wordAsValue(stream.current()); + return "extend"; + } + return popContext(state); + }; + + + /** + * Variable name + */ + states.variableName = function(type, stream, state) { + if (type == "string" || type == "[" || type == "]" || stream.current().match(/^(\.|\$)/)) { + if (stream.current().match(/^\.[\w-]+/i)) override = "variable-2"; + if (endOfLine(stream)) return popContext(state); + return "variableName"; + } + return popAndPass(type, stream, state); + }; + + + return { + startState: function(base) { + return { + tokenize: null, + state: "block", + context: new Context("block", base || 0, null) + }; + }, + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + state.state = states[state.state](type, stream, state); + return override; + }, + indent: function(state, textAfter, line) { + + var cx = state.context, + ch = textAfter && textAfter.charAt(0), + indent = cx.indent, + lineFirstWord = firstWordOfLine(textAfter), + lineIndent = line.length - line.replace(/^\s*/, "").length, + prevLineFirstWord = state.context.prev ? state.context.prev.line.firstWord : "", + prevLineIndent = state.context.prev ? state.context.prev.line.indent : lineIndent; + + if (cx.prev && + (ch == "}" && (cx.type == "block" || cx.type == "atBlock" || cx.type == "keyframes") || + ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at"))) { + indent = cx.indent - indentUnit; + cx = cx.prev; + } else if (!(/(\})/.test(ch))) { + if (/@|\$|\d/.test(ch) || + /^\{/.test(textAfter) || +/^\s*\/(\/|\*)/.test(textAfter) || + /^\s*\/\*/.test(prevLineFirstWord) || + /^\s*[\w-\.\[\]\'\"]+\s*(\?|:|\+)?=/i.test(textAfter) || +/^(\+|-)?[a-z][\w-]*\(/i.test(textAfter) || +/^return/.test(textAfter) || + wordIsBlock(lineFirstWord)) { + indent = lineIndent; + } else if (/(\.|#|:|\[|\*|&|>|~|\+|\/)/.test(ch) || wordIsTag(lineFirstWord)) { + if (/\,\s*$/.test(prevLineFirstWord)) { + indent = prevLineIndent; + } else if (/^\s+/.test(line) && (/(\.|#|:|\[|\*|&|>|~|\+|\/)/.test(prevLineFirstWord) || wordIsTag(prevLineFirstWord))) { + indent = lineIndent <= prevLineIndent ? prevLineIndent : prevLineIndent + indentUnit; + } else { + indent = lineIndent; + } + } else if (!/,\s*$/.test(line) && (wordIsVendorPrefix(lineFirstWord) || wordIsProperty(lineFirstWord))) { + if (wordIsBlock(prevLineFirstWord)) { + indent = lineIndent <= prevLineIndent ? prevLineIndent : prevLineIndent + indentUnit; + } else if (/^\{/.test(prevLineFirstWord)) { + indent = lineIndent <= prevLineIndent ? lineIndent : prevLineIndent + indentUnit; + } else if (wordIsVendorPrefix(prevLineFirstWord) || wordIsProperty(prevLineFirstWord)) { + indent = lineIndent >= prevLineIndent ? prevLineIndent : lineIndent; + } else if (/^(\.|#|:|\[|\*|&|@|\+|\-|>|~|\/)/.test(prevLineFirstWord) || + /=\s*$/.test(prevLineFirstWord) || + wordIsTag(prevLineFirstWord) || + /^\$[\w-\.\[\]\'\"]/.test(prevLineFirstWord)) { + indent = prevLineIndent + indentUnit; + } else { + indent = lineIndent; + } + } + } + return indent; + }, + electricChars: "}", + lineComment: "//", + fold: "indent" + }; + }); + + // developer.mozilla.org/en-US/docs/Web/HTML/Element + var tagKeywords_ = ["a","abbr","address","area","article","aside","audio", "b", "base","bdi", "bdo","bgsound","blockquote","body","br","button","canvas","caption","cite", "code","col","colgroup","data","datalist","dd","del","details","dfn","div", "dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1", "h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe", "img","input","ins","kbd","keygen","label","legend","li","link","main","map", "mark","marquee","menu","menuitem","meta","meter","nav","nobr","noframes", "noscript","object","ol","optgroup","option","output","p","param","pre", "progress","q","rp","rt","ruby","s","samp","script","section","select", "small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","track", "u","ul","var","video"]; + + // github.com/codemirror/CodeMirror/blob/master/mode/css/css.js + var documentTypes_ = ["domain", "regexp", "url", "url-prefix"]; + var mediaTypes_ = ["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"]; + var mediaFeatures_ = ["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"]; + var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"]; + var nonStandardPropertyKeywords_ = ["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"]; + var fontProperties_ = ["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]; + var colorKeywords_ = ["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]; + var valueKeywords_ = ["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale"]; + + var wordOperatorKeywords_ = ["in","and","or","not","is not","is a","is","isnt","defined","if unless"], + blockKeywords_ = ["for","if","else","unless", "from", "to"], + commonAtoms_ = ["null","true","false","href","title","type","not-allowed","readonly","disabled"], + commonDef_ = ["@font-face", "@keyframes", "@media", "@viewport", "@page", "@host", "@supports", "@block", "@css"]; + + var hintWords = tagKeywords_.concat(documentTypes_,mediaTypes_,mediaFeatures_, + propertyKeywords_,nonStandardPropertyKeywords_, + colorKeywords_,valueKeywords_,fontProperties_, + wordOperatorKeywords_,blockKeywords_, + commonAtoms_,commonDef_); + + function wordRegexp(words) { + words = words.sort(function(a,b){return b > a;}); + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) keys[array[i]] = true; + return keys; + } + + function escapeRegExp(text) { + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + } + + CodeMirror.registerHelper("hintWords", "stylus", hintWords); + CodeMirror.defineMIME("text/x-styl", "stylus"); +}); diff --git a/rhodecode/public/js/mode/swift/swift.js b/rhodecode/public/js/mode/swift/swift.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/swift/swift.js @@ -0,0 +1,203 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Swift mode created by Michael Kaminsky https://github.com/mkaminsky11 + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) + define(["../../lib/codemirror"], mod) + else + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + + function trim(str) { return /^\s*(.*?)\s*$/.exec(str)[1] } + + var separators = [" ","\\\+","\\\-","\\\(","\\\)","\\\*","/",":","\\\?","\\\<","\\\>"," ","\\\."] + var tokens = new RegExp(separators.join("|"),"g") + + function getWord(string, pos) { + var index = -1, count = 1 + var words = string.split(tokens) + for (var i = 0; i < words.length; i++) { + for(var j = 1; j <= words[i].length; j++) { + if (count==pos) index = i + count++ + } + count++ + } + var ret = ["", ""] + if (pos == 0) { + ret[1] = words[0] + ret[0] = null + } else { + ret[1] = words[index] + ret[0] = words[index-1] + } + return ret + } + + CodeMirror.defineMode("swift", function() { + var keywords=["var","let","class","deinit","enum","extension","func","import","init","let","protocol","static","struct","subscript","typealias","var","as","dynamicType","is","new","super","self","Self","Type","__COLUMN__","__FILE__","__FUNCTION__","__LINE__","break","case","continue","default","do","else","fallthrough","if","in","for","return","switch","where","while","associativity","didSet","get","infix","inout","left","mutating","none","nonmutating","operator","override","postfix","precedence","prefix","right","set","unowned","unowned(safe)","unowned(unsafe)","weak","willSet"] + var commonConstants=["Infinity","NaN","undefined","null","true","false","on","off","yes","no","nil","null","this","super"] + var types=["String","bool","int","string","double","Double","Int","Float","float","public","private","extension"] + var numbers=["0","1","2","3","4","5","6","7","8","9"] + var operators=["+","-","/","*","%","=","|","&","<",">"] + var punc=[";",",",".","(",")","{","}","[","]"] + var delimiters=/^(?:[()\[\]{},:`=;]|\.\.?\.?)/ + var identifiers=/^[_A-Za-z$][_A-Za-z$0-9]*/ + var properties=/^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/ + var regexPrefixes=/^(\/{3}|\/)/ + + return { + startState: function() { + return { + prev: false, + string: false, + escape: false, + inner: false, + comment: false, + num_left: 0, + num_right: 0, + doubleString: false, + singleString: false + } + }, + token: function(stream, state) { + if (stream.eatSpace()) return null + + var ch = stream.next() + if (state.string) { + if (state.escape) { + state.escape = false + return "string" + } else { + if ((ch == "\"" && (state.doubleString && !state.singleString) || + (ch == "'" && (!state.doubleString && state.singleString))) && + !state.escape) { + state.string = false + state.doubleString = false + state.singleString = false + return "string" + } else if (ch == "\\" && stream.peek() == "(") { + state.inner = true + state.string = false + return "keyword" + } else if (ch == "\\" && stream.peek() != "(") { + state.escape = true + state.string = true + return "string" + } else { + return "string" + } + } + } else if (state.comment) { + if (ch == "*" && stream.peek() == "/") { + state.prev = "*" + return "comment" + } else if (ch == "/" && state.prev == "*") { + state.prev = false + state.comment = false + return "comment" + } + return "comment" + } else { + if (ch == "/") { + if (stream.peek() == "/") { + stream.skipToEnd() + return "comment" + } + if (stream.peek() == "*") { + state.comment = true + return "comment" + } + } + if (ch == "(" && state.inner) { + state.num_left++ + return null + } + if (ch == ")" && state.inner) { + state.num_right++ + if (state.num_left == state.num_right) { + state.inner=false + state.string=true + } + return null + } + + var ret = getWord(stream.string, stream.pos) + var the_word = ret[1] + var prev_word = ret[0] + + if (operators.indexOf(ch + "") > -1) return "operator" + if (punc.indexOf(ch) > -1) return "punctuation" + + if (typeof the_word != "undefined") { + the_word = trim(the_word) + if (typeof prev_word != "undefined") prev_word = trim(prev_word) + if (the_word.charAt(0) == "#") return null + + if (types.indexOf(the_word) > -1) return "def" + if (commonConstants.indexOf(the_word) > -1) return "atom" + if (numbers.indexOf(the_word) > -1) return "number" + + if ((numbers.indexOf(the_word.charAt(0) + "") > -1 || + operators.indexOf(the_word.charAt(0) + "") > -1) && + numbers.indexOf(ch) > -1) { + return "number" + } + + if (keywords.indexOf(the_word) > -1 || + keywords.indexOf(the_word.split(tokens)[0]) > -1) + return "keyword" + if (keywords.indexOf(prev_word) > -1) return "def" + } + if (ch == '"' && !state.doubleString) { + state.string = true + state.doubleString = true + return "string" + } + if (ch == "'" && !state.singleString) { + state.string = true + state.singleString = true + return "string" + } + if (ch == "(" && state.inner) + state.num_left++ + if (ch == ")" && state.inner) { + state.num_right++ + if (state.num_left == state.num_right) { + state.inner = false + state.string = true + } + return null + } + if (stream.match(/^-?[0-9\.]/, false)) { + if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i) || + stream.match(/^-?\d+\.\d*/) || + stream.match(/^-?\.\d+/)) { + if (stream.peek() == ".") stream.backUp(1) + return "number" + } + if (stream.match(/^-?0x[0-9a-f]+/i) || + stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/) || + stream.match(/^-?0(?![\dx])/i)) + return "number" + } + if (stream.match(regexPrefixes)) { + if (stream.current()!="/" || stream.match(/^.*\//,false)) return "string" + else stream.backUp(1) + } + if (stream.match(delimiters)) return "punctuation" + if (stream.match(identifiers)) return "variable" + if (stream.match(properties)) return "property" + return "variable" + } + } + } + }) + + CodeMirror.defineMIME("text/x-swift","swift") +}) diff --git a/rhodecode/public/js/mode/tcl/tcl.js b/rhodecode/public/js/mode/tcl/tcl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/tcl/tcl.js @@ -0,0 +1,147 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +//tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("tcl", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = parseWords("Tcl safe after append array auto_execok auto_import auto_load " + + "auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror " + + "binary break catch cd close concat continue dde eof encoding error " + + "eval exec exit expr fblocked fconfigure fcopy file fileevent filename " + + "filename flush for foreach format gets glob global history http if " + + "incr info interp join lappend lindex linsert list llength load lrange " + + "lreplace lsearch lset lsort memory msgcat namespace open package parray " + + "pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp " + + "registry regsub rename resource return scan seek set socket source split " + + "string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord " + + "tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest " + + "tclvars tell time trace unknown unset update uplevel upvar variable " + + "vwait"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if ((ch == '"' || ch == "'") && state.inParams) + return chain(stream, state, tokenString(ch)); + else if (/[\[\]{}\(\),;\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "#" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == "#" && stream.match(/ *\[ *\[/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == "#" && stream.eat("#")) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.skipTo(/"/); + return "comment"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.{:]/); + stream.eatWhile(/}/); + state.beforeParams = true; + return "builtin"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "comment"; + } + else { + stream.eatWhile(/[\w\$_{}\xa1-\uffff]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == "]") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); +CodeMirror.defineMIME("text/x-tcl", "tcl"); + +}); diff --git a/rhodecode/public/js/mode/textile/textile.js b/rhodecode/public/js/mode/textile/textile.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/textile/textile.js @@ -0,0 +1,469 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") { // CommonJS + mod(require("../../lib/codemirror")); + } else if (typeof define == "function" && define.amd) { // AMD + define(["../../lib/codemirror"], mod); + } else { // Plain browser env + mod(CodeMirror); + } +})(function(CodeMirror) { + "use strict"; + + var TOKEN_STYLES = { + addition: "positive", + attributes: "attribute", + bold: "strong", + cite: "keyword", + code: "atom", + definitionList: "number", + deletion: "negative", + div: "punctuation", + em: "em", + footnote: "variable", + footCite: "qualifier", + header: "header", + html: "comment", + image: "string", + italic: "em", + link: "link", + linkDefinition: "link", + list1: "variable-2", + list2: "variable-3", + list3: "keyword", + notextile: "string-2", + pre: "operator", + p: "property", + quote: "bracket", + span: "quote", + specialChar: "tag", + strong: "strong", + sub: "builtin", + sup: "builtin", + table: "variable-3", + tableHeading: "operator" + }; + + function startNewLine(stream, state) { + state.mode = Modes.newLayout; + state.tableHeading = false; + + if (state.layoutType === "definitionList" && state.spanningLayout && + stream.match(RE("definitionListEnd"), false)) + state.spanningLayout = false; + } + + function handlePhraseModifier(stream, state, ch) { + if (ch === "_") { + if (stream.eat("_")) + return togglePhraseModifier(stream, state, "italic", /__/, 2); + else + return togglePhraseModifier(stream, state, "em", /_/, 1); + } + + if (ch === "*") { + if (stream.eat("*")) { + return togglePhraseModifier(stream, state, "bold", /\*\*/, 2); + } + return togglePhraseModifier(stream, state, "strong", /\*/, 1); + } + + if (ch === "[") { + if (stream.match(/\d+\]/)) state.footCite = true; + return tokenStyles(state); + } + + if (ch === "(") { + var spec = stream.match(/^(r|tm|c)\)/); + if (spec) + return tokenStylesWith(state, TOKEN_STYLES.specialChar); + } + + if (ch === "<" && stream.match(/(\w+)[^>]+>[^<]+<\/\1>/)) + return tokenStylesWith(state, TOKEN_STYLES.html); + + if (ch === "?" && stream.eat("?")) + return togglePhraseModifier(stream, state, "cite", /\?\?/, 2); + + if (ch === "=" && stream.eat("=")) + return togglePhraseModifier(stream, state, "notextile", /==/, 2); + + if (ch === "-" && !stream.eat("-")) + return togglePhraseModifier(stream, state, "deletion", /-/, 1); + + if (ch === "+") + return togglePhraseModifier(stream, state, "addition", /\+/, 1); + + if (ch === "~") + return togglePhraseModifier(stream, state, "sub", /~/, 1); + + if (ch === "^") + return togglePhraseModifier(stream, state, "sup", /\^/, 1); + + if (ch === "%") + return togglePhraseModifier(stream, state, "span", /%/, 1); + + if (ch === "@") + return togglePhraseModifier(stream, state, "code", /@/, 1); + + if (ch === "!") { + var type = togglePhraseModifier(stream, state, "image", /(?:\([^\)]+\))?!/, 1); + stream.match(/^:\S+/); // optional Url portion + return type; + } + return tokenStyles(state); + } + + function togglePhraseModifier(stream, state, phraseModifier, closeRE, openSize) { + var charBefore = stream.pos > openSize ? stream.string.charAt(stream.pos - openSize - 1) : null; + var charAfter = stream.peek(); + if (state[phraseModifier]) { + if ((!charAfter || /\W/.test(charAfter)) && charBefore && /\S/.test(charBefore)) { + var type = tokenStyles(state); + state[phraseModifier] = false; + return type; + } + } else if ((!charBefore || /\W/.test(charBefore)) && charAfter && /\S/.test(charAfter) && + stream.match(new RegExp("^.*\\S" + closeRE.source + "(?:\\W|$)"), false)) { + state[phraseModifier] = true; + state.mode = Modes.attributes; + } + return tokenStyles(state); + }; + + function tokenStyles(state) { + var disabled = textileDisabled(state); + if (disabled) return disabled; + + var styles = []; + if (state.layoutType) styles.push(TOKEN_STYLES[state.layoutType]); + + styles = styles.concat(activeStyles( + state, "addition", "bold", "cite", "code", "deletion", "em", "footCite", + "image", "italic", "link", "span", "strong", "sub", "sup", "table", "tableHeading")); + + if (state.layoutType === "header") + styles.push(TOKEN_STYLES.header + "-" + state.header); + + return styles.length ? styles.join(" ") : null; + } + + function textileDisabled(state) { + var type = state.layoutType; + + switch(type) { + case "notextile": + case "code": + case "pre": + return TOKEN_STYLES[type]; + default: + if (state.notextile) + return TOKEN_STYLES.notextile + (type ? (" " + TOKEN_STYLES[type]) : ""); + return null; + } + } + + function tokenStylesWith(state, extraStyles) { + var disabled = textileDisabled(state); + if (disabled) return disabled; + + var type = tokenStyles(state); + if (extraStyles) + return type ? (type + " " + extraStyles) : extraStyles; + else + return type; + } + + function activeStyles(state) { + var styles = []; + for (var i = 1; i < arguments.length; ++i) { + if (state[arguments[i]]) + styles.push(TOKEN_STYLES[arguments[i]]); + } + return styles; + } + + function blankLine(state) { + var spanningLayout = state.spanningLayout, type = state.layoutType; + + for (var key in state) if (state.hasOwnProperty(key)) + delete state[key]; + + state.mode = Modes.newLayout; + if (spanningLayout) { + state.layoutType = type; + state.spanningLayout = true; + } + } + + var REs = { + cache: {}, + single: { + bc: "bc", + bq: "bq", + definitionList: /- [^(?::=)]+:=+/, + definitionListEnd: /.*=:\s*$/, + div: "div", + drawTable: /\|.*\|/, + foot: /fn\d+/, + header: /h[1-6]/, + html: /\s*<(?:\/)?(\w+)(?:[^>]+)?>(?:[^<]+<\/\1>)?/, + link: /[^"]+":\S/, + linkDefinition: /\[[^\s\]]+\]\S+/, + list: /(?:#+|\*+)/, + notextile: "notextile", + para: "p", + pre: "pre", + table: "table", + tableCellAttributes: /[\/\\]\d+/, + tableHeading: /\|_\./, + tableText: /[^"_\*\[\(\?\+~\^%@|-]+/, + text: /[^!"_=\*\[\(<\?\+~\^%@-]+/ + }, + attributes: { + align: /(?:<>|<|>|=)/, + selector: /\([^\(][^\)]+\)/, + lang: /\[[^\[\]]+\]/, + pad: /(?:\(+|\)+){1,2}/, + css: /\{[^\}]+\}/ + }, + createRe: function(name) { + switch (name) { + case "drawTable": + return REs.makeRe("^", REs.single.drawTable, "$"); + case "html": + return REs.makeRe("^", REs.single.html, "(?:", REs.single.html, ")*", "$"); + case "linkDefinition": + return REs.makeRe("^", REs.single.linkDefinition, "$"); + case "listLayout": + return REs.makeRe("^", REs.single.list, RE("allAttributes"), "*\\s+"); + case "tableCellAttributes": + return REs.makeRe("^", REs.choiceRe(REs.single.tableCellAttributes, + RE("allAttributes")), "+\\."); + case "type": + return REs.makeRe("^", RE("allTypes")); + case "typeLayout": + return REs.makeRe("^", RE("allTypes"), RE("allAttributes"), + "*\\.\\.?", "(\\s+|$)"); + case "attributes": + return REs.makeRe("^", RE("allAttributes"), "+"); + + case "allTypes": + return REs.choiceRe(REs.single.div, REs.single.foot, + REs.single.header, REs.single.bc, REs.single.bq, + REs.single.notextile, REs.single.pre, REs.single.table, + REs.single.para); + + case "allAttributes": + return REs.choiceRe(REs.attributes.selector, REs.attributes.css, + REs.attributes.lang, REs.attributes.align, REs.attributes.pad); + + default: + return REs.makeRe("^", REs.single[name]); + } + }, + makeRe: function() { + var pattern = ""; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + pattern += (typeof arg === "string") ? arg : arg.source; + } + return new RegExp(pattern); + }, + choiceRe: function() { + var parts = [arguments[0]]; + for (var i = 1; i < arguments.length; ++i) { + parts[i * 2 - 1] = "|"; + parts[i * 2] = arguments[i]; + } + + parts.unshift("(?:"); + parts.push(")"); + return REs.makeRe.apply(null, parts); + } + }; + + function RE(name) { + return (REs.cache[name] || (REs.cache[name] = REs.createRe(name))); + } + + var Modes = { + newLayout: function(stream, state) { + if (stream.match(RE("typeLayout"), false)) { + state.spanningLayout = false; + return (state.mode = Modes.blockType)(stream, state); + } + var newMode; + if (!textileDisabled(state)) { + if (stream.match(RE("listLayout"), false)) + newMode = Modes.list; + else if (stream.match(RE("drawTable"), false)) + newMode = Modes.table; + else if (stream.match(RE("linkDefinition"), false)) + newMode = Modes.linkDefinition; + else if (stream.match(RE("definitionList"))) + newMode = Modes.definitionList; + else if (stream.match(RE("html"), false)) + newMode = Modes.html; + } + return (state.mode = (newMode || Modes.text))(stream, state); + }, + + blockType: function(stream, state) { + var match, type; + state.layoutType = null; + + if (match = stream.match(RE("type"))) + type = match[0]; + else + return (state.mode = Modes.text)(stream, state); + + if (match = type.match(RE("header"))) { + state.layoutType = "header"; + state.header = parseInt(match[0][1]); + } else if (type.match(RE("bq"))) { + state.layoutType = "quote"; + } else if (type.match(RE("bc"))) { + state.layoutType = "code"; + } else if (type.match(RE("foot"))) { + state.layoutType = "footnote"; + } else if (type.match(RE("notextile"))) { + state.layoutType = "notextile"; + } else if (type.match(RE("pre"))) { + state.layoutType = "pre"; + } else if (type.match(RE("div"))) { + state.layoutType = "div"; + } else if (type.match(RE("table"))) { + state.layoutType = "table"; + } + + state.mode = Modes.attributes; + return tokenStyles(state); + }, + + text: function(stream, state) { + if (stream.match(RE("text"))) return tokenStyles(state); + + var ch = stream.next(); + if (ch === '"') + return (state.mode = Modes.link)(stream, state); + return handlePhraseModifier(stream, state, ch); + }, + + attributes: function(stream, state) { + state.mode = Modes.layoutLength; + + if (stream.match(RE("attributes"))) + return tokenStylesWith(state, TOKEN_STYLES.attributes); + else + return tokenStyles(state); + }, + + layoutLength: function(stream, state) { + if (stream.eat(".") && stream.eat(".")) + state.spanningLayout = true; + + state.mode = Modes.text; + return tokenStyles(state); + }, + + list: function(stream, state) { + var match = stream.match(RE("list")); + state.listDepth = match[0].length; + var listMod = (state.listDepth - 1) % 3; + if (!listMod) + state.layoutType = "list1"; + else if (listMod === 1) + state.layoutType = "list2"; + else + state.layoutType = "list3"; + + state.mode = Modes.attributes; + return tokenStyles(state); + }, + + link: function(stream, state) { + state.mode = Modes.text; + if (stream.match(RE("link"))) { + stream.match(/\S+/); + return tokenStylesWith(state, TOKEN_STYLES.link); + } + return tokenStyles(state); + }, + + linkDefinition: function(stream, state) { + stream.skipToEnd(); + return tokenStylesWith(state, TOKEN_STYLES.linkDefinition); + }, + + definitionList: function(stream, state) { + stream.match(RE("definitionList")); + + state.layoutType = "definitionList"; + + if (stream.match(/\s*$/)) + state.spanningLayout = true; + else + state.mode = Modes.attributes; + + return tokenStyles(state); + }, + + html: function(stream, state) { + stream.skipToEnd(); + return tokenStylesWith(state, TOKEN_STYLES.html); + }, + + table: function(stream, state) { + state.layoutType = "table"; + return (state.mode = Modes.tableCell)(stream, state); + }, + + tableCell: function(stream, state) { + if (stream.match(RE("tableHeading"))) + state.tableHeading = true; + else + stream.eat("|"); + + state.mode = Modes.tableCellAttributes; + return tokenStyles(state); + }, + + tableCellAttributes: function(stream, state) { + state.mode = Modes.tableText; + + if (stream.match(RE("tableCellAttributes"))) + return tokenStylesWith(state, TOKEN_STYLES.attributes); + else + return tokenStyles(state); + }, + + tableText: function(stream, state) { + if (stream.match(RE("tableText"))) + return tokenStyles(state); + + if (stream.peek() === "|") { // end of cell + state.mode = Modes.tableCell; + return tokenStyles(state); + } + return handlePhraseModifier(stream, state, stream.next()); + } + }; + + CodeMirror.defineMode("textile", function() { + return { + startState: function() { + return { mode: Modes.newLayout }; + }, + token: function(stream, state) { + if (stream.sol()) startNewLine(stream, state); + return state.mode(stream, state); + }, + blankLine: blankLine + }; + }); + + CodeMirror.defineMIME("text/x-textile", "textile"); +}); diff --git a/rhodecode/public/js/mode/tiddlywiki/tiddlywiki.js b/rhodecode/public/js/mode/tiddlywiki/tiddlywiki.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/tiddlywiki/tiddlywiki.js @@ -0,0 +1,358 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/*** + |''Name''|tiddlywiki.js| + |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror| + |''Author''|PMario| + |''Version''|0.1.7| + |''Status''|''stable''| + |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]| + |''Documentation''|http://codemirror.tiddlyspace.com/| + |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]| + |''CoreVersion''|2.5.0| + |''Requires''|codemirror.js| + |''Keywords''|syntax highlighting color code mirror codemirror| + ! Info + CoreVersion parameter is needed for TiddlyWiki only! +***/ +//{{{ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("tiddlywiki", function () { + // Tokenizer + var textwords = {}; + + var keywords = function () { + function kw(type) { + return { type: type, style: "macro"}; + } + return { + "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'), + "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'), + "permaview": kw('permaview'), "saveChanges": kw('saveChanges'), + "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'), + "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'), + "tiddler": kw('tiddler'), "timeline": kw('timeline'), + "today": kw('today'), "version": kw('version'), "option": kw('option'), + + "with": kw('with'), + "filter": kw('filter') + }; + }(); + + var isSpaceName = /[\w_\-]/i, + reHR = /^\-\-\-\-+$/, // <hr> + reWikiCommentStart = /^\/\*\*\*$/, // /*** + reWikiCommentStop = /^\*\*\*\/$/, // ***/ + reBlockQuote = /^<<<$/, + + reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start + reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop + reXmlCodeStart = /^<!--\{\{\{-->$/, // xml block start + reXmlCodeStop = /^<!--\}\}\}-->$/, // xml stop + + reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start + reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop + + reUntilCodeStop = /.*?\}\}\}/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function jsTokenBase(stream, state) { + var sol = stream.sol(), ch; + + state.block = false; // indicates the start of a code block. + + ch = stream.peek(); // don't eat, to make matching simpler + + // check start of blocks + if (sol && /[<\/\*{}\-]/.test(ch)) { + if (stream.match(reCodeBlockStart)) { + state.block = true; + return chain(stream, state, twTokenCode); + } + if (stream.match(reBlockQuote)) { + return 'quote'; + } + if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) { + return 'comment'; + } + if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) { + return 'comment'; + } + if (stream.match(reHR)) { + return 'hr'; + } + } // sol + ch = stream.next(); + + if (sol && /[\/\*!#;:>|]/.test(ch)) { + if (ch == "!") { // tw header + stream.skipToEnd(); + return "header"; + } + if (ch == "*") { // tw list + stream.eatWhile('*'); + return "comment"; + } + if (ch == "#") { // tw numbered list + stream.eatWhile('#'); + return "comment"; + } + if (ch == ";") { // definition list, term + stream.eatWhile(';'); + return "comment"; + } + if (ch == ":") { // definition list, description + stream.eatWhile(':'); + return "comment"; + } + if (ch == ">") { // single line quote + stream.eatWhile(">"); + return "quote"; + } + if (ch == '|') { + return 'header'; + } + } + + if (ch == '{' && stream.match(/\{\{/)) { + return chain(stream, state, twTokenCode); + } + + // rudimentary html:// file:// link matching. TW knows much more ... + if (/[hf]/i.test(ch)) { + if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) { + return "link"; + } + } + // just a little string indicator, don't want to have the whole string covered + if (ch == '"') { + return 'string'; + } + if (ch == '~') { // _no_ CamelCase indicator should be bold + return 'brace'; + } + if (/[\[\]]/.test(ch)) { // check for [[..]] + if (stream.peek() == ch) { + stream.next(); + return 'brace'; + } + } + if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting + stream.eatWhile(isSpaceName); + return "link"; + } + if (/\d/.test(ch)) { // numbers + stream.eatWhile(/\d/); + return "number"; + } + if (ch == "/") { // tw invisible comment + if (stream.eat("%")) { + return chain(stream, state, twTokenComment); + } + else if (stream.eat("/")) { // + return chain(stream, state, twTokenEm); + } + } + if (ch == "_") { // tw underline + if (stream.eat("_")) { + return chain(stream, state, twTokenUnderline); + } + } + // strikethrough and mdash handling + if (ch == "-") { + if (stream.eat("-")) { + // if strikethrough looks ugly, change CSS. + if (stream.peek() != ' ') + return chain(stream, state, twTokenStrike); + // mdash + if (stream.peek() == ' ') + return 'brace'; + } + } + if (ch == "'") { // tw bold + if (stream.eat("'")) { + return chain(stream, state, twTokenStrong); + } + } + if (ch == "<") { // tw macro + if (stream.eat("<")) { + return chain(stream, state, twTokenMacro); + } + } + else { + return null; + } + + // core macro handling + stream.eatWhile(/[\w\$_]/); + var word = stream.current(), + known = textwords.propertyIsEnumerable(word) && textwords[word]; + + return known ? known.style : null; + } // jsTokenBase() + + // tw invisible comment + function twTokenComment(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "%"); + } + return "comment"; + } + + // tw strong / bold + function twTokenStrong(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "'" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "'"); + } + return "strong"; + } + + // tw code + function twTokenCode(stream, state) { + var sb = state.block; + + if (sb && stream.current()) { + return "comment"; + } + + if (!sb && stream.match(reUntilCodeStop)) { + state.tokenize = jsTokenBase; + return "comment"; + } + + if (sb && stream.sol() && stream.match(reCodeBlockStop)) { + state.tokenize = jsTokenBase; + return "comment"; + } + + stream.next(); + return "comment"; + } + + // tw em / italic + function twTokenEm(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "/"); + } + return "em"; + } + + // tw underlined text + function twTokenUnderline(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "_" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "_"); + } + return "underlined"; + } + + // tw strike through text looks ugly + // change CSS if needed + function twTokenStrike(stream, state) { + var maybeEnd = false, ch; + + while (ch = stream.next()) { + if (ch == "-" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "-"); + } + return "strikethrough"; + } + + // macro + function twTokenMacro(stream, state) { + var ch, word, known; + + if (stream.current() == '<<') { + return 'macro'; + } + + ch = stream.next(); + if (!ch) { + state.tokenize = jsTokenBase; + return null; + } + if (ch == ">") { + if (stream.peek() == '>') { + stream.next(); + state.tokenize = jsTokenBase; + return "macro"; + } + } + + stream.eatWhile(/[\w\$_]/); + word = stream.current(); + known = keywords.propertyIsEnumerable(word) && keywords[word]; + + if (known) { + return known.style, word; + } + else { + return null, word; + } + } + + // Interface + return { + startState: function () { + return { + tokenize: jsTokenBase, + indented: 0, + level: 0 + }; + }, + + token: function (stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + }, + + electricChars: "" + }; +}); + +CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki"); +}); + +//}}} diff --git a/rhodecode/public/js/mode/tiki/tiki.js b/rhodecode/public/js/mode/tiki/tiki.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/tiki/tiki.js @@ -0,0 +1,312 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('tiki', function(config) { + function inBlock(style, terminator, returnTokenizer) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + + if (returnTokenizer) state.tokenize = returnTokenizer; + + return style; + }; + } + + function inLine(style) { + return function(stream, state) { + while(!stream.eol()) { + stream.next(); + } + state.tokenize = inText; + return style; + }; + } + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var sol = stream.sol(); + var ch = stream.next(); + + //non start of line + switch (ch) { //switch is generally much faster than if, so it is used here + case "{": //plugin + stream.eat("/"); + stream.eatSpace(); + stream.eatWhile(/[^\s\u00a0=\"\'\/?(}]/); + state.tokenize = inPlugin; + return "tag"; + case "_": //bold + if (stream.eat("_")) + return chain(inBlock("strong", "__", inText)); + break; + case "'": //italics + if (stream.eat("'")) + return chain(inBlock("em", "''", inText)); + break; + case "(":// Wiki Link + if (stream.eat("(")) + return chain(inBlock("variable-2", "))", inText)); + break; + case "[":// Weblink + return chain(inBlock("variable-3", "]", inText)); + break; + case "|": //table + if (stream.eat("|")) + return chain(inBlock("comment", "||")); + break; + case "-": + if (stream.eat("=")) {//titleBar + return chain(inBlock("header string", "=-", inText)); + } else if (stream.eat("-")) {//deleted + return chain(inBlock("error tw-deleted", "--", inText)); + } + break; + case "=": //underline + if (stream.match("==")) + return chain(inBlock("tw-underline", "===", inText)); + break; + case ":": + if (stream.eat(":")) + return chain(inBlock("comment", "::")); + break; + case "^": //box + return chain(inBlock("tw-box", "^")); + break; + case "~": //np + if (stream.match("np~")) + return chain(inBlock("meta", "~/np~")); + break; + } + + //start of line types + if (sol) { + switch (ch) { + case "!": //header at start of line + if (stream.match('!!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!')) { + return chain(inLine("header string")); + } else { + return chain(inLine("header string")); + } + break; + case "*": //unordered list line item, or <li /> at start of line + case "#": //ordered list line item, or <li /> at start of line + case "+": //ordered list line item, or <li /> at start of line + return chain(inLine("tw-listitem bracket")); + break; + } + } + + //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki + return null; + } + + var indentUnit = config.indentUnit; + + // Return variables for tokenizers + var pluginName, type; + function inPlugin(stream, state) { + var ch = stream.next(); + var peek = stream.peek(); + + if (ch == "}") { + state.tokenize = inText; + //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin + return "tag"; + } else if (ch == "(" || ch == ")") { + return "bracket"; + } else if (ch == "=") { + type = "equals"; + + if (peek == ">") { + ch = stream.next(); + peek = stream.peek(); + } + + //here we detect values directly after equal character with no quotes + if (!/[\'\"]/.test(peek)) { + state.tokenize = inAttributeNoQuote(); + } + //end detect values + + return "operator"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + return state.tokenize(stream, state); + } else { + stream.eatWhile(/[^\s\u00a0=\"\'\/?]/); + return "keyword"; + } + } + + function inAttribute(quote) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inPlugin; + break; + } + } + return "string"; + }; + } + + function inAttributeNoQuote() { + return function(stream, state) { + while (!stream.eol()) { + var ch = stream.next(); + var peek = stream.peek(); + if (ch == " " || ch == "," || /[ )}]/.test(peek)) { + state.tokenize = inPlugin; + break; + } + } + return "string"; +}; + } + +var curState, setStyle; +function pass() { + for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); +} + +function cont() { + pass.apply(null, arguments); + return true; +} + +function pushContext(pluginName, startOfLine) { + var noIndent = curState.context && curState.context.noIndent; + curState.context = { + prev: curState.context, + pluginName: pluginName, + indent: curState.indented, + startOfLine: startOfLine, + noIndent: noIndent + }; +} + +function popContext() { + if (curState.context) curState.context = curState.context.prev; +} + +function element(type) { + if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));} + else if (type == "closePlugin") { + var err = false; + if (curState.context) { + err = curState.context.pluginName != pluginName; + popContext(); + } else { + err = true; + } + if (err) setStyle = "error"; + return cont(endcloseplugin(err)); + } + else if (type == "string") { + if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); + if (curState.tokenize == inText) popContext(); + return cont(); + } + else return cont(); +} + +function endplugin(startOfLine) { + return function(type) { + if ( + type == "selfclosePlugin" || + type == "endPlugin" + ) + return cont(); + if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();} + return cont(); + }; +} + +function endcloseplugin(err) { + return function(type) { + if (err) setStyle = "error"; + if (type == "endPlugin") return cont(); + return pass(); + }; +} + +function attributes(type) { + if (type == "keyword") {setStyle = "attribute"; return cont(attributes);} + if (type == "equals") return cont(attvalue, attributes); + return pass(); +} +function attvalue(type) { + if (type == "keyword") {setStyle = "string"; return cont();} + if (type == "string") return cont(attvaluemaybe); + return pass(); +} +function attvaluemaybe(type) { + if (type == "string") return cont(attvaluemaybe); + else return pass(); +} +return { + startState: function() { + return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null}; + }, + token: function(stream, state) { + if (stream.sol()) { + state.startOfLine = true; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + + setStyle = type = pluginName = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + curState = state; + while (true) { + var comb = state.cc.pop() || element; + if (comb(type || style)) break; + } + } + state.startOfLine = false; + return setStyle || style; + }, + indent: function(state, textAfter) { + var context = state.context; + if (context && context.noIndent) return 0; + if (context && /^{\//.test(textAfter)) + context = context.prev; + while (context && !context.startOfLine) + context = context.prev; + if (context) return context.indent + indentUnit; + else return 0; + }, + electricChars: "/" + }; +}); + +CodeMirror.defineMIME("text/tiki", "tiki"); + +}); diff --git a/rhodecode/public/js/mode/toml/toml.js b/rhodecode/public/js/mode/toml/toml.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/toml/toml.js @@ -0,0 +1,88 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("toml", function () { + return { + startState: function () { + return { + inString: false, + stringType: "", + lhs: true, + inArray: 0 + }; + }, + token: function (stream, state) { + //check for state changes + if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (stream.sol() && state.inArray === 0) { + state.lhs = true; + } + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inArray && stream.peek() === ']') { + stream.next(); + state.inArray--; + return 'bracket'; + } else if (state.lhs && stream.peek() === '[' && stream.skipTo(']')) { + stream.next();//skip closing ] + // array of objects has an extra open & close [] + if (stream.peek() === ']') stream.next(); + return "atom"; + } else if (stream.peek() === "#") { + stream.skipToEnd(); + return "comment"; + } else if (stream.eatSpace()) { + return null; + } else if (state.lhs && stream.eatWhile(function (c) { return c != '=' && c != ' '; })) { + return "property"; + } else if (state.lhs && stream.peek() === "=") { + stream.next(); + state.lhs = false; + return null; + } else if (!state.lhs && stream.match(/^\d\d\d\d[\d\-\:\.T]*Z/)) { + return 'atom'; //date + } else if (!state.lhs && (stream.match('true') || stream.match('false'))) { + return 'atom'; + } else if (!state.lhs && stream.peek() === '[') { + state.inArray++; + stream.next(); + return 'bracket'; + } else if (!state.lhs && stream.match(/^\-?\d+(?:\.\d+)?/)) { + return 'number'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME('text/x-toml', 'toml'); + +}); diff --git a/rhodecode/public/js/mode/tornado/tornado.js b/rhodecode/public/js/mode/tornado/tornado.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/tornado/tornado.js @@ -0,0 +1,68 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("tornado:inner", function() { + var keywords = ["and","as","assert","autoescape","block","break","class","comment","context", + "continue","datetime","def","del","elif","else","end","escape","except", + "exec","extends","false","finally","for","from","global","if","import","in", + "include","is","json_encode","lambda","length","linkify","load","module", + "none","not","or","pass","print","put","raise","raw","return","self","set", + "squeeze","super","true","try","url_escape","while","with","without","xhtml_escape","yield"]; + keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b"); + + function tokenBase (stream, state) { + stream.eatWhile(/[^\{]/); + var ch = stream.next(); + if (ch == "{") { + if (ch = stream.eat(/\{|%|#/)) { + state.tokenize = inTag(ch); + return "tag"; + } + } + } + function inTag (close) { + if (close == "{") { + close = "}"; + } + return function (stream, state) { + var ch = stream.next(); + if ((ch == close) && stream.eat("}")) { + state.tokenize = tokenBase; + return "tag"; + } + if (stream.match(keywords)) { + return "keyword"; + } + return close == "#" ? "comment" : "string"; + }; + } + return { + startState: function () { + return {tokenize: tokenBase}; + }, + token: function (stream, state) { + return state.tokenize(stream, state); + } + }; + }); + + CodeMirror.defineMode("tornado", function(config) { + var htmlBase = CodeMirror.getMode(config, "text/html"); + var tornadoInner = CodeMirror.getMode(config, "tornado:inner"); + return CodeMirror.overlayMode(htmlBase, tornadoInner); + }); + + CodeMirror.defineMIME("text/x-tornado", "tornado"); +}); diff --git a/rhodecode/public/js/mode/troff/troff.js b/rhodecode/public/js/mode/troff/troff.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/troff/troff.js @@ -0,0 +1,82 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) + define(["../../lib/codemirror"], mod); + else + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('troff', function() { + + var words = {}; + + function tokenBase(stream) { + if (stream.eatSpace()) return null; + + var sol = stream.sol(); + var ch = stream.next(); + + if (ch === '\\') { + if (stream.match('fB') || stream.match('fR') || stream.match('fI') || + stream.match('u') || stream.match('d') || + stream.match('%') || stream.match('&')) { + return 'string'; + } + if (stream.match('m[')) { + stream.skipTo(']'); + stream.next(); + return 'string'; + } + if (stream.match('s+') || stream.match('s-')) { + stream.eatWhile(/[\d-]/); + return 'string'; + } + if (stream.match('\(') || stream.match('*\(')) { + stream.eatWhile(/[\w-]/); + return 'string'; + } + return 'string'; + } + if (sol && (ch === '.' || ch === '\'')) { + if (stream.eat('\\') && stream.eat('\"')) { + stream.skipToEnd(); + return 'comment'; + } + } + if (sol && ch === '.') { + if (stream.match('B ') || stream.match('I ') || stream.match('R ')) { + return 'attribute'; + } + if (stream.match('TH ') || stream.match('SH ') || stream.match('SS ') || stream.match('HP ')) { + stream.skipToEnd(); + return 'quote'; + } + if ((stream.match(/[A-Z]/) && stream.match(/[A-Z]/)) || (stream.match(/[a-z]/) && stream.match(/[a-z]/))) { + return 'attribute'; + } + } + stream.eatWhile(/[\w-]/); + var cur = stream.current(); + return words.hasOwnProperty(cur) ? words[cur] : null; + } + + function tokenize(stream, state) { + return (state.tokens[0] || tokenBase) (stream, state); + }; + + return { + startState: function() {return {tokens:[]};}, + token: function(stream, state) { + return tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME('troff', 'troff'); + +}); diff --git a/rhodecode/public/js/mode/ttcn-cfg/ttcn-cfg.js b/rhodecode/public/js/mode/ttcn-cfg/ttcn-cfg.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ttcn-cfg/ttcn-cfg.js @@ -0,0 +1,214 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("ttcn-cfg", function(config, parserConfig) { + var indentUnit = config.indentUnit, + keywords = parserConfig.keywords || {}, + fileNCtrlMaskOptions = parserConfig.fileNCtrlMaskOptions || {}, + externalCommands = parserConfig.externalCommands || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false; + var isOperatorChar = /[\|]/; + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[:=]/.test(ch)) { + curPunc = ch; + return "punctuation"; + } + if (ch == "#"){ + stream.skipToEnd(); + return "comment"; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + if (ch == "["){ + stream.eatWhile(/[\w_\]]/); + return "number sectionTitle"; + } + + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + if (fileNCtrlMaskOptions.propertyIsEnumerable(cur)) + return "negative fileNCtrlMaskOptions"; + if (externalCommands.propertyIsEnumerable(cur)) return "negative externalCommands"; + + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped){ + var afterNext = stream.peek(); + //look if the character if the quote is like the B in '10100010'B + if (afterNext){ + afterNext = afterNext.toLowerCase(); + if(afterNext == "b" || afterNext == "h" || afterNext == "o") + stream.next(); + } + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + //Interface + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") + && ctx.type == "statement"){ + popContext(state); + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && (((ctx.type == "}" || ctx.type == "top") + && curPunc != ';') || (ctx.type == "statement" + && curPunc == "newstatement"))) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + electricChars: "{}", + lineComment: "#", + fold: "brace" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) + obj[words[i]] = true; + return obj; + } + + CodeMirror.defineMIME("text/x-ttcn-cfg", { + name: "ttcn-cfg", + keywords: words("Yes No LogFile FileMask ConsoleMask AppendFile" + + " TimeStampFormat LogEventTypes SourceInfoFormat" + + " LogEntityName LogSourceInfo DiskFullAction" + + " LogFileNumber LogFileSize MatchingHints Detailed" + + " Compact SubCategories Stack Single None Seconds" + + " DateTime Time Stop Error Retry Delete TCPPort KillTimer" + + " NumHCs UnixSocketsEnabled LocalAddress"), + fileNCtrlMaskOptions: words("TTCN_EXECUTOR TTCN_ERROR TTCN_WARNING" + + " TTCN_PORTEVENT TTCN_TIMEROP TTCN_VERDICTOP" + + " TTCN_DEFAULTOP TTCN_TESTCASE TTCN_ACTION" + + " TTCN_USER TTCN_FUNCTION TTCN_STATISTICS" + + " TTCN_PARALLEL TTCN_MATCHING TTCN_DEBUG" + + " EXECUTOR ERROR WARNING PORTEVENT TIMEROP" + + " VERDICTOP DEFAULTOP TESTCASE ACTION USER" + + " FUNCTION STATISTICS PARALLEL MATCHING DEBUG" + + " LOG_ALL LOG_NOTHING ACTION_UNQUALIFIED" + + " DEBUG_ENCDEC DEBUG_TESTPORT" + + " DEBUG_UNQUALIFIED DEFAULTOP_ACTIVATE" + + " DEFAULTOP_DEACTIVATE DEFAULTOP_EXIT" + + " DEFAULTOP_UNQUALIFIED ERROR_UNQUALIFIED" + + " EXECUTOR_COMPONENT EXECUTOR_CONFIGDATA" + + " EXECUTOR_EXTCOMMAND EXECUTOR_LOGOPTIONS" + + " EXECUTOR_RUNTIME EXECUTOR_UNQUALIFIED" + + " FUNCTION_RND FUNCTION_UNQUALIFIED" + + " MATCHING_DONE MATCHING_MCSUCCESS" + + " MATCHING_MCUNSUCC MATCHING_MMSUCCESS" + + " MATCHING_MMUNSUCC MATCHING_PCSUCCESS" + + " MATCHING_PCUNSUCC MATCHING_PMSUCCESS" + + " MATCHING_PMUNSUCC MATCHING_PROBLEM" + + " MATCHING_TIMEOUT MATCHING_UNQUALIFIED" + + " PARALLEL_PORTCONN PARALLEL_PORTMAP" + + " PARALLEL_PTC PARALLEL_UNQUALIFIED" + + " PORTEVENT_DUALRECV PORTEVENT_DUALSEND" + + " PORTEVENT_MCRECV PORTEVENT_MCSEND" + + " PORTEVENT_MMRECV PORTEVENT_MMSEND" + + " PORTEVENT_MQUEUE PORTEVENT_PCIN" + + " PORTEVENT_PCOUT PORTEVENT_PMIN" + + " PORTEVENT_PMOUT PORTEVENT_PQUEUE" + + " PORTEVENT_STATE PORTEVENT_UNQUALIFIED" + + " STATISTICS_UNQUALIFIED STATISTICS_VERDICT" + + " TESTCASE_FINISH TESTCASE_START" + + " TESTCASE_UNQUALIFIED TIMEROP_GUARD" + + " TIMEROP_READ TIMEROP_START TIMEROP_STOP" + + " TIMEROP_TIMEOUT TIMEROP_UNQUALIFIED" + + " USER_UNQUALIFIED VERDICTOP_FINAL" + + " VERDICTOP_GETVERDICT VERDICTOP_SETVERDICT" + + " VERDICTOP_UNQUALIFIED WARNING_UNQUALIFIED"), + externalCommands: words("BeginControlPart EndControlPart BeginTestCase" + + " EndTestCase"), + multiLineStrings: true + }); +}); \ No newline at end of file diff --git a/rhodecode/public/js/mode/ttcn/ttcn.js b/rhodecode/public/js/mode/ttcn/ttcn.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/ttcn/ttcn.js @@ -0,0 +1,283 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("ttcn", function(config, parserConfig) { + var indentUnit = config.indentUnit, + keywords = parserConfig.keywords || {}, + builtin = parserConfig.builtin || {}, + timerOps = parserConfig.timerOps || {}, + portOps = parserConfig.portOps || {}, + configOps = parserConfig.configOps || {}, + verdictOps = parserConfig.verdictOps || {}, + sutOps = parserConfig.sutOps || {}, + functionOps = parserConfig.functionOps || {}, + + verdictConsts = parserConfig.verdictConsts || {}, + booleanConsts = parserConfig.booleanConsts || {}, + otherConsts = parserConfig.otherConsts || {}, + + types = parserConfig.types || {}, + visibilityModifiers = parserConfig.visibilityModifiers || {}, + templateMatch = parserConfig.templateMatch || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false; + var isOperatorChar = /[+\-*&@=<>!\/]/; + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\\:\?\.]/.test(ch)) { + curPunc = ch; + return "punctuation"; + } + if (ch == "#"){ + stream.skipToEnd(); + return "atom preprocessor"; + } + if (ch == "%"){ + stream.eatWhile(/\b/); + return "atom ttcn3Macros"; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + if(ch == "@"){ + if(stream.match("try") || stream.match("catch") + || stream.match("lazy")){ + return "keyword"; + } + } + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + var cur = stream.current(); + + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + if (builtin.propertyIsEnumerable(cur)) return "builtin"; + + if (timerOps.propertyIsEnumerable(cur)) return "def timerOps"; + if (configOps.propertyIsEnumerable(cur)) return "def configOps"; + if (verdictOps.propertyIsEnumerable(cur)) return "def verdictOps"; + if (portOps.propertyIsEnumerable(cur)) return "def portOps"; + if (sutOps.propertyIsEnumerable(cur)) return "def sutOps"; + if (functionOps.propertyIsEnumerable(cur)) return "def functionOps"; + + if (verdictConsts.propertyIsEnumerable(cur)) return "string verdictConsts"; + if (booleanConsts.propertyIsEnumerable(cur)) return "string booleanConsts"; + if (otherConsts.propertyIsEnumerable(cur)) return "string otherConsts"; + + if (types.propertyIsEnumerable(cur)) return "builtin types"; + if (visibilityModifiers.propertyIsEnumerable(cur)) + return "builtin visibilityModifiers"; + if (templateMatch.propertyIsEnumerable(cur)) return "atom templateMatch"; + + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped){ + var afterQuote = stream.peek(); + //look if the character after the quote is like the B in '10100010'B + if (afterQuote){ + afterQuote = afterQuote.toLowerCase(); + if(afterQuote == "b" || afterQuote == "h" || afterQuote == "o") + stream.next(); + } + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + //Interface + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") + && ctx.type == "statement"){ + popContext(state); + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && + (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || + (ctx.type == "statement" && curPunc == "newstatement"))) + pushContext(state, stream.column(), "statement"); + + state.startOfLine = false; + + return style; + }, + + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + fold: "brace" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + function def(mimes, mode) { + if (typeof mimes == "string") mimes = [mimes]; + var words = []; + function add(obj) { + if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) + words.push(prop); + } + + add(mode.keywords); + add(mode.builtin); + add(mode.timerOps); + add(mode.portOps); + + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i = 0; i < mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def(["text/x-ttcn", "text/x-ttcn3", "text/x-ttcnpp"], { + name: "ttcn", + keywords: words("activate address alive all alt altstep and and4b any" + + " break case component const continue control deactivate" + + " display do else encode enumerated except exception" + + " execute extends extension external for from function" + + " goto group if import in infinity inout interleave" + + " label language length log match message mixed mod" + + " modifies module modulepar mtc noblock not not4b nowait" + + " of on optional or or4b out override param pattern port" + + " procedure record recursive rem repeat return runs select" + + " self sender set signature system template testcase to" + + " type union value valueof var variant while with xor xor4b"), + builtin: words("bit2hex bit2int bit2oct bit2str char2int char2oct encvalue" + + " decomp decvalue float2int float2str hex2bit hex2int" + + " hex2oct hex2str int2bit int2char int2float int2hex" + + " int2oct int2str int2unichar isbound ischosen ispresent" + + " isvalue lengthof log2str oct2bit oct2char oct2hex oct2int" + + " oct2str regexp replace rnd sizeof str2bit str2float" + + " str2hex str2int str2oct substr unichar2int unichar2char" + + " enum2int"), + types: words("anytype bitstring boolean char charstring default float" + + " hexstring integer objid octetstring universal verdicttype timer"), + timerOps: words("read running start stop timeout"), + portOps: words("call catch check clear getcall getreply halt raise receive" + + " reply send trigger"), + configOps: words("create connect disconnect done kill killed map unmap"), + verdictOps: words("getverdict setverdict"), + sutOps: words("action"), + functionOps: words("apply derefers refers"), + + verdictConsts: words("error fail inconc none pass"), + booleanConsts: words("true false"), + otherConsts: words("null NULL omit"), + + visibilityModifiers: words("private public friend"), + templateMatch: words("complement ifpresent subset superset permutation"), + multiLineStrings: true + }); +}); diff --git a/rhodecode/public/js/mode/turtle/turtle.js b/rhodecode/public/js/mode/turtle/turtle.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/turtle/turtle.js @@ -0,0 +1,162 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("turtle", function(config) { + var indentUnit = config.indentUnit; + var curPunc; + + function wordRegexp(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var ops = wordRegexp([]); + var keywords = wordRegexp(["@prefix", "@base", "a"]); + var operatorChars = /[*+\-<>=&|]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + curPunc = null; + if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { + stream.match(/^[^\s\u00a0>]*>?/); + return "atom"; + } + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } + else if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return null; + } + else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return null; + } + else if (ch == ":") { + return "operator"; + } else { + stream.eatWhile(/[_\w\d]/); + if(stream.peek() == ":") { + return "variable-3"; + } else { + var word = stream.current(); + + if(keywords.test(word)) { + return "meta"; + } + + if(ch >= "A" && ch <= "Z") { + return "comment"; + } else { + return "keyword"; + } + } + var word = stream.current(); + if (ops.test(word)) + return null; + else if (keywords.test(word)) + return "meta"; + else + return "variable"; + } + } + + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function pushContext(state, type, col) { + state.context = {prev: state.context, indent: state.indent, col: col, type: type}; + } + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + context: null, + indent: 0, + col: 0}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) state.context.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { + state.context.align = true; + } + + if (curPunc == "(") pushContext(state, ")", stream.column()); + else if (curPunc == "[") pushContext(state, "]", stream.column()); + else if (curPunc == "{") pushContext(state, "}", stream.column()); + else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type == "pattern") popContext(state); + if (state.context && curPunc == state.context.type) popContext(state); + } + else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); + else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) + pushContext(state, "pattern", stream.column()); + else if (state.context.type == "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + + return style; + }, + + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) + while (context && context.type == "pattern") context = context.prev; + + var closing = context && firstChar == context.type; + if (!context) + return 0; + else if (context.type == "pattern") + return context.col; + else if (context.align) + return context.col + (closing ? 0 : 1); + else + return context.indent + (closing ? 0 : indentUnit); + }, + + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/turtle", "turtle"); + +}); diff --git a/rhodecode/public/js/mode/twig/twig.js b/rhodecode/public/js/mode/twig/twig.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/twig/twig.js @@ -0,0 +1,132 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("twig", function() { + var keywords = ["and", "as", "autoescape", "endautoescape", "block", "do", "endblock", "else", "elseif", "extends", "for", "endfor", "embed", "endembed", "filter", "endfilter", "flush", "from", "if", "endif", "in", "is", "include", "import", "not", "or", "set", "spaceless", "endspaceless", "with", "endwith", "trans", "endtrans", "blocktrans", "endblocktrans", "macro", "endmacro", "use", "verbatim", "endverbatim"], + operator = /^[+\-*&%=<>!?|~^]/, + sign = /^[:\[\(\{]/, + atom = ["true", "false", "null", "empty", "defined", "divisibleby", "divisible by", "even", "odd", "iterable", "sameas", "same as"], + number = /^(\d[+\-\*\/])?\d+(\.\d+)?/; + + keywords = new RegExp("((" + keywords.join(")|(") + "))\\b"); + atom = new RegExp("((" + atom.join(")|(") + "))\\b"); + + function tokenBase (stream, state) { + var ch = stream.peek(); + + //Comment + if (state.incomment) { + if (!stream.skipTo("#}")) { + stream.skipToEnd(); + } else { + stream.eatWhile(/\#|}/); + state.incomment = false; + } + return "comment"; + //Tag + } else if (state.intag) { + //After operator + if (state.operator) { + state.operator = false; + if (stream.match(atom)) { + return "atom"; + } + if (stream.match(number)) { + return "number"; + } + } + //After sign + if (state.sign) { + state.sign = false; + if (stream.match(atom)) { + return "atom"; + } + if (stream.match(number)) { + return "number"; + } + } + + if (state.instring) { + if (ch == state.instring) { + state.instring = false; + } + stream.next(); + return "string"; + } else if (ch == "'" || ch == '"') { + state.instring = ch; + stream.next(); + return "string"; + } else if (stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) { + state.intag = false; + return "tag"; + } else if (stream.match(operator)) { + state.operator = true; + return "operator"; + } else if (stream.match(sign)) { + state.sign = true; + } else { + if (stream.eat(" ") || stream.sol()) { + if (stream.match(keywords)) { + return "keyword"; + } + if (stream.match(atom)) { + return "atom"; + } + if (stream.match(number)) { + return "number"; + } + if (stream.sol()) { + stream.next(); + } + } else { + stream.next(); + } + + } + return "variable"; + } else if (stream.eat("{")) { + if (ch = stream.eat("#")) { + state.incomment = true; + if (!stream.skipTo("#}")) { + stream.skipToEnd(); + } else { + stream.eatWhile(/\#|}/); + state.incomment = false; + } + return "comment"; + //Open tag + } else if (ch = stream.eat(/\{|%/)) { + //Cache close tag + state.intag = ch; + if (ch == "{") { + state.intag = "}"; + } + stream.eat("-"); + return "tag"; + } + } + stream.next(); + }; + + return { + startState: function () { + return {}; + }, + token: function (stream, state) { + return tokenBase(stream, state); + } + }; + }); + + CodeMirror.defineMIME("text/x-twig", "twig"); +}); diff --git a/rhodecode/public/js/mode/vb/vb.js b/rhodecode/public/js/mode/vb/vb.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/vb/vb.js @@ -0,0 +1,276 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("vb", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]"); + var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); + var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); + var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); + var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + + var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try']; + var middleKeywords = ['else','elseif','case', 'catch']; + var endKeywords = ['next','loop']; + + var operatorKeywords = ['and', 'or', 'not', 'xor', 'in']; + var wordOperators = wordRegexp(operatorKeywords); + var commonKeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until', + 'goto', 'byval','byref','new','handles','property', 'return', + 'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false']; + var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single']; + + var keywords = wordRegexp(commonKeywords); + var types = wordRegexp(commontypes); + var stringPrefixes = '"'; + + var opening = wordRegexp(openingKeywords); + var middle = wordRegexp(middleKeywords); + var closing = wordRegexp(endKeywords); + var doubleClosing = wordRegexp(['end']); + var doOpening = wordRegexp(['do']); + + var indentInfo = null; + + CodeMirror.registerHelper("hintWords", "vb", openingKeywords.concat(middleKeywords).concat(endKeywords) + .concat(operatorKeywords).concat(commonKeywords).concat(commontypes)); + + function indent(_stream, state) { + state.currentIndent++; + } + + function dedent(_stream, state) { + state.currentIndent--; + } + // tokenizers + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return null; + } + + var ch = stream.peek(); + + // Handle Comments + if (ch === "'") { + stream.skipToEnd(); + return 'comment'; + } + + + // Handle Number Literals + if (stream.match(/^((&H)|(&O))?[0-9\.a-f]/i, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; } + else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; } + else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; } + + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; } + // Octal + else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; } + // Decimal + else if (stream.match(/^[1-9]\d*F?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { + return null; + } + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) { + return 'operator'; + } + if (stream.match(singleDelimiters)) { + return null; + } + if (stream.match(doOpening)) { + indent(stream,state); + state.doInCurrentLine = true; + return 'keyword'; + } + if (stream.match(opening)) { + if (! state.doInCurrentLine) + indent(stream,state); + else + state.doInCurrentLine = false; + return 'keyword'; + } + if (stream.match(middle)) { + return 'keyword'; + } + + if (stream.match(doubleClosing)) { + dedent(stream,state); + dedent(stream,state); + return 'keyword'; + } + if (stream.match(closing)) { + dedent(stream,state); + return 'keyword'; + } + + if (stream.match(types)) { + return 'keyword'; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(identifiers)) { + return 'variable'; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + return function(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"]/); + if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + }; + } + + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = state.tokenize(stream, state); + current = stream.current(); + if (style === 'variable') { + return 'variable'; + } else { + return ERRORCLASS; + } + } + + + var delimiter_index = '[({'.indexOf(current); + if (delimiter_index !== -1) { + indent(stream, state ); + } + if (indentInfo === 'dedent') { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + delimiter_index = '])}'.indexOf(current); + if (delimiter_index !== -1) { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + + return style; + } + + var external = { + electricChars:"dDpPtTfFeE ", + startState: function() { + return { + tokenize: tokenBase, + lastToken: null, + currentIndent: 0, + nextLineIndent: 0, + doInCurrentLine: false + + + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.currentIndent += state.nextLineIndent; + state.nextLineIndent = 0; + state.doInCurrentLine = 0; + } + var style = tokenLexer(stream, state); + + state.lastToken = {style:style, content: stream.current()}; + + + + return style; + }, + + indent: function(state, textAfter) { + var trueText = textAfter.replace(/^\s+|\s+$/g, '') ; + if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1); + if(state.currentIndent < 0) return 0; + return state.currentIndent * conf.indentUnit; + }, + + lineComment: "'" + }; + return external; +}); + +CodeMirror.defineMIME("text/x-vb", "vb"); + +}); diff --git a/rhodecode/public/js/mode/vbscript/vbscript.js b/rhodecode/public/js/mode/vbscript/vbscript.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/vbscript/vbscript.js @@ -0,0 +1,350 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* +For extra ASP classic objects, initialize CodeMirror instance with this option: + isASP: true + +E.G.: + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { + lineNumbers: true, + isASP: true + }); +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("vbscript", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]"); + var doubleOperators = new RegExp("^((<>)|(<=)|(>=))"); + var singleDelimiters = new RegExp('^[\\.,]'); + var brakets = new RegExp('^[\\(\\)]'); + var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*"); + + var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for']; + var middleKeywords = ['else','elseif','case']; + var endKeywords = ['next','loop','wend']; + + var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']); + var commonkeywords = ['dim', 'redim', 'then', 'until', 'randomize', + 'byval','byref','new','property', 'exit', 'in', + 'const','private', 'public', + 'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me']; + + //This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx + var atomWords = ['true', 'false', 'nothing', 'empty', 'null']; + //This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx + var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart', + 'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject', + 'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left', + 'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round', + 'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp', + 'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year']; + + //This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx + var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare', + 'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek', + 'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError', + 'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2', + 'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo', + 'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse', + 'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray']; + //This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx + var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp']; + var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count']; + var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit']; + + var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application']; + var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response + 'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request + 'contents', 'staticobjects', //application + 'codepage', 'lcid', 'sessionid', 'timeout', //session + 'scripttimeout']; //server + var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response + 'binaryread', //request + 'remove', 'removeall', 'lock', 'unlock', //application + 'abandon', //session + 'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server + + var knownWords = knownMethods.concat(knownProperties); + + builtinObjsWords = builtinObjsWords.concat(builtinConsts); + + if (conf.isASP){ + builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords); + knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties); + }; + + var keywords = wordRegexp(commonkeywords); + var atoms = wordRegexp(atomWords); + var builtinFuncs = wordRegexp(builtinFuncsWords); + var builtinObjs = wordRegexp(builtinObjsWords); + var known = wordRegexp(knownWords); + var stringPrefixes = '"'; + + var opening = wordRegexp(openingKeywords); + var middle = wordRegexp(middleKeywords); + var closing = wordRegexp(endKeywords); + var doubleClosing = wordRegexp(['end']); + var doOpening = wordRegexp(['do']); + var noIndentWords = wordRegexp(['on error resume next', 'exit']); + var comment = wordRegexp(['rem']); + + + function indent(_stream, state) { + state.currentIndent++; + } + + function dedent(_stream, state) { + state.currentIndent--; + } + // tokenizers + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return 'space'; + //return null; + } + + var ch = stream.peek(); + + // Handle Comments + if (ch === "'") { + stream.skipToEnd(); + return 'comment'; + } + if (stream.match(comment)){ + stream.skipToEnd(); + return 'comment'; + } + + + // Handle Number Literals + if (stream.match(/^((&H)|(&O))?[0-9\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+/i)) { floatLiteral = true; } + else if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + else if (stream.match(/^\.\d+/)) { floatLiteral = true; } + + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; } + // Octal + else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; } + // Decimal + else if (stream.match(/^[1-9]\d*F?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) { + return 'operator'; + } + if (stream.match(singleDelimiters)) { + return null; + } + + if (stream.match(brakets)) { + return "bracket"; + } + + if (stream.match(noIndentWords)) { + state.doInCurrentLine = true; + + return 'keyword'; + } + + if (stream.match(doOpening)) { + indent(stream,state); + state.doInCurrentLine = true; + + return 'keyword'; + } + if (stream.match(opening)) { + if (! state.doInCurrentLine) + indent(stream,state); + else + state.doInCurrentLine = false; + + return 'keyword'; + } + if (stream.match(middle)) { + return 'keyword'; + } + + + if (stream.match(doubleClosing)) { + dedent(stream,state); + dedent(stream,state); + + return 'keyword'; + } + if (stream.match(closing)) { + if (! state.doInCurrentLine) + dedent(stream,state); + else + state.doInCurrentLine = false; + + return 'keyword'; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(atoms)) { + return 'atom'; + } + + if (stream.match(known)) { + return 'variable-2'; + } + + if (stream.match(builtinFuncs)) { + return 'builtin'; + } + + if (stream.match(builtinObjs)){ + return 'variable-2'; + } + + if (stream.match(identifiers)) { + return 'variable'; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + return function(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"]/); + if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + }; + } + + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = state.tokenize(stream, state); + + current = stream.current(); + if (style && (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword')){//|| knownWords.indexOf(current.substring(1)) > -1) { + if (style === 'builtin' || style === 'keyword') style='variable'; + if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2'; + + return style; + } else { + return ERRORCLASS; + } + } + + return style; + } + + var external = { + electricChars:"dDpPtTfFeE ", + startState: function() { + return { + tokenize: tokenBase, + lastToken: null, + currentIndent: 0, + nextLineIndent: 0, + doInCurrentLine: false, + ignoreKeyword: false + + + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.currentIndent += state.nextLineIndent; + state.nextLineIndent = 0; + state.doInCurrentLine = 0; + } + var style = tokenLexer(stream, state); + + state.lastToken = {style:style, content: stream.current()}; + + if (style==='space') style=null; + + return style; + }, + + indent: function(state, textAfter) { + var trueText = textAfter.replace(/^\s+|\s+$/g, '') ; + if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1); + if(state.currentIndent < 0) return 0; + return state.currentIndent * conf.indentUnit; + } + + }; + return external; +}); + +CodeMirror.defineMIME("text/vbscript", "vbscript"); + +}); diff --git a/rhodecode/public/js/mode/velocity/velocity.js b/rhodecode/public/js/mode/velocity/velocity.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/velocity/velocity.js @@ -0,0 +1,201 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("velocity", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = parseWords("#end #else #break #stop #[[ #]] " + + "#{end} #{else} #{break} #{stop}"); + var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " + + "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}"); + var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent"); + var isOperatorChar = /[+\-*&%=<>!?:\/|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + // start of unparsed string? + if ((ch == "'") && state.inParams) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenString(ch)); + } + // start of parsed string? + else if ((ch == '"')) { + state.lastTokenWasBuiltin = false; + if (state.inString) { + state.inString = false; + return "string"; + } + else if (state.inParams) + return chain(stream, state, tokenString(ch)); + } + // is it one of the special signs []{}().,;? Seperator? + else if (/[\[\]{}\(\),;\.]/.test(ch)) { + if (ch == "(" && beforeParams) + state.inParams = true; + else if (ch == ")") { + state.inParams = false; + state.lastTokenWasBuiltin = true; + } + return null; + } + // start of a number value? + else if (/\d/.test(ch)) { + state.lastTokenWasBuiltin = false; + stream.eatWhile(/[\w\.]/); + return "number"; + } + // multi line comment? + else if (ch == "#" && stream.eat("*")) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenComment); + } + // unparsed content? + else if (ch == "#" && stream.match(/ *\[ *\[/)) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenUnparsed); + } + // single line comment? + else if (ch == "#" && stream.eat("#")) { + state.lastTokenWasBuiltin = false; + stream.skipToEnd(); + return "comment"; + } + // variable? + else if (ch == "$") { + stream.eatWhile(/[\w\d\$_\.{}]/); + // is it one of the specials? + if (specials && specials.propertyIsEnumerable(stream.current())) { + return "keyword"; + } + else { + state.lastTokenWasBuiltin = true; + state.beforeParams = true; + return "builtin"; + } + } + // is it a operator? + else if (isOperatorChar.test(ch)) { + state.lastTokenWasBuiltin = false; + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + // get the whole word + stream.eatWhile(/[\w\$_{}@]/); + var word = stream.current(); + // is it one of the listed keywords? + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + // is it one of the listed functions? + if (functions && functions.propertyIsEnumerable(word) || + (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") && + !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) { + state.beforeParams = true; + state.lastTokenWasBuiltin = false; + return "keyword"; + } + if (state.inString) { + state.lastTokenWasBuiltin = false; + return "string"; + } + if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin) + return "builtin"; + // default: just a "word" + state.lastTokenWasBuiltin = false; + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if ((next == quote) && !escaped) { + end = true; + break; + } + if (quote=='"' && stream.peek() == '$' && !escaped) { + state.inString = true; + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == "]") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + // Interface + + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false, + inString: false, + lastTokenWasBuiltin: false + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + blockCommentStart: "#*", + blockCommentEnd: "*#", + lineComment: "##", + fold: "velocity" + }; +}); + +CodeMirror.defineMIME("text/velocity", "velocity"); + +}); diff --git a/rhodecode/public/js/mode/verilog/verilog.js b/rhodecode/public/js/mode/verilog/verilog.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/verilog/verilog.js @@ -0,0 +1,537 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("verilog", function(config, parserConfig) { + + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + noIndentKeywords = parserConfig.noIndentKeywords || [], + multiLineStrings = parserConfig.multiLineStrings, + hooks = parserConfig.hooks || {}; + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + /** + * Keywords from IEEE 1800-2012 + */ + var keywords = words( + "accept_on alias always always_comb always_ff always_latch and assert assign assume automatic before begin bind " + + "bins binsof bit break buf bufif0 bufif1 byte case casex casez cell chandle checker class clocking cmos config " + + "const constraint context continue cover covergroup coverpoint cross deassign default defparam design disable " + + "dist do edge else end endcase endchecker endclass endclocking endconfig endfunction endgenerate endgroup " + + "endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask " + + "enum event eventually expect export extends extern final first_match for force foreach forever fork forkjoin " + + "function generate genvar global highz0 highz1 if iff ifnone ignore_bins illegal_bins implements implies import " + + "incdir include initial inout input inside instance int integer interconnect interface intersect join join_any " + + "join_none large let liblist library local localparam logic longint macromodule matches medium modport module " + + "nand negedge nettype new nexttime nmos nor noshowcancelled not notif0 notif1 null or output package packed " + + "parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup " + + "pulsestyle_ondetect pulsestyle_onevent pure rand randc randcase randsequence rcmos real realtime ref reg " + + "reject_on release repeat restrict return rnmos rpmos rtran rtranif0 rtranif1 s_always s_eventually s_nexttime " + + "s_until s_until_with scalared sequence shortint shortreal showcancelled signed small soft solve specify " + + "specparam static string strong strong0 strong1 struct super supply0 supply1 sync_accept_on sync_reject_on " + + "table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior " + + "trireg type typedef union unique unique0 unsigned until until_with untyped use uwire var vectored virtual void " + + "wait wait_order wand weak weak0 weak1 while wildcard wire with within wor xnor xor"); + + /** Operators from IEEE 1800-2012 + unary_operator ::= + + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ + binary_operator ::= + + | - | * | / | % | == | != | === | !== | ==? | !=? | && | || | ** + | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<< + | -> | <-> + inc_or_dec_operator ::= ++ | -- + unary_module_path_operator ::= + ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ + binary_module_path_operator ::= + == | != | && | || | & | | | ^ | ^~ | ~^ + */ + var isOperatorChar = /[\+\-\*\/!~&|^%=?:]/; + var isBracketChar = /[\[\]{}()]/; + + var unsignedNumber = /\d[0-9_]*/; + var decimalLiteral = /\d*\s*'s?d\s*\d[0-9_]*/i; + var binaryLiteral = /\d*\s*'s?b\s*[xz01][xz01_]*/i; + var octLiteral = /\d*\s*'s?o\s*[xz0-7][xz0-7_]*/i; + var hexLiteral = /\d*\s*'s?h\s*[0-9a-fxz?][0-9a-fxz?_]*/i; + var realLiteral = /(\d[\d_]*(\.\d[\d_]*)?E-?[\d_]+)|(\d[\d_]*\.\d[\d_]*)/i; + + var closingBracketOrWord = /^((\w+)|[)}\]])/; + var closingBracket = /[)}\]]/; + + var curPunc; + var curKeyword; + + // Block openings which are closed by a matching keyword in the form of ("end" + keyword) + // E.g. "task" => "endtask" + var blockKeywords = words( + "case checker class clocking config function generate interface module package" + + "primitive program property specify sequence table task" + ); + + // Opening/closing pairs + var openClose = {}; + for (var keyword in blockKeywords) { + openClose[keyword] = "end" + keyword; + } + openClose["begin"] = "end"; + openClose["casex"] = "endcase"; + openClose["casez"] = "endcase"; + openClose["do" ] = "while"; + openClose["fork" ] = "join;join_any;join_none"; + openClose["covergroup"] = "endgroup"; + + for (var i in noIndentKeywords) { + var keyword = noIndentKeywords[i]; + if (openClose[keyword]) { + openClose[keyword] = undefined; + } + } + + // Keywords which open statements that are ended with a semi-colon + var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while"); + + function tokenBase(stream, state) { + var ch = stream.peek(), style; + if (hooks[ch] && (style = hooks[ch](stream, state)) != false) return style; + if (hooks.tokenBase && (style = hooks.tokenBase(stream, state)) != false) + return style; + + if (/[,;:\.]/.test(ch)) { + curPunc = stream.next(); + return null; + } + if (isBracketChar.test(ch)) { + curPunc = stream.next(); + return "bracket"; + } + // Macros (tick-defines) + if (ch == '`') { + stream.next(); + if (stream.eatWhile(/[\w\$_]/)) { + return "def"; + } else { + return null; + } + } + // System calls + if (ch == '$') { + stream.next(); + if (stream.eatWhile(/[\w\$_]/)) { + return "meta"; + } else { + return null; + } + } + // Time literals + if (ch == '#') { + stream.next(); + stream.eatWhile(/[\d_.]/); + return "def"; + } + // Strings + if (ch == '"') { + stream.next(); + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + // Comments + if (ch == "/") { + stream.next(); + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + stream.backUp(1); + } + + // Numeric literals + if (stream.match(realLiteral) || + stream.match(decimalLiteral) || + stream.match(binaryLiteral) || + stream.match(octLiteral) || + stream.match(hexLiteral) || + stream.match(unsignedNumber) || + stream.match(realLiteral)) { + return "number"; + } + + // Operators + if (stream.eatWhile(isOperatorChar)) { + return "meta"; + } + + // Keywords / plain variables + if (stream.eatWhile(/[\w\$_]/)) { + var cur = stream.current(); + if (keywords[cur]) { + if (openClose[cur]) { + curPunc = "newblock"; + } + if (statementKeywords[cur]) { + curPunc = "newstatement"; + } + curKeyword = cur; + return "keyword"; + } + return "variable"; + } + + stream.next(); + return null; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + var c = new Context(indent, col, type, null, state.context); + return state.context = c; + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") { + state.indented = state.context.indented; + } + return state.context = state.context.prev; + } + + function isClosing(text, contextClosing) { + if (text == contextClosing) { + return true; + } else { + // contextClosing may be mulitple keywords separated by ; + var closingKeywords = contextClosing.split(";"); + for (var i in closingKeywords) { + if (text == closingKeywords[i]) { + return true; + } + } + return false; + } + } + + function buildElectricInputRegEx() { + // Reindentation should occur on any bracket char: {}()[] + // or on a match of any of the block closing keywords, at + // the end of a line + var allClosings = []; + for (var i in openClose) { + if (openClose[i]) { + var closings = openClose[i].split(";"); + for (var j in closings) { + allClosings.push(closings[j]); + } + } + } + var re = new RegExp("[{}()\\[\\]]|(" + allClosings.join("|") + ")$"); + return re; + } + + // Interface + return { + + // Regex to force current line to reindent + electricInput: buildElectricInputRegEx(), + + startState: function(basecolumn) { + var state = { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + if (hooks.startState) hooks.startState(state); + return state; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (hooks.token) hooks.token(stream, state); + if (stream.eatSpace()) return null; + curPunc = null; + curKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta" || style == "variable") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == ctx.type) { + popContext(state); + } else if ((curPunc == ";" && ctx.type == "statement") || + (ctx.type && isClosing(curKeyword, ctx.type))) { + ctx = popContext(state); + while (ctx && ctx.type == "statement") ctx = popContext(state); + } else if (curPunc == "{") { + pushContext(state, stream.column(), "}"); + } else if (curPunc == "[") { + pushContext(state, stream.column(), "]"); + } else if (curPunc == "(") { + pushContext(state, stream.column(), ")"); + } else if (ctx && ctx.type == "endcase" && curPunc == ":") { + pushContext(state, stream.column(), "statement"); + } else if (curPunc == "newstatement") { + pushContext(state, stream.column(), "statement"); + } else if (curPunc == "newblock") { + if (curKeyword == "function" && ctx && (ctx.type == "statement" || ctx.type == "endgroup")) { + // The 'function' keyword can appear in some other contexts where it actually does not + // indicate a function (import/export DPI and covergroup definitions). + // Do nothing in this case + } else if (curKeyword == "task" && ctx && ctx.type == "statement") { + // Same thing for task + } else { + var close = openClose[curKeyword]; + pushContext(state, stream.column(), close); + } + } + + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + if (hooks.indent) { + var fromHook = hooks.indent(state); + if (fromHook >= 0) return fromHook; + } + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = false; + var possibleClosing = textAfter.match(closingBracketOrWord); + if (possibleClosing) + closing = isClosing(possibleClosing[0], ctx.type); + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1); + else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + + CodeMirror.defineMIME("text/x-verilog", { + name: "verilog" + }); + + CodeMirror.defineMIME("text/x-systemverilog", { + name: "verilog" + }); + + // TLVVerilog mode + + var tlvchScopePrefixes = { + ">": "property", "->": "property", "-": "hr", "|": "link", "?$": "qualifier", "?*": "qualifier", + "@-": "variable-3", "@": "variable-3", "?": "qualifier" + }; + + function tlvGenIndent(stream, state) { + var tlvindentUnit = 2; + var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation(); + switch (state.tlvCurCtlFlowChar) { + case "\\": + curIndent = 0; + break; + case "|": + if (state.tlvPrevPrevCtlFlowChar == "@") { + indentUnitRq = -2; //-2 new pipe rq after cur pipe + break; + } + if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + case "M": // m4 + if (state.tlvPrevPrevCtlFlowChar == "@") { + indentUnitRq = -2; //-2 new inst rq after pipe + break; + } + if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + case "@": + if (state.tlvPrevCtlFlowChar == "S") + indentUnitRq = -1; // new pipe stage after stmts + if (state.tlvPrevCtlFlowChar == "|") + indentUnitRq = 1; // 1st pipe stage + break; + case "S": + if (state.tlvPrevCtlFlowChar == "@") + indentUnitRq = 1; // flow in pipe stage + if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + } + var statementIndentUnit = tlvindentUnit; + rtnIndent = curIndent + (indentUnitRq*statementIndentUnit); + return rtnIndent >= 0 ? rtnIndent : curIndent; + } + + CodeMirror.defineMIME("text/x-tlv", { + name: "verilog", + hooks: { + "\\": function(stream, state) { + var vxIndent = 0, style = false; + var curPunc = stream.string; + if ((stream.sol()) && ((/\\SV/.test(stream.string)) || (/\\TLV/.test(stream.string)))) { + curPunc = (/\\TLV_version/.test(stream.string)) + ? "\\TLV_version" : stream.string; + stream.skipToEnd(); + if (curPunc == "\\SV" && state.vxCodeActive) {state.vxCodeActive = false;}; + if ((/\\TLV/.test(curPunc) && !state.vxCodeActive) + || (curPunc=="\\TLV_version" && state.vxCodeActive)) {state.vxCodeActive = true;}; + style = "keyword"; + state.tlvCurCtlFlowChar = state.tlvPrevPrevCtlFlowChar + = state.tlvPrevCtlFlowChar = ""; + if (state.vxCodeActive == true) { + state.tlvCurCtlFlowChar = "\\"; + vxIndent = tlvGenIndent(stream, state); + } + state.vxIndentRq = vxIndent; + } + return style; + }, + tokenBase: function(stream, state) { + var vxIndent = 0, style = false; + var tlvisOperatorChar = /[\[\]=:]/; + var tlvkpScopePrefixs = { + "**":"variable-2", "*":"variable-2", "$$":"variable", "$":"variable", + "^^":"attribute", "^":"attribute"}; + var ch = stream.peek(); + var vxCurCtlFlowCharValueAtStart = state.tlvCurCtlFlowChar; + if (state.vxCodeActive == true) { + if (/[\[\]{}\(\);\:]/.test(ch)) { + // bypass nesting and 1 char punc + style = "meta"; + stream.next(); + } else if (ch == "/") { + stream.next(); + if (stream.eat("/")) { + stream.skipToEnd(); + style = "comment"; + state.tlvCurCtlFlowChar = "S"; + } else { + stream.backUp(1); + } + } else if (ch == "@") { + // pipeline stage + style = tlvchScopePrefixes[ch]; + state.tlvCurCtlFlowChar = "@"; + stream.next(); + stream.eatWhile(/[\w\$_]/); + } else if (stream.match(/\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive) + // m4 pre proc + stream.skipTo("("); + style = "def"; + state.tlvCurCtlFlowChar = "M"; + } else if (ch == "!" && stream.sol()) { + // v stmt in tlv region + // state.tlvCurCtlFlowChar = "S"; + style = "comment"; + stream.next(); + } else if (tlvisOperatorChar.test(ch)) { + // operators + stream.eatWhile(tlvisOperatorChar); + style = "operator"; + } else if (ch == "#") { + // phy hier + state.tlvCurCtlFlowChar = (state.tlvCurCtlFlowChar == "") + ? ch : state.tlvCurCtlFlowChar; + stream.next(); + stream.eatWhile(/[+-]\d/); + style = "tag"; + } else if (tlvkpScopePrefixs.propertyIsEnumerable(ch)) { + // special TLV operators + style = tlvkpScopePrefixs[ch]; + state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? "S" : state.tlvCurCtlFlowChar; // stmt + stream.next(); + stream.match(/[a-zA-Z_0-9]+/); + } else if (style = tlvchScopePrefixes[ch] || false) { + // special TLV operators + state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? ch : state.tlvCurCtlFlowChar; + stream.next(); + stream.match(/[a-zA-Z_0-9]+/); + } + if (state.tlvCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change + vxIndent = tlvGenIndent(stream, state); + state.vxIndentRq = vxIndent; + } + } + return style; + }, + token: function(stream, state) { + if (state.vxCodeActive == true && stream.sol() && state.tlvCurCtlFlowChar != "") { + state.tlvPrevPrevCtlFlowChar = state.tlvPrevCtlFlowChar; + state.tlvPrevCtlFlowChar = state.tlvCurCtlFlowChar; + state.tlvCurCtlFlowChar = ""; + } + }, + indent: function(state) { + return (state.vxCodeActive == true) ? state.vxIndentRq : -1; + }, + startState: function(state) { + state.tlvCurCtlFlowChar = ""; + state.tlvPrevCtlFlowChar = ""; + state.tlvPrevPrevCtlFlowChar = ""; + state.vxCodeActive = true; + state.vxIndentRq = 0; + } + } + }); +}); diff --git a/rhodecode/public/js/mode/vhdl/vhdl.js b/rhodecode/public/js/mode/vhdl/vhdl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/vhdl/vhdl.js @@ -0,0 +1,189 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Originally written by Alf Nielsen, re-written by Michael Zhou +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function words(str) { + var obj = {}, words = str.split(","); + for (var i = 0; i < words.length; ++i) { + var allCaps = words[i].toUpperCase(); + var firstCap = words[i].charAt(0).toUpperCase() + words[i].slice(1); + obj[words[i]] = true; + obj[allCaps] = true; + obj[firstCap] = true; + } + return obj; +} + +function metaHook(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; +} + +CodeMirror.defineMode("vhdl", function(config, parserConfig) { + var indentUnit = config.indentUnit, + atoms = parserConfig.atoms || words("null"), + hooks = parserConfig.hooks || {"`": metaHook, "$": metaHook}, + multiLineStrings = parserConfig.multiLineStrings; + + var keywords = words("abs,access,after,alias,all,and,architecture,array,assert,attribute,begin,block," + + "body,buffer,bus,case,component,configuration,constant,disconnent,downto,else,elsif,end,end block,end case," + + "end component,end for,end generate,end if,end loop,end process,end record,end units,entity,exit,file,for," + + "function,generate,generic,generic map,group,guarded,if,impure,in,inertial,inout,is,label,library,linkage," + + "literal,loop,map,mod,nand,new,next,nor,null,of,on,open,or,others,out,package,package body,port,port map," + + "postponed,procedure,process,pure,range,record,register,reject,rem,report,return,rol,ror,select,severity,signal," + + "sla,sll,sra,srl,subtype,then,to,transport,type,unaffected,units,until,use,variable,wait,when,while,with,xnor,xor"); + + var blockKeywords = words("architecture,entity,begin,case,port,else,elsif,end,for,function,if"); + + var isOperatorChar = /[&|~><!\)\(*#%@+\/=?\:;}{,\.\^\-\[\]]/; + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"') { + state.tokenize = tokenString2(ch); + return state.tokenize(stream, state); + } + if (ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/[\d']/.test(ch)) { + stream.eatWhile(/[\w\.']/); + return "number"; + } + if (ch == "-") { + if (stream.eat("-")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur.toLowerCase())) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "--"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return "string"; + }; + } + function tokenString2(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "--"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return "string-2"; + }; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}" + }; +}); + +CodeMirror.defineMIME("text/x-vhdl", "vhdl"); + +}); diff --git a/rhodecode/public/js/mode/vue/vue.js b/rhodecode/public/js/mode/vue/vue.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/vue/vue.js @@ -0,0 +1,69 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function (mod) { + "use strict"; + if (typeof exports === "object" && typeof module === "object") {// CommonJS + mod(require("../../lib/codemirror"), + require("../../addon/mode/overlay"), + require("../xml/xml"), + require("../javascript/javascript"), + require("../coffeescript/coffeescript"), + require("../css/css"), + require("../sass/sass"), + require("../stylus/stylus"), + require("../jade/jade"), + require("../handlebars/handlebars")); + } else if (typeof define === "function" && define.amd) { // AMD + define(["../../lib/codemirror", + "../../addon/mode/overlay", + "../xml/xml", + "../javascript/javascript", + "../coffeescript/coffeescript", + "../css/css", + "../sass/sass", + "../stylus/stylus", + "../jade/jade", + "../handlebars/handlebars"], mod); + } else { // Plain browser env + mod(CodeMirror); + } +})(function (CodeMirror) { + var tagLanguages = { + script: [ + ["lang", /coffee(script)?/, "coffeescript"], + ["type", /^(?:text|application)\/(?:x-)?coffee(?:script)?$/, "coffeescript"] + ], + style: [ + ["lang", /^stylus$/i, "stylus"], + ["lang", /^sass$/i, "sass"], + ["type", /^(text\/)?(x-)?styl(us)?$/i, "stylus"], + ["type", /^text\/sass/i, "sass"] + ], + template: [ + ["lang", /^vue-template$/i, "vue"], + ["lang", /^jade$/i, "jade"], + ["lang", /^handlebars$/i, "handlebars"], + ["type", /^(text\/)?(x-)?jade$/i, "jade"], + ["type", /^text\/x-handlebars-template$/i, "handlebars"], + [null, null, "vue-template"] + ] + }; + + CodeMirror.defineMode("vue-template", function (config, parserConfig) { + var mustacheOverlay = { + token: function (stream) { + if (stream.match(/^\{\{.*?\}\}/)) return "meta mustache"; + while (stream.next() && !stream.match("{{", false)) {} + return null; + } + }; + return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay); + }); + + CodeMirror.defineMode("vue", function (config) { + return CodeMirror.getMode(config, {name: "htmlmixed", tags: tagLanguages}); + }, "htmlmixed", "xml", "javascript", "coffeescript", "css", "sass", "stylus", "jade", "handlebars"); + + CodeMirror.defineMIME("script/x-vue", "vue"); +}); diff --git a/rhodecode/public/js/mode/xml/xml.js b/rhodecode/public/js/mode/xml/xml.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/xml/xml.js @@ -0,0 +1,384 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("xml", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; + var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag; + if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true; + + var Kludges = parserConfig.htmlMode ? { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true, 'menuitem': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: true, + caseFold: true + } : { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false, + caseFold: false + }; + var alignCDATA = parserConfig.alignCDATA; + + // Return variables for tokenizers + var type, setStyle; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else { + return null; + } + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + state.tokenize = inTag; + return "tag bracket"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return null; + } + } + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag bracket"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (ch == "<") { + state.tokenize = inText; + state.state = baseState; + state.tagName = state.tagStart = null; + var next = state.tokenize(stream, state); + return next ? next + " tag error" : "tag error"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + state.stringStartCol = stream.column(); + return state.tokenize(stream, state); + } else { + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); + return "word"; + } + } + + function inAttribute(quote) { + var closure = function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + closure.isInAttribute = true; + return closure; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + function Context(state, tagName, startOfLine) { + this.prev = state.context; + this.tagName = tagName; + this.indent = state.indented; + this.startOfLine = startOfLine; + if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) + this.noIndent = true; + } + function popContext(state) { + if (state.context) state.context = state.context.prev; + } + function maybePopContext(state, nextTagName) { + var parentTagName; + while (true) { + if (!state.context) { + return; + } + parentTagName = state.context.tagName; + if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || + !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(state); + } + } + + function baseState(type, stream, state) { + if (type == "openTag") { + state.tagStart = stream.column(); + return tagNameState; + } else if (type == "closeTag") { + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if (state.context && state.context.tagName == tagName) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else { + setStyle = "error"; + return closeStateErr; + } + } + + function closeState(type, _stream, state) { + if (type != "endTag") { + setStyle = "error"; + return closeState; + } + popContext(state); + return baseState; + } + function closeStateErr(type, stream, state) { + setStyle = "error"; + return closeState(type, stream, state); + } + + function attrState(type, _stream, state) { + if (type == "word") { + setStyle = "attribute"; + return attrEqState; + } else if (type == "endTag" || type == "selfcloseTag") { + var tagName = state.tagName, tagStart = state.tagStart; + state.tagName = state.tagStart = null; + if (type == "selfcloseTag" || + Kludges.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); + } else { + maybePopContext(state, tagName); + state.context = new Context(state, tagName, tagStart == state.indented); + } + return baseState; + } + setStyle = "error"; + return attrState; + } + function attrEqState(type, stream, state) { + if (type == "equals") return attrValueState; + if (!Kludges.allowMissing) setStyle = "error"; + return attrState(type, stream, state); + } + function attrValueState(type, stream, state) { + if (type == "string") return attrContinuedState; + if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;} + setStyle = "error"; + return attrState(type, stream, state); + } + function attrContinuedState(type, stream, state) { + if (type == "string") return attrContinuedState; + return attrState(type, stream, state); + } + + return { + startState: function() { + return {tokenize: inText, + state: baseState, + indented: 0, + tagName: null, tagStart: null, + context: null}; + }, + + token: function(stream, state) { + if (!state.tagName && stream.sol()) + state.indented = stream.indentation(); + + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + setStyle = null; + state.state = state.state(type || style, stream, state); + if (setStyle) + style = setStyle == "error" ? style + " error" : setStyle; + } + return style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + // Indent multi-line strings (e.g. css). + if (state.tokenize.isInAttribute) { + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; + } + if (context && context.noIndent) return CodeMirror.Pass; + if (state.tokenize != inTag && state.tokenize != inText) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + // Indent the starts of attribute names. + if (state.tagName) { + if (multilineTagIndentPastTag) + return state.tagStart + state.tagName.length + 2; + else + return state.tagStart + indentUnit * multilineTagIndentFactor; + } + if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0; + var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter); + if (tagAfter && tagAfter[1]) { // Closing tag spotted + while (context) { + if (context.tagName == tagAfter[2]) { + context = context.prev; + break; + } else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) { + context = context.prev; + } else { + break; + } + } + } else if (tagAfter) { // Opening tag spotted + while (context) { + var grabbers = Kludges.contextGrabbers[context.tagName]; + if (grabbers && grabbers.hasOwnProperty(tagAfter[2])) + context = context.prev; + else + break; + } + } + while (context && !context.startOfLine) + context = context.prev; + if (context) return context.indent + indentUnit; + else return 0; + }, + + electricInput: /<\/[\s\w:]+>$/, + blockCommentStart: "<!--", + blockCommentEnd: "-->", + + configuration: parserConfig.htmlMode ? "html" : "xml", + helperType: parserConfig.htmlMode ? "html" : "xml" + }; +}); + +CodeMirror.defineMIME("text/xml", "xml"); +CodeMirror.defineMIME("application/xml", "xml"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) + CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); + +}); diff --git a/rhodecode/public/js/mode/xquery/xquery.js b/rhodecode/public/js/mode/xquery/xquery.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/xquery/xquery.js @@ -0,0 +1,437 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("xquery", function() { + + // The keywords object is set to the result of this self executing + // function. Each keyword is a property of the keywords object whose + // value is {type: atype, style: astyle} + var keywords = function(){ + // conveinence functions used to build keywords object + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a") + , B = kw("keyword b") + , C = kw("keyword c") + , operator = kw("operator") + , atom = {type: "atom", style: "atom"} + , punctuation = {type: "punctuation", style: null} + , qualifier = {type: "axis_specifier", style: "qualifier"}; + + // kwObj is what is return from this function at the end + var kwObj = { + 'if': A, 'switch': A, 'while': A, 'for': A, + 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B, + 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C, + 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C, + ',': punctuation, + 'null': atom, 'fn:false()': atom, 'fn:true()': atom + }; + + // a list of 'basic' keywords. For each add a property to kwObj with the value of + // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"} + var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before', + 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self', + 'descending','document','document-node','element','else','eq','every','except','external','following', + 'following-sibling','follows','for','function','if','import','in','instance','intersect','item', + 'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding', + 'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element', + 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where', + 'xquery', 'empty-sequence']; + for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);}; + + // a list of types. For each add a property to kwObj with the value of + // {type: "atom", style: "atom"} + var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime', + 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary', + 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration']; + for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;}; + + // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"} + var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-']; + for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;}; + + // each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"} + var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::", + "ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"]; + for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; }; + + return kwObj; + }(); + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + // the primary mode tokenizer + function tokenBase(stream, state) { + var ch = stream.next(), + mightBeFunction = false, + isEQName = isEQNameAhead(stream); + + // an XML tag (if not in some sub, chained tokenizer) + if (ch == "<") { + if(stream.match("!--", true)) + return chain(stream, state, tokenXMLComment); + + if(stream.match("![CDATA", false)) { + state.tokenize = tokenCDATA; + return "tag"; + } + + if(stream.match("?", false)) { + return chain(stream, state, tokenPreProcessing); + } + + var isclose = stream.eat("/"); + stream.eatSpace(); + var tagName = "", c; + while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; + + return chain(stream, state, tokenTag(tagName, isclose)); + } + // start code block + else if(ch == "{") { + pushStateStack(state,{ type: "codeblock"}); + return null; + } + // end code block + else if(ch == "}") { + popStateStack(state); + return null; + } + // if we're in an XML block + else if(isInXmlBlock(state)) { + if(ch == ">") + return "tag"; + else if(ch == "/" && stream.eat(">")) { + popStateStack(state); + return "tag"; + } + else + return "variable"; + } + // if a number + else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:E[+\-]?\d+)?/); + return "atom"; + } + // comment start + else if (ch === "(" && stream.eat(":")) { + pushStateStack(state, { type: "comment"}); + return chain(stream, state, tokenComment); + } + // quoted string + else if ( !isEQName && (ch === '"' || ch === "'")) + return chain(stream, state, tokenString(ch)); + // variable + else if(ch === "$") { + return chain(stream, state, tokenVariable); + } + // assignment + else if(ch ===":" && stream.eat("=")) { + return "keyword"; + } + // open paren + else if(ch === "(") { + pushStateStack(state, { type: "paren"}); + return null; + } + // close paren + else if(ch === ")") { + popStateStack(state); + return null; + } + // open paren + else if(ch === "[") { + pushStateStack(state, { type: "bracket"}); + return null; + } + // close paren + else if(ch === "]") { + popStateStack(state); + return null; + } + else { + var known = keywords.propertyIsEnumerable(ch) && keywords[ch]; + + // if there's a EQName ahead, consume the rest of the string portion, it's likely a function + if(isEQName && ch === '\"') while(stream.next() !== '"'){} + if(isEQName && ch === '\'') while(stream.next() !== '\''){} + + // gobble up a word if the character is not known + if(!known) stream.eatWhile(/[\w\$_-]/); + + // gobble a colon in the case that is a lib func type call fn:doc + var foundColon = stream.eat(":"); + + // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier + // which should get matched as a keyword + if(!stream.eat(":") && foundColon) { + stream.eatWhile(/[\w\$_-]/); + } + // if the next non whitespace character is an open paren, this is probably a function (if not a keyword of other sort) + if(stream.match(/^[ \t]*\(/, false)) { + mightBeFunction = true; + } + // is the word a keyword? + var word = stream.current(); + known = keywords.propertyIsEnumerable(word) && keywords[word]; + + // if we think it's a function call but not yet known, + // set style to variable for now for lack of something better + if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"}; + + // if the previous word was element, attribute, axis specifier, this word should be the name of that + if(isInXmlConstructor(state)) { + popStateStack(state); + return "variable"; + } + // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and + // push the stack so we know to look for it on the next word + if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"}); + + // if the word is known, return the details of that else just call this a generic 'word' + return known ? known.style : "variable"; + } + } + + // handle comments, including nested + function tokenComment(stream, state) { + var maybeEnd = false, maybeNested = false, nestedCount = 0, ch; + while (ch = stream.next()) { + if (ch == ")" && maybeEnd) { + if(nestedCount > 0) + nestedCount--; + else { + popStateStack(state); + break; + } + } + else if(ch == ":" && maybeNested) { + nestedCount++; + } + maybeEnd = (ch == ":"); + maybeNested = (ch == "("); + } + + return "comment"; + } + + // tokenizer for string literals + // optionally pass a tokenizer function to set state.tokenize back to when finished + function tokenString(quote, f) { + return function(stream, state) { + var ch; + + if(isInString(state) && stream.current() == quote) { + popStateStack(state); + if(f) state.tokenize = f; + return "string"; + } + + pushStateStack(state, { type: "string", name: quote, tokenize: tokenString(quote, f) }); + + // if we're in a string and in an XML block, allow an embedded code block + if(stream.match("{", false) && isInXmlAttributeBlock(state)) { + state.tokenize = tokenBase; + return "string"; + } + + + while (ch = stream.next()) { + if (ch == quote) { + popStateStack(state); + if(f) state.tokenize = f; + break; + } + else { + // if we're in a string and in an XML block, allow an embedded code block in an attribute + if(stream.match("{", false) && isInXmlAttributeBlock(state)) { + state.tokenize = tokenBase; + return "string"; + } + + } + } + + return "string"; + }; + } + + // tokenizer for variables + function tokenVariable(stream, state) { + var isVariableChar = /[\w\$_-]/; + + // a variable may start with a quoted EQName so if the next character is quote, consume to the next quote + if(stream.eat("\"")) { + while(stream.next() !== '\"'){}; + stream.eat(":"); + } else { + stream.eatWhile(isVariableChar); + if(!stream.match(":=", false)) stream.eat(":"); + } + stream.eatWhile(isVariableChar); + state.tokenize = tokenBase; + return "variable"; + } + + // tokenizer for XML tags + function tokenTag(name, isclose) { + return function(stream, state) { + stream.eatSpace(); + if(isclose && stream.eat(">")) { + popStateStack(state); + state.tokenize = tokenBase; + return "tag"; + } + // self closing tag without attributes? + if(!stream.eat("/")) + pushStateStack(state, { type: "tag", name: name, tokenize: tokenBase}); + if(!stream.eat(">")) { + state.tokenize = tokenAttribute; + return "tag"; + } + else { + state.tokenize = tokenBase; + } + return "tag"; + }; + } + + // tokenizer for XML attributes + function tokenAttribute(stream, state) { + var ch = stream.next(); + + if(ch == "/" && stream.eat(">")) { + if(isInXmlAttributeBlock(state)) popStateStack(state); + if(isInXmlBlock(state)) popStateStack(state); + return "tag"; + } + if(ch == ">") { + if(isInXmlAttributeBlock(state)) popStateStack(state); + return "tag"; + } + if(ch == "=") + return null; + // quoted string + if (ch == '"' || ch == "'") + return chain(stream, state, tokenString(ch, tokenAttribute)); + + if(!isInXmlAttributeBlock(state)) + pushStateStack(state, { type: "attribute", tokenize: tokenAttribute}); + + stream.eat(/[a-zA-Z_:]/); + stream.eatWhile(/[-a-zA-Z0-9_:.]/); + stream.eatSpace(); + + // the case where the attribute has not value and the tag was closed + if(stream.match(">", false) || stream.match("/", false)) { + popStateStack(state); + state.tokenize = tokenBase; + } + + return "attribute"; + } + + // handle comments, including nested + function tokenXMLComment(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "-" && stream.match("->", true)) { + state.tokenize = tokenBase; + return "comment"; + } + } + } + + + // handle CDATA + function tokenCDATA(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "]" && stream.match("]", true)) { + state.tokenize = tokenBase; + return "comment"; + } + } + } + + // handle preprocessing instructions + function tokenPreProcessing(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "?" && stream.match(">", true)) { + state.tokenize = tokenBase; + return "comment meta"; + } + } + } + + + // functions to test the current context of the state + function isInXmlBlock(state) { return isIn(state, "tag"); } + function isInXmlAttributeBlock(state) { return isIn(state, "attribute"); } + function isInXmlConstructor(state) { return isIn(state, "xmlconstructor"); } + function isInString(state) { return isIn(state, "string"); } + + function isEQNameAhead(stream) { + // assume we've already eaten a quote (") + if(stream.current() === '"') + return stream.match(/^[^\"]+\"\:/, false); + else if(stream.current() === '\'') + return stream.match(/^[^\"]+\'\:/, false); + else + return false; + } + + function isIn(state, type) { + return (state.stack.length && state.stack[state.stack.length - 1].type == type); + } + + function pushStateStack(state, newState) { + state.stack.push(newState); + } + + function popStateStack(state) { + state.stack.pop(); + var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize; + state.tokenize = reinstateTokenize || tokenBase; + } + + // the interface for the mode API + return { + startState: function() { + return { + tokenize: tokenBase, + cc: [], + stack: [] + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + }, + + blockCommentStart: "(:", + blockCommentEnd: ":)" + + }; + +}); + +CodeMirror.defineMIME("application/xquery", "xquery"); + +}); diff --git a/rhodecode/public/js/mode/yaml-frontmatter/yaml-frontmatter.js b/rhodecode/public/js/mode/yaml-frontmatter/yaml-frontmatter.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/yaml-frontmatter/yaml-frontmatter.js @@ -0,0 +1,68 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function (mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../yaml/yaml")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../yaml/yaml"], mod) + else // Plain browser env + mod(CodeMirror) +})(function (CodeMirror) { + + var START = 0, FRONTMATTER = 1, BODY = 2 + + // a mixed mode for Markdown text with an optional YAML front matter + CodeMirror.defineMode("yaml-frontmatter", function (config, parserConfig) { + var yamlMode = CodeMirror.getMode(config, "yaml") + var innerMode = CodeMirror.getMode(config, parserConfig && parserConfig.base || "gfm") + + function curMode(state) { + return state.state == BODY ? innerMode : yamlMode + } + + return { + startState: function () { + return { + state: START, + inner: CodeMirror.startState(yamlMode) + } + }, + copyState: function (state) { + return { + state: state.state, + inner: CodeMirror.copyState(curMode(state), state.inner) + } + }, + token: function (stream, state) { + if (state.state == START) { + if (stream.match(/---/, false)) { + state.state = FRONTMATTER + return yamlMode.token(stream, state.inner) + } else { + state.state = BODY + state.inner = CodeMirror.startState(innerMode) + return innerMode.token(stream, state.inner) + } + } else if (state.state == FRONTMATTER) { + var end = stream.sol() && stream.match(/---/, false) + var style = yamlMode.token(stream, state.inner) + if (end) { + state.state = BODY + state.inner = CodeMirror.startState(innerMode) + } + return style + } else { + return innerMode.token(stream, state.inner) + } + }, + innerMode: function (state) { + return {mode: curMode(state), state: state.inner} + }, + blankLine: function (state) { + var mode = curMode(state) + if (mode.blankLine) return mode.blankLine(state.inner) + } + } + }) +}) diff --git a/rhodecode/public/js/mode/yaml/yaml.js b/rhodecode/public/js/mode/yaml/yaml.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/yaml/yaml.js @@ -0,0 +1,117 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("yaml", function() { + + var cons = ['true', 'false', 'on', 'off', 'yes', 'no']; + var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i'); + + return { + token: function(stream, state) { + var ch = stream.peek(); + var esc = state.escaped; + state.escaped = false; + /* comments */ + if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) { + stream.skipToEnd(); + return "comment"; + } + + if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/)) + return "string"; + + if (state.literal && stream.indentation() > state.keyCol) { + stream.skipToEnd(); return "string"; + } else if (state.literal) { state.literal = false; } + if (stream.sol()) { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + /* document start */ + if(stream.match(/---/)) { return "def"; } + /* document end */ + if (stream.match(/\.\.\./)) { return "def"; } + /* array list item */ + if (stream.match(/\s*-\s+/)) { return 'meta'; } + } + /* inline pairs/lists */ + if (stream.match(/^(\{|\}|\[|\])/)) { + if (ch == '{') + state.inlinePairs++; + else if (ch == '}') + state.inlinePairs--; + else if (ch == '[') + state.inlineList++; + else + state.inlineList--; + return 'meta'; + } + + /* list seperator */ + if (state.inlineList > 0 && !esc && ch == ',') { + stream.next(); + return 'meta'; + } + /* pairs seperator */ + if (state.inlinePairs > 0 && !esc && ch == ',') { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + stream.next(); + return 'meta'; + } + + /* start of value of a pair */ + if (state.pairStart) { + /* block literals */ + if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; }; + /* references */ + if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; } + /* numbers */ + if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; } + if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; } + /* keywords */ + if (stream.match(keywordRegex)) { return 'keyword'; } + } + + /* pairs (associative arrays) -> key */ + if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)) { + state.pair = true; + state.keyCol = stream.indentation(); + return "atom"; + } + if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; } + + /* nothing found, continue */ + state.pairStart = false; + state.escaped = (ch == '\\'); + stream.next(); + return null; + }, + startState: function() { + return { + pair: false, + pairStart: false, + keyCol: 0, + inlinePairs: 0, + inlineList: 0, + literal: false, + escaped: false + }; + } + }; +}); + +CodeMirror.defineMIME("text/x-yaml", "yaml"); + +}); diff --git a/rhodecode/public/js/mode/z80/z80.js b/rhodecode/public/js/mode/z80/z80.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/z80/z80.js @@ -0,0 +1,116 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('z80', function(_config, parserConfig) { + var ez80 = parserConfig.ez80; + var keywords1, keywords2; + if (ez80) { + keywords1 = /^(exx?|(ld|cp)([di]r?)?|[lp]ea|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|[de]i|halt|im|in([di]mr?|ir?|irx|2r?)|ot(dmr?|[id]rx|imr?)|out(0?|[di]r?|[di]2r?)|tst(io)?|slp)(\.([sl]?i)?[sl])?\b/i; + keywords2 = /^(((call|j[pr]|rst|ret[in]?)(\.([sl]?i)?[sl])?)|(rs|st)mix)\b/i; + } else { + keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i; + keywords2 = /^(call|j[pr]|ret[in]?|b_?(call|jump))\b/i; + } + + var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i; + var variables2 = /^(n?[zc]|p[oe]?|m)\b/i; + var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i; + var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+d?)\b/i; + + return { + startState: function() { + return { + context: 0 + }; + }, + token: function(stream, state) { + if (!stream.column()) + state.context = 0; + + if (stream.eatSpace()) + return null; + + var w; + + if (stream.eatWhile(/\w/)) { + if (ez80 && stream.eat('.')) { + stream.eatWhile(/\w/); + } + w = stream.current(); + + if (stream.indentation()) { + if ((state.context == 1 || state.context == 4) && variables1.test(w)) { + state.context = 4; + return 'var2'; + } + + if (state.context == 2 && variables2.test(w)) { + state.context = 4; + return 'var3'; + } + + if (keywords1.test(w)) { + state.context = 1; + return 'keyword'; + } else if (keywords2.test(w)) { + state.context = 2; + return 'keyword'; + } else if (state.context == 4 && numbers.test(w)) { + return 'number'; + } + + if (errors.test(w)) + return 'error'; + } else if (stream.match(numbers)) { + return 'number'; + } else { + return null; + } + } else if (stream.eat(';')) { + stream.skipToEnd(); + return 'comment'; + } else if (stream.eat('"')) { + while (w = stream.next()) { + if (w == '"') + break; + + if (w == '\\') + stream.next(); + } + return 'string'; + } else if (stream.eat('\'')) { + if (stream.match(/\\?.'/)) + return 'number'; + } else if (stream.eat('.') || stream.sol() && stream.eat('#')) { + state.context = 5; + + if (stream.eatWhile(/\w/)) + return 'def'; + } else if (stream.eat('$')) { + if (stream.eatWhile(/[\da-f]/i)) + return 'number'; + } else if (stream.eat('%')) { + if (stream.eatWhile(/[01]/)) + return 'number'; + } else { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-z80", "z80"); +CodeMirror.defineMIME("text/x-ez80", { name: "z80", ez80: true }); + +}); diff --git a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js @@ -0,0 +1,89 @@ +// Global keyboard bindings + +function setRCMouseBindings(repoName, repoLandingRev) { + // general help "?" + Mousetrap.bind(['?'], function(e) { + $('#help_kb').modal({}); + }); + + // / open the quick filter + Mousetrap.bind(['/'], function(e) { + $('#repo_switcher').select2('open'); + + // return false to prevent default browser behavior + // and stop event from bubbling + return false; + }); + + // ctrl/command+b, show the the main bar + Mousetrap.bind(['command+b', 'ctrl+b'], function(e) { + var $headerInner = $('#header-inner'), + $content = $('#content'); + if ($headerInner.hasClass('hover') && $content.hasClass('hover')) { + $headerInner.removeClass('hover'); + $content.removeClass('hover'); + } else { + $headerInner.addClass('hover'); + $content.addClass('hover'); + } + return false; + }); + + // general nav g + action + Mousetrap.bind(['g h'], function(e) { + window.location = pyroutes.url('home'); + }); + Mousetrap.bind(['g g'], function(e) { + window.location = pyroutes.url('gists', {'private': 1}); + }); + Mousetrap.bind(['g G'], function(e) { + window.location = pyroutes.url('gists', {'public': 1}); + }); + Mousetrap.bind(['n g'], function(e) { + window.location = pyroutes.url('new_gist'); + }); + Mousetrap.bind(['n r'], function(e) { + window.location = pyroutes.url('new_repo'); + }); + + if (repoName !== '' && repoLandingRev !== '') { + // nav in repo context + Mousetrap.bind(['g s'], function(e) { + window.location = pyroutes.url( + 'summary_home', {'repo_name': repoName}); + }); + Mousetrap.bind(['g c'], function(e) { + window.location = pyroutes.url( + 'changelog_home', {'repo_name': repoName}); + }); + Mousetrap.bind(['g F'], function(e) { + window.location = pyroutes.url( + 'files_home', + { + 'repo_name': repoName, + 'revision': repoLandingRev, + 'f_path': '', + 'search': '1' + }); + }); + Mousetrap.bind(['g f'], function(e) { + window.location = pyroutes.url( + 'files_home', + { + 'repo_name': repoName, + 'revision': repoLandingRev, + 'f_path': '' + }); + }); + Mousetrap.bind(['g o'], function(e) { + window.location = pyroutes.url( + 'edit_repo', {'repo_name': repoName}); + }); + Mousetrap.bind(['g O'], function(e) { + window.location = pyroutes.url( + 'edit_repo_perms', {'repo_name': repoName}); + }); + } +} + +setRCMouseBindings(templateContext.repo_name, templateContext.repo_landing_commit); diff --git a/rhodecode/public/js/rhodecode/i18n/be.js b/rhodecode/public/js/rhodecode/i18n/be.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/be.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabled', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Open new pull request', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Submitting...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/de.js b/rhodecode/public/js/rhodecode/i18n/de.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/de.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabled', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Open new pull request', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Submitting...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/en.js b/rhodecode/public/js/rhodecode/i18n/en.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/en.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabled', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Open new pull request', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Submitting...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/es.js b/rhodecode/public/js/rhodecode/i18n/es.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/es.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabled', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Open new pull request', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Submitting...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/fr.js b/rhodecode/public/js/rhodecode/i18n/fr.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/fr.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'Désactivé', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Nouvelle requête de pull', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Envoi…', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/it.js b/rhodecode/public/js/rhodecode/i18n/it.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/it.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabilitato', + 'enabled': 'abilitato', + 'Follow': 'Segui', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Apri una richiesta PULL', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Inoltro...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Smetti di seguire', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/ja.js b/rhodecode/public/js/rhodecode/i18n/ja.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/ja.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': '無効', + 'enabled': '有効', + 'Follow': 'フォロー', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': '新しいプルリクエストを作成', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': '送信中...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'アンフォロー', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/pl.js b/rhodecode/public/js/rhodecode/i18n/pl.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/pl.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'disabled', + 'enabled': 'enabled', + 'Follow': 'Obserwuj', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Otwórz nową prośbę o połączenie gałęzi', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Przesyłanie...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Nie obserwuj', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/pt.js b/rhodecode/public/js/rhodecode/i18n/pt.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/pt.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'desabilitado', + 'enabled': 'enabled', + 'Follow': 'Seguir', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Crie novo pull request', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Enviando...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Parar de seguir', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/ru.js b/rhodecode/public/js/rhodecode/i18n/ru.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/ru.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': 'отключено', + 'enabled': 'enabled', + 'Follow': 'Наблюдать', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': 'Создать новый pull запрос', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': 'Применение...', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Не наблюдать', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/rhodecode/i18n/select2/translations.js b/rhodecode/public/js/rhodecode/i18n/select2/translations.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/select2/translations.js @@ -0,0 +1,34 @@ +// translate select2 components +select2Locales = { + formatLoadMore: function(pageNumber) { + return _TM["Loading more results..."]; + }, + formatSearching: function() { + return _TM["Searching..."]; + }, + formatNoMatches: function() { + return _TM["No matches found"]; + }, + formatAjaxError: function(jqXHR, textStatus, errorThrown) { + return _TM["Loading failed"]; + }, + formatMatches: function(matches) { + if (matches === 1) { + return _TM["One result is available, press enter to select it."]; + } + return _TM["{0} results are available, use up and down arrow keys to navigate."].format(matches); + }, + formatInputTooShort: function(input, min) { + var n = min - input.length; + return "Please enter {0} or more character".format(n) + (n === 1 ? "" : "s"); + }, + formatInputTooLong: function(input, max) { + var n = input.length - max; + return "Please delete {0} character".format(n) + (n === 1 ? "" : "s"); + }, + formatSelectionTooBig: function(limit) { + return "You can only select {0} item".format(limit) + (limit === 1 ? "" : "s"); + } +}; + +$.extend($.fn.select2.defaults, select2Locales); diff --git a/rhodecode/public/js/rhodecode/i18n/zh.js b/rhodecode/public/js/rhodecode/i18n/zh.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/rhodecode/i18n/zh.js @@ -0,0 +1,42 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_i18n_data.py + * and run the script invoke -r scripts/ generate.js-i18n . + */ +//JS translations map +var _TM = { + '{0} active out of {1} users': '{0} active out of {1} users', + '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', + 'Add another comment': 'Add another comment', + 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', + 'disabled': '禁用', + 'enabled': 'enabled', + 'Follow': 'Follow', + 'loading ...': 'loading ...', + 'Loading ...': 'Loading ...', + 'Loading failed': 'Loading failed', + 'Loading more results...': 'Loading more results...', + 'No matches found': 'No matches found', + 'No matching files': 'No matching files', + 'No results': 'No results', + 'One result is available, press enter to select it.': 'One result is available, press enter to select it.', + 'Open new pull request': '新建拉取请求', + 'Open new pull request for selected commit': 'Open new pull request for selected commit', + 'Searching...': 'Searching...', + 'Select changeset': 'Select changeset', + 'Select commit': 'Select commit', + 'Selection link': 'Selection link', + 'Set status to Approved': 'Set status to Approved', + 'Set status to Rejected': 'Set status to Rejected', + 'Show selected commit __S': 'Show selected commit __S', + 'Show selected commits __S ... __E': 'Show selected commits __S ... __E', + 'specify commit': 'specify commit', + 'Start following this repository': 'Start following this repository', + 'Status Review': 'Status Review', + 'Stop following this repository': 'Stop following this repository', + 'Submitting...': '提交中……', + 'truncated result': 'truncated result', + 'truncated results': 'truncated results', + 'Unfollow': 'Unfollow', + 'Updating...': 'Updating...' +}; \ No newline at end of file diff --git a/rhodecode/public/js/src/appenlight-client-0.4.1.min.js b/rhodecode/public/js/src/appenlight-client-0.4.1.min.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/appenlight-client-0.4.1.min.js @@ -0,0 +1,2 @@ +/*! appenlight-client 29-01-2016 */ +!function(a){"use strict";var b={version:"0.4.1",options:{apiKey:""},errorReportBuffer:[],slowReportBuffer:[],logBuffer:[],requestInfo:null,init:function(b){var c=this;"undefined"==typeof b.server&&(b.server="https://api.appenlight.com"),"undefined"==typeof b.apiKey&&(b.apiKey="undefined"),"undefined"==typeof b.protocol_version&&(b.protocol_version="0.5"),("undefined"==typeof b.windowOnError||0==b.windowOnError)&&(TraceKit.collectWindowErrors=!1),"undefined"==typeof b.sendInterval&&(b.sendInterval=1e3),"undefined"==typeof b.tracekitRemoteFetching&&(b.tracekitRemoteFetching=!0),"undefined"==typeof b.tracekitContextLines&&(b.tracekitContextLines=11),b.sendInterval>=1e3&&this.createSendInterval(b.sendInterval),this.options=b,this.requestInfo={url:a.location.href},this.reportsEndpoint=b.server+"/api/reports?public_api_key="+this.options.apiKey+"&protocol_version="+this.options.protocol_version,this.logsEndpoint=b.server+"/api/logs?public_api_key="+this.options.apiKey+"&protocol_version="+this.options.protocol_version,TraceKit.remoteFetching=b.tracekitRemoteFetching,TraceKit.linesOfContext=b.tracekitContextLines,TraceKit.report.subscribe(function(a){c.handleError(a)})},createSendInterval:function(a){var b=this;this.send_iv=setInterval(function(){b.sendReports(),b.sendLogs()},a)},setRequestInfo:function(a){for(var b in a)this.requestInfo[b]=a[b]},grabError:function(a){try{TraceKit.report(a)}catch(b){if(a!==b)throw b}},handleError:function(b){if("stack"==b.mode)var c=b.name+": "+b.message;else var c=b.message;var d={client:"javascript",language:"javascript",error:c,occurences:1,priority:5,server:"",http_status:500,request:{},traceback:[]};if(d.user_agent=a.navigator.userAgent,d.start_time=(new Date).toJSON(),null!=this.requestInfo)for(var e in this.requestInfo)d[e]=this.requestInfo[e];"undefined"!=typeof d.request_id&&d.request_id||(d.request_id=this.genUUID4());for(var f=b.stack.reverse().slice(-100),e=0;e<f.length;e++){var g="";try{if(f[e].context)for(var h=0;h<f[e].context.length;h++){var i=f[e].context[h];g+=i.length>300?"<minified-context>":i,g+="\n"}}catch(j){}var k={cline:g,file:f[e].url,fn:f[e].func,line:f[e].line,vars:[]};d.traceback.push(k)}d.traceback.length>0&&(d.traceback[d.traceback.length-1].cline=g+"\n"+c),this.errorReportBuffer.push(d)},log:function(b,c,d,e){if("undefined"==typeof d)var d=a.location.pathname;if("undefined"==typeof e)var e=null;this.logBuffer.push({log_level:b.toUpperCase(),message:c,date:(new Date).toJSON(),namespace:d}),null!=this.requestInfo&&"undefined"!=typeof this.requestInfo.server&&(this.logBuffer[this.logBuffer.length-1].server=this.requestInfo.server)},genUUID4:function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(a){var b=16*Math.random()|0,c="x"==a?b:3&b|8;return c.toString(16)})},sendReports:function(){if(this.errorReportBuffer.length<1)return!0;var a=this.errorReportBuffer;return this.submitData(this.reportsEndpoint,a),this.errorReportBuffer=[],!0},sendLogs:function(){if(this.logBuffer.length<1)return!0;var a=this.logBuffer;return this.submitData(this.logsEndpoint,a),this.logBuffer=[],!0},submitData:function(b,c){var d=new a.XMLHttpRequest;!d&&a.ActiveXObject&&(d=new a.ActiveXObject("Microsoft.XMLHTTP")),d.open("POST",b,!0),d.setRequestHeader("Content-Type","application/json"),d.send(JSON.stringify(c))}};a.AppEnlight=b,"function"==typeof define&&define.amd&&define("appenlight",[],function(){return b})}(window),function(a,b){function c(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function d(a){return"undefined"==typeof a}if(a){var e={},f=a.TraceKit,g=[].slice,h="?";e.noConflict=function(){return a.TraceKit=f,e},e.wrap=function(a){function b(){try{return a.apply(this,arguments)}catch(b){throw e.report(b),b}}return b},e.report=function(){function b(a){i(),n.push(a)}function d(a){for(var b=n.length-1;b>=0;--b)n[b]===a&&n.splice(b,1)}function f(a,b){var d=null;if(!b||e.collectWindowErrors){for(var f in n)if(c(n,f))try{n[f].apply(null,[a].concat(g.call(arguments,2)))}catch(h){d=h}if(d)throw d}}function h(a,b,c,d,g){var h=null;if(q)e.computeStackTrace.augmentStackTraceWithInitialElement(q,b,c,a),j();else if(g)h=e.computeStackTrace(g),f(h,!0);else{var i={url:b,line:c,column:d};i.func=e.computeStackTrace.guessFunctionName(i.url,i.line),i.context=e.computeStackTrace.gatherContext(i.url,i.line),h={mode:"onerror",message:a,stack:[i]},f(h,!0)}return l?l.apply(this,arguments):!1}function i(){m!==!0&&(l=a.onerror,a.onerror=h,m=!0)}function j(){var a=q,b=o;o=null,q=null,p=null,f.apply(null,[a,!1].concat(b))}function k(b){if(q){if(p===b)return;j()}var c=e.computeStackTrace(b);throw q=c,p=b,o=g.call(arguments,1),a.setTimeout(function(){p===b&&j()},c.incomplete?2e3:0),b}var l,m,n=[],o=null,p=null,q=null;return k.subscribe=b,k.unsubscribe=d,k}(),e.computeStackTrace=function(){function b(b){if(!e.remoteFetching)return"";try{var c=function(){try{return new a.XMLHttpRequest}catch(b){return new a.ActiveXObject("Microsoft.XMLHTTP")}},d=c();return d.open("GET",b,!1),d.send(""),d.responseText}catch(f){return""}}function f(a){if("string"!=typeof a)return[];if(!c(w,a)){var d="",e="";try{e=document.domain}catch(f){}-1!==a.indexOf(e)&&(d=b(a)),w[a]=d?d.split("\n"):[]}return w[a]}function g(a,b){var c,e=/function ([^(]*)\(([^)]*)\)/,g=/['"]?([0-9A-Za-z$_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,i="",j=10,k=f(a);if(!k.length)return h;for(var l=0;j>l;++l)if(i=k[b-l]+i,!d(i)){if(c=g.exec(i))return c[1];if(c=e.exec(i))return c[1]}return h}function i(a,b){var c=f(a);if(!c.length)return null;var g=[],h=Math.floor(e.linesOfContext/2),i=h+e.linesOfContext%2,j=Math.max(0,b-h-1),k=Math.min(c.length,b+i-1);b-=1;for(var l=j;k>l;++l)d(c[l])||g.push(c[l]);return g.length>0?g:null}function j(a){return a.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g,"\\$&")}function k(a){return j(a).replace("<","(?:<|<)").replace(">","(?:>|>)").replace("&","(?:&|&)").replace('"','(?:"|")').replace(/\s+/g,"\\s+")}function l(a,b){for(var c,d,e=0,g=b.length;g>e;++e)if((c=f(b[e])).length&&(c=c.join("\n"),d=a.exec(c)))return{url:b[e],line:c.substring(0,d.index).split("\n").length,column:d.index-c.lastIndexOf("\n",d.index)-1};return null}function m(a,b,c){var d,e=f(b),g=new RegExp("\\b"+j(a)+"\\b");return c-=1,e&&e.length>c&&(d=g.exec(e[c]))?d.index:null}function n(b){if(!d(document)){for(var c,e,f,g,h=[a.location.href],i=document.getElementsByTagName("script"),m=""+b,n=/^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,o=/^function on([\w$]+)\s*\(event\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,p=0;p<i.length;++p){var q=i[p];q.src&&h.push(q.src)}if(f=n.exec(m)){var r=f[1]?"\\s+"+f[1]:"",s=f[2].split(",").join("\\s*,\\s*");c=j(f[3]).replace(/;$/,";?"),e=new RegExp("function"+r+"\\s*\\(\\s*"+s+"\\s*\\)\\s*{\\s*"+c+"\\s*}")}else e=new RegExp(j(m).replace(/\s+/g,"\\s+"));if(g=l(e,h))return g;if(f=o.exec(m)){var t=f[1];if(c=k(f[2]),e=new RegExp("on"+t+"=[\\'\"]\\s*"+c+"\\s*[\\'\"]","i"),g=l(e,h[0]))return g;if(e=new RegExp(c),g=l(e,h))return g}return null}}function o(a){if(!a.stack)return null;for(var b,c,e=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,f=/^\s*(.*?)(?:\((.*?)\))?@?((?:file|https?|blob|chrome|\[).*?)(?::(\d+))?(?::(\d+))?\s*$/i,j=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,k=a.stack.split("\n"),l=[],n=/^(.*) is undefined$/.exec(a.message),o=0,p=k.length;p>o;++o){if(b=e.exec(k[o])){var q=b[2]&&-1!==b[2].indexOf("native");c={url:q?null:b[2],func:b[1]||h,args:q?[b[2]]:[],line:b[3]?+b[3]:null,column:b[4]?+b[4]:null}}else if(b=j.exec(k[o]))c={url:b[2],func:b[1]||h,args:[],line:+b[3],column:b[4]?+b[4]:null};else{if(!(b=f.exec(k[o])))continue;c={url:b[3],func:b[1]||h,args:b[2]?b[2].split(","):[],line:b[4]?+b[4]:null,column:b[5]?+b[5]:null}}!c.func&&c.line&&(c.func=g(c.url,c.line)),c.line&&(c.context=i(c.url,c.line)),l.push(c)}return l.length?(l[0]&&l[0].line&&!l[0].column&&n?l[0].column=m(n[1],l[0].url,l[0].line):l[0].column||d(a.columnNumber)||(l[0].column=a.columnNumber+1),{mode:"stack",name:a.name,message:a.message,stack:l}):null}function p(a){var b=a.stacktrace;if(b){for(var c,d=/ line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i,e=/ line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\))? in (.*):\s*$/i,f=b.split("\n"),h=[],j=0;j<f.length;j+=2){var k=null;if((c=d.exec(f[j]))?k={url:c[2],line:+c[1],column:null,func:c[3],args:[]}:(c=e.exec(f[j]))&&(k={url:c[6],line:+c[1],column:+c[2],func:c[3]||c[4],args:c[5]?c[5].split(","):[]}),k){if(!k.func&&k.line&&(k.func=g(k.url,k.line)),k.line)try{k.context=i(k.url,k.line)}catch(l){}k.context||(k.context=[f[j+1]]),h.push(k)}}return h.length?{mode:"stacktrace",name:a.name,message:a.message,stack:h}:null}}function q(b){var d=b.message.split("\n");if(d.length<4)return null;var e,h=/^\s*Line (\d+) of linked script ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,j=/^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,m=/^\s*Line (\d+) of function script\s*$/i,n=[],o=document.getElementsByTagName("script"),p=[];for(var q in o)c(o,q)&&!o[q].src&&p.push(o[q]);for(var r=2;r<d.length;r+=2){var s=null;if(e=h.exec(d[r]))s={url:e[2],func:e[3],args:[],line:+e[1],column:null};else if(e=j.exec(d[r])){s={url:e[3],func:e[4],args:[],line:+e[1],column:null};var t=+e[1],u=p[e[2]-1];if(u){var v=f(s.url);if(v){v=v.join("\n");var w=v.indexOf(u.innerText);w>=0&&(s.line=t+v.substring(0,w).split("\n").length)}}}else if(e=m.exec(d[r])){var x=a.location.href.replace(/#.*$/,""),y=new RegExp(k(d[r+1])),z=l(y,[x]);s={url:x,func:"",args:[],line:z?z.line:e[1],column:null}}if(s){s.func||(s.func=g(s.url,s.line));var A=i(s.url,s.line),B=A?A[Math.floor(A.length/2)]:null;A&&B.replace(/^\s*/,"")===d[r+1].replace(/^\s*/,"")?s.context=A:s.context=[d[r+1]],n.push(s)}}return n.length?{mode:"multiline",name:b.name,message:d[0],stack:n}:null}function r(a,b,c,d){var e={url:b,line:c};if(e.url&&e.line){a.incomplete=!1,e.func||(e.func=g(e.url,e.line)),e.context||(e.context=i(e.url,e.line));var f=/ '([^']+)' /.exec(d);if(f&&(e.column=m(f[1],e.url,e.line)),a.stack.length>0&&a.stack[0].url===e.url){if(a.stack[0].line===e.line)return!1;if(!a.stack[0].line&&a.stack[0].func===e.func)return a.stack[0].line=e.line,a.stack[0].context=e.context,!1}return a.stack.unshift(e),a.partial=!0,!0}return a.incomplete=!0,!1}function s(a,b){for(var c,d,f,i=/function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,j=[],k={},l=!1,o=s.caller;o&&!l;o=o.caller)if(o!==t&&o!==e.report){if(d={url:null,func:h,args:[],line:null,column:null},o.name?d.func=o.name:(c=i.exec(o.toString()))&&(d.func=c[1]),"undefined"==typeof d.func)try{d.func=c.input.substring(0,c.input.indexOf("{"))}catch(p){}if(f=n(o)){d.url=f.url,d.line=f.line,d.func===h&&(d.func=g(d.url,d.line));var q=/ '([^']+)' /.exec(a.message||a.description);q&&(d.column=m(q[1],f.url,f.line))}k[""+o]?l=!0:k[""+o]=!0,j.push(d)}b&&j.splice(0,b);var u={mode:"callers",name:a.name,message:a.message,stack:j};return r(u,a.sourceURL||a.fileName,a.line||a.lineNumber,a.message||a.description),u}function t(a,b){var c=null;b=null==b?0:+b;try{if(c=p(a))return c}catch(d){if(v)throw d}try{if(c=o(a))return c}catch(d){if(v)throw d}try{if(c=q(a))return c}catch(d){if(v)throw d}try{if(c=s(a,b+1))return c}catch(d){if(v)throw d}return{mode:"failed"}}function u(a){a=(null==a?0:+a)+1;try{throw new Error}catch(b){return t(b,a+1)}}var v=!1,w={};return t.augmentStackTraceWithInitialElement=r,t.guessFunctionName=g,t.gatherContext=i,t.ofCaller=u,t.getSource=f,t}(),e.extendToAsynchronousCallbacks=function(){var b=function(b){var c=a[b];a[b]=function(){var a=g.call(arguments),b=a[0];return"function"==typeof b&&(a[0]=e.wrap(b)),c.apply?c.apply(this,a):c(a[0],a[1])}};b("setTimeout"),b("setInterval")},e.remoteFetching||(e.remoteFetching=!0),e.collectWindowErrors||(e.collectWindowErrors=!0),(!e.linesOfContext||e.linesOfContext<1)&&(e.linesOfContext=11),a.TraceKit=e}}("undefined"!=typeof window?window:global); \ No newline at end of file diff --git a/rhodecode/public/js/src/bootstrap.js b/rhodecode/public/js/src/bootstrap.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/bootstrap.js @@ -0,0 +1,1999 @@ +/** +* bootstrap.js v3.0.0 by @fat and @mdo +* Copyright 2013 Twitter Inc. +* http://www.apache.org/licenses/LICENSE-2.0 +*/ +if (!jQuery) { throw new Error("Bootstrap requires jQuery") } + +/* ======================================================================== + * Bootstrap: transition.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#transitions + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#alerts + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#buttons + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d); + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + .prop('checked', !this.$element.hasClass('active')) + .trigger('change') + if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active') + } + + this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#carousel + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000 + , pause: 'hover' + , wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + this.sliding = true + + isCycling && this.pause() + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + .emulateTransitionEnd(600) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#collapse + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#dropdowns + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + var $el = $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we we use a backdrop because click events don't delegate + $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus) + } + + $parent.trigger(e = $.Event('show.bs.dropdown')) + + if (e.isDefaultPrevented()) return + + $parent + .toggleClass('open') + .trigger('shown.bs.dropdown') + + $this.focus() + } + + return false + } + + Dropdown.prototype.keydown = function (e) { + if (!/(38|40|27)/.test(e.keyCode)) return + + var $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) { + if (e.which == 27) $parent.find(toggle).focus() + return $this.click() + } + + var $items = $('[role=menu] li:not(.divider):visible a', $parent) + + if (!$items.length) return + + var index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index=0 + + $items.eq(index).focus() + } + + function clearMenus() { + $(backdrop).remove() + $(toggle).each(function (e) { + var $parent = getParent($(this)) + if (!$parent.hasClass('open')) return + $parent.trigger(e = $.Event('hide.bs.dropdown')) + if (e.isDefaultPrevented()) return + $parent.removeClass('open').trigger('hidden.bs.dropdown') + }) + } + + function getParent($this) { + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + var $parent = selector && $(selector) + + return $parent && $parent.length ? $parent : $this.parent() + } + + + // DROPDOWN PLUGIN DEFINITION + // ========================== + + var old = $.fn.dropdown + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('dropdown') + + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + // DROPDOWN NO CONFLICT + // ==================== + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + // APPLY TO STANDARD DROPDOWN ELEMENTS + // =================================== + + $(document) + .on('click.bs.dropdown.data-api', clearMenus) + .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.bs.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: modal.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#modals + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // MODAL CLASS DEFINITION + // ====================== + + var Modal = function (element, options) { + this.options = options + this.$element = $(element) + this.$backdrop = + this.isShown = null + + if (this.options.remote) this.$element.load(this.options.remote) + } + + Modal.DEFAULTS = { + backdrop: true + , keyboard: true + , show: true + } + + Modal.prototype.toggle = function (_relatedTarget) { + return this[!this.isShown ? 'show' : 'hide'](_relatedTarget) + } + + Modal.prototype.show = function (_relatedTarget) { + var that = this + var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.escape() + + this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) // don't move modals dom position + } + + that.$element.show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element + .addClass('in') + .attr('aria-hidden', false) + + that.enforceFocus() + + var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + + transition ? + that.$element.find('.modal-dialog') // wait for modal to slide in + .one($.support.transition.end, function () { + that.$element.focus().trigger(e) + }) + .emulateTransitionEnd(300) : + that.$element.focus().trigger(e) + }) + } + + Modal.prototype.hide = function (e) { + if (e) e.preventDefault() + + e = $.Event('hide.bs.modal') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + + $(document).off('focusin.bs.modal') + + this.$element + .removeClass('in') + .attr('aria-hidden', true) + .off('click.dismiss.modal') + + $.support.transition && this.$element.hasClass('fade') ? + this.$element + .one($.support.transition.end, $.proxy(this.hideModal, this)) + .emulateTransitionEnd(300) : + this.hideModal() + } + + Modal.prototype.enforceFocus = function () { + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function (e) { + if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { + this.$element.focus() + } + }, this)) + } + + Modal.prototype.escape = function () { + if (this.isShown && this.options.keyboard) { + this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { + e.which == 27 && this.hide() + }, this)) + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.bs.modal') + } + } + + Modal.prototype.hideModal = function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.removeBackdrop() + that.$element.trigger('hidden.bs.modal') + }) + } + + Modal.prototype.removeBackdrop = function () { + this.$backdrop && this.$backdrop.remove() + this.$backdrop = null + } + + Modal.prototype.backdrop = function (callback) { + var that = this + var animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') + .appendTo(document.body) + + this.$element.on('click.dismiss.modal', $.proxy(function (e) { + if (e.target !== e.currentTarget) return + this.options.backdrop == 'static' + ? this.$element[0].focus.call(this.$element[0]) + : this.hide.call(this) + }, this)) + + if (doAnimate) this.$backdrop[0].offsetWidth // force reflow + + this.$backdrop.addClass('in') + + if (!callback) return + + doAnimate ? + this.$backdrop + .one($.support.transition.end, callback) + .emulateTransitionEnd(150) : + callback() + + } else if (!this.isShown && this.$backdrop) { + this.$backdrop.removeClass('in') + + $.support.transition && this.$element.hasClass('fade')? + this.$backdrop + .one($.support.transition.end, callback) + .emulateTransitionEnd(150) : + callback() + + } else if (callback) { + callback() + } + } + + + // MODAL PLUGIN DEFINITION + // ======================= + + var old = $.fn.modal + + $.fn.modal = function (option, _relatedTarget) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.modal') + var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.modal', (data = new Modal(this, options))) + if (typeof option == 'string') data[option](_relatedTarget) + else if (options.show) data.show(_relatedTarget) + }) + } + + $.fn.modal.Constructor = Modal + + + // MODAL NO CONFLICT + // ================= + + $.fn.modal.noConflict = function () { + $.fn.modal = old + return this + } + + + // MODAL DATA-API + // ============== + + $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { + var $this = $(this) + var href = $this.attr('href') + var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 + var option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + + e.preventDefault() + + $target + .modal(option, this) + .one('hide', function () { + $this.is(':visible') && $this.focus() + }) + }) + + $(document) + .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') }) + .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: tooltip.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#tooltip + * Inspired by the original jQuery.tipsy by Jason Frame + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // TOOLTIP PUBLIC CLASS DEFINITION + // =============================== + + var Tooltip = function (element, options) { + this.type = + this.options = + this.enabled = + this.timeout = + this.hoverState = + this.$element = null + + this.init('tooltip', element, options) + } + + Tooltip.DEFAULTS = { + animation: true + , placement: 'top' + , selector: false + , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' + , trigger: 'hover focus' + , title: '' + , delay: 0 + , html: false + , container: false + } + + Tooltip.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + + var triggers = this.options.trigger.split(' ') + + for (var i = triggers.length; i--;) { + var trigger = triggers[i] + + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focus' + var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur' + + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() + } + + Tooltip.prototype.getDefaults = function () { + return Tooltip.DEFAULTS + } + + Tooltip.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay + , hide: options.delay + } + } + + return options + } + + Tooltip.prototype.getDelegateOptions = function () { + var options = {} + var defaults = this.getDefaults() + + this._options && $.each(this._options, function (key, value) { + if (defaults[key] != value) options[key] = value + }) + + return options + } + + Tooltip.prototype.enter = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) + + clearTimeout(self.timeout) + + self.hoverState = 'in' + + if (!self.options.delay || !self.options.delay.show) return self.show() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) + } + + Tooltip.prototype.leave = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) + + clearTimeout(self.timeout) + + self.hoverState = 'out' + + if (!self.options.delay || !self.options.delay.hide) return self.hide() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) + } + + Tooltip.prototype.show = function () { + var e = $.Event('show.bs.'+ this.type) + + if (this.hasContent() && this.enabled) { + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + var $tip = this.tip() + + this.setContent() + + if (this.options.animation) $tip.addClass('fade') + + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement + + var autoToken = /\s?auto?\s?/i + var autoPlace = autoToken.test(placement) + if (autoPlace) placement = placement.replace(autoToken, '') || 'top' + + $tip + .detach() + .css({ top: 0, left: 0, display: 'block' }) + .addClass(placement) + + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + + var pos = this.getPosition() + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (autoPlace) { + var $parent = this.$element.parent() + + var orgPlacement = placement + var docScroll = document.documentElement.scrollTop || document.body.scrollTop + var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth() + var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight() + var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left + + placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' : + placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' : + placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' : + placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' : + placement + + $tip + .removeClass(orgPlacement) + .addClass(placement) + } + + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + + this.applyPlacement(calculatedOffset, placement) + this.$element.trigger('shown.bs.' + this.type) + } + } + + Tooltip.prototype.applyPlacement = function(offset, placement) { + var replace + var $tip = this.tip() + var width = $tip[0].offsetWidth + var height = $tip[0].offsetHeight + + // manually read margins because getBoundingClientRect includes difference + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) + + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 + + offset.top = offset.top + marginTop + offset.left = offset.left + marginLeft + + $tip + .offset(offset) + .addClass('in') + + // check to see if placing tip in new offset caused the tip to resize itself + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (placement == 'top' && actualHeight != height) { + replace = true + offset.top = offset.top + height - actualHeight + } + + if (/bottom|top/.test(placement)) { + var delta = 0 + + if (offset.left < 0) { + delta = offset.left * -2 + offset.left = 0 + + $tip.offset(offset) + + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + } + + this.replaceArrow(delta - width + actualWidth, actualWidth, 'left') + } else { + this.replaceArrow(actualHeight - height, actualHeight, 'top') + } + + if (replace) $tip.offset(offset) + } + + Tooltip.prototype.replaceArrow = function(delta, dimension, position) { + this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '') + } + + Tooltip.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } + + Tooltip.prototype.hide = function () { + var that = this + var $tip = this.tip() + var e = $.Event('hide.bs.' + this.type) + + function complete() { + if (that.hoverState != 'in') $tip.detach() + } + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + $tip.removeClass('in') + + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one($.support.transition.end, complete) + .emulateTransitionEnd(150) : + complete() + + this.$element.trigger('hidden.bs.' + this.type) + + return this + } + + Tooltip.prototype.fixTitle = function () { + var $e = this.$element + if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + } + } + + Tooltip.prototype.hasContent = function () { + return this.getTitle() + } + + Tooltip.prototype.getPosition = function () { + var el = this.$element[0] + return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : { + width: el.offsetWidth + , height: el.offsetHeight + }, this.$element.offset()) + } + + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + } + + Tooltip.prototype.getTitle = function () { + var title + var $e = this.$element + var o = this.options + + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) + + return title + } + + Tooltip.prototype.tip = function () { + return this.$tip = this.$tip || $(this.options.template) + } + + Tooltip.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') + } + + Tooltip.prototype.validate = function () { + if (!this.$element[0].parentNode) { + this.hide() + this.$element = null + this.options = null + } + } + + Tooltip.prototype.enable = function () { + this.enabled = true + } + + Tooltip.prototype.disable = function () { + this.enabled = false + } + + Tooltip.prototype.toggleEnabled = function () { + this.enabled = !this.enabled + } + + Tooltip.prototype.toggle = function (e) { + var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this + self.tip().hasClass('in') ? self.leave(self) : self.enter(self) + } + + Tooltip.prototype.destroy = function () { + this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) + } + + + // TOOLTIP PLUGIN DEFINITION + // ========================= + + var old = $.fn.tooltip + + $.fn.tooltip = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tooltip') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tooltip.Constructor = Tooltip + + + // TOOLTIP NO CONFLICT + // =================== + + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: popover.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#popovers + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== + + var Popover = function (element, options) { + this.init('popover', element, options) + } + + if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') + + Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, { + placement: 'right' + , trigger: 'click' + , content: '' + , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' + }) + + + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ + + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) + + Popover.prototype.constructor = Popover + + Popover.prototype.getDefaults = function () { + return Popover.DEFAULTS + } + + Popover.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + var content = this.getContent() + + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content) + + $tip.removeClass('fade top bottom left right in') + + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + } + + Popover.prototype.hasContent = function () { + return this.getTitle() || this.getContent() + } + + Popover.prototype.getContent = function () { + var $e = this.$element + var o = this.options + + return $e.attr('data-content') + || (typeof o.content == 'function' ? + o.content.call($e[0]) : + o.content) + } + + Popover.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.arrow') + } + + Popover.prototype.tip = function () { + if (!this.$tip) this.$tip = $(this.options.template) + return this.$tip + } + + + // POPOVER PLUGIN DEFINITION + // ========================= + + var old = $.fn.popover + + $.fn.popover = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.popover') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.popover', (data = new Popover(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.popover.Constructor = Popover + + + // POPOVER NO CONFLICT + // =================== + + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: scrollspy.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#scrollspy + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + var href + var process = $.proxy(this.process, this) + + this.$element = $(element).is('body') ? $(window) : $(element) + this.$body = $('body') + this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target + || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + || '') + ' .nav li > a' + this.offsets = $([]) + this.targets = $([]) + this.activeTarget = null + + this.refresh() + this.process() + } + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.refresh = function () { + var offsetMethod = this.$element[0] == window ? 'offset' : 'position' + + this.offsets = $([]) + this.targets = $([]) + + var self = this + var $targets = this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#\w/.test(href) && $(href) + + return ($href + && $href.length + && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + self.offsets.push(this[0]) + self.targets.push(this[1]) + }) + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight + var maxScroll = scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets.last()[0]) && this.activate(i) + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) + && this.activate( targets[i] ) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + $(this.selector) + .parents('.active') + .removeClass('active') + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + var old = $.fn.scrollspy + + $.fn.scrollspy = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + $spy.scrollspy($spy.data()) + }) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: tab.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#tabs + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // TAB CLASS DEFINITION + // ==================== + + var Tab = function (element) { + this.element = $(element) + } + + Tab.prototype.show = function () { + var $this = this.element + var $ul = $this.closest('ul:not(.dropdown-menu)') + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ($this.parent('li').hasClass('active')) return + + var previous = $ul.find('.active:last a')[0] + var e = $.Event('show.bs.tab', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + var $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown.bs.tab' + , relatedTarget: previous + }) + }) + } + + Tab.prototype.activate = function (element, container, callback) { + var $active = container.find('> .active') + var transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if (element.parent('.dropdown-menu')) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active + .one($.support.transition.end, next) + .emulateTransitionEnd(150) : + next() + + $active.removeClass('in') + } + + + // TAB PLUGIN DEFINITION + // ===================== + + var old = $.fn.tab + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tab') + + if (!data) $this.data('bs.tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + // TAB NO CONFLICT + // =============== + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + + // TAB DATA-API + // ============ + + $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: affix.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#affix + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + this.$window = $(window) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = + this.unpin = null + + this.checkPosition() + } + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0 + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + var scrollTop = this.$window.scrollTop() + var position = this.$element.offset() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top() + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() + + var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : + offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : + offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false + + if (this.affixed === affix) return + if (this.unpin) this.$element.css('top', '') + + this.affixed = affix + this.unpin = affix == 'bottom' ? position.top - scrollTop : null + + this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : '')) + + if (affix == 'bottom') { + this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + var old = $.fn.affix + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom) data.offset.bottom = data.offsetBottom + if (data.offsetTop) data.offset.top = data.offsetTop + + $spy.affix(data) + }) + }) + +}(window.jQuery); diff --git a/rhodecode/public/js/src/codemirror/codemirror.js b/rhodecode/public/js/src/codemirror/codemirror.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/codemirror/codemirror.js @@ -0,0 +1,8735 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + module.exports = mod(); + else if (typeof define == "function" && define.amd) // AMD + return define([], mod); + else // Plain browser env + this.CodeMirror = mod(); +})(function() { + "use strict"; + + // BROWSER SNIFFING + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + + var gecko = /gecko\/\d/i.test(navigator.userAgent); + var ie_upto10 = /MSIE \d/.test(navigator.userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var ie = ie_upto10 || ie_11up; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); + var webkit = /WebKit\//.test(navigator.userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var presto = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); + var phantom = /PhantomJS/.test(navigator.userAgent); + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var windows = /win/i.test(navigator.platform); + + var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) presto_version = Number(presto_version[1]); + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // EDITOR CONSTRUCTOR + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode); + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) display.input.focus(); + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + var cm = this; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || cm.hasFocus()) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + display.lineDiv.style.textRendering = "auto"; + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + + if (place) { + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + input.init(d); + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + }; + } + + function NativeScrollbars(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + place(vert); place(horiz); + + on(vert, "scroll", function() { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); + }); + on(horiz, "scroll", function() { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); + }); + + this.checkedOverlay = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + } + + NativeScrollbars.prototype = copyObj({ + update: function(measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedOverlay && measure.clientHeight > 0) { + if (sWidth == 0) this.overlayHack(); + this.checkedOverlay = true; + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; + }, + setScrollLeft: function(pos) { + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + }, + setScrollTop: function(pos) { + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + }, + overlayHack: function() { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.minHeight = this.vert.style.minWidth = w; + var self = this; + var barMouseDown = function(e) { + if (e_target(e) != self.vert && e_target(e) != self.horiz) + operation(self.cm, onMouseDown)(e); + }; + on(this.vert, "mousedown", barMouseDown); + on(this.horiz, "mousedown", barMouseDown); + }, + clear: function() { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + } + }, NativeScrollbars.prototype); + + function NullScrollbars() {} + + NullScrollbars.prototype = copyObj({ + update: function() { return {bottom: 0, right: 0}; }, + setScrollLeft: function() {}, + setScrollTop: function() {}, + clear: function() {} + }, NullScrollbars.prototype); + + CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function() { + if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); + }); + node.setAttribute("cm-not-content", "true"); + }, function(pos, axis) { + if (axis == "horizontal") setScrollLeft(cm, pos); + else setScrollTop(cm, pos); + }, cm); + if (cm.display.scrollbars.addClass) + addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + updateHeightsInViewport(cm); + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else d.scrollbarFiller.style.display = ""; + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else d.gutterFiller.style.display = ""; + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return {from: from, to: Math.max(to, from + 1)}; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + } + + DisplayUpdate.prototype.signal = function(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function() { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + return false; + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + return false; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true; + } + + function postUpdateDisplay(cm, update) { + var viewport = update.viewport; + for (var first = true;; first = false) { + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + update.finish(); + } + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px"; + var total = measure.docHeight + cm.display.barHeight; + cm.display.heightForcer.style.top = total + "px"; + cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; + width[cm.options.gutters[i]] = n.clientWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(cm, lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + cm.display.input.setUneditable(gutterWrap); + wrap.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + gutterWrap.className += " " + lineView.line.gutterClass; + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) {return Pos(x.line, x.ch);} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // INPUT HANDLING + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // This will be set to an array of strings when copying, so that, + // when pasting, we know what kind of selections the copied text + // was made out of. + var lastCopied = null; + + function applyTextInput(cm, inserted, deleted, sel, origin) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) sel = doc.sel; + + var paste = cm.state.pasteIncoming || origin == "paste"; + var textLines = splitLines(inserted), multiPaste = null; + // When pasing N lines into N selections, insert one line per selection + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) + multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); + else if (textLines.length == sel.ranges.length) + multiPaste = map(textLines, function(l) { return [l]; }); + } + + // Normal behavior is to insert the new text into every selection + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + var from = range.from(), to = range.to(); + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + from = Pos(from.line, from.ch - deleted); + else if (cm.state.overwrite && !paste) // Handle overwrite + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + } + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + } + if (inserted && !paste) + triggerElectric(cm, inserted); + + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = false; + } + + function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); + return true; + } + } + + function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) return; + var sel = cm.doc.sel; + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; + var mode = cm.getModeAt(range.head); + var indented = false; + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range.head.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + indented = indentLine(cm, range.head.line, "smart"); + } + if (indented) signalLater(cm, "electricInput", cm, range.head.line); + } + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return {text: text, ranges: ranges}; + } + + function disableBrowserMagic(field) { + field.setAttribute("autocorrect", "off"); + field.setAttribute("autocapitalize", "off"); + field.setAttribute("spellcheck", "false"); + } + + // TEXTAREA INPUT STYLE + + function TextareaInput(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false; + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + this.composing = null; + }; + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) te.style.width = "1000px"; + else te.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) te.style.border = "1px solid black"; + disableBrowserMagic(te); + return div; + } + + TextareaInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = this.cm; + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild; + display.wrapper.insertBefore(div, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) te.style.width = "0px"; + + on(te, "input", function() { + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; + input.poll(); + }); + + on(te, "paste", function(e) { + if (handlePaste(e, cm)) return true; + + cm.state.pasteIncoming = true; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (input.inaccurateSelection) { + input.prevInput = ""; + input.inaccurateSelection = false; + te.value = lastCopied.join("\n"); + selectInput(te); + } + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function(e) { + if (eventInWidget(display, e)) return; + cm.state.pasteIncoming = true; + input.focus(); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function(e) { + if (!eventInWidget(display, e)) e_preventDefault(e); + }); + + on(te, "compositionstart", function() { + var start = cm.getCursor("from"); + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) + }; + }); + on(te, "compositionend", function() { + if (input.composing) { + input.poll(); + input.composing.range.clear(); + input.composing = null; + } + }); + }, + + prepareSelection: function() { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result; + }, + + showSelection: function(drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }, + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + reset: function(typing) { + if (this.contextMenuPending) return; + var minimal, selected, cm = this.cm, doc = cm.doc; + if (cm.somethingSelected()) { + this.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) selectInput(this.textarea); + if (ie && ie_version >= 9) this.hasSelection = content; + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) this.hasSelection = null; + } + this.inaccurateSelection = minimal; + }, + + getField: function() { return this.textarea; }, + + supportsTouch: function() { return false; }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } + }, + + blur: function() { this.textarea.blur(); }, + + resetPosition: function() { + this.wrapper.style.top = this.wrapper.style.left = 0; + }, + + receivedFocus: function() { this.slowPoll(); }, + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + slowPoll: function() { + var input = this; + if (input.pollingFast) return; + input.polling.set(this.cm.options.pollInterval, function() { + input.poll(); + if (input.cm.state.focused) input.slowPoll(); + }); + }, + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + fastPoll: function() { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) {missed = true; input.polling.set(60, p);} + else {input.pollingFast = false; input.slowPoll();} + } + input.polling.set(20, p); + }, + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + poll: function() { + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput) || + isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) + return false; + + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false; + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + + var self = this; + runInOp(cm, function() { + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, self.composing ? "*compose" : null); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; + else self.prevInput = text; + + if (self.composing) { + self.composing.range.clear(); + self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), + {className: "CodeMirror-composing"}); + } + }); + return true; + }, + + ensurePolled: function() { + if (this.pollingFast && this.poll()) this.pollingFast = false; + }, + + onKeyPress: function() { + if (ie && ie_version >= 9) this.hasSelection = null; + this.fastPoll(); + }, + + onContextMenu: function(e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = te.style.cssText; + input.wrapper.style.position = "absolute"; + te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) window.scrollTo(null, oldScrollY); + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) te.value = input.prevInput = " "; + input.contextMenuPending = true; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + input.contextMenuPending = false; + input.wrapper.style.position = "relative"; + te.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function() { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else display.input.reset(); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }, + + setUneditable: nothing, + + needsContentAttribute: false + }, TextareaInput.prototype); + + // CONTENTEDITABLE INPUT STYLE + + function ContentEditableInput(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.gracePeriod = false; + } + + ContentEditableInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + div.contentEditable = "true"; + disableBrowserMagic(div); + + on(div, "paste", function(e) { handlePaste(e, cm); }) + + on(div, "compositionstart", function(e) { + var data = e.data; + input.composing = {sel: cm.doc.sel, data: data, startData: data}; + if (!data) return; + var prim = cm.doc.sel.primary(); + var line = cm.getLine(prim.head.line); + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + if (found > -1 && found <= prim.head.ch) + input.composing.sel = simpleSelection(Pos(prim.head.line, found), + Pos(prim.head.line, found + data.length)); + }); + on(div, "compositionupdate", function(e) { + input.composing.data = e.data; + }); + on(div, "compositionend", function(e) { + var ours = input.composing; + if (!ours) return; + if (e.data != ours.startData && !/\u200b/.test(e.data)) + ours.data = e.data; + // Need a small delay to prevent other code (input event, + // selection polling) from doing damage when fired right after + // compositionend. + setTimeout(function() { + if (!ours.handled) + input.applyComposition(ours); + if (input.composing == ours) + input.composing = null; + }, 50); + }); + + on(div, "touchstart", function() { + input.forceCompositionEnd(); + }); + + on(div, "input", function() { + if (input.composing) return; + if (!input.pollContent()) + runInOp(input.cm, function() {regChange(cm);}); + }); + + function onCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.operation(function() { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + // iOS exposes the clipboard API, but seems to discard content inserted into it + if (e.clipboardData && !ios) { + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData("text/plain", lastCopied.join("\n")); + } else { + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function() { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + }, 50); + } + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }, + + prepareSelection: function() { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result; + }, + + showSelection: function(info) { + if (!info || !this.cm.display.view.length) return; + if (info.focus) this.showPrimarySelection(); + this.showMultipleSelections(info); + }, + + showPrimarySelection: function() { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + return; + + var start = posToDOM(this.cm, prim.from()); + var end = posToDOM(this.cm, prim.to()); + if (!start && !end) return; + + var view = this.cm.display.view; + var old = sel.rangeCount && sel.getRangeAt(0); + if (!start) { + start = {node: view[0].measure.map[2], offset: 0}; + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; + } + + try { var rng = range(start.node, start.offset, end.offset, end.node); } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + sel.removeAllRanges(); + sel.addRange(rng); + if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); + } + this.rememberSelection(); + }, + + startGracePeriod: function() { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function() { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + + showMultipleSelections: function(info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }, + + rememberSelection: function() { + var sel = window.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }, + + selectionInEditor: function() { + var sel = window.getSelection(); + if (!sel.rangeCount) return false; + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node); + }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor") this.div.focus(); + }, + blur: function() { this.div.blur(); }, + getField: function() { return this.div; }, + + supportsTouch: function() { return true; }, + + receivedFocus: function() { + var input = this; + if (this.selectionInEditor()) + this.pollSelection(); + else + runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }, + + selectionChanged: function() { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, + + pollSelection: function() { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) runInOp(cm, function() { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; + }); + } + }, + + pollContent: function() { + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + + var fromIndex; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + var fromLine = lineNo(display.view[0].line); + var fromNode = display.view[0].node; + } else { + var fromLine = lineNo(display.view[fromIndex].line); + var fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + if (toIndex == display.view.length - 1) { + var toLine = display.viewTo - 1; + var toNode = display.lineDiv.lastChild; + } else { + var toLine = lineNo(display.view[toIndex + 1].line) - 1; + var toNode = display.view[toIndex + 1].node.previousSibling; + } + + var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else break; + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + ++cutFront; + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + ++cutEnd; + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); + newText[0] = newText[0].slice(cutFront); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true; + } + }, + + ensurePolled: function() { + this.forceCompositionEnd(); + }, + reset: function() { + this.forceCompositionEnd(); + }, + forceCompositionEnd: function() { + if (!this.composing || this.composing.handled) return; + this.applyComposition(this.composing); + this.composing.handled = true; + this.div.blur(); + this.div.focus(); + }, + applyComposition: function(composing) { + if (composing.data && composing.data != composing.startData) + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + }, + + setUneditable: function(node) { + node.setAttribute("contenteditable", "false"); + }, + + onKeyPress: function(e) { + e.preventDefault(); + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + onContextMenu: nothing, + resetPosition: nothing, + + needsContentAttribute: true + }, ContentEditableInput.prototype); + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) return null; + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); + result.offset = result.collapse == "right" ? result.end : result.start; + return result; + } + + function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); + node = null; offset = 0; + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) return null; + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + return locateNodeInLineView(lineView, node, offset); + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad); + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) offset = textNode.nodeValue.length; + } + while (topNode.parentNode != wrapper) topNode = topNode.parentNode; + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; + return Pos(line, ch); + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) return badPos(found, bad); + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + return badPos(Pos(found.line, found.ch - dist), bad); + else + dist += after.textContent.length; + } + for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + return badPos(Pos(found.line, found.ch + dist), bad); + else + dist += after.textContent.length; + } + } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false; + function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText != null) { + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); + text += cmText; + return; + } + var markerID = node.getAttribute("cm-marker"), range; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range = found[0].find())) + text += getBetween(cm.doc, range.from, range.to).join("\n"); + return; + } + if (node.getAttribute("contenteditable") == "false") return; + for (var i = 0; i < node.childNodes.length; i++) + walk(node.childNodes[i]); + if (/^(pre|div|p)$/i.test(node.nodeName)) + closing = true; + } else if (node.nodeType == 3) { + var val = node.nodeValue; + if (!val) return; + if (closing) { + text += "\n"; + closing = false; + } + text += val; + } + } + for (;;) { + walk(from); + if (from == to) break; + from = from.nextSibling; + } + return text; + } + + CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function() { return this.ranges[this.primIndex]; }, + equals: function(other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function() { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function() { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function(pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function() { return minPos(this.anchor, this.head); }, + to: function() { return maxPos(this.anchor, this.head); }, + empty: function() { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + } + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find(dir < 0 ? -1 : 1); + if (cmp(newPos, curPos) == 0) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SELECTION DRAWING + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) continue; + var range = doc.sel.ranges[i]; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + return result; + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, range, output) { + var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changedLines = []; + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var highlighted = highlightLine(cm, line, state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) changedLines.push(doc.frontier); + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changedLines.length) runInOp(cm, function() { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return {map: lineView.measure.map, cache: lineView.measure.cache}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) + view = null; + else if (view && view.changes) + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom}; + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { + rect = node.parentNode.getBoundingClientRect(); + } else if (ie && cm.options.lineWrapping) { + var rects = range(node, start, end).getClientRects(); + if (rects.length) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = nullRect; + } else { + rect = range(node, start, end).getBoundingClientRect() || nullRect; + } + if (rect.left || rect.right || start == 0) break; + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result; + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + return rect; + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height}; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var operationGroup = null; + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i](); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + } + } while (i < callbacks.length); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + group.ops[i].cm.curOp = null; + endOperations(group); + } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) findMaxLine(cm); + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) updateHeightsInViewport(cm); + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + op.preparedSelection = display.input.prepareSelection(); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); + cm.display.maxLineChanged = false; + } + + if (op.preparedSelection) + cm.display.input.showSelection(op.preparedSelection); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + cm.display.input.reset(op.typing); + if (op.focus && op.focus == activeElt()) ensureFocus(op.cm); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scrollbars.setScrollTop(doc.scrollTop); + display.scroller.scrollTop = doc.scrollTop; + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + display.scrollbars.setScrollLeft(doc.scrollLeft); + display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return {index: index, lineN: newN}; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN}; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0}; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + }; + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) return false; + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1; + } + function farAway(touch, other) { + if (other.left == null) return true; + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20; + } + on(d.scroller, "touchstart", function(e) { + if (!isMouseLikeTouchEvent(e)) { + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null}; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function() { + if (d.activeTouch) d.activeTouch.moved = true; + }); + on(d.scroller, "touchend", function(e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + range = new Range(pos, pos); + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + range = cm.findWordAt(pos); + else // Triple tap + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, + start: function(e){onDragStart(cm, e);}, + drop: operation(cm, onDrop) + }; + + var inp = d.input.getField(); + on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", bind(onFocus, cm)); + on(inp, "blur", bind(onBlur, cm)); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.simple); + toggle(cm.display.scroller, "dragover", funcs.simple); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + return; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(function() {display.input.focus();}, 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + if (ie) setTimeout(bind(ensureFocus, cm), 0); + else cm.curOp.focus = activeElt(); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + } else { + type = "single"; + lastClick = {time: now, pos: start}; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + type == "single" && (contained = sel.contains(start)) > -1 && + (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && + (cmp(contained.to(), start) > 0 || start.xRel < 0)) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display, startTime = +new Date; + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier && +new Date - 200 < startTime) + extendSelection(cm.doc, start); + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + else + display.input.focus(); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = cm.findWordAt(start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = cm.findWordAt(pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + display.input.focus(); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function(e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent, signalfn) { + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalfn(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true, signalLater); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = operation(cm, function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function() {cm.display.input.focus();}, 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + cm.display.input.focus(); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplaySimple(cm, {top: val}); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (gecko) updateDisplaySimple(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + cm.display.scrollbars.setScrollLeft(val); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + var wheelEventDelta = function(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + return {x: dx, y: dy}; + }; + CodeMirror.wheelEventPixels = function(e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta; + }; + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplaySimple(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) return result; + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); + } + + var stopSeq = new Delayed; + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) return "handled"; + stopSeq.set(50, function() { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); + name = seq + " " + name; + } + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + cm.state.keySeq = name; + if (result == "handled") + signalLater(cm, "keyHandled", cm, name, e); + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e); + return true; + } + return !!result; + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) return false; + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) + || dispatchKey(cm, name, e, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, + function(b) { return doHandleBinding(cm, b, true); }); + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + cm.display.input.onKeyPress(e); + } + + // FOCUS/BLUR EVENTS + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function() { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + cm.display.input.onContextMenu(e); + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false, signal); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function(range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + regChange(cm); + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (var limit = 0; limit < 5; limit++) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) break; + } + return coords; + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (y2 - y1 > screen) y2 = y1 + screen; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = x2 - x1 > screenw; + if (tooWide) x2 = x1 + screenw; + if (x1 < 10) + result.scrollLeft = 0; + else if (x1 < screenleft) + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + else if (x2 > screenw + screenleft - 3) + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + line.stateAfter = null; + return true; + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function() { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus();}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function(how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); + var start = Math.max(end, from.line); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + var newRanges = this.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise); + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true); + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function(pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return found; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: methodOp(function(line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd](this); + }, + + triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function(dir, unit) { + var cm = this; + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function(range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; + }); + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function(dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function(range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function(ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return this.display.input.getField() == activeElt(); }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function() { + var scroller = this.display.scroller; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function(width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function(){return this.display.input.getField();}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function() { + throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME + }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", function(cm, val, old) { + var next = getKeyMap(val); + var prev = old != CodeMirror.Init && getKeyMap(old); + if (prev && prev.detach) prev.detach(cm, next); + if (next.attach) next.attach(cm, prev || null); + }); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); + option("scrollbarStyle", "native", function(cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) cm.display.input.reset(); + } + }); + option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); + option("dragDrop", true, dragDropChanged); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.input.resetPosition(); + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.getField().tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, + singleSelection: function(cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function(cm) { + deleteNearSelection(cm, function(range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)}; + else + return {from: range.head, to: Pos(range.head.line, len)}; + } else { + return {from: range.from(), to: range.to()}; + } + }); + }, + deleteLine: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; + }); + }, + delLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), to: range.from()}; + }); + }, + delWrappedLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({left: 0, top: top}, "div"); + return {from: leftPos, to: range.from()}; + }); + }, + delWrappedLineRight: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + return {from: range.from(), to: rightPos }; + }); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + undoSelection: function(cm) {cm.undoSelection();}, + redoSelection: function(cm) {cm.redoSelection();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1}); + }, + goLineStartSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + return lineStartSmart(cm, range.head); + }, {origin: "+move", bias: 1}); + }, + goLineEnd: function(cm) { + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1}); + }, + goLineRight: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + }, sel_move); + }, + goLineLeft: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div"); + }, sel_move); + }, + goLineLeftSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({left: 0, top: top}, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); + return pos; + }, sel_move); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t");}, + insertSoftTab: function(cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); + } + cm.replaceSelections(spaces); + }, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function(cm) { + runInOp(cm, function() { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function(cm) { + runInOp(cm, function() { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + ensureCursorVisible(cm); + } + }); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; + else if (/^a(lt)?$/i.test(mod)) alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; + else if (/^s(hift)$/i.test(mod)) shift = true; + else throw new Error("Unrecognized modifier name: " + mod); + } + if (alt) name = "Alt-" + name; + if (ctrl) name = "Ctrl-" + name; + if (cmd) name = "Cmd-" + name; + if (shift) name = "Shift-" + name; + return name; + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + CodeMirror.normalizeKeyMap = function(keymap) { + var copy = {}; + for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; + if (value == "...") { delete keymap[keyname]; continue; } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val, name; + if (i == keys.length - 1) { + name = keys.join(" "); + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) copy[name] = val; + else if (prev != val) throw new Error("Inconsistent bindings for " + name); + } + delete keymap[keyname]; + } + for (var prop in copy) keymap[prop] = copy[prop]; + return keymap; + }; + + var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + return lookupKey(key, map.fallthrough, handle, context); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); + if (result) return result; + } + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var base = keyNames[event.keyCode], name = base; + if (name == null || event.altGraphKey) return false; + if (event.altKey && base != "Alt") name = "Alt-" + name; + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; + return name; + }; + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val; + } + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + options.tabindex = textarea.tabIndex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + options.finishInit = function(cm) { + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var nextMarkerId = 0; + + var TextMarker = CodeMirror.TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function(side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && {from: from, to: to}; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function() { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function() { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function(side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function(doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) return null; + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({from: p.from, to: m.from}); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || + fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.doc = doc; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function() { + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function() { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + }; + LineWidget.prototype.changed = function() { + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function() { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + if (widget.noHScroll) + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + function getObj(copy) { + return {start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state}; + } + + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize), tokens; + if (asArray) tokens = []; + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, state); + if (asArray) tokens.push(getObj(true)); + } + return asArray ? tokens : getObj(); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: elt("pre", [content]), content: content, + col: 0, pos: 0, cm: cm, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) + builder.content.className = "cm-tab-wrap-hack"; + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) return; + var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; + var special = builder.cm.state.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); + txt.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + txt.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle, css); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function splitSpaces(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function(builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + widget = builder.content.appendChild(document.createElement("span")); + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = []; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m); + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to; + spanEndStyle = ""; + } + if (m.className) spanStyle += " " + m.className; + if (m.css) css = m.css; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + if (collapsed.to == pos) collapsed = false; + } + if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + for (var i = start, result = []; i < end; ++i) + result.push(new Line(text[i], spansFor(i), estimateHeight)); + return result; + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added = linesFor(1, text.length - 1); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added = linesFor(1, text.length - 1); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue", full: true}, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function() { return this.sel.ranges; }, + somethingSelected: function() {return this.sel.somethingSelected();}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads, options)); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + extendSelections(this, map(this.sel.ranges, f), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || "\n"); + }, + getSelections: function(lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || "\n"); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend;}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return {undo: done, redo: undone}; + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (classTest(cls).test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(classTest(cls)); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function(widget) { widget.clear(); }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var off = CodeMirror.off = function(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + }; + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + list.push(bnd(arr[i])); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + function Delayed() {this.id = null;} + Delayed.prototype.set = function(ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function(node) { try { node.select(); } catch(_e) {} }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + + function nothing() {} + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function(node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r; + }; + else range = function(node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch(e) { return r; } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + var contains = CodeMirror.contains = function(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + child = child.parentNode; + if (parent.contains) + return parent.contains(child); + do { + if (child.nodeType == 11) child = child.host; + if (child == parent) return true; + } while (child = child.parentNode); + }; + + function activeElt() { return document.activeElement; } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function() { + try { return document.activeElement; } + catch(e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } + var rmClass = CodeMirror.rmClass = function(node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + var addClass = CodeMirror.addClass = function(node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + }; + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function() { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node; + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) + var r1 = range(txt, 1, 2).getBoundingClientRect(); + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) return badZoomedRects; + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + } + + // KEY NAMES + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level == 2) + order.unshift(new BidiSpan(1, order[0].to, order[0].to)); + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "5.4.0"; + + return CodeMirror; +}); diff --git a/rhodecode/public/js/src/codemirror/codemirror_hint.js b/rhodecode/public/js/src/codemirror/codemirror_hint.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/codemirror/codemirror_hint.js @@ -0,0 +1,383 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function(options) { + // We want a single cursor position. + if (this.listSelections().length > 1 || this.somethingSelected()) return; + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); + }); + + function Completion(cm, options) { + this.cm = cm; + this.options = this.buildOptions(options); + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor(); + this.startLen = this.cm.getLine(this.startPos.line).length; + + var self = this; + cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + } + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + this.cm.off("cursorActivity", this.activityFunc); + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + cursorActivity: function() { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < this.startPos.ch || this.cm.somethingSelected() || + (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function() {self.update();}); + if (this.widget) this.widget.disable(); + } + }, + + update: function(first) { + if (this.tick == null) return; + if (this.data) CodeMirror.signal(this.data, "update"); + if (!this.options.hint.async) { + this.finishUpdate(this.options.hint(this.cm, this.options), first); + } else { + var myTick = ++this.tick, self = this; + this.options.hint(this.cm, function(data) { + if (self.tick == myTick) self.finishUpdate(data, first); + }, this.options); + } + }, + + finishUpdate: function(data, first) { + this.data = data; + + var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } + }, + + buildOptions: function(options) { + var editor = this.cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + return out; + } + }; + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (completion.options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + var startScroll = cm.getScrollInfo(); + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[0], hints.firstChild); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function() { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = {Enter: function() { widget.picked = true; }}; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + CodeMirror.registerHelper("hint", "auto", function(cm, options) { + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; + if (helpers.length) { + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, options); + if (cur && cur.list.length) return cur; + } + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + if (words) return CodeMirror.hint.fromList(cm, {words: words}); + } else if (CodeMirror.hint.anyword) { + return CodeMirror.hint.anyword(cm, options); + } + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, token.string.length) == token.string) + found.push(word); + } + + if (found.length) return { + list: found, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: false, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/rhodecode/public/js/src/codemirror/codemirror_loadmode.js b/rhodecode/public/js/src/codemirror/codemirror_loadmode.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/codemirror/codemirror_loadmode.js @@ -0,0 +1,64 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), "cjs"); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); + else // Plain browser env + mod(CodeMirror, "plain"); +})(function(CodeMirror, env) { + if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; + + var loading = {}; + function splitCallback(cont, n) { + var countDown = n; + return function() { if (--countDown == 0) cont(); }; + } + function ensureDeps(mode, cont) { + var deps = CodeMirror.modes[mode].dependencies; + if (!deps) return cont(); + var missing = []; + for (var i = 0; i < deps.length; ++i) { + if (!CodeMirror.modes.hasOwnProperty(deps[i])) + missing.push(deps[i]); + } + if (!missing.length) return cont(); + var split = splitCallback(cont, missing.length); + for (var i = 0; i < missing.length; ++i) + CodeMirror.requireMode(missing[i], split); + } + + CodeMirror.requireMode = function(mode, cont) { + if (typeof mode != "string") mode = mode.name; + if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); + if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); + + var file = CodeMirror.modeURL.replace(/%N/g, mode); + if (env == "plain") { + var script = document.createElement("script"); + script.src = file; + var others = document.getElementsByTagName("script")[0]; + var list = loading[mode] = [cont]; + CodeMirror.on(script, "load", function() { + ensureDeps(mode, function() { + for (var i = 0; i < list.length; ++i) list[i](); + }); + }); + others.parentNode.insertBefore(script, others); + } else if (env == "cjs") { + require(file); + cont(); + } else if (env == "amd") { + requirejs([file], cont); + } + }; + + CodeMirror.autoLoadMode = function(instance, mode) { + if (!CodeMirror.modes.hasOwnProperty(mode)) + CodeMirror.requireMode(mode, function() { + instance.setOption("mode", instance.getOption("mode")); + }); + }; +}); diff --git a/rhodecode/public/js/src/codemirror/codemirror_overlay.js b/rhodecode/public/js/src/codemirror/codemirror_overlay.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/codemirror/codemirror_overlay.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Utility function that allows modes to be combined. The mode given +// as the base argument takes care of most of the normal mode +// functionality, but a second (typically simple) mode is used, which +// can override the style of text. Both modes get to parse all of the +// text, but when both assign a non-null style to a piece of code, the +// overlay wins, unless the combine argument was true and not overridden, +// or state.overlay.combineTokens was true, in which case the styles are +// combined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.overlayMode = function(base, overlay, combine) { + return { + startState: function() { + return { + base: CodeMirror.startState(base), + overlay: CodeMirror.startState(overlay), + basePos: 0, baseCur: null, + overlayPos: 0, overlayCur: null, + streamSeen: null + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(base, state.base), + overlay: CodeMirror.copyState(overlay, state.overlay), + basePos: state.basePos, baseCur: null, + overlayPos: state.overlayPos, overlayCur: null + }; + }, + + token: function(stream, state) { + if (stream != state.streamSeen || + Math.min(state.basePos, state.overlayPos) < stream.start) { + state.streamSeen = stream; + state.basePos = state.overlayPos = stream.start; + } + + if (stream.start == state.basePos) { + state.baseCur = base.token(stream, state.base); + state.basePos = stream.pos; + } + if (stream.start == state.overlayPos) { + stream.pos = stream.start; + state.overlayCur = overlay.token(stream, state.overlay); + state.overlayPos = stream.pos; + } + stream.pos = Math.min(state.basePos, state.overlayPos); + + // state.overlay.combineTokens always takes precedence over combine, + // unless set to null + if (state.overlayCur == null) return state.baseCur; + else if (state.baseCur != null && + state.overlay.combineTokens || + combine && state.overlay.combineTokens == null) + return state.baseCur + " " + state.overlayCur; + else return state.overlayCur; + }, + + indent: base.indent && function(state, textAfter) { + return base.indent(state.base, textAfter); + }, + electricChars: base.electricChars, + + innerMode: function(state) { return {state: state.base, mode: base}; }, + + blankLine: function(state) { + if (base.blankLine) base.blankLine(state.base); + if (overlay.blankLine) overlay.blankLine(state.overlay); + } + }; +}; + +}); diff --git a/rhodecode/public/js/src/codemirror/codemirror_placeholder.js b/rhodecode/public/js/src/codemirror/codemirror_placeholder.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/codemirror/codemirror_placeholder.js @@ -0,0 +1,58 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.className = "CodeMirror-placeholder"; + elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/rhodecode/public/js/src/jquery-1.11.1.min.js b/rhodecode/public/js/src/jquery-1.11.1.min.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/jquery-1.11.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px") +},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m}); diff --git a/rhodecode/public/js/src/jquery-1.11.1.min.map b/rhodecode/public/js/src/jquery-1.11.1.min.map new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/jquery-1.11.1.min.map @@ -0,0 +1,1 @@ +{"version":3,"file":"jquery-1.11.1.min.js","sources":["jquery-1.11.1.js"],"names":["global","factory","module","exports","document","w","Error","window","this","noGlobal","deletedIds","slice","concat","push","indexOf","class2type","toString","hasOwn","hasOwnProperty","support","version","jQuery","selector","context","fn","init","rtrim","rmsPrefix","rdashAlpha","fcamelCase","all","letter","toUpperCase","prototype","jquery","constructor","length","toArray","call","get","num","pushStack","elems","ret","merge","prevObject","each","callback","args","map","elem","i","apply","arguments","first","eq","last","len","j","end","sort","splice","extend","src","copyIsArray","copy","name","options","clone","target","deep","isFunction","isPlainObject","isArray","undefined","expando","Math","random","replace","isReady","error","msg","noop","obj","type","Array","isWindow","isNumeric","parseFloat","isEmptyObject","key","nodeType","e","ownLast","globalEval","data","trim","execScript","camelCase","string","nodeName","toLowerCase","value","isArraylike","text","makeArray","arr","results","Object","inArray","max","second","grep","invert","callbackInverse","matches","callbackExpect","arg","guid","proxy","tmp","now","Date","split","Sizzle","Expr","getText","isXML","tokenize","compile","select","outermostContext","sortInput","hasDuplicate","setDocument","docElem","documentIsHTML","rbuggyQSA","rbuggyMatches","contains","preferredDoc","dirruns","done","classCache","createCache","tokenCache","compilerCache","sortOrder","a","b","strundefined","MAX_NEGATIVE","pop","push_native","booleans","whitespace","characterEncoding","identifier","attributes","pseudos","RegExp","rcomma","rcombinators","rattributeQuotes","rpseudo","ridentifier","matchExpr","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","rinputs","rheader","rnative","rquickExpr","rsibling","rescape","runescape","funescape","_","escaped","escapedWhitespace","high","String","fromCharCode","childNodes","els","seed","match","m","groups","old","nid","newContext","newSelector","ownerDocument","exec","getElementById","parentNode","id","getElementsByTagName","getElementsByClassName","qsa","test","getAttribute","setAttribute","toSelector","testContext","join","querySelectorAll","qsaError","removeAttribute","keys","cache","cacheLength","shift","markFunction","assert","div","createElement","removeChild","addHandle","attrs","handler","attrHandle","siblingCheck","cur","diff","sourceIndex","nextSibling","createInputPseudo","createButtonPseudo","createPositionalPseudo","argument","matchIndexes","documentElement","node","hasCompare","doc","parent","defaultView","top","addEventListener","attachEvent","className","appendChild","createComment","innerHTML","firstChild","getById","getElementsByName","find","filter","attrId","getAttributeNode","tag","input","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","adown","bup","compare","sortDetached","aup","ap","bp","unshift","expr","elements","attr","val","specified","uniqueSort","duplicates","detectDuplicates","sortStable","textContent","nodeValue","selectors","createPseudo","relative",">","dir"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","result","what","simple","forward","ofType","xml","outerCache","nodeIndex","start","useCache","lastChild","pseudo","setFilters","idx","matched","not","matcher","unmatched","has","innerText","lang","elemLang","hash","location","root","focus","activeElement","hasFocus","href","tabIndex","enabled","disabled","checked","selected","selectedIndex","empty","header","button","even","odd","lt","gt","radio","checkbox","file","password","image","submit","reset","filters","parseOnly","tokens","soFar","preFilters","cached","addCombinator","combinator","base","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","multipleContexts","contexts","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","matcherFromGroupMatchers","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","div1","defaultValue","unique","isXMLDoc","rneedsContext","rsingleTag","risSimple","winnow","qualifier","self","is","rootjQuery","charAt","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","next","prev","until","sibling","n","r","targets","closest","l","pos","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","siblings","contentDocument","contentWindow","reverse","rnotwhite","optionsCache","createOptions","object","flag","Callbacks","firing","memory","fired","firingLength","firingIndex","firingStart","list","stack","once","fire","stopOnFalse","disable","remove","lock","locked","fireWith","Deferred","func","tuples","state","promise","always","deferred","fail","then","fns","newDefer","tuple","returned","resolve","reject","progress","notify","pipe","stateString","when","subordinate","resolveValues","remaining","updateFunc","values","progressValues","notifyWith","resolveWith","progressContexts","resolveContexts","readyList","readyWait","holdReady","hold","wait","body","setTimeout","triggerHandler","off","detach","removeEventListener","completed","detachEvent","event","readyState","frameElement","doScroll","doScrollCheck","inlineBlockNeedsLayout","container","style","cssText","zoom","offsetWidth","deleteExpando","acceptData","noData","rbrace","rmultiDash","dataAttr","parseJSON","isEmptyDataObject","internalData","pvt","thisCache","internalKey","isNode","toJSON","internalRemoveData","cleanData","applet ","embed ","object ","hasData","removeData","_data","_removeData","queue","dequeue","startLength","hooks","_queueHooks","stop","setter","clearQueue","count","defer","pnum","source","cssExpand","isHidden","el","css","access","chainable","emptyGet","raw","bulk","rcheckableType","fragment","createDocumentFragment","leadingWhitespace","tbody","htmlSerialize","html5Clone","cloneNode","outerHTML","appendChecked","noCloneChecked","checkClone","noCloneEvent","click","eventName","change","focusin","rformElems","rkeyEvent","rmouseEvent","rfocusMorph","rtypenamespace","returnTrue","returnFalse","safeActiveElement","err","types","events","t","handleObjIn","special","eventHandle","handleObj","handlers","namespaces","origType","elemData","handle","triggered","dispatch","delegateType","bindType","namespace","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","trigger","onlyHandlers","ontype","bubbleType","eventPath","Event","isTrigger","namespace_re","noBubble","parentWindow","isPropagationStopped","preventDefault","isDefaultPrevented","_default","fix","handlerQueue","delegateTarget","preDispatch","currentTarget","isImmediatePropagationStopped","stopPropagation","postDispatch","sel","prop","originalEvent","fixHook","fixHooks","mouseHooks","keyHooks","props","srcElement","metaKey","original","which","charCode","keyCode","eventDoc","fromElement","pageX","clientX","scrollLeft","clientLeft","pageY","clientY","scrollTop","clientTop","relatedTarget","toElement","load","blur","beforeunload","returnValue","simulate","bubble","isSimulated","defaultPrevented","timeStamp","cancelBubble","stopImmediatePropagation","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","submitBubbles","form","_submit_bubble","changeBubbles","propertyName","_just_changed","focusinBubbles","attaches","on","one","origFn","createSafeFragment","nodeNames","safeFrag","rinlinejQuery","rnoshimcache","rleadingWhitespace","rxhtmlTag","rtagName","rtbody","rhtml","rnoInnerhtml","rchecked","rscriptType","rscriptTypeMasked","rcleanScript","wrapMap","option","legend","area","param","thead","tr","col","td","safeFragment","fragmentDiv","optgroup","tfoot","colgroup","caption","th","getAll","found","fixDefaultChecked","defaultChecked","manipulationTarget","content","disableScript","restoreScript","setGlobalEval","refElements","cloneCopyEvent","dest","oldData","curData","fixCloneNodeIssues","defaultSelected","dataAndEvents","deepDataAndEvents","destElements","srcElements","inPage","buildFragment","scripts","selection","wrap","safe","nodes","createTextNode","append","domManip","prepend","insertBefore","before","after","keepData","html","replaceWith","replaceChild","hasScripts","set","iNoClone","_evalUrl","appendTo","prependTo","insertAfter","replaceAll","insert","iframe","elemdisplay","actualDisplay","display","getDefaultComputedStyle","defaultDisplay","write","close","shrinkWrapBlocksVal","shrinkWrapBlocks","width","rmargin","rnumnonpx","getStyles","curCSS","rposition","getComputedStyle","computed","minWidth","maxWidth","getPropertyValue","currentStyle","left","rs","rsLeft","runtimeStyle","pixelLeft","addGetHookIf","conditionFn","hookFn","condition","pixelPositionVal","boxSizingReliableVal","reliableHiddenOffsetsVal","reliableMarginRightVal","opacity","cssFloat","backgroundClip","clearCloneStyle","boxSizing","MozBoxSizing","WebkitBoxSizing","reliableHiddenOffsets","computeStyleTests","boxSizingReliable","pixelPosition","reliableMarginRight","marginRight","offsetHeight","swap","ralpha","ropacity","rdisplayswap","rnumsplit","rrelNum","cssShow","position","visibility","cssNormalTransform","letterSpacing","fontWeight","cssPrefixes","vendorPropName","capName","origName","showHide","show","hidden","setPositiveNumber","subtract","augmentWidthOrHeight","extra","isBorderBox","styles","getWidthOrHeight","valueIsBorderBox","cssHooks","cssNumber","columnCount","fillOpacity","flexGrow","flexShrink","lineHeight","order","orphans","widows","zIndex","cssProps","float","$1","margin","padding","border","prefix","suffix","expand","expanded","parts","hide","toggle","Tween","easing","unit","propHooks","run","percent","eased","duration","step","tween","fx","linear","p","swing","cos","PI","fxNow","timerId","rfxtypes","rfxnum","rrun","animationPrefilters","defaultPrefilter","tweeners","*","createTween","scale","maxIterations","createFxNow","genFx","includeWidth","height","animation","collection","opts","oldfire","checkDisplay","anim","dataShow","unqueued","overflow","overflowX","overflowY","propFilter","specialEasing","Animation","properties","stopped","tick","currentTime","startTime","tweens","originalProperties","originalOptions","gotoEnd","rejectWith","timer","complete","tweener","prefilter","speed","opt","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","interval","setInterval","clearInterval","slow","fast","delay","time","timeout","clearTimeout","getSetAttribute","hrefNormalized","checkOn","optSelected","enctype","optDisabled","radioValue","rreturn","valHooks","optionSet","scrollHeight","nodeHook","boolHook","ruseDefault","getSetInput","removeAttr","nType","attrHooks","propName","attrNames","propFix","getter","setAttributeNode","createAttribute","coords","contenteditable","rfocusable","rclickable","removeProp","for","class","notxml","tabindex","parseInt","rclass","addClass","classes","clazz","finalValue","proceed","removeClass","toggleClass","stateVal","classNames","hasClass","hover","fnOver","fnOut","bind","unbind","delegate","undelegate","nonce","rquery","rvalidtokens","JSON","parse","requireNonComma","depth","str","comma","open","Function","parseXML","DOMParser","parseFromString","ActiveXObject","async","loadXML","ajaxLocParts","ajaxLocation","rhash","rts","rheaders","rlocalProtocol","rnoContent","rprotocol","rurl","prefilters","transports","allTypes","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","ajaxHandleResponses","s","responses","firstDataType","ct","finalDataType","mimeType","getResponseHeader","converters","ajaxConvert","response","isSuccess","conv2","current","conv","responseFields","dataFilter","active","lastModified","etag","url","isLocal","processData","contentType","accepts","json","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","cacheURL","responseHeadersString","timeoutTimer","fireGlobals","transport","responseHeaders","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getAllResponseHeaders","setRequestHeader","lname","overrideMimeType","code","status","abort","statusText","finalText","success","method","crossDomain","traditional","hasContent","ifModified","headers","beforeSend","send","nativeStatusText","modified","getJSON","getScript","throws","wrapAll","wrapInner","unwrap","visible","r20","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","v","encodeURIComponent","serialize","serializeArray","xhr","createStandardXHR","createActiveXHR","xhrId","xhrCallbacks","xhrSupported","cors","username","xhrFields","isAbort","onreadystatechange","responseText","XMLHttpRequest","script","text script","head","scriptCharset","charset","onload","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","keepScripts","parsed","_load","params","animated","getWindow","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","calculatePosition","curElem","using","win","box","getBoundingClientRect","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","defaultExtra","funcName","size","andSelf","define","amd","_jQuery","_$","$","noConflict"],"mappings":"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"} \ No newline at end of file diff --git a/rhodecode/public/js/src/logging.js b/rhodecode/public/js/src/logging.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/logging.js @@ -0,0 +1,272 @@ +/** + * LOGGING CONFIG + * + * + Usage: + Logger.debug("I'm a debug message!"); + Logger.info("OMG! Check this window out!", window); + Logger.warn("Purple Alert! Purple Alert!"); + Logger.error("HOLY SHI... no carrier."); + + // Only log WARN and ERROR messages. + Logger.setLevel(Logger.WARN); + Logger.debug("Donut machine is out of pink ones"); // Not a peep. + Logger.warn("Asteroid detected!"); // yes show + // Retrieve a named logger and store it for use. + var myLogger = Logger.get('ModuleA'); + myLogger.info("FizzWozz starting up"); + + // This logger instance can be configured independent of + // all others (including the global one). + myLogger.setLevel(Logger.WARN); + + // As it's the same instance being returned each time, you + // don't have to store a reference: + Logger.get('ModuleA').warn('FizzWozz combombulated!"); + + */ +/*! + * js-logger - http://github.com/jonnyreeves/js-logger + * Jonny Reeves, http://jonnyreeves.co.uk/ + * js-logger may be freely distributed under the MIT license. + */ +(function (global) { + "use strict"; + + // Top level module for the global, static logger instance. + var Logger = { }; + + // For those that are at home that are keeping score. + Logger.VERSION = "1.0.0"; + + // Function which handles all incoming log messages. + var logHandler; + + // Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance. + var contextualLoggersByNameMap = {}; + + // Polyfill for ES5's Function.bind. + var bind = function(scope, func) { + return function() { + return func.apply(scope, arguments); + }; + }; + + // Super exciting object merger-matron 9000 adding another 100 bytes to your download. + var merge = function () { + var args = arguments, target = args[0], key, i; + for (i = 1; i < args.length; i++) { + for (key in args[i]) { + if (!(key in target) && args[i].hasOwnProperty(key)) { + target[key] = args[i][key]; + } + } + } + return target; + }; + + // Helper to define a logging level object; helps with optimisation. + var defineLogLevel = function(value, name) { + return { value: value, name: name }; + }; + + // Predefined logging levels. + Logger.DEBUG = defineLogLevel(1, 'DEBUG'); + Logger.INFO = defineLogLevel(2, 'INFO'); + Logger.TIME = defineLogLevel(3, 'TIME'); + Logger.WARN = defineLogLevel(4, 'WARN'); + Logger.ERROR = defineLogLevel(8, 'ERROR'); + Logger.OFF = defineLogLevel(99, 'OFF'); + + // Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently + // of each other. + var ContextualLogger = function(defaultContext) { + this.context = defaultContext; + this.setLevel(defaultContext.filterLevel); + this.log = this.info; // Convenience alias. + }; + + ContextualLogger.prototype = { + // Changes the current logging level for the logging instance. + setLevel: function (newLevel) { + // Ensure the supplied Level object looks valid. + if (newLevel && "value" in newLevel) { + this.context.filterLevel = newLevel; + } + }, + + // Is the logger configured to output messages at the supplied level? + enabledFor: function (lvl) { + var filterLevel = this.context.filterLevel; + return lvl.value >= filterLevel.value; + }, + + debug: function () { + this.invoke(Logger.DEBUG, arguments); + }, + + info: function () { + this.invoke(Logger.INFO, arguments); + }, + + warn: function () { + this.invoke(Logger.WARN, arguments); + }, + + error: function () { + this.invoke(Logger.ERROR, arguments); + }, + + time: function (label) { + if (typeof label === 'string' && label.length > 0) { + this.invoke(Logger.TIME, [ label, 'start' ]); + } + }, + + timeEnd: function (label) { + if (typeof label === 'string' && label.length > 0) { + this.invoke(Logger.TIME, [ label, 'end' ]); + } + }, + + // Invokes the logger callback if it's not being filtered. + invoke: function (level, msgArgs) { + if (logHandler && this.enabledFor(level)) { + logHandler(msgArgs, merge({ level: level }, this.context)); + } + } + }; + + // Protected instance which all calls to the to level `Logger` module will be routed through. + var globalLogger = new ContextualLogger({ filterLevel: Logger.OFF }); + + // Configure the global Logger instance. + (function() { + // Shortcut for optimisers. + var L = Logger; + + L.enabledFor = bind(globalLogger, globalLogger.enabledFor); + L.debug = bind(globalLogger, globalLogger.debug); + L.time = bind(globalLogger, globalLogger.time); + L.timeEnd = bind(globalLogger, globalLogger.timeEnd); + L.info = bind(globalLogger, globalLogger.info); + L.warn = bind(globalLogger, globalLogger.warn); + L.error = bind(globalLogger, globalLogger.error); + + // Don't forget the convenience alias! + L.log = L.info; + }()); + + // Set the global logging handler. The supplied function should expect two arguments, the first being an arguments + // object with the supplied log messages and the second being a context object which contains a hash of stateful + // parameters which the logging function can consume. + Logger.setHandler = function (func) { + logHandler = func; + }; + + // Sets the global logging filter level which applies to *all* previously registered, and future Logger instances. + // (note that named loggers (retrieved via `Logger.get`) can be configured independently if required). + Logger.setLevel = function(level) { + // Set the globalLogger's level. + globalLogger.setLevel(level); + + // Apply this level to all registered contextual loggers. + for (var key in contextualLoggersByNameMap) { + if (contextualLoggersByNameMap.hasOwnProperty(key)) { + contextualLoggersByNameMap[key].setLevel(level); + } + } + }; + + // Retrieve a ContextualLogger instance. Note that named loggers automatically inherit the global logger's level, + // default context and log handler. + Logger.get = function (name) { + // All logger instances are cached so they can be configured ahead of use. + return contextualLoggersByNameMap[name] || + (contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context))); + }; + + // Configure and example a Default implementation which writes to the `window.console` (if present). + Logger.useDefaults = function(defaultLevel) { + // Check for the presence of a logger. + if (typeof console === "undefined") { + return; + } + + // Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments + // that don't offer a native console method. + var timerStartTimeByLabelMap = {}; + + // Support for IE8+ (and other, slightly more sane environments) + var invokeConsoleMethod = function (hdlr, messages) { + Function.prototype.apply.call(hdlr, console, messages); + }; + + Logger.setLevel(defaultLevel || Logger.DEBUG); + Logger.setHandler(function(messages, context) { + var hdlr = console.log; + + // append INFO/DEBUG etc into the messages + var levelPrefix = ((context.level.name+" ").toUpperCase()).substr(0,6); + messages[0] = levelPrefix + messages[0]; + + // Prepend the logger's name to the log message for easy identification. + if (context.name) { + messages[0] = "[" + context.name + "] " + messages[0]; + } + + + if (context.level === Logger.TIME) { + if (messages[1] === 'start') { + if (console.time) { + console.time(messages[0]); + } + else { + timerStartTimeByLabelMap[messages[0]] = new Date().getTime(); + } + } + else { + if (console.timeEnd) { + console.timeEnd(messages[0]); + } + else { + invokeConsoleMethod(hdlr, [ messages[0] + ': ' + + (new Date().getTime() - timerStartTimeByLabelMap[messages[0]]) + 'ms' ]); + } + } + } + else { + // Delegate through to custom warn/error loggers if present on the console. + if (context.level === Logger.WARN && console.warn) { + hdlr = console.warn; + } else if (context.level === Logger.ERROR && console.error) { + hdlr = console.error; + } else if (context.level === Logger.INFO && console.info) { + hdlr = console.info; + } + + invokeConsoleMethod(hdlr, messages); + } + }); + }; + + // Export to popular environments boilerplate. + if (typeof define === 'function' && define.amd) { + define(Logger); + } + else if (typeof module !== 'undefined' && module.exports) { + module.exports = Logger; + } + else { + Logger._prevLogger = global.Logger; + + Logger.noConflict = function () { + global.Logger = Logger._prevLogger; + return Logger; + }; + + global.Logger = Logger; + } +}(this)); +// init defaults +Logger.useDefaults(); diff --git a/rhodecode/public/js/src/moment.js b/rhodecode/public/js/src/moment.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/moment.js @@ -0,0 +1,3606 @@ +//! moment.js +//! version : 2.11.2 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + global.moment = factory() +}(this, function () { 'use strict'; + + var hookCallback; + + function utils_hooks__hooks () { + return hookCallback.apply(null, arguments); + } + + // This is done to register the method called with moment() + // without creating circular dependencies. + function setHookCallback (callback) { + hookCallback = callback; + } + + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; + } + + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function hasOwnProp(a, b) { + return Object.prototype.hasOwnProperty.call(a, b); + } + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function create_utc__createUTC (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, true).utc(); + } + + function defaultParsingFlags() { + // We need to deep clone this object. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso : false + }; + } + + function getParsingFlags(m) { + if (m._pf == null) { + m._pf = defaultParsingFlags(); + } + return m._pf; + } + + function valid__isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m); + m._isValid = !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + } + return m._isValid; + } + + function valid__createInvalid (flags) { + var m = create_utc__createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } + else { + getParsingFlags(m).userInvalidated = true; + } + + return m; + } + + function isUndefined(input) { + return input === void 0; + } + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + var momentProperties = utils_hooks__hooks.momentProperties = []; + + function copyConfig(to, from) { + var i, prop, val; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; + } + + var updateInProgress = false; + + // Moment prototype object + function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + utils_hooks__hooks.updateOffset(this); + updateInProgress = false; + } + } + + function isMoment (obj) { + return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); + } + + function absFloor (number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function Locale() { + } + + // internal storage for locale config files + var locales = {}; + var globalLocale; + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + // TODO: Find a better way to register and load all the locales in Node + if (!locales[name] && (typeof module !== 'undefined') && + module && module.exports) { + try { + oldLocale = globalLocale._abbr; + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we + // want to undo that for lazy loaded locales + locale_locales__getSetGlobalLocale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + function locale_locales__getSetGlobalLocale (key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = locale_locales__getLocale(key); + } + else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } + } + + return globalLocale._abbr; + } + + function defineLocale (name, values) { + if (values !== null) { + values.abbr = name; + locales[name] = locales[name] || new Locale(); + locales[name].set(values); + + // backwards compat for now: also set the locale + locale_locales__getSetGlobalLocale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + } + + // returns locale data + function locale_locales__getLocale (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + } + + var aliases = {}; + + function addUnitAlias (unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; + } + + function normalizeUnits(units) { + return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function isFunction(input) { + return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]'; + } + + function makeGetSet (unit, keepTime) { + return function (value) { + if (value != null) { + get_set__set(this, unit, value); + utils_hooks__hooks.updateOffset(this, keepTime); + return this; + } else { + return get_set__get(this, unit); + } + }; + } + + function get_set__get (mom, unit) { + return mom.isValid() ? + mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN; + } + + function get_set__set (mom, unit, value) { + if (mom.isValid()) { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + + // MOMENTS + + function getSet (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + + function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; + } + + var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; + + var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; + + var formatFunctions = {}; + + var formatTokenFunctions = {}; + + // token: 'M' + // padded: ['MM', 2] + // ordinal: 'Mo' + // callback: function () { this.month() + 1 } + function addFormatToken (token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal(func.apply(this, arguments), token); + }; + } + } + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + var match1 = /\d/; // 0 - 9 + var match2 = /\d\d/; // 00 - 99 + var match3 = /\d{3}/; // 000 - 999 + var match4 = /\d{4}/; // 0000 - 9999 + var match6 = /[+-]?\d{6}/; // -999999 - 999999 + var match1to2 = /\d\d?/; // 0 - 99 + var match3to4 = /\d\d\d\d?/; // 999 - 9999 + var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999 + var match1to3 = /\d{1,3}/; // 0 - 999 + var match1to4 = /\d{1,4}/; // 0 - 9999 + var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 + + var matchUnsigned = /\d+/; // 0 - inf + var matchSigned = /[+-]?\d+/; // -inf - inf + + var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z + var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z + + var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 + + // any word (or two) characters or numbers including two/three word month in arabic. + // includes scottish gaelic two word and hyphenated months + var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; + + + var regexes = {}; + + function addRegexToken (token, regex, strictRegex) { + regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) { + return (isStrict && strictRegex) ? strictRegex : regex; + }; + } + + function getParseRegexForToken (token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function unescapeFormat(s) { + return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + })); + } + + function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + var tokens = {}; + + function addParseToken (token, callback) { + var i, func = callback; + if (typeof token === 'string') { + token = [token]; + } + if (typeof callback === 'number') { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + for (i = 0; i < token.length; i++) { + tokens[token[i]] = func; + } + } + + function addWeekParseToken (token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); + } + + function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } + } + + var YEAR = 0; + var MONTH = 1; + var DATE = 2; + var HOUR = 3; + var MINUTE = 4; + var SECOND = 5; + var MILLISECOND = 6; + var WEEK = 7; + var WEEKDAY = 8; + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + // FORMATTING + + addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; + }); + + addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); + }); + + addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); + }); + + // ALIASES + + addUnitAlias('month', 'M'); + + // PARSING + + addRegexToken('M', match1to2); + addRegexToken('MM', match1to2, match2); + addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); + }); + addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); + }); + + addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; + }); + + addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } + }); + + // LOCALES + + var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/; + var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); + function localeMonths (m, format) { + return isArray(this._months) ? this._months[m.month()] : + this._months[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; + } + + var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); + function localeMonthsShort (m, format) { + return isArray(this._monthsShort) ? this._monthsShort[m.month()] : + this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; + } + + function localeMonthsParse (monthName, format, strict) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = create_utc__createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + } + + // MOMENTS + + function setMonth (mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function getSetMonth (value) { + if (value != null) { + setMonth(this, value); + utils_hooks__hooks.updateOffset(this, true); + return this; + } else { + return get_set__get(this, 'Month'); + } + } + + function getDaysInMonth () { + return daysInMonth(this.year(), this.month()); + } + + var defaultMonthsShortRegex = matchWord; + function monthsShortRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + return this._monthsShortStrictRegex && isStrict ? + this._monthsShortStrictRegex : this._monthsShortRegex; + } + } + + var defaultMonthsRegex = matchWord; + function monthsRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + return this._monthsStrictRegex && isStrict ? + this._monthsStrictRegex : this._monthsRegex; + } + } + + function computeMonthsParse () { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], longPieces = [], mixedPieces = [], + i, mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = create_utc__createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')$', 'i'); + this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')$', 'i'); + } + + function checkOverflow (m) { + var overflow; + var a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : + a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : + a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : + a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : + a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : + a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; + } + + function warn(msg) { + if (utils_hooks__hooks.suppressDeprecationWarnings === false && + (typeof console !== 'undefined') && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (firstTime) { + warn(msg + '\nArguments: ' + Array.prototype.slice.call(arguments).join(', ') + '\n' + (new Error()).stack); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + var deprecations = {}; + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } + } + + utils_hooks__hooks.suppressDeprecationWarnings = false; + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/; + var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/; + + var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/; + + var isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + // YYYYMM is NOT allowed by the standard + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/] + ]; + + // iso time formats and regexes + var isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/] + ]; + + var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; + + // date from iso format + function configFromISO(config) { + var i, l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, dateFormat, timeFormat, tzFormat; + + if (match) { + getParsingFlags(config).iso = true; + + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + // date from iso format or fallback + function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + utils_hooks__hooks.createFromInputFallback(config); + } + } + + utils_hooks__hooks.createFromInputFallback = deprecate( + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + function createDate (y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getFullYear())) { + date.setFullYear(y); + } + return date; + } + + function createUTCDate (y) { + var date = new Date(Date.UTC.apply(null, arguments)); + + //the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + return date; + } + + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? '' + y : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // ALIASES + + addUnitAlias('year', 'y'); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + // HOOKS + + utils_hooks__hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', false); + + function getIsLeapYear () { + return isLeapYear(this.year()); + } + + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear + }; + } + + function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear + }; + } + + function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; + } + + // Pick the first defined of two or three arguments. + function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; + } + + function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(utils_hooks__hooks.now()); + if (config._useUTC) { + return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function configFromArray (config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year); + week = defaults(w.w, 1); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to begining of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + } + + // constant that refers to the ISO standard + utils_hooks__hooks.ISO_8601 = function () {}; + + // date from string and format string + function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === utils_hooks__hooks.ISO_8601) { + configFromISO(config); + return; + } + + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + // console.log('token', token, 'parsedInput', parsedInput, + // 'regex', getParseRegexForToken(token, config)); + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } + else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (getParsingFlags(config).bigHour === true && + config._a[HOUR] <= 12 && + config._a[HOUR] > 0) { + getParsingFlags(config).bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); + + configFromArray(config); + checkOverflow(config); + } + + + function meridiemFixWrap (locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } + } + + // date from string and array of format strings + function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (!valid__isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i); + config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) { + return obj && parseInt(obj, 10); + }); + + configFromArray(config); + } + + function createFromConfig (config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig (config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || locale_locales__getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return valid__createInvalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else if (isDate(input)) { + config._d = input; + } else { + configFromInput(config); + } + + if (!valid__isValid(config)) { + config._d = null; + } + + return config; + } + + function configFromInput(config) { + var input = config._i; + if (input === undefined) { + config._d = new Date(utils_hooks__hooks.now()); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (typeof(input) === 'object') { + configFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + utils_hooks__hooks.createFromInputFallback(config); + } + } + + function createLocalOrUTC (input, format, locale, strict, isUTC) { + var c = {}; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); + } + + function local__createLocal (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); + } + + var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', + function () { + var other = local__createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return valid__createInvalid(); + } + } + ); + + var prototypeMax = deprecate( + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', + function () { + var other = local__createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return valid__createInvalid(); + } + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return local__createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + // TODO: Use [].sort instead? + function min () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + } + + function max () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + } + + var now = function () { + return Date.now ? Date.now() : +(new Date()); + }; + + function Duration (duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = locale_locales__getLocale(); + + this._bubble(); + } + + function isDuration (obj) { + return obj instanceof Duration; + } + + // FORMATTING + + function offset (token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(); + var sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); + }); + } + + offset('Z', ':'); + offset('ZZ', ''); + + // PARSING + + addRegexToken('Z', matchShortOffset); + addRegexToken('ZZ', matchShortOffset); + addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); + }); + + // HELPERS + + // timezone chunker + // '+10:00' > ['10', '00'] + // '-1530' > ['-15', '30'] + var chunkOffset = /([\+\-]|\d\d)/gi; + + function offsetFromString(matcher, string) { + var matches = ((string || '').match(matcher) || []); + var chunk = matches[matches.length - 1] || []; + var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + var minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? minutes : -minutes; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + utils_hooks__hooks.updateOffset(res, false); + return res; + } else { + return local__createLocal(input).local(); + } + } + + function getDateOffset (m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset() / 15) * 15; + } + + // HOOKS + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + utils_hooks__hooks.updateOffset = function () {}; + + // MOMENTS + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + function getSetOffset (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + } else if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + utils_hooks__hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } + } + + function getSetZone (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + + function setOffsetToUTC (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + } + + function setOffsetToLocal (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; + } + + function setOffsetToParsedOffset () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(offsetFromString(matchOffset, this._i)); + } + return this; + } + + function hasAlignedHourOffset (input) { + if (!this.isValid()) { + return false; + } + input = input ? local__createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; + } + + function isDaylightSavingTime () { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); + } + + function isDaylightSavingTimeShifted () { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a); + this._isDSTShifted = this.isValid() && + compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; + } + + function isLocal () { + return this.isValid() ? !this._isUTC : false; + } + + function isUtcOffset () { + return this.isValid() ? this._isUTC : false; + } + + function isUtc () { + return this.isValid() ? this._isUTC && this._offset === 0 : false; + } + + // ASP.NET json date format regex + var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/; + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + var isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/; + + function create__createDuration (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms : input._milliseconds, + d : input._days, + M : input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : 0, + d : toInt(match[DATE]) * sign, + h : toInt(match[HOUR]) * sign, + m : toInt(match[MINUTE]) * sign, + s : toInt(match[SECOND]) * sign, + ms : toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : parseIso(match[2], sign), + M : parseIso(match[3], sign), + d : parseIso(match[4], sign), + h : parseIso(match[5], sign), + m : parseIso(match[6], sign), + s : parseIso(match[7], sign), + w : parseIso(match[8], sign) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + return ret; + } + + create__createDuration.fn = Duration.prototype; + + function parseIso (inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + } + + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return {milliseconds: 0, months: 0}; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = create__createDuration(val, period); + add_subtract__addSubtract(this, dur, direction); + return this; + }; + } + + function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding); + } + if (months) { + setMonth(mom, get_set__get(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + utils_hooks__hooks.updateOffset(mom, days || months); + } + } + + var add_subtract__add = createAdder(1, 'add'); + var add_subtract__subtract = createAdder(-1, 'subtract'); + + function moment_calendar__calendar (time, formats) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || local__createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + + var output = formats && (isFunction(formats[format]) ? formats[format]() : formats[format]); + + return this.format(output || this.localeData().calendar(format, this, local__createLocal(now))); + } + + function clone () { + return new Moment(this); + } + + function isAfter (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return +this > +localInput; + } else { + return +localInput < +this.clone().startOf(units); + } + } + + function isBefore (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return +this < +localInput; + } else { + return +this.clone().endOf(units) < +localInput; + } + } + + function isBetween (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + } + + function isSame (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + return +this === +localInput; + } else { + inputMs = +localInput; + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + } + + function isSameOrAfter (input, units) { + return this.isSame(input, units) || this.isAfter(input,units); + } + + function isSameOrBefore (input, units) { + return this.isSame(input, units) || this.isBefore(input,units); + } + + function diff (input, units, asFloat) { + var that, + zoneDelta, + delta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + delta = this - that; + output = units === 'second' ? delta / 1e3 : // 1000 + units === 'minute' ? delta / 6e4 : // 1000 * 60 + units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + delta; + } + return asFloat ? output : absFloor(output); + } + + function monthDiff (a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + return -(wholeMonthDiff + adjust); + } + + utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; + + function toString () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + } + + function moment_format__toISOString () { + var m = this.clone().utc(); + if (0 < m.year() && m.year() <= 9999) { + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } + + function format (inputString) { + var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat); + return this.localeData().postformat(output); + } + + function from (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + local__createLocal(time).isValid())) { + return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function fromNow (withoutSuffix) { + return this.from(local__createLocal(), withoutSuffix); + } + + function to (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + local__createLocal(time).isValid())) { + return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function toNow (withoutSuffix) { + return this.to(local__createLocal(), withoutSuffix); + } + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + function locale (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = locale_locales__getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + } + + var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ); + + function localeData () { + return this._locale; + } + + function startOf (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } + if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + } + + function endOf (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + } + + function to_type__valueOf () { + return +this._d - ((this._offset || 0) * 60000); + } + + function unix () { + return Math.floor(+this / 1000); + } + + function toDate () { + return this._offset ? new Date(+this) : this._d; + } + + function toArray () { + var m = this; + return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; + } + + function toObject () { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds() + }; + } + + function toJSON () { + // JSON.stringify(new Date(NaN)) === 'null' + return this.isValid() ? this.toISOString() : 'null'; + } + + function moment_valid__isValid () { + return valid__isValid(this); + } + + function parsingFlags () { + return extend({}, getParsingFlags(this)); + } + + function invalidAt () { + return getParsingFlags(this).overflow; + } + + function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict + }; + } + + // FORMATTING + + addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; + }); + + addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; + }); + + function addWeekYearFormatToken (token, getter) { + addFormatToken(0, [token, token.length], 0, getter); + } + + addWeekYearFormatToken('gggg', 'weekYear'); + addWeekYearFormatToken('ggggg', 'weekYear'); + addWeekYearFormatToken('GGGG', 'isoWeekYear'); + addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + + // ALIASES + + addUnitAlias('weekYear', 'gg'); + addUnitAlias('isoWeekYear', 'GG'); + + // PARSING + + addRegexToken('G', matchSigned); + addRegexToken('g', matchSigned); + addRegexToken('GG', match1to2, match2); + addRegexToken('gg', match1to2, match2); + addRegexToken('GGGG', match1to4, match4); + addRegexToken('gggg', match1to4, match4); + addRegexToken('GGGGG', match1to6, match6); + addRegexToken('ggggg', match1to6, match6); + + addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); + }); + + addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = utils_hooks__hooks.parseTwoDigitYear(input); + }); + + // MOMENTS + + function getSetWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy); + } + + function getSetISOWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, this.isoWeek(), this.isoWeekday(), 1, 4); + } + + function getISOWeeksInYear () { + return weeksInYear(this.year(), 1, 4); + } + + function getWeeksInYear () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + } + + function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } + } + + function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + // console.log("got", weekYear, week, weekday, "set", date.toISOString()); + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; + } + + // FORMATTING + + addFormatToken('Q', 0, 'Qo', 'quarter'); + + // ALIASES + + addUnitAlias('quarter', 'Q'); + + // PARSING + + addRegexToken('Q', match1); + addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; + }); + + // MOMENTS + + function getSetQuarter (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + } + + // FORMATTING + + addFormatToken('w', ['ww', 2], 'wo', 'week'); + addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + + // ALIASES + + addUnitAlias('week', 'w'); + addUnitAlias('isoWeek', 'W'); + + // PARSING + + addRegexToken('w', match1to2); + addRegexToken('ww', match1to2, match2); + addRegexToken('W', match1to2); + addRegexToken('WW', match1to2, match2); + + addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); + }); + + // HELPERS + + // LOCALES + + function localeWeek (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + } + + var defaultLocaleWeek = { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }; + + function localeFirstDayOfWeek () { + return this._week.dow; + } + + function localeFirstDayOfYear () { + return this._week.doy; + } + + // MOMENTS + + function getSetWeek (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + function getSetISOWeek (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + // FORMATTING + + addFormatToken('D', ['DD', 2], 'Do', 'date'); + + // ALIASES + + addUnitAlias('date', 'D'); + + // PARSING + + addRegexToken('D', match1to2); + addRegexToken('DD', match1to2, match2); + addRegexToken('Do', function (isStrict, locale) { + return isStrict ? locale._ordinalParse : locale._ordinalParseLenient; + }); + + addParseToken(['D', 'DD'], DATE); + addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0], 10); + }); + + // MOMENTS + + var getSetDayOfMonth = makeGetSet('Date', true); + + // FORMATTING + + addFormatToken('d', 0, 'do', 'day'); + + addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); + }); + + addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); + }); + + addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); + }); + + addFormatToken('e', 0, 0, 'weekday'); + addFormatToken('E', 0, 0, 'isoWeekday'); + + // ALIASES + + addUnitAlias('day', 'd'); + addUnitAlias('weekday', 'e'); + addUnitAlias('isoWeekday', 'E'); + + // PARSING + + addRegexToken('d', match1to2); + addRegexToken('e', match1to2); + addRegexToken('E', match1to2); + addRegexToken('dd', matchWord); + addRegexToken('ddd', matchWord); + addRegexToken('dddd', matchWord); + + addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } + }); + + addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); + }); + + // HELPERS + + function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; + } + + // LOCALES + + var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); + function localeWeekdays (m, format) { + return isArray(this._weekdays) ? this._weekdays[m.day()] : + this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()]; + } + + var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); + function localeWeekdaysShort (m) { + return this._weekdaysShort[m.day()]; + } + + var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); + function localeWeekdaysMin (m) { + return this._weekdaysMin[m.day()]; + } + + function localeWeekdaysParse (weekdayName, format, strict) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = local__createLocal([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i'); + this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i'); + this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i'); + } + if (!this._weekdaysParse[i]) { + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + } + + // MOMENTS + + function getSetDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + } + + function getSetLocaleDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + } + + function getSetISODayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + } + + // FORMATTING + + addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + + // ALIASES + + addUnitAlias('dayOfYear', 'DDD'); + + // PARSING + + addRegexToken('DDD', match1to3); + addRegexToken('DDDD', match3); + addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); + }); + + // HELPERS + + // MOMENTS + + function getSetDayOfYear (input) { + var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + } + + // FORMATTING + + function hFormat() { + return this.hours() % 12 || 12; + } + + addFormatToken('H', ['HH', 2], 0, 'hour'); + addFormatToken('h', ['hh', 2], 0, hFormat); + + addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); + }); + + addFormatToken('hmmss', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); + }); + + addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); + }); + + addFormatToken('Hmmss', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); + }); + + function meridiem (token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); + }); + } + + meridiem('a', true); + meridiem('A', false); + + // ALIASES + + addUnitAlias('hour', 'h'); + + // PARSING + + function matchMeridiem (isStrict, locale) { + return locale._meridiemParse; + } + + addRegexToken('a', matchMeridiem); + addRegexToken('A', matchMeridiem); + addRegexToken('H', match1to2); + addRegexToken('h', match1to2); + addRegexToken('HH', match1to2, match2); + addRegexToken('hh', match1to2, match2); + + addRegexToken('hmm', match3to4); + addRegexToken('hmmss', match5to6); + addRegexToken('Hmm', match3to4); + addRegexToken('Hmmss', match5to6); + + addParseToken(['H', 'HH'], HOUR); + addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; + }); + addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + }); + addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + }); + + // LOCALES + + function localeIsPM (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + } + + var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; + function localeMeridiem (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + } + + + // MOMENTS + + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + var getSetHour = makeGetSet('Hours', true); + + // FORMATTING + + addFormatToken('m', ['mm', 2], 0, 'minute'); + + // ALIASES + + addUnitAlias('minute', 'm'); + + // PARSING + + addRegexToken('m', match1to2); + addRegexToken('mm', match1to2, match2); + addParseToken(['m', 'mm'], MINUTE); + + // MOMENTS + + var getSetMinute = makeGetSet('Minutes', false); + + // FORMATTING + + addFormatToken('s', ['ss', 2], 0, 'second'); + + // ALIASES + + addUnitAlias('second', 's'); + + // PARSING + + addRegexToken('s', match1to2); + addRegexToken('ss', match1to2, match2); + addParseToken(['s', 'ss'], SECOND); + + // MOMENTS + + var getSetSecond = makeGetSet('Seconds', false); + + // FORMATTING + + addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); + }); + + addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); + }); + + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); + + + // ALIASES + + addUnitAlias('millisecond', 'ms'); + + // PARSING + + addRegexToken('S', match1to3, match1); + addRegexToken('SS', match1to3, match2); + addRegexToken('SSS', match1to3, match3); + + var token; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); + } + + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } + // MOMENTS + + var getSetMillisecond = makeGetSet('Milliseconds', false); + + // FORMATTING + + addFormatToken('z', 0, 0, 'zoneAbbr'); + addFormatToken('zz', 0, 0, 'zoneName'); + + // MOMENTS + + function getZoneAbbr () { + return this._isUTC ? 'UTC' : ''; + } + + function getZoneName () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + } + + var momentPrototype__proto = Moment.prototype; + + momentPrototype__proto.add = add_subtract__add; + momentPrototype__proto.calendar = moment_calendar__calendar; + momentPrototype__proto.clone = clone; + momentPrototype__proto.diff = diff; + momentPrototype__proto.endOf = endOf; + momentPrototype__proto.format = format; + momentPrototype__proto.from = from; + momentPrototype__proto.fromNow = fromNow; + momentPrototype__proto.to = to; + momentPrototype__proto.toNow = toNow; + momentPrototype__proto.get = getSet; + momentPrototype__proto.invalidAt = invalidAt; + momentPrototype__proto.isAfter = isAfter; + momentPrototype__proto.isBefore = isBefore; + momentPrototype__proto.isBetween = isBetween; + momentPrototype__proto.isSame = isSame; + momentPrototype__proto.isSameOrAfter = isSameOrAfter; + momentPrototype__proto.isSameOrBefore = isSameOrBefore; + momentPrototype__proto.isValid = moment_valid__isValid; + momentPrototype__proto.lang = lang; + momentPrototype__proto.locale = locale; + momentPrototype__proto.localeData = localeData; + momentPrototype__proto.max = prototypeMax; + momentPrototype__proto.min = prototypeMin; + momentPrototype__proto.parsingFlags = parsingFlags; + momentPrototype__proto.set = getSet; + momentPrototype__proto.startOf = startOf; + momentPrototype__proto.subtract = add_subtract__subtract; + momentPrototype__proto.toArray = toArray; + momentPrototype__proto.toObject = toObject; + momentPrototype__proto.toDate = toDate; + momentPrototype__proto.toISOString = moment_format__toISOString; + momentPrototype__proto.toJSON = toJSON; + momentPrototype__proto.toString = toString; + momentPrototype__proto.unix = unix; + momentPrototype__proto.valueOf = to_type__valueOf; + momentPrototype__proto.creationData = creationData; + + // Year + momentPrototype__proto.year = getSetYear; + momentPrototype__proto.isLeapYear = getIsLeapYear; + + // Week Year + momentPrototype__proto.weekYear = getSetWeekYear; + momentPrototype__proto.isoWeekYear = getSetISOWeekYear; + + // Quarter + momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter; + + // Month + momentPrototype__proto.month = getSetMonth; + momentPrototype__proto.daysInMonth = getDaysInMonth; + + // Week + momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek; + momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek; + momentPrototype__proto.weeksInYear = getWeeksInYear; + momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear; + + // Day + momentPrototype__proto.date = getSetDayOfMonth; + momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek; + momentPrototype__proto.weekday = getSetLocaleDayOfWeek; + momentPrototype__proto.isoWeekday = getSetISODayOfWeek; + momentPrototype__proto.dayOfYear = getSetDayOfYear; + + // Hour + momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour; + + // Minute + momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute; + + // Second + momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond; + + // Millisecond + momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond; + + // Offset + momentPrototype__proto.utcOffset = getSetOffset; + momentPrototype__proto.utc = setOffsetToUTC; + momentPrototype__proto.local = setOffsetToLocal; + momentPrototype__proto.parseZone = setOffsetToParsedOffset; + momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset; + momentPrototype__proto.isDST = isDaylightSavingTime; + momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted; + momentPrototype__proto.isLocal = isLocal; + momentPrototype__proto.isUtcOffset = isUtcOffset; + momentPrototype__proto.isUtc = isUtc; + momentPrototype__proto.isUTC = isUtc; + + // Timezone + momentPrototype__proto.zoneAbbr = getZoneAbbr; + momentPrototype__proto.zoneName = getZoneName; + + // Deprecations + momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); + momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); + momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); + momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone); + + var momentPrototype = momentPrototype__proto; + + function moment__createUnix (input) { + return local__createLocal(input * 1000); + } + + function moment__createInZone () { + return local__createLocal.apply(null, arguments).parseZone(); + } + + var defaultCalendar = { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }; + + function locale_calendar__calendar (key, mom, now) { + var output = this._calendar[key]; + return isFunction(output) ? output.call(mom, now) : output; + } + + var defaultLongDateFormat = { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY h:mm A', + LLLL : 'dddd, MMMM D, YYYY h:mm A' + }; + + function longDateFormat (key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + + return this._longDateFormat[key]; + } + + var defaultInvalidDate = 'Invalid date'; + + function invalidDate () { + return this._invalidDate; + } + + var defaultOrdinal = '%d'; + var defaultOrdinalParse = /\d{1,2}/; + + function ordinal (number) { + return this._ordinal.replace('%d', number); + } + + function preParsePostFormat (string) { + return string; + } + + var defaultRelativeTime = { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }; + + function relative__relativeTime (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (isFunction(output)) ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + } + + function pastFuture (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); + } + + function locale_set__set (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source); + } + + var prototype__proto = Locale.prototype; + + prototype__proto._calendar = defaultCalendar; + prototype__proto.calendar = locale_calendar__calendar; + prototype__proto._longDateFormat = defaultLongDateFormat; + prototype__proto.longDateFormat = longDateFormat; + prototype__proto._invalidDate = defaultInvalidDate; + prototype__proto.invalidDate = invalidDate; + prototype__proto._ordinal = defaultOrdinal; + prototype__proto.ordinal = ordinal; + prototype__proto._ordinalParse = defaultOrdinalParse; + prototype__proto.preparse = preParsePostFormat; + prototype__proto.postformat = preParsePostFormat; + prototype__proto._relativeTime = defaultRelativeTime; + prototype__proto.relativeTime = relative__relativeTime; + prototype__proto.pastFuture = pastFuture; + prototype__proto.set = locale_set__set; + + // Month + prototype__proto.months = localeMonths; + prototype__proto._months = defaultLocaleMonths; + prototype__proto.monthsShort = localeMonthsShort; + prototype__proto._monthsShort = defaultLocaleMonthsShort; + prototype__proto.monthsParse = localeMonthsParse; + prototype__proto._monthsRegex = defaultMonthsRegex; + prototype__proto.monthsRegex = monthsRegex; + prototype__proto._monthsShortRegex = defaultMonthsShortRegex; + prototype__proto.monthsShortRegex = monthsShortRegex; + + // Week + prototype__proto.week = localeWeek; + prototype__proto._week = defaultLocaleWeek; + prototype__proto.firstDayOfYear = localeFirstDayOfYear; + prototype__proto.firstDayOfWeek = localeFirstDayOfWeek; + + // Day of Week + prototype__proto.weekdays = localeWeekdays; + prototype__proto._weekdays = defaultLocaleWeekdays; + prototype__proto.weekdaysMin = localeWeekdaysMin; + prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin; + prototype__proto.weekdaysShort = localeWeekdaysShort; + prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort; + prototype__proto.weekdaysParse = localeWeekdaysParse; + + // Hours + prototype__proto.isPM = localeIsPM; + prototype__proto._meridiemParse = defaultLocaleMeridiemParse; + prototype__proto.meridiem = localeMeridiem; + + function lists__get (format, index, field, setter) { + var locale = locale_locales__getLocale(); + var utc = create_utc__createUTC().set(setter, index); + return locale[field](utc, format); + } + + function list (format, index, field, count, setter) { + if (typeof format === 'number') { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return lists__get(format, index, field, setter); + } + + var i; + var out = []; + for (i = 0; i < count; i++) { + out[i] = lists__get(format, i, field, setter); + } + return out; + } + + function lists__listMonths (format, index) { + return list(format, index, 'months', 12, 'month'); + } + + function lists__listMonthsShort (format, index) { + return list(format, index, 'monthsShort', 12, 'month'); + } + + function lists__listWeekdays (format, index) { + return list(format, index, 'weekdays', 7, 'day'); + } + + function lists__listWeekdaysShort (format, index) { + return list(format, index, 'weekdaysShort', 7, 'day'); + } + + function lists__listWeekdaysMin (format, index) { + return list(format, index, 'weekdaysMin', 7, 'day'); + } + + locale_locales__getSetGlobalLocale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + // Side effect imports + utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale); + utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale); + + var mathAbs = Math.abs; + + function duration_abs__abs () { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; + } + + function duration_add_subtract__addSubtract (duration, input, value, direction) { + var other = create__createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); + } + + // supports only 2.0-style add(1, 's') or add(duration) + function duration_add_subtract__add (input, value) { + return duration_add_subtract__addSubtract(this, input, value, 1); + } + + // supports only 2.0-style subtract(1, 's') or subtract(duration) + function duration_add_subtract__subtract (input, value) { + return duration_add_subtract__addSubtract(this, input, value, -1); + } + + function absCeil (number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + + function bubble () { + var milliseconds = this._milliseconds; + var days = this._days; + var months = this._months; + var data = this._data; + var seconds, minutes, hours, years, monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if (!((milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0))) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; + } + + function daysToMonths (days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return days * 4800 / 146097; + } + + function monthsToDays (months) { + // the reverse of daysToMonths + return months * 146097 / 4800; + } + + function as (units) { + var days; + var months; + var milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week' : return days / 7 + milliseconds / 6048e5; + case 'day' : return days + milliseconds / 864e5; + case 'hour' : return days * 24 + milliseconds / 36e5; + case 'minute' : return days * 1440 + milliseconds / 6e4; + case 'second' : return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 864e5) + milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + } + + // TODO: Use this.as('ms')? + function duration_as__valueOf () { + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); + } + + function makeAs (alias) { + return function () { + return this.as(alias); + }; + } + + var asMilliseconds = makeAs('ms'); + var asSeconds = makeAs('s'); + var asMinutes = makeAs('m'); + var asHours = makeAs('h'); + var asDays = makeAs('d'); + var asWeeks = makeAs('w'); + var asMonths = makeAs('M'); + var asYears = makeAs('y'); + + function duration_get__get (units) { + units = normalizeUnits(units); + return this[units + 's'](); + } + + function makeGetter(name) { + return function () { + return this._data[name]; + }; + } + + var milliseconds = makeGetter('milliseconds'); + var seconds = makeGetter('seconds'); + var minutes = makeGetter('minutes'); + var hours = makeGetter('hours'); + var days = makeGetter('days'); + var months = makeGetter('months'); + var years = makeGetter('years'); + + function weeks () { + return absFloor(this.days() / 7); + } + + var round = Math.round; + var thresholds = { + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year + }; + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) { + var duration = create__createDuration(posNegDuration).abs(); + var seconds = round(duration.as('s')); + var minutes = round(duration.as('m')); + var hours = round(duration.as('h')); + var days = round(duration.as('d')); + var months = round(duration.as('M')); + var years = round(duration.as('y')); + + var a = seconds < thresholds.s && ['s', seconds] || + minutes <= 1 && ['m'] || + minutes < thresholds.m && ['mm', minutes] || + hours <= 1 && ['h'] || + hours < thresholds.h && ['hh', hours] || + days <= 1 && ['d'] || + days < thresholds.d && ['dd', days] || + months <= 1 && ['M'] || + months < thresholds.M && ['MM', months] || + years <= 1 && ['y'] || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); + } + + // This function allows you to set a threshold for relative time strings + function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + return true; + } + + function humanize (withSuffix) { + var locale = this.localeData(); + var output = duration_humanize__relativeTime(this, !withSuffix, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); + } + + var iso_string__abs = Math.abs; + + function iso_string__toISOString() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + var seconds = iso_string__abs(this._milliseconds) / 1000; + var days = iso_string__abs(this._days); + var months = iso_string__abs(this._months); + var minutes, hours, years; + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var Y = years; + var M = months; + var D = days; + var h = hours; + var m = minutes; + var s = seconds; + var total = this.asSeconds(); + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (total < 0 ? '-' : '') + + 'P' + + (Y ? Y + 'Y' : '') + + (M ? M + 'M' : '') + + (D ? D + 'D' : '') + + ((h || m || s) ? 'T' : '') + + (h ? h + 'H' : '') + + (m ? m + 'M' : '') + + (s ? s + 'S' : ''); + } + + var duration_prototype__proto = Duration.prototype; + + duration_prototype__proto.abs = duration_abs__abs; + duration_prototype__proto.add = duration_add_subtract__add; + duration_prototype__proto.subtract = duration_add_subtract__subtract; + duration_prototype__proto.as = as; + duration_prototype__proto.asMilliseconds = asMilliseconds; + duration_prototype__proto.asSeconds = asSeconds; + duration_prototype__proto.asMinutes = asMinutes; + duration_prototype__proto.asHours = asHours; + duration_prototype__proto.asDays = asDays; + duration_prototype__proto.asWeeks = asWeeks; + duration_prototype__proto.asMonths = asMonths; + duration_prototype__proto.asYears = asYears; + duration_prototype__proto.valueOf = duration_as__valueOf; + duration_prototype__proto._bubble = bubble; + duration_prototype__proto.get = duration_get__get; + duration_prototype__proto.milliseconds = milliseconds; + duration_prototype__proto.seconds = seconds; + duration_prototype__proto.minutes = minutes; + duration_prototype__proto.hours = hours; + duration_prototype__proto.days = days; + duration_prototype__proto.weeks = weeks; + duration_prototype__proto.months = months; + duration_prototype__proto.years = years; + duration_prototype__proto.humanize = humanize; + duration_prototype__proto.toISOString = iso_string__toISOString; + duration_prototype__proto.toString = iso_string__toISOString; + duration_prototype__proto.toJSON = iso_string__toISOString; + duration_prototype__proto.locale = locale; + duration_prototype__proto.localeData = localeData; + + // Deprecations + duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString); + duration_prototype__proto.lang = lang; + + // Side effect imports + + // FORMATTING + + addFormatToken('X', 0, 0, 'unix'); + addFormatToken('x', 0, 0, 'valueOf'); + + // PARSING + + addRegexToken('x', matchSigned); + addRegexToken('X', matchTimestamp); + addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input, 10) * 1000); + }); + addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); + }); + + // Side effect imports + + + utils_hooks__hooks.version = '2.11.2'; + + setHookCallback(local__createLocal); + + utils_hooks__hooks.fn = momentPrototype; + utils_hooks__hooks.min = min; + utils_hooks__hooks.max = max; + utils_hooks__hooks.now = now; + utils_hooks__hooks.utc = create_utc__createUTC; + utils_hooks__hooks.unix = moment__createUnix; + utils_hooks__hooks.months = lists__listMonths; + utils_hooks__hooks.isDate = isDate; + utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale; + utils_hooks__hooks.invalid = valid__createInvalid; + utils_hooks__hooks.duration = create__createDuration; + utils_hooks__hooks.isMoment = isMoment; + utils_hooks__hooks.weekdays = lists__listWeekdays; + utils_hooks__hooks.parseZone = moment__createInZone; + utils_hooks__hooks.localeData = locale_locales__getLocale; + utils_hooks__hooks.isDuration = isDuration; + utils_hooks__hooks.monthsShort = lists__listMonthsShort; + utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin; + utils_hooks__hooks.defineLocale = defineLocale; + utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort; + utils_hooks__hooks.normalizeUnits = normalizeUnits; + utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold; + utils_hooks__hooks.prototype = momentPrototype; + + var _moment = utils_hooks__hooks; + + return _moment; + +})); \ No newline at end of file diff --git a/rhodecode/public/js/src/mousetrap.js b/rhodecode/public/js/src/mousetrap.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/mousetrap.js @@ -0,0 +1,931 @@ +/*global define:false */ +/** + * Copyright 2013 Craig Campbell + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.4.5 + * @url craig.is/killing/mice + */ +(function(window, document, undefined) { + + /** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ + var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' + }, + + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }, + + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }, + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }, + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + _REVERSE_MAP, + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + _callbacks = {}, + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + _directMap = {}, + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + _sequenceLevels = {}, + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + _resetTimer, + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + _ignoreNextKeyup = false, + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + _ignoreNextKeypress = false, + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + _nextExpectedAction = false; + + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } + + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + _MAP[i + 96] = i; + } + + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); + } + + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); + } + + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } + + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ + function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } + } + + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ + function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i, + callback, + matches = [], + action = e.type; + + // if there are no events related to this keycode + if (!_callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < _callbacks[character].length; ++i) { + callback = _callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + _callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; + } + + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e, combo) { + + // if this event should not happen stop here + if (Mousetrap.stopCallback(e, e.target || e.srcElement, combo)) { + return; + } + + if (callback(e, combo) === false) { + if (e.preventDefault) { + e.preventDefault(); + } + + if (e.stopPropagation) { + e.stopPropagation(); + } + + e.returnValue = false; + e.cancelBubble = true; + } + } + + /** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ + function _handleKey(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e), + i, + doNotReset = {}, + maxLevel = 0, + processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; + } + + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + Mousetrap.handleKey(character, _eventModifiers(e), e); + } + + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } + + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); + } + + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } + + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; + } + + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } + } + + /** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ + function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + return combination.split('+'); + } + + /** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ + function _getKeyInfo(combination, action) { + var keys, + key, + i, + modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; + } + + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + _directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '), + info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + _callbacks[info.key] = _callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + _callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); + } + + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + function _bindMultiple(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + } + + // start! + _addEvent(document, 'keypress', _handleKeyEvent); + _addEvent(document, 'keydown', _handleKeyEvent); + _addEvent(document, 'keyup', _handleKeyEvent); + + var Mousetrap = { + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + bind: function(keys, callback, action) { + keys = keys instanceof Array ? keys : [keys]; + _bindMultiple(keys, callback, action); + return this; + }, + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + unbind: function(keys, action) { + return Mousetrap.bind(keys, function() {}, action); + }, + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + trigger: function(keys, action) { + if (_directMap[keys + ':' + action]) { + _directMap[keys + ':' + action]({}, keys); + } + return this; + }, + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + reset: function() { + _callbacks = {}; + _directMap = {}; + return this; + }, + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + stopCallback: function(e, element) { + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }, + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + handleKey: _handleKey + }; + + // expose mousetrap to the global object + window.Mousetrap = Mousetrap; + + // expose mousetrap as an AMD module + if (typeof define === 'function' && define.amd) { + define(Mousetrap); + } +}) (window, document); diff --git a/rhodecode/public/js/src/plugins/flavoured_checkbox.js b/rhodecode/public/js/src/plugins/flavoured_checkbox.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/flavoured_checkbox.js @@ -0,0 +1,71 @@ +var FlavoredCheckbox = (function($) { + +"use strict"; + +// makes Markdown FlavoredCheckbox interactive +// `container` is either a DOM element, jQuery collection or selector containing +// the Markdown content +// `retriever` is a function being passed the respective checkbox and a +// callback - the latter is expected to be called with the container's raw +// Markdown source +// `storer` is a function being passed the updated Markdown content, the +// respective checkbox and a callback +// both functions' are invoked with the respective `FlavoredCheckbox` instance as +// execution context (i.e. `this`) +// use like that:: +// var retriever = function(checkbox, callback) { +// var url = '/checkbox_update_url'; +// $.get(url, callback); +// } +// +// var storer = function(markdown_txt, checkbox, callback) { +// var url = '/checkbox_update_url'; +// $.ajax({ +// type: "put", +// url: url, +// data: markdown_txt, +// success: callback +// }); +// } +// new FlavoredCheckbox("article", retriever, storer); + +function FlavoredCheckbox(container, retriever, storer) { + this.container = container.jquery ? container : $(container); + this.retriever = retriever; + this.storer = storer; + this._used_class = '.flavored_checkbox_list' + + var checkbox_objects = $(this._used_class, container); + checkbox_objects.find(this.checkboxSelector).prop("disabled", false); + var self = this; + checkbox_objects.on("change", this.checkboxSelector, function() { + var args = Array.prototype.slice.call(arguments); + args.push(self); + self.onChange.apply(this, args); + }); +} +FlavoredCheckbox.prototype.checkboxSelector = "> li > input:checkbox"; +FlavoredCheckbox.prototype.onChange = function(ev, self) { + var checkbox = $(this).prop("disabled", true); + var index = $("ul" + self.checkboxSelector, self.container).index(this); + var reactivate = function() { checkbox.prop("disabled", false); }; + self.retriever(checkbox, function(markdown) { + markdown = self.toggleCheckbox(index, markdown); + self.storer(markdown, checkbox, reactivate); + }); +}; +FlavoredCheckbox.prototype.toggleCheckbox = function(index, markdown) { + var pattern = /^([*-]) \[([ x])\]/mg; // XXX: duplicates server-side logic!? + var count = 0; + return markdown.replace(pattern, function(match, prefix, marker) { + if(count === index) { + marker = marker === " " ? "x" : " "; + } + count++; + return prefix + " [" + marker + "]"; + }); +}; + +return FlavoredCheckbox; + +}(jQuery)); diff --git a/rhodecode/public/js/src/plugins/jquery.auto-grow-input.js b/rhodecode/public/js/src/plugins/jquery.auto-grow-input.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.auto-grow-input.js @@ -0,0 +1,62 @@ +/*** + * Use like $('#input_box').autoGrowInput() + */ +(function($){ + + $.fn.autoGrowInput = function(o) { + + o = $.extend({ + maxWidth: 1000, + minWidth: 0, + comfortZone: 70 + }, o); + + this.filter('input:text').each(function(){ + + var minWidth = o.minWidth || $(this).width(), + val = '', + input = $(this), + testSubject = $('<tester/>').css({ + position: 'absolute', + top: -9999, + left: -9999, + width: 'auto', + fontSize: input.css('fontSize'), + fontFamily: input.css('fontFamily'), + fontWeight: input.css('fontWeight'), + letterSpacing: input.css('letterSpacing'), + whiteSpace: 'nowrap' + }), + check = function() { + + if (val === (val = input.val())) {return;} + + // Enter new content into testSubject + var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>'); + testSubject.html(escaped); + + // Calculate new width + whether to change + var testerWidth = testSubject.width(), + newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, + currentWidth = input.width(), + isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) + || (newWidth > minWidth && newWidth < o.maxWidth); + + // Animate width + if (isValidWidthChange) { + input.width(newWidth); + } + + }; + + testSubject.insertAfter(input); + + $(this).bind('keyup keydown blur update', check); + + }); + + return this; + + }; + +})(jQuery); diff --git a/rhodecode/public/js/src/plugins/jquery.autocomplete.js b/rhodecode/public/js/src/plugins/jquery.autocomplete.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.autocomplete.js @@ -0,0 +1,936 @@ +/** +* Ajax Autocomplete for jQuery, version dev +* RhodeCode additions +* (c) 2014 Tomas Kirda +* (c) 2014 Marcin Kuzminski +* +* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. +* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete +*/ +// Expose plugin as an AMD module if AMD loader is present: +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object' && typeof require === 'function') { + // Browserify + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + 'use strict'; + + var + utils = (function () { + return { + escapeRegExChars: function (value) { + return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + createNode: function (containerClass) { + var div = document.createElement('div'); + div.className = containerClass; + div.style.position = 'absolute'; + div.style.display = 'none'; + return div; + } + }; + }()), + + keys = { + ESC: 27, + TAB: 9, + RETURN: 13, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40 + }; + + function Autocomplete(el, options) { + var noop = function () { }, + that = this, + defaults = { + ajaxSettings: {}, + autoSelectFirst: false, + appendTo: document.body, + serviceUrl: null, + lookup: null, + width: 'auto', + minChars: 1, + maxHeight: 300, + deferRequestBy: 0, + params: {}, + formatResult: Autocomplete.formatResult, + lookupFilter: Autocomplete.lookupFilter, + delimiter: null, + zIndex: 9999, + type: 'GET', + noCache: false, + onSelect: noop, + onSearchStart: noop, + onSearchComplete: noop, + onSearchError: noop, + containerClass: 'autocomplete-suggestions', + tabDisabled: false, + dataType: 'text', + currentRequest: null, + triggerSelectOnValidInput: false, + preventBadQueries: true, + paramName: 'query', + transformResult: function (response) { + return typeof response === 'string' ? $.parseJSON(response) : response; + }, + showNoSuggestionNotice: false, + noSuggestionNotice: _TM['No results'], + orientation: 'bottom', + forceFixPosition: false, + replaceOnArrowKey: true + }; + + // Shared variables: + that.element = el; + that.el = $(el); + that.suggestions = []; + that.badQueries = []; + that.selectedIndex = -1; + that.currentValue = that.element.value; + that.intervalId = 0; + that.cachedResponse = {}; + that.onChangeInterval = null; + that.onChange = null; + that.isLocal = false; + that.suggestionsContainer = null; + that.noSuggestionsContainer = null; + that.options = $.extend({}, defaults, options); + that.classes = { + selected: 'autocomplete-selected', + suggestion: 'autocomplete-suggestion' + }; + that.hint = null; + that.hintValue = ''; + that.selection = null; + + // Initialize and set options: + that.initialize(); + that.setOptions(options); + } + + Autocomplete.utils = utils; + + $.Autocomplete = Autocomplete; + + Autocomplete.formatResult = function (suggestion, currentValue) { + var pattern = '(' + utils.escapeRegExChars(currentValue) + ')'; + return suggestion.value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); + }; + Autocomplete.lookupFilter = function (suggestion, originalQuery, queryLowerCase) { + return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1; + }; + + Autocomplete.prototype = { + + killerFn: null, + + initialize: function () { + var that = this, + suggestionSelector = '.' + that.classes.suggestion, + selected = that.classes.selected, + options = that.options, + container; + + // Remove autocomplete attribute to prevent native suggestions: + that.element.setAttribute('autocomplete', 'off'); + + that.killerFn = function (e) { + if ($(e.target).closest('.' + that.options.containerClass).length === 0) { + that.killSuggestions(); + that.disableKillerFn(); + } + }; + + // html() deals with many types: htmlString or Element or Array or jQuery + that.noSuggestionsContainer = $('<div class="autocomplete-no-suggestion"></div>') + .html(this.options.noSuggestionNotice).get(0); + + that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass); + + container = $(that.suggestionsContainer); + + container.appendTo(options.appendTo); + + // Only set width if it was provided: + if (options.width !== 'auto') { + container.width(options.width); + } + + // Listen for mouse over event on suggestions list: + container.on('mouseover.autocomplete', suggestionSelector, function () { + that.activate($(this).data('index')); + }); + + // Deselect active element when mouse leaves suggestions container: + container.on('mouseout.autocomplete', function () { + that.selectedIndex = -1; + container.children('.' + selected).removeClass(selected); + }); + + // Listen for click event on suggestions list: + container.on('click.autocomplete', suggestionSelector, function () { + that.select($(this).data('index')); + }); + + that.fixPositionCapture = function () { + if (that.visible) { + that.fixPosition(); + } + }; + + $(window).on('resize.autocomplete', that.fixPositionCapture); + + that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); }); + that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); }); + that.el.on('blur.autocomplete', function () { that.onBlur(); }); + that.el.on('focus.autocomplete', function () { that.onFocus(); }); + that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); }); + }, + + onFocus: function () { + var that = this; + that.fixPosition(); + if (that.options.minChars <= that.el.val().length) { + that.onValueChange(); + } + }, + + onBlur: function () { + this.enableKillerFn(); + }, + + setOptions: function (suppliedOptions) { + var that = this, + options = that.options; + + $.extend(options, suppliedOptions); + + that.isLocal = $.isArray(options.lookup); + + if (that.isLocal) { + options.lookup = that.verifySuggestionsFormat(options.lookup); + } + + options.orientation = that.validateOrientation(options.orientation, 'bottom'); + + // Adjust height, width and z-index: + $(that.suggestionsContainer).css({ + 'max-height': options.maxHeight + 'px', + 'width': options.width + 'px', + 'z-index': options.zIndex + }); + }, + + clearCache: function () { + this.cachedResponse = {}; + this.badQueries = []; + }, + + clear: function () { + this.clearCache(); + this.currentValue = ''; + this.suggestions = []; + }, + + disable: function () { + var that = this; + that.disabled = true; + if (that.currentRequest) { + that.currentRequest.abort(); + } + }, + + enable: function () { + this.disabled = false; + }, + + fixPosition: function () { + // Use only when container has already its content + + var that = this, + $container = $(that.suggestionsContainer), + containerParent = $container.parent().get(0); + // Fix position automatically when appended to body. + // In other cases force parameter must be given. + if (containerParent !== document.body && !that.options.forceFixPosition) + return; + + // Choose orientation + var orientation = that.options.orientation, + containerHeight = $container.outerHeight(), + height = that.el.outerHeight(), + offset = that.el.offset(), + styles = { 'top': offset.top, 'left': offset.left }; + + if (orientation == 'auto') { + var viewPortHeight = $(window).height(), + scrollTop = $(window).scrollTop(), + topOverflow = -scrollTop + offset.top - containerHeight, + bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight); + + orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) + ? 'top' + : 'bottom'; + } + + if (orientation === 'top') { + styles.top += -containerHeight; + } else { + styles.top += height; + } + + // If container is not positioned to body, + // correct its position using offset parent offset + if(containerParent !== document.body) { + var opacity = $container.css('opacity'), + parentOffsetDiff; + + if (!that.visible){ + $container.css('opacity', 0).show(); + } + + parentOffsetDiff = $container.offsetParent().offset(); + styles.top -= parentOffsetDiff.top; + styles.left -= parentOffsetDiff.left; + + if (!that.visible){ + $container.css('opacity', opacity).hide(); + } + } + + // -2px to account for suggestions border. + if (that.options.width === 'auto') { + styles.width = (that.el.outerWidth() - 2) + 'px'; + } + + $container.css(styles); + }, + + enableKillerFn: function () { + var that = this; + $(document).on('click.autocomplete', that.killerFn); + }, + + disableKillerFn: function () { + var that = this; + $(document).off('click.autocomplete', that.killerFn); + }, + + killSuggestions: function () { + var that = this; + that.stopKillSuggestions(); + that.intervalId = window.setInterval(function () { + that.hide(); + that.stopKillSuggestions(); + }, 50); + }, + + stopKillSuggestions: function () { + window.clearInterval(this.intervalId); + }, + + isCursorAtEnd: function () { + var that = this, + valLength = that.el.val().length, + selectionStart = that.element.selectionStart, + range; + + if (typeof selectionStart === 'number') { + return selectionStart === valLength; + } + if (document.selection) { + range = document.selection.createRange(); + range.moveStart('character', -valLength); + return valLength === range.text.length; + } + return true; + }, + + onKeyPress: function (e) { + var that = this; + + // If suggestions are hidden and user presses arrow down, display suggestions: + if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) { + that.suggest(); + return; + } + + if (that.disabled || !that.visible) { + return; + } + + switch (e.which) { + case keys.ESC: + that.el.val(that.currentValue); + that.hide(); + break; + case keys.RIGHT: + if (that.hint && that.options.onHint && that.isCursorAtEnd()) { + that.selectHint(); + break; + } + return; + case keys.TAB: + if (that.hint && that.options.onHint) { + that.selectHint(); + return; + } + // Fall through to RETURN + case keys.RETURN: + if (that.selectedIndex === -1) { + that.hide(); + return; + } + that.select(that.selectedIndex); + if (e.which === keys.TAB && that.options.tabDisabled === false) { + return; + } + break; + case keys.UP: + that.moveUp(); + break; + case keys.DOWN: + that.moveDown(); + break; + default: + return; + } + + // Cancel event if function did not return: + e.stopImmediatePropagation(); + e.preventDefault(); + }, + + onKeyUp: function (e) { + var that = this; + + if (that.disabled) { + return; + } + + switch (e.which) { + case keys.UP: + case keys.DOWN: + return; + } + + clearInterval(that.onChangeInterval); + + if (that.currentValue !== that.el.val()) { + that.findBestHint(); + if (that.options.deferRequestBy > 0) { + // Defer lookup in case when value changes very quickly: + that.onChangeInterval = setInterval(function () { + that.onValueChange(); + }, that.options.deferRequestBy); + } else { + that.onValueChange(); + } + } + }, + + onValueChange: function () { + var that = this, + options = that.options, + value = that.el.val(), + query = that.getQuery(value), + index; + + if (that.selection && that.currentValue !== query) { + that.selection = null; + (options.onInvalidateSelection || $.noop).call(that.element); + } + + clearInterval(that.onChangeInterval); + that.currentValue = value; + that.selectedIndex = -1; + + // Check existing suggestion for the match before proceeding: + if (options.triggerSelectOnValidInput) { + index = that.findSuggestionIndex(query); + if (index !== -1) { + that.select(index); + return; + } + } + + if (query.length < options.minChars) { + that.hide(); + } else { + that.getSuggestions(query); + } + }, + + findSuggestionIndex: function (query) { + var that = this, + index = -1, + queryLowerCase = query.toLowerCase(); + + $.each(that.suggestions, function (i, suggestion) { + if (suggestion.value.toLowerCase() === queryLowerCase) { + index = i; + return false; + } + }); + + return index; + }, + + getQuery: function (value) { + var delimiter = this.options.delimiter, + parts; + + if (!delimiter) { + return value; + } + parts = value.split(delimiter); + return $.trim(parts[parts.length - 1]); + }, + + getSuggestionsLocal: function (query) { + var that = this, + options = that.options, + queryLowerCase = query.toLowerCase(), + data; + + // re-pack the data as it was comming from AJAX + data = { + suggestions: data + }; + return data; + }, + + getSuggestions: function (query) { + var response, + that = this, + options = that.options, + serviceUrl = options.serviceUrl, + params, + cacheKey, + ajaxSettings; + + options.params[options.paramName] = query; + params = options.ignoreParams ? null : options.params; + + if (that.isLocal) { + response = that.getSuggestionsLocal(query); + } else { + if ($.isFunction(serviceUrl)) { + serviceUrl = serviceUrl.call(that.element, query); + } + cacheKey = serviceUrl + '?' + $.param(params || {}); + response = that.cachedResponse[cacheKey]; + } + + if (response && $.isArray(response.suggestions)) { + that.suggestions = response.suggestions; + that.suggest(); + } else if (!that.isBadQuery(query)) { + if (options.onSearchStart.call(that.element, options.params) === false) { + return; + } + if (that.currentRequest) { + that.currentRequest.abort(); + } + + ajaxSettings = { + url: serviceUrl, + data: params, + type: options.type, + dataType: options.dataType + }; + + $.extend(ajaxSettings, options.ajaxSettings); + + that.currentRequest = $.ajax(ajaxSettings).done(function (data) { + var result; + that.currentRequest = null; + result = options.transformResult(data); + that.processResponse(result, query, cacheKey); + options.onSearchComplete.call(that.element, query, result.suggestions); + }).fail(function (jqXHR, textStatus, errorThrown) { + options.onSearchError.call(that.element, query, jqXHR, textStatus, errorThrown); + }); + } + }, + + isBadQuery: function (q) { + if (!this.options.preventBadQueries){ + return false; + } + + var badQueries = this.badQueries, + i = badQueries.length; + + while (i--) { + if (q.indexOf(badQueries[i]) === 0) { + return true; + } + } + + return false; + }, + + hide: function () { + var that = this; + that.visible = false; + that.selectedIndex = -1; + $(that.suggestionsContainer).hide(); + that.signalHint(null); + }, + + suggest: function () { + + var that = this, + options = that.options, + formatResult = options.formatResult, + filterResult = options.lookupFilter, + value = that.getQuery(that.currentValue), + className = that.classes.suggestion, + classSelected = that.classes.selected, + container = $(that.suggestionsContainer), + noSuggestionsContainer = $(that.noSuggestionsContainer), + beforeRender = options.beforeRender, + limit = parseInt(that.options.lookupLimit, 10), + html = '', + index; + + // filter and limit given results + var filtered_suggestions = $.grep(that.suggestions, function (suggestion) { + return filterResult(suggestion, value, value.toLowerCase(), that.element); + }); + + if (limit && filtered_suggestions.length > limit) { + filtered_suggestions = filtered_suggestions.slice(0, limit); + } + + if (filtered_suggestions.length === 0) { + this.options.showNoSuggestionNotice ? this.noSuggestions() : this.hide(); + return; + } + + if (options.triggerSelectOnValidInput) { + index = that.findSuggestionIndex(value); + if (index !== -1) { + that.select(index); + return; + } + } + + // Build suggestions inner HTML: + $.each(filtered_suggestions, function (i, suggestion) { + html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value, Autocomplete.formatResult, that.element) + '</div>'; + }); + // set internal suggestion for INDEX pick to work correctly + that.suggestions = filtered_suggestions; + this.adjustContainerWidth(); + + noSuggestionsContainer.detach(); + container.html(html); + + // Select first value by default: + if (options.autoSelectFirst) { + that.selectedIndex = 0; + container.children().first().addClass(classSelected); + } + + if ($.isFunction(beforeRender)) { + beforeRender.call(that.element, container); + } + + that.fixPosition(); + + container.show(); + that.visible = true; + + that.findBestHint(); + }, + + noSuggestions: function() { + var that = this, + container = $(that.suggestionsContainer), + noSuggestionsContainer = $(that.noSuggestionsContainer); + + this.adjustContainerWidth(); + + // Some explicit steps. Be careful here as it easy to get + // noSuggestionsContainer removed from DOM if not detached properly. + noSuggestionsContainer.detach(); + container.empty(); // clean suggestions if any + container.append(noSuggestionsContainer); + + that.fixPosition(); + + container.show(); + that.visible = true; + }, + + adjustContainerWidth: function() { + var that = this, + options = that.options, + width, + container = $(that.suggestionsContainer); + + // If width is auto, adjust width before displaying suggestions, + // because if instance was created before input had width, it will be zero. + // Also it adjusts if input width has changed. + // -2px to account for suggestions border. + if (options.width === 'auto') { + width = that.el.outerWidth() - 2; + container.width(width > 0 ? width : 300); + } + }, + + findBestHint: function () { + var that = this, + value = that.el.val().toLowerCase(), + bestMatch = null; + + if (!value) { + return; + } + + $.each(that.suggestions, function (i, suggestion) { + var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0; + if (foundMatch) { + bestMatch = suggestion; + } + return !foundMatch; + }); + that.signalHint(bestMatch); + }, + + signalHint: function (suggestion) { + var hintValue = '', + that = this; + if (suggestion) { + hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length); + } + if (that.hintValue !== hintValue) { + that.hintValue = hintValue; + that.hint = suggestion; + (this.options.onHint || $.noop)(hintValue); + } + }, + + verifySuggestionsFormat: function (suggestions) { + // If suggestions is string array, convert them to supported format: + if (suggestions.length && typeof suggestions[0] === 'string') { + return $.map(suggestions, function (value) { + return { value: value, data: null }; + }); + } + + return suggestions; + }, + + validateOrientation: function(orientation, fallback) { + orientation = $.trim(orientation || '').toLowerCase(); + + if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){ + orientation = fallback; + } + + return orientation; + }, + + processResponse: function (result, originalQuery, cacheKey) { + var that = this, + options = that.options; + + result.suggestions = that.verifySuggestionsFormat(result.suggestions); + + // Cache results if cache is not disabled: + if (!options.noCache) { + that.cachedResponse[cacheKey] = result; + if (options.preventBadQueries && result.suggestions.length === 0) { + that.badQueries.push(originalQuery); + } + } + + // Return if originalQuery is not matching current query: + if (originalQuery !== that.getQuery(that.currentValue)) { + return; + } + + that.suggestions = result.suggestions; + that.suggest(); + }, + + activate: function (index) { + var that = this, + activeItem, + selected = that.classes.selected, + container = $(that.suggestionsContainer), + children = container.find('.' + that.classes.suggestion); + + container.find('.' + selected).removeClass(selected); + + that.selectedIndex = index; + + if (that.selectedIndex !== -1 && children.length > that.selectedIndex) { + activeItem = children.get(that.selectedIndex); + $(activeItem).addClass(selected); + return activeItem; + } + + return null; + }, + + selectHint: function () { + var that = this, + i = $.inArray(that.hint, that.suggestions); + that.select(i); + }, + + select: function (index) { + var that = this; + that.hide(); + that.onSelect(index); + }, + + moveUp: function () { + var that = this; + + if (that.selectedIndex === -1) { + return; + } + + if (that.selectedIndex === 0) { + $(that.suggestionsContainer).children().first().removeClass(that.classes.selected); + that.selectedIndex = -1; + that.el.val(that.currentValue); + that.findBestHint(); + return; + } + + that.adjustScroll(that.selectedIndex - 1); + }, + + moveDown: function () { + var that = this; + + if (that.selectedIndex === (that.suggestions.length - 1)) { + return; + } + + that.adjustScroll(that.selectedIndex + 1); + }, + + adjustScroll: function (index) { + var that = this, + activeItem = that.activate(index), + offsetTop, + upperBound, + lowerBound, + heightDelta = 25; + + if (!activeItem) { + return; + } + + offsetTop = activeItem.offsetTop; + upperBound = $(that.suggestionsContainer).scrollTop(); + lowerBound = upperBound + that.options.maxHeight - heightDelta; + + if (offsetTop < upperBound) { + $(that.suggestionsContainer).scrollTop(offsetTop); + } else if (offsetTop > lowerBound) { + $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta); + } + + if (that.options.replaceOnArrowKey) { + that.el.val(that.getValue(that.suggestions[index].value)); + } + that.signalHint(null); + }, + + onSelect: function (index) { + var that = this, + onSelectCallback = that.options.onSelect, + suggestion = that.suggestions[index]; + + that.currentValue = that.getValue(suggestion.value); + var prevElem = {'value': that.el.val(), + 'caret': that.element.selectionStart} + + if (that.currentValue !== that.el.val()) { + that.el.val(that.currentValue); + } + + that.signalHint(null); + that.suggestions = []; + that.selection = suggestion; + + if ($.isFunction(onSelectCallback)) { + onSelectCallback.call(this, that.element, suggestion, prevElem); + } + }, + + getValue: function (value) { + var that = this, + delimiter = that.options.delimiter, + currentValue, + parts; + + if (!delimiter) { + return value; + } + + currentValue = that.currentValue; + parts = currentValue.split(delimiter); + + if (parts.length === 1) { + return value; + } + + return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value; + }, + + dispose: function () { + var that = this; + that.el.off('.autocomplete').removeData('autocomplete'); + that.disableKillerFn(); + $(window).off('resize.autocomplete', that.fixPositionCapture); + $(that.suggestionsContainer).remove(); + } + }; + + // Create chainable jQuery plugin: + $.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) { + var dataKey = 'autocomplete'; + // If function invoked without argument return + // instance of the first matched element: + if (arguments.length === 0) { + return this.first().data(dataKey); + } + + return this.each(function () { + var inputElement = $(this), + instance = inputElement.data(dataKey); + + if (typeof options === 'string') { + if (instance && typeof instance[options] === 'function') { + instance[options](args); + } + } else { + // If instance already exists, destroy it: + if (instance && instance.dispose) { + instance.dispose(); + } + instance = new Autocomplete(this, options); + inputElement.data(dataKey, instance); + } + }); + }; +})); diff --git a/rhodecode/public/js/src/plugins/jquery.dataTables.css b/rhodecode/public/js/src/plugins/jquery.dataTables.css new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.dataTables.css @@ -0,0 +1,476 @@ +/* + * Table styles + */ +table.dataTable { + width: 100%; + margin: 0 auto; + clear: both; + border-collapse: separate; + border-spacing: 0; + /* + * Header and footer styles + */ + /* + * Body styles + */ +} +table.dataTable thead th, +table.dataTable tfoot th { + font-weight: bold; +} +table.dataTable thead th, +table.dataTable thead td { + padding: 10px 18px; + border-bottom: 1px solid #111111; +} +table.dataTable thead th:active, +table.dataTable thead td:active { + outline: none; +} +table.dataTable tfoot th, +table.dataTable tfoot td { + padding: 10px 18px 6px 18px; + border-top: 1px solid #111111; +} +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc, +table.dataTable thead .sorting { + cursor: pointer; + *cursor: hand; +} +table.dataTable thead .sorting { + background: url("../images/sort_both.png") no-repeat center right; +} +table.dataTable thead .sorting_asc { + background: url("../images/sort_asc.png") no-repeat center right; +} +table.dataTable thead .sorting_desc { + background: url("../images/sort_desc.png") no-repeat center right; +} +table.dataTable thead .sorting_asc_disabled { + background: url("../images/sort_asc_disabled.png") no-repeat center right; +} +table.dataTable thead .sorting_desc_disabled { + background: url("../images/sort_desc_disabled.png") no-repeat center right; +} +table.dataTable tbody tr { + background-color: white; +} +table.dataTable tbody tr.selected { + background-color: #b0bed9; +} +table.dataTable tbody th, +table.dataTable tbody td { + padding: 8px 10px; +} +table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td { + border-top: 1px solid #dddddd; +} +table.dataTable.row-border tbody tr:first-child th, +table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th, +table.dataTable.display tbody tr:first-child td { + border-top: none; +} +table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td { + border-top: 1px solid #dddddd; + border-right: 1px solid #dddddd; +} +table.dataTable.cell-border tbody tr th:first-child, +table.dataTable.cell-border tbody tr td:first-child { + border-left: 1px solid #dddddd; +} +table.dataTable.cell-border tbody tr:first-child th, +table.dataTable.cell-border tbody tr:first-child td { + border-top: none; +} +table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd { + background-color: #f9f9f9; +} +table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected { + background-color: #abb9d3; +} +table.dataTable.hover tbody tr:hover, +table.dataTable.hover tbody tr.odd:hover, +table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover, +table.dataTable.display tbody tr.odd:hover, +table.dataTable.display tbody tr.even:hover { + background-color: whitesmoke; +} +table.dataTable.hover tbody tr:hover.selected, +table.dataTable.hover tbody tr.odd:hover.selected, +table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected, +table.dataTable.display tbody tr.odd:hover.selected, +table.dataTable.display tbody tr.even:hover.selected { + background-color: #a9b7d1; +} +table.dataTable.order-column tbody tr > .sorting_1, +table.dataTable.order-column tbody tr > .sorting_2, +table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1, +table.dataTable.display tbody tr > .sorting_2, +table.dataTable.display tbody tr > .sorting_3 { + background-color: #f9f9f9; +} +table.dataTable.order-column tbody tr.selected > .sorting_1, +table.dataTable.order-column tbody tr.selected > .sorting_2, +table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1, +table.dataTable.display tbody tr.selected > .sorting_2, +table.dataTable.display tbody tr.selected > .sorting_3 { + background-color: #acbad4; +} +table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 { + background-color: #f1f1f1; +} +table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 { + background-color: #f3f3f3; +} +table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 { + background-color: whitesmoke; +} +table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 { + background-color: #a6b3cd; +} +table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 { + background-color: #a7b5ce; +} +table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 { + background-color: #a9b6d0; +} +table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 { + background-color: #f9f9f9; +} +table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 { + background-color: #fbfbfb; +} +table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 { + background-color: #fdfdfd; +} +table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 { + background-color: #acbad4; +} +table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 { + background-color: #adbbd6; +} +table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 { + background-color: #afbdd8; +} +table.dataTable.display tbody tr:hover > .sorting_1, +table.dataTable.display tbody tr.odd:hover > .sorting_1, +table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1, +table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1, +table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 { + background-color: #eaeaea; +} +table.dataTable.display tbody tr:hover > .sorting_2, +table.dataTable.display tbody tr.odd:hover > .sorting_2, +table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2, +table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2, +table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 { + background-color: #ebebeb; +} +table.dataTable.display tbody tr:hover > .sorting_3, +table.dataTable.display tbody tr.odd:hover > .sorting_3, +table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3, +table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3, +table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 { + background-color: #eeeeee; +} +table.dataTable.display tbody tr:hover.selected > .sorting_1, +table.dataTable.display tbody tr.odd:hover.selected > .sorting_1, +table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1, +table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1, +table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 { + background-color: #a1aec7; +} +table.dataTable.display tbody tr:hover.selected > .sorting_2, +table.dataTable.display tbody tr.odd:hover.selected > .sorting_2, +table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2, +table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2, +table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 { + background-color: #a2afc8; +} +table.dataTable.display tbody tr:hover.selected > .sorting_3, +table.dataTable.display tbody tr.odd:hover.selected > .sorting_3, +table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3, +table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3, +table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 { + background-color: #a4b2cb; +} +table.dataTable.no-footer { + border-bottom: 1px solid #111111; +} +table.dataTable.nowrap th, table.dataTable.nowrap td { + white-space: nowrap; +} +table.dataTable.compact thead th, +table.dataTable.compact thead td { + padding: 5px 9px; +} +table.dataTable.compact tfoot th, +table.dataTable.compact tfoot td { + padding: 5px 9px 3px 9px; +} +table.dataTable.compact tbody th, +table.dataTable.compact tbody td { + padding: 4px 5px; +} +table.dataTable th.dt-left, +table.dataTable td.dt-left { + text-align: left; +} +table.dataTable th.dt-center, +table.dataTable td.dt-center, +table.dataTable td.dataTables_empty { + text-align: center; +} +table.dataTable th.dt-right, +table.dataTable td.dt-right { + text-align: right; +} +table.dataTable th.dt-justify, +table.dataTable td.dt-justify { + text-align: justify; +} +table.dataTable th.dt-nowrap, +table.dataTable td.dt-nowrap { + white-space: nowrap; +} +table.dataTable thead th.dt-head-left, +table.dataTable thead td.dt-head-left, +table.dataTable tfoot th.dt-head-left, +table.dataTable tfoot td.dt-head-left { + text-align: left; +} +table.dataTable thead th.dt-head-center, +table.dataTable thead td.dt-head-center, +table.dataTable tfoot th.dt-head-center, +table.dataTable tfoot td.dt-head-center { + text-align: center; +} +table.dataTable thead th.dt-head-right, +table.dataTable thead td.dt-head-right, +table.dataTable tfoot th.dt-head-right, +table.dataTable tfoot td.dt-head-right { + text-align: right; +} +table.dataTable thead th.dt-head-justify, +table.dataTable thead td.dt-head-justify, +table.dataTable tfoot th.dt-head-justify, +table.dataTable tfoot td.dt-head-justify { + text-align: justify; +} +table.dataTable thead th.dt-head-nowrap, +table.dataTable thead td.dt-head-nowrap, +table.dataTable tfoot th.dt-head-nowrap, +table.dataTable tfoot td.dt-head-nowrap { + white-space: nowrap; +} +table.dataTable tbody th.dt-body-left, +table.dataTable tbody td.dt-body-left { + text-align: left; +} +table.dataTable tbody th.dt-body-center, +table.dataTable tbody td.dt-body-center { + text-align: center; +} +table.dataTable tbody th.dt-body-right, +table.dataTable tbody td.dt-body-right { + text-align: right; +} +table.dataTable tbody th.dt-body-justify, +table.dataTable tbody td.dt-body-justify { + text-align: justify; +} +table.dataTable tbody th.dt-body-nowrap, +table.dataTable tbody td.dt-body-nowrap { + white-space: nowrap; +} + +table.dataTable, +table.dataTable th, +table.dataTable td { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* + * Control feature layout + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; + zoom: 1; +} +.dataTables_wrapper .dataTables_length { + float: left; +} +.dataTables_wrapper .dataTables_filter { + float: right; + text-align: right; +} +.dataTables_wrapper .dataTables_filter input { + margin-left: 0.5em; +} +.dataTables_wrapper .dataTables_info { + clear: both; + float: left; + padding-top: 0.755em; +} +.dataTables_wrapper .dataTables_paginate { + float: right; + text-align: right; + padding-top: 0.25em; +} +.dataTables_wrapper .dataTables_paginate .paginate_button { + box-sizing: border-box; + display: inline-block; + min-width: 1.5em; + padding: 0.5em 1em; + margin-left: 2px; + text-align: center; + text-decoration: none !important; + cursor: pointer; + *cursor: hand; + color: #333333 !important; + border: 1px solid transparent; +} +.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { + color: #333333 !important; + border: 1px solid #cacaca; + background-color: white; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, gainsboro)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, white 0%, gainsboro 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, white 0%, gainsboro 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, white 0%, gainsboro 100%); + /* IE10+ */ + background: -o-linear-gradient(top, white 0%, gainsboro 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, white 0%, gainsboro 100%); + /* W3C */ +} +.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active { + cursor: default; + color: #666 !important; + border: 1px solid transparent; + background: transparent; + box-shadow: none; +} +.dataTables_wrapper .dataTables_paginate .paginate_button:hover { + color: white !important; + border: 1px solid #111111; + background-color: #585858; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111111)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #585858 0%, #111111 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #585858 0%, #111111 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, #585858 0%, #111111 100%); + /* IE10+ */ + background: -o-linear-gradient(top, #585858 0%, #111111 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #585858 0%, #111111 100%); + /* W3C */ +} +.dataTables_wrapper .dataTables_paginate .paginate_button:active { + outline: none; + background-color: #2b2b2b; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* IE10+ */ + background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); + /* W3C */ + box-shadow: inset 0 0 3px #111; +} +.dataTables_wrapper .dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 40px; + margin-left: -50%; + margin-top: -25px; + padding-top: 20px; + text-align: center; + font-size: 1.2em; + background-color: white; + background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0))); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + /* IE10+ */ + background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + /* Opera 11.10+ */ + background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + /* W3C */ +} +.dataTables_wrapper .dataTables_length, +.dataTables_wrapper .dataTables_filter, +.dataTables_wrapper .dataTables_info, +.dataTables_wrapper .dataTables_processing, +.dataTables_wrapper .dataTables_paginate { + color: #333333; +} +.dataTables_wrapper .dataTables_scroll { + clear: both; +} +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing, +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing { + height: 0; + overflow: hidden; + margin: 0 !important; + padding: 0 !important; +} +.dataTables_wrapper.no-footer .dataTables_scrollBody { + border-bottom: 1px solid #111111; +} +.dataTables_wrapper.no-footer div.dataTables_scrollHead table, +.dataTables_wrapper.no-footer div.dataTables_scrollBody table { + border-bottom: none; +} +.dataTables_wrapper:after { + visibility: hidden; + display: block; + content: ""; + clear: both; + height: 0; +} + +@media screen and (max-width: 767px) { + .dataTables_wrapper .dataTables_info, + .dataTables_wrapper .dataTables_paginate { + float: none; + text-align: center; + } + .dataTables_wrapper .dataTables_paginate { + margin-top: 0.5em; + } +} +@media screen and (max-width: 640px) { + .dataTables_wrapper .dataTables_length, + .dataTables_wrapper .dataTables_filter { + float: none; + text-align: center; + } + .dataTables_wrapper .dataTables_filter { + margin-top: 0.5em; + } +} diff --git a/rhodecode/public/js/src/plugins/jquery.dataTables.js b/rhodecode/public/js/src/plugins/jquery.dataTables.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.dataTables.js @@ -0,0 +1,14841 @@ +/*! DataTables 1.10.4 + * ©2008-2014 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary DataTables + * @description Paginate, search and order HTML tables + * @version 1.10.4 + * @file jquery.dataTables.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2008-2014 SpryMedia Ltd. + * + * This source file is free software, available under the following license: + * MIT license - http://datatables.net/license + * + * This source file 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 license files for details. + * + * For details please refer to: http://www.datatables.net + */ + +/*jslint evil: true, undef: true, browser: true */ +/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ + +(/** @lends <global> */function( window, document, undefined ) { + +(function( factory ) { + "use strict"; + + if ( typeof define === 'function' && define.amd ) { + // Define as an AMD module if possible + define( 'datatables', ['jquery'], factory ); + } + else if ( typeof exports === 'object' ) { + // Node/CommonJS + factory( require( 'jquery' ) ); + } + else if ( jQuery && !jQuery.fn.dataTable ) { + // Define using browser globals otherwise + // Prevent multiple instantiations if the script is loaded twice + factory( jQuery ); + } +} +(/** @lends <global> */function( $ ) { + "use strict"; + + /** + * DataTables is a plug-in for the jQuery Javascript library. It is a highly + * flexible tool, based upon the foundations of progressive enhancement, + * which will add advanced interaction controls to any HTML table. For a + * full list of features please refer to + * [DataTables.net](href="http://datatables.net). + * + * Note that the `DataTable` object is not a global variable but is aliased + * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may + * be accessed. + * + * @class + * @param {object} [init={}] Configuration object for DataTables. Options + * are defined by {@link DataTable.defaults} + * @requires jQuery 1.7+ + * + * @example + * // Basic initialisation + * $(document).ready( function { + * $('#example').dataTable(); + * } ); + * + * @example + * // Initialisation with configuration options - in this case, disable + * // pagination and sorting. + * $(document).ready( function { + * $('#example').dataTable( { + * "paginate": false, + * "sort": false + * } ); + * } ); + */ + var DataTable; + + + /* + * It is useful to have variables which are scoped locally so only the + * DataTables functions can access them and they don't leak into global space. + * At the same time these functions are often useful over multiple files in the + * core and API, so we list, or at least document, all variables which are used + * by DataTables as private variables here. This also ensures that there is no + * clashing of variable names and that they can easily referenced for reuse. + */ + + + // Defined else where + // _selector_run + // _selector_opts + // _selector_first + // _selector_row_indexes + + var _ext; // DataTable.ext + var _Api; // DataTable.Api + var _api_register; // DataTable.Api.register + var _api_registerPlural; // DataTable.Api.registerPlural + + var _re_dic = {}; + var _re_new_lines = /[\r\n]/g; + var _re_html = /<.*?>/g; + var _re_date_start = /^[\w\+\-]/; + var _re_date_end = /[\w\+\-]$/; + + // Escape regular expression special characters + var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); + + // U+2009 is thin space and U+202F is narrow no-break space, both used in many + // standards as thousands separators + var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g; + + + var _empty = function ( d ) { + return !d || d === true || d === '-' ? true : false; + }; + + + var _intVal = function ( s ) { + var integer = parseInt( s, 10 ); + return !isNaN(integer) && isFinite(s) ? integer : null; + }; + + // Convert from a formatted number with characters other than `.` as the + // decimal place, to a Javascript number + var _numToDecimal = function ( num, decimalPoint ) { + // Cache created regular expressions for speed as this function is called often + if ( ! _re_dic[ decimalPoint ] ) { + _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); + } + return typeof num === 'string' && decimalPoint !== '.' ? + num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : + num; + }; + + + var _isNumber = function ( d, decimalPoint, formatted ) { + var strType = typeof d === 'string'; + + if ( decimalPoint && strType ) { + d = _numToDecimal( d, decimalPoint ); + } + + if ( formatted && strType ) { + d = d.replace( _re_formatted_numeric, '' ); + } + + return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d )); + }; + + + // A string without HTML in it can be considered to be HTML still + var _isHtml = function ( d ) { + return _empty( d ) || typeof d === 'string'; + }; + + + var _htmlNumeric = function ( d, decimalPoint, formatted ) { + if ( _empty( d ) ) { + return true; + } + + var html = _isHtml( d ); + return ! html ? + null : + _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? + true : + null; + }; + + + var _pluck = function ( a, prop, prop2 ) { + var out = []; + var i=0, ien=a.length; + + // Could have the test in the loop for slightly smaller code, but speed + // is essential here + if ( prop2 !== undefined ) { + for ( ; i<ien ; i++ ) { + if ( a[i] && a[i][ prop ] ) { + out.push( a[i][ prop ][ prop2 ] ); + } + } + } + else { + for ( ; i<ien ; i++ ) { + if ( a[i] ) { + out.push( a[i][ prop ] ); + } + } + } + + return out; + }; + + + // Basically the same as _pluck, but rather than looping over `a` we use `order` + // as the indexes to pick from `a` + var _pluck_order = function ( a, order, prop, prop2 ) + { + var out = []; + var i=0, ien=order.length; + + // Could have the test in the loop for slightly smaller code, but speed + // is essential here + if ( prop2 !== undefined ) { + for ( ; i<ien ; i++ ) { + if ( a[ order[i] ][ prop ] ) { + out.push( a[ order[i] ][ prop ][ prop2 ] ); + } + } + } + else { + for ( ; i<ien ; i++ ) { + out.push( a[ order[i] ][ prop ] ); + } + } + + return out; + }; + + + var _range = function ( len, start ) + { + var out = []; + var end; + + if ( start === undefined ) { + start = 0; + end = len; + } + else { + end = start; + start = len; + } + + for ( var i=start ; i<end ; i++ ) { + out.push( i ); + } + + return out; + }; + + + var _removeEmpty = function ( a ) + { + var out = []; + + for ( var i=0, ien=a.length ; i<ien ; i++ ) { + if ( a[i] ) { // careful - will remove all falsy values! + out.push( a[i] ); + } + } + + return out; + }; + + + var _stripHtml = function ( d ) { + return d.replace( _re_html, '' ); + }; + + + /** + * Find the unique elements in a source array. + * + * @param {array} src Source array + * @return {array} Array of unique items + * @ignore + */ + var _unique = function ( src ) + { + // A faster unique method is to use object keys to identify used values, + // but this doesn't work with arrays or objects, which we must also + // consider. See jsperf.com/compare-array-unique-versions/4 for more + // information. + var + out = [], + val, + i, ien=src.length, + j, k=0; + + again: for ( i=0 ; i<ien ; i++ ) { + val = src[i]; + + for ( j=0 ; j<k ; j++ ) { + if ( out[j] === val ) { + continue again; + } + } + + out.push( val ); + k++; + } + + return out; + }; + + + + /** + * Create a mapping object that allows camel case parameters to be looked up + * for their Hungarian counterparts. The mapping is stored in a private + * parameter called `_hungarianMap` which can be accessed on the source object. + * @param {object} o + * @memberof DataTable#oApi + */ + function _fnHungarianMap ( o ) + { + var + hungarian = 'a aa ai ao as b fn i m o s ', + match, + newKey, + map = {}; + + $.each( o, function (key, val) { + match = key.match(/^([^A-Z]+?)([A-Z])/); + + if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) + { + newKey = key.replace( match[0], match[2].toLowerCase() ); + map[ newKey ] = key; + + if ( match[1] === 'o' ) + { + _fnHungarianMap( o[key] ); + } + } + } ); + + o._hungarianMap = map; + } + + + /** + * Convert from camel case parameters to Hungarian, based on a Hungarian map + * created by _fnHungarianMap. + * @param {object} src The model object which holds all parameters that can be + * mapped. + * @param {object} user The object to convert from camel case to Hungarian. + * @param {boolean} force When set to `true`, properties which already have a + * Hungarian value in the `user` object will be overwritten. Otherwise they + * won't be. + * @memberof DataTable#oApi + */ + function _fnCamelToHungarian ( src, user, force ) + { + if ( ! src._hungarianMap ) { + _fnHungarianMap( src ); + } + + var hungarianKey; + + $.each( user, function (key, val) { + hungarianKey = src._hungarianMap[ key ]; + + if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) + { + // For objects, we need to buzz down into the object to copy parameters + if ( hungarianKey.charAt(0) === 'o' ) + { + // Copy the camelCase options over to the hungarian + if ( ! user[ hungarianKey ] ) { + user[ hungarianKey ] = {}; + } + $.extend( true, user[hungarianKey], user[key] ); + + _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); + } + else { + user[hungarianKey] = user[ key ]; + } + } + } ); + } + + + /** + * Language compatibility - when certain options are given, and others aren't, we + * need to duplicate the values over, in order to provide backwards compatibility + * with older language files. + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnLanguageCompat( lang ) + { + var defaults = DataTable.defaults.oLanguage; + var zeroRecords = lang.sZeroRecords; + + /* Backwards compatibility - if there is no sEmptyTable given, then use the same as + * sZeroRecords - assuming that is given. + */ + if ( ! lang.sEmptyTable && zeroRecords && + defaults.sEmptyTable === "No data available in table" ) + { + _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); + } + + /* Likewise with loading records */ + if ( ! lang.sLoadingRecords && zeroRecords && + defaults.sLoadingRecords === "Loading..." ) + { + _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); + } + + // Old parameter name of the thousands separator mapped onto the new + if ( lang.sInfoThousands ) { + lang.sThousands = lang.sInfoThousands; + } + + var decimal = lang.sDecimal; + if ( decimal ) { + _addNumericSort( decimal ); + } + } + + + /** + * Map one parameter onto another + * @param {object} o Object to map + * @param {*} knew The new parameter name + * @param {*} old The old parameter name + */ + var _fnCompatMap = function ( o, knew, old ) { + if ( o[ knew ] !== undefined ) { + o[ old ] = o[ knew ]; + } + }; + + + /** + * Provide backwards compatibility for the main DT options. Note that the new + * options are mapped onto the old parameters, so this is an external interface + * change only. + * @param {object} init Object to map + */ + function _fnCompatOpts ( init ) + { + _fnCompatMap( init, 'ordering', 'bSort' ); + _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); + _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); + _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); + _fnCompatMap( init, 'order', 'aaSorting' ); + _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); + _fnCompatMap( init, 'paging', 'bPaginate' ); + _fnCompatMap( init, 'pagingType', 'sPaginationType' ); + _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); + _fnCompatMap( init, 'searching', 'bFilter' ); + + // Column search objects are in an array, so it needs to be converted + // element by element + var searchCols = init.aoSearchCols; + + if ( searchCols ) { + for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { + if ( searchCols[i] ) { + _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); + } + } + } + } + + + /** + * Provide backwards compatibility for column options. Note that the new options + * are mapped onto the old parameters, so this is an external interface change + * only. + * @param {object} init Object to map + */ + function _fnCompatCols ( init ) + { + _fnCompatMap( init, 'orderable', 'bSortable' ); + _fnCompatMap( init, 'orderData', 'aDataSort' ); + _fnCompatMap( init, 'orderSequence', 'asSorting' ); + _fnCompatMap( init, 'orderDataType', 'sortDataType' ); + } + + + /** + * Browser feature detection for capabilities, quirks + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnBrowserDetect( settings ) + { + var browser = settings.oBrowser; + + // Scrolling feature / quirks detection + var n = $('<div/>') + .css( { + position: 'absolute', + top: 0, + left: 0, + height: 1, + width: 1, + overflow: 'hidden' + } ) + .append( + $('<div/>') + .css( { + position: 'absolute', + top: 1, + left: 1, + width: 100, + overflow: 'scroll' + } ) + .append( + $('<div class="test"/>') + .css( { + width: '100%', + height: 10 + } ) + ) + ) + .appendTo( 'body' ); + + var test = n.find('.test'); + + // IE6/7 will oversize a width 100% element inside a scrolling element, to + // include the width of the scrollbar, while other browsers ensure the inner + // element is contained without forcing scrolling + browser.bScrollOversize = test[0].offsetWidth === 100; + + // In rtl text layout, some browsers (most, but not all) will place the + // scrollbar on the left, rather than the right. + browser.bScrollbarLeft = test.offset().left !== 1; + + n.remove(); + } + + + /** + * Array.prototype reduce[Right] method, used for browsers which don't support + * JS 1.6. Done this way to reduce code size, since we iterate either way + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnReduce ( that, fn, init, start, end, inc ) + { + var + i = start, + value, + isSet = false; + + if ( init !== undefined ) { + value = init; + isSet = true; + } + + while ( i !== end ) { + if ( ! that.hasOwnProperty(i) ) { + continue; + } + + value = isSet ? + fn( value, that[i], i, that ) : + that[i]; + + isSet = true; + i += inc; + } + + return value; + } + + /** + * Add a column to the list used for the table with default values + * @param {object} oSettings dataTables settings object + * @param {node} nTh The th element for this column + * @memberof DataTable#oApi + */ + function _fnAddColumn( oSettings, nTh ) + { + // Add column to aoColumns array + var oDefaults = DataTable.defaults.column; + var iCol = oSettings.aoColumns.length; + var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { + "nTh": nTh ? nTh : document.createElement('th'), + "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', + "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], + "mData": oDefaults.mData ? oDefaults.mData : iCol, + idx: iCol + } ); + oSettings.aoColumns.push( oCol ); + + // Add search object for column specific search. Note that the `searchCols[ iCol ]` + // passed into extend can be undefined. This allows the user to give a default + // with only some of the parameters defined, and also not give a default + var searchCols = oSettings.aoPreSearchCols; + searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); + + // Use the default column options function to initialise classes etc + _fnColumnOptions( oSettings, iCol, null ); + } + + + /** + * Apply options for a column + * @param {object} oSettings dataTables settings object + * @param {int} iCol column index to consider + * @param {object} oOptions object with sType, bVisible and bSearchable etc + * @memberof DataTable#oApi + */ + function _fnColumnOptions( oSettings, iCol, oOptions ) + { + var oCol = oSettings.aoColumns[ iCol ]; + var oClasses = oSettings.oClasses; + var th = $(oCol.nTh); + + // Try to get width information from the DOM. We can't get it from CSS + // as we'd need to parse the CSS stylesheet. `width` option can override + if ( ! oCol.sWidthOrig ) { + // Width attribute + oCol.sWidthOrig = th.attr('width') || null; + + // Style attribute + var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); + if ( t ) { + oCol.sWidthOrig = t[1]; + } + } + + /* User specified column options */ + if ( oOptions !== undefined && oOptions !== null ) + { + // Backwards compatibility + _fnCompatCols( oOptions ); + + // Map camel case parameters to their Hungarian counterparts + _fnCamelToHungarian( DataTable.defaults.column, oOptions ); + + /* Backwards compatibility for mDataProp */ + if ( oOptions.mDataProp !== undefined && !oOptions.mData ) + { + oOptions.mData = oOptions.mDataProp; + } + + if ( oOptions.sType ) + { + oCol._sManualType = oOptions.sType; + } + + // `class` is a reserved word in Javascript, so we need to provide + // the ability to use a valid name for the camel case input + if ( oOptions.className && ! oOptions.sClass ) + { + oOptions.sClass = oOptions.className; + } + + $.extend( oCol, oOptions ); + _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); + + /* iDataSort to be applied (backwards compatibility), but aDataSort will take + * priority if defined + */ + if ( typeof oOptions.iDataSort === 'number' ) + { + oCol.aDataSort = [ oOptions.iDataSort ]; + } + _fnMap( oCol, oOptions, "aDataSort" ); + } + + /* Cache the data get and set functions for speed */ + var mDataSrc = oCol.mData; + var mData = _fnGetObjectDataFn( mDataSrc ); + var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; + + var attrTest = function( src ) { + return typeof src === 'string' && src.indexOf('@') !== -1; + }; + oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( + attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) + ); + + oCol.fnGetData = function (rowData, type, meta) { + var innerData = mData( rowData, type, undefined, meta ); + + return mRender && type ? + mRender( innerData, type, rowData, meta ) : + innerData; + }; + oCol.fnSetData = function ( rowData, val, meta ) { + return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); + }; + + // Indicate if DataTables should read DOM data as an object or array + // Used in _fnGetRowElements + if ( typeof mDataSrc !== 'number' ) { + oSettings._rowReadObject = true; + } + + /* Feature sorting overrides column specific when off */ + if ( !oSettings.oFeatures.bSort ) + { + oCol.bSortable = false; + th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called + } + + /* Check that the class assignment is correct for sorting */ + var bAsc = $.inArray('asc', oCol.asSorting) !== -1; + var bDesc = $.inArray('desc', oCol.asSorting) !== -1; + if ( !oCol.bSortable || (!bAsc && !bDesc) ) + { + oCol.sSortingClass = oClasses.sSortableNone; + oCol.sSortingClassJUI = ""; + } + else if ( bAsc && !bDesc ) + { + oCol.sSortingClass = oClasses.sSortableAsc; + oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; + } + else if ( !bAsc && bDesc ) + { + oCol.sSortingClass = oClasses.sSortableDesc; + oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; + } + else + { + oCol.sSortingClass = oClasses.sSortable; + oCol.sSortingClassJUI = oClasses.sSortJUI; + } + } + + + /** + * Adjust the table column widths for new data. Note: you would probably want to + * do a redraw after calling this function! + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAdjustColumnSizing ( settings ) + { + /* Not interested in doing column width calculation if auto-width is disabled */ + if ( settings.oFeatures.bAutoWidth !== false ) + { + var columns = settings.aoColumns; + + _fnCalculateColumnWidths( settings ); + for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) + { + columns[i].nTh.style.width = columns[i].sWidth; + } + } + + var scroll = settings.oScroll; + if ( scroll.sY !== '' || scroll.sX !== '') + { + _fnScrollDraw( settings ); + } + + _fnCallbackFire( settings, null, 'column-sizing', [settings] ); + } + + + /** + * Covert the index of a visible column to the index in the data array (take account + * of hidden columns) + * @param {object} oSettings dataTables settings object + * @param {int} iMatch Visible column index to lookup + * @returns {int} i the data index + * @memberof DataTable#oApi + */ + function _fnVisibleToColumnIndex( oSettings, iMatch ) + { + var aiVis = _fnGetColumns( oSettings, 'bVisible' ); + + return typeof aiVis[iMatch] === 'number' ? + aiVis[iMatch] : + null; + } + + + /** + * Covert the index of an index in the data array and convert it to the visible + * column index (take account of hidden columns) + * @param {int} iMatch Column index to lookup + * @param {object} oSettings dataTables settings object + * @returns {int} i the data index + * @memberof DataTable#oApi + */ + function _fnColumnIndexToVisible( oSettings, iMatch ) + { + var aiVis = _fnGetColumns( oSettings, 'bVisible' ); + var iPos = $.inArray( iMatch, aiVis ); + + return iPos !== -1 ? iPos : null; + } + + + /** + * Get the number of visible columns + * @param {object} oSettings dataTables settings object + * @returns {int} i the number of visible columns + * @memberof DataTable#oApi + */ + function _fnVisbleColumns( oSettings ) + { + return _fnGetColumns( oSettings, 'bVisible' ).length; + } + + + /** + * Get an array of column indexes that match a given property + * @param {object} oSettings dataTables settings object + * @param {string} sParam Parameter in aoColumns to look for - typically + * bVisible or bSearchable + * @returns {array} Array of indexes with matched properties + * @memberof DataTable#oApi + */ + function _fnGetColumns( oSettings, sParam ) + { + var a = []; + + $.map( oSettings.aoColumns, function(val, i) { + if ( val[sParam] ) { + a.push( i ); + } + } ); + + return a; + } + + + /** + * Calculate the 'type' of a column + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnColumnTypes ( settings ) + { + var columns = settings.aoColumns; + var data = settings.aoData; + var types = DataTable.ext.type.detect; + var i, ien, j, jen, k, ken; + var col, cell, detectedType, cache; + + // For each column, spin over the + for ( i=0, ien=columns.length ; i<ien ; i++ ) { + col = columns[i]; + cache = []; + + if ( ! col.sType && col._sManualType ) { + col.sType = col._sManualType; + } + else if ( ! col.sType ) { + for ( j=0, jen=types.length ; j<jen ; j++ ) { + for ( k=0, ken=data.length ; k<ken ; k++ ) { + // Use a cache array so we only need to get the type data + // from the formatter once (when using multiple detectors) + if ( cache[k] === undefined ) { + cache[k] = _fnGetCellData( settings, k, i, 'type' ); + } + + detectedType = types[j]( cache[k], settings ); + + // If null, then this type can't apply to this column, so + // rather than testing all cells, break out. There is an + // exception for the last type which is `html`. We need to + // scan all rows since it is possible to mix string and HTML + // types + if ( ! detectedType && j !== types.length-1 ) { + break; + } + + // Only a single match is needed for html type since it is + // bottom of the pile and very similar to string + if ( detectedType === 'html' ) { + break; + } + } + + // Type is valid for all data points in the column - use this + // type + if ( detectedType ) { + col.sType = detectedType; + break; + } + } + + // Fall back - if no type was detected, always use string + if ( ! col.sType ) { + col.sType = 'string'; + } + } + } + } + + + /** + * Take the column definitions and static columns arrays and calculate how + * they relate to column indexes. The callback function will then apply the + * definition found for a column to a suitable configuration object. + * @param {object} oSettings dataTables settings object + * @param {array} aoColDefs The aoColumnDefs array that is to be applied + * @param {array} aoCols The aoColumns array that defines columns individually + * @param {function} fn Callback function - takes two parameters, the calculated + * column index and the definition for that column. + * @memberof DataTable#oApi + */ + function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) + { + var i, iLen, j, jLen, k, kLen, def; + var columns = oSettings.aoColumns; + + // Column definitions with aTargets + if ( aoColDefs ) + { + /* Loop over the definitions array - loop in reverse so first instance has priority */ + for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) + { + def = aoColDefs[i]; + + /* Each definition can target multiple columns, as it is an array */ + var aTargets = def.targets !== undefined ? + def.targets : + def.aTargets; + + if ( ! $.isArray( aTargets ) ) + { + aTargets = [ aTargets ]; + } + + for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) + { + if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) + { + /* Add columns that we don't yet know about */ + while( columns.length <= aTargets[j] ) + { + _fnAddColumn( oSettings ); + } + + /* Integer, basic index */ + fn( aTargets[j], def ); + } + else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) + { + /* Negative integer, right to left column counting */ + fn( columns.length+aTargets[j], def ); + } + else if ( typeof aTargets[j] === 'string' ) + { + /* Class name matching on TH element */ + for ( k=0, kLen=columns.length ; k<kLen ; k++ ) + { + if ( aTargets[j] == "_all" || + $(columns[k].nTh).hasClass( aTargets[j] ) ) + { + fn( k, def ); + } + } + } + } + } + } + + // Statically defined columns array + if ( aoCols ) + { + for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) + { + fn( i, aoCols[i] ); + } + } + } + + /** + * Add a data array to the table, creating DOM node etc. This is the parallel to + * _fnGatherData, but for adding rows from a Javascript source, rather than a + * DOM source. + * @param {object} oSettings dataTables settings object + * @param {array} aData data array to be added + * @param {node} [nTr] TR element to add to the table - optional. If not given, + * DataTables will create a row automatically + * @param {array} [anTds] Array of TD|TH elements for the row - must be given + * if nTr is. + * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed + * @memberof DataTable#oApi + */ + function _fnAddData ( oSettings, aDataIn, nTr, anTds ) + { + /* Create the object for storing information about this new row */ + var iRow = oSettings.aoData.length; + var oData = $.extend( true, {}, DataTable.models.oRow, { + src: nTr ? 'dom' : 'data' + } ); + + oData._aData = aDataIn; + oSettings.aoData.push( oData ); + + /* Create the cells */ + var nTd, sThisType; + var columns = oSettings.aoColumns; + for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) + { + // When working with a row, the data source object must be populated. In + // all other cases, the data source object is already populated, so we + // don't overwrite it, which might break bindings etc + if ( nTr ) { + _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) ); + } + columns[i].sType = null; + } + + /* Add to the display array */ + oSettings.aiDisplayMaster.push( iRow ); + + /* Create the DOM information, or register it if already present */ + if ( nTr || ! oSettings.oFeatures.bDeferRender ) + { + _fnCreateTr( oSettings, iRow, nTr, anTds ); + } + + return iRow; + } + + + /** + * Add one or more TR elements to the table. Generally we'd expect to + * use this for reading data from a DOM sourced table, but it could be + * used for an TR element. Note that if a TR is given, it is used (i.e. + * it is not cloned). + * @param {object} settings dataTables settings object + * @param {array|node|jQuery} trs The TR element(s) to add to the table + * @returns {array} Array of indexes for the added rows + * @memberof DataTable#oApi + */ + function _fnAddTr( settings, trs ) + { + var row; + + // Allow an individual node to be passed in + if ( ! (trs instanceof $) ) { + trs = $(trs); + } + + return trs.map( function (i, el) { + row = _fnGetRowElements( settings, el ); + return _fnAddData( settings, row.data, el, row.cells ); + } ); + } + + + /** + * Take a TR element and convert it to an index in aoData + * @param {object} oSettings dataTables settings object + * @param {node} n the TR element to find + * @returns {int} index if the node is found, null if not + * @memberof DataTable#oApi + */ + function _fnNodeToDataIndex( oSettings, n ) + { + return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; + } + + + /** + * Take a TD element and convert it into a column data index (not the visible index) + * @param {object} oSettings dataTables settings object + * @param {int} iRow The row number the TD/TH can be found in + * @param {node} n The TD/TH element to find + * @returns {int} index if the node is found, -1 if not + * @memberof DataTable#oApi + */ + function _fnNodeToColumnIndex( oSettings, iRow, n ) + { + return $.inArray( n, oSettings.aoData[ iRow ].anCells ); + } + + + /** + * Get the data for a given cell from the internal cache, taking into account data mapping + * @param {object} settings dataTables settings object + * @param {int} rowIdx aoData row id + * @param {int} colIdx Column index + * @param {string} type data get type ('display', 'type' 'filter' 'sort') + * @returns {*} Cell data + * @memberof DataTable#oApi + */ + function _fnGetCellData( settings, rowIdx, colIdx, type ) + { + var draw = settings.iDraw; + var col = settings.aoColumns[colIdx]; + var rowData = settings.aoData[rowIdx]._aData; + var defaultContent = col.sDefaultContent; + var cellData = col.fnGetData( rowData, type, { + settings: settings, + row: rowIdx, + col: colIdx + } ); + + if ( cellData === undefined ) { + if ( settings.iDrawError != draw && defaultContent === null ) { + _fnLog( settings, 0, "Requested unknown parameter "+ + (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ + " for row "+rowIdx, 4 ); + settings.iDrawError = draw; + } + return defaultContent; + } + + /* When the data source is null, we can use default column data */ + if ( (cellData === rowData || cellData === null) && defaultContent !== null ) { + cellData = defaultContent; + } + else if ( typeof cellData === 'function' ) { + // If the data source is a function, then we run it and use the return, + // executing in the scope of the data object (for instances) + return cellData.call( rowData ); + } + + if ( cellData === null && type == 'display' ) { + return ''; + } + return cellData; + } + + + /** + * Set the value for a specific cell, into the internal data cache + * @param {object} settings dataTables settings object + * @param {int} rowIdx aoData row id + * @param {int} colIdx Column index + * @param {*} val Value to set + * @memberof DataTable#oApi + */ + function _fnSetCellData( settings, rowIdx, colIdx, val ) + { + var col = settings.aoColumns[colIdx]; + var rowData = settings.aoData[rowIdx]._aData; + + col.fnSetData( rowData, val, { + settings: settings, + row: rowIdx, + col: colIdx + } ); + } + + + // Private variable that is used to match action syntax in the data property object + var __reArray = /\[.*?\]$/; + var __reFn = /\(\)$/; + + /** + * Split string on periods, taking into account escaped periods + * @param {string} str String to split + * @return {array} Split string + */ + function _fnSplitObjNotation( str ) + { + return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) { + return s.replace(/\\./g, '.'); + } ); + } + + + /** + * Return a function that can be used to get data from a source object, taking + * into account the ability to use nested objects as a source + * @param {string|int|function} mSource The data source for the object + * @returns {function} Data get function + * @memberof DataTable#oApi + */ + function _fnGetObjectDataFn( mSource ) + { + if ( $.isPlainObject( mSource ) ) + { + /* Build an object of get functions, and wrap them in a single call */ + var o = {}; + $.each( mSource, function (key, val) { + if ( val ) { + o[key] = _fnGetObjectDataFn( val ); + } + } ); + + return function (data, type, row, meta) { + var t = o[type] || o._; + return t !== undefined ? + t(data, type, row, meta) : + data; + }; + } + else if ( mSource === null ) + { + /* Give an empty string for rendering / sorting etc */ + return function (data) { // type, row and meta also passed, but not used + return data; + }; + } + else if ( typeof mSource === 'function' ) + { + return function (data, type, row, meta) { + return mSource( data, type, row, meta ); + }; + } + else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || + mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) + { + /* If there is a . in the source string then the data source is in a + * nested object so we loop over the data for each level to get the next + * level down. On each loop we test for undefined, and if found immediately + * return. This allows entire objects to be missing and sDefaultContent to + * be used if defined, rather than throwing an error + */ + var fetchData = function (data, type, src) { + var arrayNotation, funcNotation, out, innerSrc; + + if ( src !== "" ) + { + var a = _fnSplitObjNotation( src ); + + for ( var i=0, iLen=a.length ; i<iLen ; i++ ) + { + // Check if we are dealing with special notation + arrayNotation = a[i].match(__reArray); + funcNotation = a[i].match(__reFn); + + if ( arrayNotation ) + { + // Array notation + a[i] = a[i].replace(__reArray, ''); + + // Condition allows simply [] to be passed in + if ( a[i] !== "" ) { + data = data[ a[i] ]; + } + out = []; + + // Get the remainder of the nested object to get + a.splice( 0, i+1 ); + innerSrc = a.join('.'); + + // Traverse each entry in the array getting the properties requested + for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { + out.push( fetchData( data[j], type, innerSrc ) ); + } + + // If a string is given in between the array notation indicators, that + // is used to join the strings together, otherwise an array is returned + var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); + data = (join==="") ? out : out.join(join); + + // The inner call to fetchData has already traversed through the remainder + // of the source requested, so we exit from the loop + break; + } + else if ( funcNotation ) + { + // Function call + a[i] = a[i].replace(__reFn, ''); + data = data[ a[i] ](); + continue; + } + + if ( data === null || data[ a[i] ] === undefined ) + { + return undefined; + } + data = data[ a[i] ]; + } + } + + return data; + }; + + return function (data, type) { // row and meta also passed, but not used + return fetchData( data, type, mSource ); + }; + } + else + { + /* Array or flat object mapping */ + return function (data, type) { // row and meta also passed, but not used + return data[mSource]; + }; + } + } + + + /** + * Return a function that can be used to set data from a source object, taking + * into account the ability to use nested objects as a source + * @param {string|int|function} mSource The data source for the object + * @returns {function} Data set function + * @memberof DataTable#oApi + */ + function _fnSetObjectDataFn( mSource ) + { + if ( $.isPlainObject( mSource ) ) + { + /* Unlike get, only the underscore (global) option is used for for + * setting data since we don't know the type here. This is why an object + * option is not documented for `mData` (which is read/write), but it is + * for `mRender` which is read only. + */ + return _fnSetObjectDataFn( mSource._ ); + } + else if ( mSource === null ) + { + /* Nothing to do when the data source is null */ + return function () {}; + } + else if ( typeof mSource === 'function' ) + { + return function (data, val, meta) { + mSource( data, 'set', val, meta ); + }; + } + else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || + mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) + { + /* Like the get, we need to get data from a nested object */ + var setData = function (data, val, src) { + var a = _fnSplitObjNotation( src ), b; + var aLast = a[a.length-1]; + var arrayNotation, funcNotation, o, innerSrc; + + for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) + { + // Check if we are dealing with an array notation request + arrayNotation = a[i].match(__reArray); + funcNotation = a[i].match(__reFn); + + if ( arrayNotation ) + { + a[i] = a[i].replace(__reArray, ''); + data[ a[i] ] = []; + + // Get the remainder of the nested object to set so we can recurse + b = a.slice(); + b.splice( 0, i+1 ); + innerSrc = b.join('.'); + + // Traverse each entry in the array setting the properties requested + for ( var j=0, jLen=val.length ; j<jLen ; j++ ) + { + o = {}; + setData( o, val[j], innerSrc ); + data[ a[i] ].push( o ); + } + + // The inner call to setData has already traversed through the remainder + // of the source and has set the data, thus we can exit here + return; + } + else if ( funcNotation ) + { + // Function call + a[i] = a[i].replace(__reFn, ''); + data = data[ a[i] ]( val ); + } + + // If the nested object doesn't currently exist - since we are + // trying to set the value - create it + if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) + { + data[ a[i] ] = {}; + } + data = data[ a[i] ]; + } + + // Last item in the input - i.e, the actual set + if ( aLast.match(__reFn ) ) + { + // Function call + data = data[ aLast.replace(__reFn, '') ]( val ); + } + else + { + // If array notation is used, we just want to strip it and use the property name + // and assign the value. If it isn't used, then we get the result we want anyway + data[ aLast.replace(__reArray, '') ] = val; + } + }; + + return function (data, val) { // meta is also passed in, but not used + return setData( data, val, mSource ); + }; + } + else + { + /* Array or flat object mapping */ + return function (data, val) { // meta is also passed in, but not used + data[mSource] = val; + }; + } + } + + + /** + * Return an array with the full table data + * @param {object} oSettings dataTables settings object + * @returns array {array} aData Master data array + * @memberof DataTable#oApi + */ + function _fnGetDataMaster ( settings ) + { + return _pluck( settings.aoData, '_aData' ); + } + + + /** + * Nuke the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnClearTable( settings ) + { + settings.aoData.length = 0; + settings.aiDisplayMaster.length = 0; + settings.aiDisplay.length = 0; + } + + + /** + * Take an array of integers (index array) and remove a target integer (value - not + * the key!) + * @param {array} a Index array to target + * @param {int} iTarget value to find + * @memberof DataTable#oApi + */ + function _fnDeleteIndex( a, iTarget, splice ) + { + var iTargetIndex = -1; + + for ( var i=0, iLen=a.length ; i<iLen ; i++ ) + { + if ( a[i] == iTarget ) + { + iTargetIndex = i; + } + else if ( a[i] > iTarget ) + { + a[i]--; + } + } + + if ( iTargetIndex != -1 && splice === undefined ) + { + a.splice( iTargetIndex, 1 ); + } + } + + + /** + * Mark cached data as invalid such that a re-read of the data will occur when + * the cached data is next requested. Also update from the data source object. + * + * @param {object} settings DataTables settings object + * @param {int} rowIdx Row index to invalidate + * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' + * or 'data' + * @param {int} [colIdx] Column index to invalidate. If undefined the whole + * row will be invalidated + * @memberof DataTable#oApi + * + * @todo For the modularisation of v1.11 this will need to become a callback, so + * the sort and filter methods can subscribe to it. That will required + * initialisation options for sorting, which is why it is not already baked in + */ + function _fnInvalidate( settings, rowIdx, src, colIdx ) + { + var row = settings.aoData[ rowIdx ]; + var i, ien; + var cellWrite = function ( cell, col ) { + // This is very frustrating, but in IE if you just write directly + // to innerHTML, and elements that are overwritten are GC'ed, + // even if there is a reference to them elsewhere + while ( cell.childNodes.length ) { + cell.removeChild( cell.firstChild ); + } + + cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); + }; + + // Are we reading last data from DOM or the data object? + if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { + // Read the data from the DOM + row._aData = _fnGetRowElements( + settings, row, colIdx, colIdx === undefined ? undefined : row._aData + ) + .data; + } + else { + // Reading from data object, update the DOM + var cells = row.anCells; + + if ( cells ) { + if ( colIdx !== undefined ) { + cellWrite( cells[colIdx], colIdx ); + } + else { + for ( i=0, ien=cells.length ; i<ien ; i++ ) { + cellWrite( cells[i], i ); + } + } + } + } + + // For both row and cell invalidation, the cached data for sorting and + // filtering is nulled out + row._aSortData = null; + row._aFilterData = null; + + // Invalidate the type for a specific column (if given) or all columns since + // the data might have changed + var cols = settings.aoColumns; + if ( colIdx !== undefined ) { + cols[ colIdx ].sType = null; + } + else { + for ( i=0, ien=cols.length ; i<ien ; i++ ) { + cols[i].sType = null; + } + + // Update DataTables special `DT_*` attributes for the row + _fnRowAttributes( row ); + } + } + + + /** + * Build a data source object from an HTML row, reading the contents of the + * cells that are in the row. + * + * @param {object} settings DataTables settings object + * @param {node|object} TR element from which to read data or existing row + * object from which to re-read the data from the cells + * @param {int} [colIdx] Optional column index + * @param {array|object} [d] Data source object. If `colIdx` is given then this + * parameter should also be given and will be used to write the data into. + * Only the column in question will be written + * @returns {object} Object with two parameters: `data` the data read, in + * document order, and `cells` and array of nodes (they can be useful to the + * caller, so rather than needing a second traversal to get them, just return + * them from here). + * @memberof DataTable#oApi + */ + function _fnGetRowElements( settings, row, colIdx, d ) + { + var + tds = [], + td = row.firstChild, + name, col, o, i=0, contents, + columns = settings.aoColumns, + objectRead = settings._rowReadObject; + + // Allow the data object to be passed in, or construct + d = d || objectRead ? {} : []; + + var attr = function ( str, td ) { + if ( typeof str === 'string' ) { + var idx = str.indexOf('@'); + + if ( idx !== -1 ) { + var attr = str.substring( idx+1 ); + var setter = _fnSetObjectDataFn( str ); + setter( d, td.getAttribute( attr ) ); + } + } + }; + + // Read data from a cell and store into the data object + var cellProcess = function ( cell ) { + if ( colIdx === undefined || colIdx === i ) { + col = columns[i]; + contents = $.trim(cell.innerHTML); + + if ( col && col._bAttrSrc ) { + var setter = _fnSetObjectDataFn( col.mData._ ); + setter( d, contents ); + + attr( col.mData.sort, cell ); + attr( col.mData.type, cell ); + attr( col.mData.filter, cell ); + } + else { + // Depending on the `data` option for the columns the data can + // be read to either an object or an array. + if ( objectRead ) { + if ( ! col._setter ) { + // Cache the setter function + col._setter = _fnSetObjectDataFn( col.mData ); + } + col._setter( d, contents ); + } + else { + d[i] = contents; + } + } + } + + i++; + }; + + if ( td ) { + // `tr` element was passed in + while ( td ) { + name = td.nodeName.toUpperCase(); + + if ( name == "TD" || name == "TH" ) { + cellProcess( td ); + tds.push( td ); + } + + td = td.nextSibling; + } + } + else { + // Existing row object passed in + tds = row.anCells; + + for ( var j=0, jen=tds.length ; j<jen ; j++ ) { + cellProcess( tds[j] ); + } + } + + return { + data: d, + cells: tds + }; + } + /** + * Create a new TR element (and it's TD children) for a row + * @param {object} oSettings dataTables settings object + * @param {int} iRow Row to consider + * @param {node} [nTrIn] TR element to add to the table - optional. If not given, + * DataTables will create a row automatically + * @param {array} [anTds] Array of TD|TH elements for the row - must be given + * if nTr is. + * @memberof DataTable#oApi + */ + function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) + { + var + row = oSettings.aoData[iRow], + rowData = row._aData, + cells = [], + nTr, nTd, oCol, + i, iLen; + + if ( row.nTr === null ) + { + nTr = nTrIn || document.createElement('tr'); + + row.nTr = nTr; + row.anCells = cells; + + /* Use a private property on the node to allow reserve mapping from the node + * to the aoData array for fast look up + */ + nTr._DT_RowIndex = iRow; + + /* Special parameters can be given by the data source to be used on the row */ + _fnRowAttributes( row ); + + /* Process each column */ + for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) + { + oCol = oSettings.aoColumns[i]; + + nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); + cells.push( nTd ); + + // Need to create the HTML if new, or if a rendering function is defined + if ( !nTrIn || oCol.mRender || oCol.mData !== i ) + { + nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); + } + + /* Add user defined class */ + if ( oCol.sClass ) + { + nTd.className += ' '+oCol.sClass; + } + + // Visibility - add or remove as required + if ( oCol.bVisible && ! nTrIn ) + { + nTr.appendChild( nTd ); + } + else if ( ! oCol.bVisible && nTrIn ) + { + nTd.parentNode.removeChild( nTd ); + } + + if ( oCol.fnCreatedCell ) + { + oCol.fnCreatedCell.call( oSettings.oInstance, + nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i + ); + } + } + + _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); + } + + // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved + // and deployed + row.nTr.setAttribute( 'role', 'row' ); + } + + + /** + * Add attributes to a row based on the special `DT_*` parameters in a data + * source object. + * @param {object} DataTables row object for the row to be modified + * @memberof DataTable#oApi + */ + function _fnRowAttributes( row ) + { + var tr = row.nTr; + var data = row._aData; + + if ( tr ) { + if ( data.DT_RowId ) { + tr.id = data.DT_RowId; + } + + if ( data.DT_RowClass ) { + // Remove any classes added by DT_RowClass before + var a = data.DT_RowClass.split(' '); + row.__rowc = row.__rowc ? + _unique( row.__rowc.concat( a ) ) : + a; + + $(tr) + .removeClass( row.__rowc.join(' ') ) + .addClass( data.DT_RowClass ); + } + + if ( data.DT_RowData ) { + $(tr).data( data.DT_RowData ); + } + } + } + + + /** + * Create the HTML header for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnBuildHead( oSettings ) + { + var i, ien, cell, row, column; + var thead = oSettings.nTHead; + var tfoot = oSettings.nTFoot; + var createHeader = $('th, td', thead).length === 0; + var classes = oSettings.oClasses; + var columns = oSettings.aoColumns; + + if ( createHeader ) { + row = $('<tr/>').appendTo( thead ); + } + + for ( i=0, ien=columns.length ; i<ien ; i++ ) { + column = columns[i]; + cell = $( column.nTh ).addClass( column.sClass ); + + if ( createHeader ) { + cell.appendTo( row ); + } + + // 1.11 move into sorting + if ( oSettings.oFeatures.bSort ) { + cell.addClass( column.sSortingClass ); + + if ( column.bSortable !== false ) { + cell + .attr( 'tabindex', oSettings.iTabIndex ) + .attr( 'aria-controls', oSettings.sTableId ); + + _fnSortAttachListener( oSettings, column.nTh, i ); + } + } + + if ( column.sTitle != cell.html() ) { + cell.html( column.sTitle ); + } + + _fnRenderer( oSettings, 'header' )( + oSettings, cell, column, classes + ); + } + + if ( createHeader ) { + _fnDetectHeader( oSettings.aoHeader, thead ); + } + + /* ARIA role for the rows */ + $(thead).find('>tr').attr('role', 'row'); + + /* Deal with the footer - add classes if required */ + $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); + $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); + + // Cache the footer cells. Note that we only take the cells from the first + // row in the footer. If there is more than one row the user wants to + // interact with, they need to use the table().foot() method. Note also this + // allows cells to be used for multiple columns using colspan + if ( tfoot !== null ) { + var cells = oSettings.aoFooter[0]; + + for ( i=0, ien=cells.length ; i<ien ; i++ ) { + column = columns[i]; + column.nTf = cells[i].cell; + + if ( column.sClass ) { + $(column.nTf).addClass( column.sClass ); + } + } + } + } + + + /** + * Draw the header (or footer) element based on the column visibility states. The + * methodology here is to use the layout array from _fnDetectHeader, modified for + * the instantaneous column visibility, to construct the new layout. The grid is + * traversed over cell at a time in a rows x columns grid fashion, although each + * cell insert can cover multiple elements in the grid - which is tracks using the + * aApplied array. Cell inserts in the grid will only occur where there isn't + * already a cell in that position. + * @param {object} oSettings dataTables settings object + * @param array {objects} aoSource Layout array from _fnDetectHeader + * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, + * @memberof DataTable#oApi + */ + function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) + { + var i, iLen, j, jLen, k, kLen, n, nLocalTr; + var aoLocal = []; + var aApplied = []; + var iColumns = oSettings.aoColumns.length; + var iRowspan, iColspan; + + if ( ! aoSource ) + { + return; + } + + if ( bIncludeHidden === undefined ) + { + bIncludeHidden = false; + } + + /* Make a copy of the master layout array, but without the visible columns in it */ + for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) + { + aoLocal[i] = aoSource[i].slice(); + aoLocal[i].nTr = aoSource[i].nTr; + + /* Remove any columns which are currently hidden */ + for ( j=iColumns-1 ; j>=0 ; j-- ) + { + if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) + { + aoLocal[i].splice( j, 1 ); + } + } + + /* Prep the applied array - it needs an element for each row */ + aApplied.push( [] ); + } + + for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) + { + nLocalTr = aoLocal[i].nTr; + + /* All cells are going to be replaced, so empty out the row */ + if ( nLocalTr ) + { + while( (n = nLocalTr.firstChild) ) + { + nLocalTr.removeChild( n ); + } + } + + for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) + { + iRowspan = 1; + iColspan = 1; + + /* Check to see if there is already a cell (row/colspan) covering our target + * insert point. If there is, then there is nothing to do. + */ + if ( aApplied[i][j] === undefined ) + { + nLocalTr.appendChild( aoLocal[i][j].cell ); + aApplied[i][j] = 1; + + /* Expand the cell to cover as many rows as needed */ + while ( aoLocal[i+iRowspan] !== undefined && + aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) + { + aApplied[i+iRowspan][j] = 1; + iRowspan++; + } + + /* Expand the cell to cover as many columns as needed */ + while ( aoLocal[i][j+iColspan] !== undefined && + aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) + { + /* Must update the applied array over the rows for the columns */ + for ( k=0 ; k<iRowspan ; k++ ) + { + aApplied[i+k][j+iColspan] = 1; + } + iColspan++; + } + + /* Do the actual expansion in the DOM */ + $(aoLocal[i][j].cell) + .attr('rowspan', iRowspan) + .attr('colspan', iColspan); + } + } + } + } + + + /** + * Insert the required TR nodes into the table for display + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnDraw( oSettings ) + { + /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ + var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); + if ( $.inArray( false, aPreDraw ) !== -1 ) + { + _fnProcessingDisplay( oSettings, false ); + return; + } + + var i, iLen, n; + var anRows = []; + var iRowCount = 0; + var asStripeClasses = oSettings.asStripeClasses; + var iStripes = asStripeClasses.length; + var iOpenRows = oSettings.aoOpenRows.length; + var oLang = oSettings.oLanguage; + var iInitDisplayStart = oSettings.iInitDisplayStart; + var bServerSide = _fnDataSource( oSettings ) == 'ssp'; + var aiDisplay = oSettings.aiDisplay; + + oSettings.bDrawing = true; + + /* Check and see if we have an initial draw position from state saving */ + if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) + { + oSettings._iDisplayStart = bServerSide ? + iInitDisplayStart : + iInitDisplayStart >= oSettings.fnRecordsDisplay() ? + 0 : + iInitDisplayStart; + + oSettings.iInitDisplayStart = -1; + } + + var iDisplayStart = oSettings._iDisplayStart; + var iDisplayEnd = oSettings.fnDisplayEnd(); + + /* Server-side processing draw intercept */ + if ( oSettings.bDeferLoading ) + { + oSettings.bDeferLoading = false; + oSettings.iDraw++; + _fnProcessingDisplay( oSettings, false ); + } + else if ( !bServerSide ) + { + oSettings.iDraw++; + } + else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) + { + return; + } + + if ( aiDisplay.length !== 0 ) + { + var iStart = bServerSide ? 0 : iDisplayStart; + var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; + + for ( var j=iStart ; j<iEnd ; j++ ) + { + var iDataIndex = aiDisplay[j]; + var aoData = oSettings.aoData[ iDataIndex ]; + if ( aoData.nTr === null ) + { + _fnCreateTr( oSettings, iDataIndex ); + } + + var nRow = aoData.nTr; + + /* Remove the old striping classes and then add the new one */ + if ( iStripes !== 0 ) + { + var sStripe = asStripeClasses[ iRowCount % iStripes ]; + if ( aoData._sRowStripe != sStripe ) + { + $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); + aoData._sRowStripe = sStripe; + } + } + + // Row callback functions - might want to manipulate the row + // iRowCount and j are not currently documented. Are they at all + // useful? + _fnCallbackFire( oSettings, 'aoRowCallback', null, + [nRow, aoData._aData, iRowCount, j] ); + + anRows.push( nRow ); + iRowCount++; + } + } + else + { + /* Table is empty - create a row with an empty message in it */ + var sZero = oLang.sZeroRecords; + if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) + { + sZero = oLang.sLoadingRecords; + } + else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) + { + sZero = oLang.sEmptyTable; + } + + anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) + .append( $('<td />', { + 'valign': 'top', + 'colSpan': _fnVisbleColumns( oSettings ), + 'class': oSettings.oClasses.sRowEmpty + } ).html( sZero ) )[0]; + } + + /* Header and footer callbacks */ + _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], + _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); + + _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], + _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); + + var body = $(oSettings.nTBody); + + body.children().detach(); + body.append( $(anRows) ); + + /* Call all required callback functions for the end of a draw */ + _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); + + /* Draw is complete, sorting and filtering must be as well */ + oSettings.bSorted = false; + oSettings.bFiltered = false; + oSettings.bDrawing = false; + } + + + /** + * Redraw the table - taking account of the various features which are enabled + * @param {object} oSettings dataTables settings object + * @param {boolean} [holdPosition] Keep the current paging position. By default + * the paging is reset to the first page + * @memberof DataTable#oApi + */ + function _fnReDraw( settings, holdPosition ) + { + var + features = settings.oFeatures, + sort = features.bSort, + filter = features.bFilter; + + if ( sort ) { + _fnSort( settings ); + } + + if ( filter ) { + _fnFilterComplete( settings, settings.oPreviousSearch ); + } + else { + // No filtering, so we want to just use the display master + settings.aiDisplay = settings.aiDisplayMaster.slice(); + } + + if ( holdPosition !== true ) { + settings._iDisplayStart = 0; + } + + // Let any modules know about the draw hold position state (used by + // scrolling internally) + settings._drawHold = holdPosition; + + _fnDraw( settings ); + + settings._drawHold = false; + } + + + /** + * Add the options to the page HTML for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAddOptionsHtml ( oSettings ) + { + var classes = oSettings.oClasses; + var table = $(oSettings.nTable); + var holding = $('<div/>').insertBefore( table ); // Holding element for speed + var features = oSettings.oFeatures; + + // All DataTables are wrapped in a div + var insert = $('<div/>', { + id: oSettings.sTableId+'_wrapper', + 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) + } ); + + oSettings.nHolding = holding[0]; + oSettings.nTableWrapper = insert[0]; + oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; + + /* Loop over the user set positioning and place the elements as needed */ + var aDom = oSettings.sDom.split(''); + var featureNode, cOption, nNewNode, cNext, sAttr, j; + for ( var i=0 ; i<aDom.length ; i++ ) + { + featureNode = null; + cOption = aDom[i]; + + if ( cOption == '<' ) + { + /* New container div */ + nNewNode = $('<div/>')[0]; + + /* Check to see if we should append an id and/or a class name to the container */ + cNext = aDom[i+1]; + if ( cNext == "'" || cNext == '"' ) + { + sAttr = ""; + j = 2; + while ( aDom[i+j] != cNext ) + { + sAttr += aDom[i+j]; + j++; + } + + /* Replace jQuery UI constants @todo depreciated */ + if ( sAttr == "H" ) + { + sAttr = classes.sJUIHeader; + } + else if ( sAttr == "F" ) + { + sAttr = classes.sJUIFooter; + } + + /* The attribute can be in the format of "#id.class", "#id" or "class" This logic + * breaks the string into parts and applies them as needed + */ + if ( sAttr.indexOf('.') != -1 ) + { + var aSplit = sAttr.split('.'); + nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); + nNewNode.className = aSplit[1]; + } + else if ( sAttr.charAt(0) == "#" ) + { + nNewNode.id = sAttr.substr(1, sAttr.length-1); + } + else + { + nNewNode.className = sAttr; + } + + i += j; /* Move along the position array */ + } + + insert.append( nNewNode ); + insert = $(nNewNode); + } + else if ( cOption == '>' ) + { + /* End container div */ + insert = insert.parent(); + } + // @todo Move options into their own plugins? + else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) + { + /* Length */ + featureNode = _fnFeatureHtmlLength( oSettings ); + } + else if ( cOption == 'f' && features.bFilter ) + { + /* Filter */ + featureNode = _fnFeatureHtmlFilter( oSettings ); + } + else if ( cOption == 'r' && features.bProcessing ) + { + /* pRocessing */ + featureNode = _fnFeatureHtmlProcessing( oSettings ); + } + else if ( cOption == 't' ) + { + /* Table */ + featureNode = _fnFeatureHtmlTable( oSettings ); + } + else if ( cOption == 'i' && features.bInfo ) + { + /* Info */ + featureNode = _fnFeatureHtmlInfo( oSettings ); + } + else if ( cOption == 'p' && features.bPaginate ) + { + /* Pagination */ + featureNode = _fnFeatureHtmlPaginate( oSettings ); + } + else if ( DataTable.ext.feature.length !== 0 ) + { + /* Plug-in features */ + var aoFeatures = DataTable.ext.feature; + for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) + { + if ( cOption == aoFeatures[k].cFeature ) + { + featureNode = aoFeatures[k].fnInit( oSettings ); + break; + } + } + } + + /* Add to the 2D features array */ + if ( featureNode ) + { + var aanFeatures = oSettings.aanFeatures; + + if ( ! aanFeatures[cOption] ) + { + aanFeatures[cOption] = []; + } + + aanFeatures[cOption].push( featureNode ); + insert.append( featureNode ); + } + } + + /* Built our DOM structure - replace the holding div with what we want */ + holding.replaceWith( insert ); + } + + + /** + * Use the DOM source to create up an array of header cells. The idea here is to + * create a layout grid (array) of rows x columns, which contains a reference + * to the cell that that point in the grid (regardless of col/rowspan), such that + * any column / row could be removed and the new grid constructed + * @param array {object} aLayout Array to store the calculated layout in + * @param {node} nThead The header/footer element for the table + * @memberof DataTable#oApi + */ + function _fnDetectHeader ( aLayout, nThead ) + { + var nTrs = $(nThead).children('tr'); + var nTr, nCell; + var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; + var bUnique; + var fnShiftCol = function ( a, i, j ) { + var k = a[i]; + while ( k[j] ) { + j++; + } + return j; + }; + + aLayout.splice( 0, aLayout.length ); + + /* We know how many rows there are in the layout - so prep it */ + for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) + { + aLayout.push( [] ); + } + + /* Calculate a layout array */ + for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) + { + nTr = nTrs[i]; + iColumn = 0; + + /* For every cell in the row... */ + nCell = nTr.firstChild; + while ( nCell ) { + if ( nCell.nodeName.toUpperCase() == "TD" || + nCell.nodeName.toUpperCase() == "TH" ) + { + /* Get the col and rowspan attributes from the DOM and sanitise them */ + iColspan = nCell.getAttribute('colspan') * 1; + iRowspan = nCell.getAttribute('rowspan') * 1; + iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; + iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; + + /* There might be colspan cells already in this row, so shift our target + * accordingly + */ + iColShifted = fnShiftCol( aLayout, i, iColumn ); + + /* Cache calculation for unique columns */ + bUnique = iColspan === 1 ? true : false; + + /* If there is col / rowspan, copy the information into the layout grid */ + for ( l=0 ; l<iColspan ; l++ ) + { + for ( k=0 ; k<iRowspan ; k++ ) + { + aLayout[i+k][iColShifted+l] = { + "cell": nCell, + "unique": bUnique + }; + aLayout[i+k].nTr = nTr; + } + } + } + nCell = nCell.nextSibling; + } + } + } + + + /** + * Get an array of unique th elements, one for each column + * @param {object} oSettings dataTables settings object + * @param {node} nHeader automatically detect the layout from this node - optional + * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional + * @returns array {node} aReturn list of unique th's + * @memberof DataTable#oApi + */ + function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) + { + var aReturn = []; + if ( !aLayout ) + { + aLayout = oSettings.aoHeader; + if ( nHeader ) + { + aLayout = []; + _fnDetectHeader( aLayout, nHeader ); + } + } + + for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) + { + for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) + { + if ( aLayout[i][j].unique && + (!aReturn[j] || !oSettings.bSortCellsTop) ) + { + aReturn[j] = aLayout[i][j].cell; + } + } + } + + return aReturn; + } + + + + /** + * Create an Ajax call based on the table's settings, taking into account that + * parameters can have multiple forms, and backwards compatibility. + * + * @param {object} oSettings dataTables settings object + * @param {array} data Data to send to the server, required by + * DataTables - may be augmented by developer callbacks + * @param {function} fn Callback function to run when data is obtained + */ + function _fnBuildAjax( oSettings, data, fn ) + { + // Compatibility with 1.9-, allow fnServerData and event to manipulate + _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); + + // Convert to object based for 1.10+ if using the old array scheme which can + // come from server-side processing or serverParams + if ( data && $.isArray(data) ) { + var tmp = {}; + var rbracket = /(.*?)\[\]$/; + + $.each( data, function (key, val) { + var match = val.name.match(rbracket); + + if ( match ) { + // Support for arrays + var name = match[0]; + + if ( ! tmp[ name ] ) { + tmp[ name ] = []; + } + tmp[ name ].push( val.value ); + } + else { + tmp[val.name] = val.value; + } + } ); + data = tmp; + } + + var ajaxData; + var ajax = oSettings.ajax; + var instance = oSettings.oInstance; + + if ( $.isPlainObject( ajax ) && ajax.data ) + { + ajaxData = ajax.data; + + var newData = $.isFunction( ajaxData ) ? + ajaxData( data ) : // fn can manipulate data or return an object + ajaxData; // object or array to merge + + // If the function returned an object, use that alone + data = $.isFunction( ajaxData ) && newData ? + newData : + $.extend( true, data, newData ); + + // Remove the data property as we've resolved it already and don't want + // jQuery to do it again (it is restored at the end of the function) + delete ajax.data; + } + + var baseAjax = { + "data": data, + "success": function (json) { + var error = json.error || json.sError; + if ( error ) { + oSettings.oApi._fnLog( oSettings, 0, error ); + } + + oSettings.json = json; + _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] ); + fn( json ); + }, + "dataType": "json", + "cache": false, + "type": oSettings.sServerMethod, + "error": function (xhr, error, thrown) { + var log = oSettings.oApi._fnLog; + + if ( error == "parsererror" ) { + log( oSettings, 0, 'Invalid JSON response', 1 ); + } + else if ( xhr.readyState === 4 ) { + log( oSettings, 0, 'Ajax error', 7 ); + } + + _fnProcessingDisplay( oSettings, false ); + } + }; + + // Store the data submitted for the API + oSettings.oAjaxData = data; + + // Allow plug-ins and external processes to modify the data + _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); + + if ( oSettings.fnServerData ) + { + // DataTables 1.9- compatibility + oSettings.fnServerData.call( instance, + oSettings.sAjaxSource, + $.map( data, function (val, key) { // Need to convert back to 1.9 trad format + return { name: key, value: val }; + } ), + fn, + oSettings + ); + } + else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) + { + // DataTables 1.9- compatibility + oSettings.jqXHR = $.ajax( $.extend( baseAjax, { + url: ajax || oSettings.sAjaxSource + } ) ); + } + else if ( $.isFunction( ajax ) ) + { + // Is a function - let the caller define what needs to be done + oSettings.jqXHR = ajax.call( instance, data, fn, oSettings ); + } + else + { + // Object to extend the base settings + oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); + + // Restore for next time around + ajax.data = ajaxData; + } + } + + + /** + * Update the table using an Ajax call + * @param {object} settings dataTables settings object + * @returns {boolean} Block the table drawing or not + * @memberof DataTable#oApi + */ + function _fnAjaxUpdate( settings ) + { + if ( settings.bAjaxDataGet ) { + settings.iDraw++; + _fnProcessingDisplay( settings, true ); + + _fnBuildAjax( + settings, + _fnAjaxParameters( settings ), + function(json) { + _fnAjaxUpdateDraw( settings, json ); + } + ); + + return false; + } + return true; + } + + + /** + * Build up the parameters in an object needed for a server-side processing + * request. Note that this is basically done twice, is different ways - a modern + * method which is used by default in DataTables 1.10 which uses objects and + * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if + * the sAjaxSource option is used in the initialisation, or the legacyAjax + * option is set. + * @param {object} oSettings dataTables settings object + * @returns {bool} block the table drawing or not + * @memberof DataTable#oApi + */ + function _fnAjaxParameters( settings ) + { + var + columns = settings.aoColumns, + columnCount = columns.length, + features = settings.oFeatures, + preSearch = settings.oPreviousSearch, + preColSearch = settings.aoPreSearchCols, + i, data = [], dataProp, column, columnSearch, + sort = _fnSortFlatten( settings ), + displayStart = settings._iDisplayStart, + displayLength = features.bPaginate !== false ? + settings._iDisplayLength : + -1; + + var param = function ( name, value ) { + data.push( { 'name': name, 'value': value } ); + }; + + // DataTables 1.9- compatible method + param( 'sEcho', settings.iDraw ); + param( 'iColumns', columnCount ); + param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); + param( 'iDisplayStart', displayStart ); + param( 'iDisplayLength', displayLength ); + + // DataTables 1.10+ method + var d = { + draw: settings.iDraw, + columns: [], + order: [], + start: displayStart, + length: displayLength, + search: { + value: preSearch.sSearch, + regex: preSearch.bRegex + } + }; + + for ( i=0 ; i<columnCount ; i++ ) { + column = columns[i]; + columnSearch = preColSearch[i]; + dataProp = typeof column.mData=="function" ? 'function' : column.mData ; + + d.columns.push( { + data: dataProp, + name: column.sName, + searchable: column.bSearchable, + orderable: column.bSortable, + search: { + value: columnSearch.sSearch, + regex: columnSearch.bRegex + } + } ); + + param( "mDataProp_"+i, dataProp ); + + if ( features.bFilter ) { + param( 'sSearch_'+i, columnSearch.sSearch ); + param( 'bRegex_'+i, columnSearch.bRegex ); + param( 'bSearchable_'+i, column.bSearchable ); + } + + if ( features.bSort ) { + param( 'bSortable_'+i, column.bSortable ); + } + } + + if ( features.bFilter ) { + param( 'sSearch', preSearch.sSearch ); + param( 'bRegex', preSearch.bRegex ); + } + + if ( features.bSort ) { + $.each( sort, function ( i, val ) { + d.order.push( { column: val.col, dir: val.dir } ); + + param( 'iSortCol_'+i, val.col ); + param( 'sSortDir_'+i, val.dir ); + } ); + + param( 'iSortingCols', sort.length ); + } + + // If the legacy.ajax parameter is null, then we automatically decide which + // form to use, based on sAjaxSource + var legacy = DataTable.ext.legacy.ajax; + if ( legacy === null ) { + return settings.sAjaxSource ? data : d; + } + + // Otherwise, if legacy has been specified then we use that to decide on the + // form + return legacy ? data : d; + } + + + /** + * Data the data from the server (nuking the old) and redraw the table + * @param {object} oSettings dataTables settings object + * @param {object} json json data return from the server. + * @param {string} json.sEcho Tracking flag for DataTables to match requests + * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering + * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering + * @param {array} json.aaData The data to display on this page + * @param {string} [json.sColumns] Column ordering (sName, comma separated) + * @memberof DataTable#oApi + */ + function _fnAjaxUpdateDraw ( settings, json ) + { + // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. + // Support both + var compat = function ( old, modern ) { + return json[old] !== undefined ? json[old] : json[modern]; + }; + + var draw = compat( 'sEcho', 'draw' ); + var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); + var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); + + if ( draw ) { + // Protect against out of sequence returns + if ( draw*1 < settings.iDraw ) { + return; + } + settings.iDraw = draw * 1; + } + + _fnClearTable( settings ); + settings._iRecordsTotal = parseInt(recordsTotal, 10); + settings._iRecordsDisplay = parseInt(recordsFiltered, 10); + + var data = _fnAjaxDataSrc( settings, json ); + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + _fnAddData( settings, data[i] ); + } + settings.aiDisplay = settings.aiDisplayMaster.slice(); + + settings.bAjaxDataGet = false; + _fnDraw( settings ); + + if ( ! settings._bInitComplete ) { + _fnInitComplete( settings, json ); + } + + settings.bAjaxDataGet = true; + _fnProcessingDisplay( settings, false ); + } + + + /** + * Get the data from the JSON data source to use for drawing a table. Using + * `_fnGetObjectDataFn` allows the data to be sourced from a property of the + * source object, or from a processing function. + * @param {object} oSettings dataTables settings object + * @param {object} json Data source object / array from the server + * @return {array} Array of data to use + */ + function _fnAjaxDataSrc ( oSettings, json ) + { + var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? + oSettings.ajax.dataSrc : + oSettings.sAjaxDataProp; // Compatibility with 1.9-. + + // Compatibility with 1.9-. In order to read from aaData, check if the + // default has been changed, if not, check for aaData + if ( dataSrc === 'data' ) { + return json.aaData || json[dataSrc]; + } + + return dataSrc !== "" ? + _fnGetObjectDataFn( dataSrc )( json ) : + json; + } + + + /** + * Generate the node required for filtering text + * @returns {node} Filter control element + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlFilter ( settings ) + { + var classes = settings.oClasses; + var tableId = settings.sTableId; + var language = settings.oLanguage; + var previousSearch = settings.oPreviousSearch; + var features = settings.aanFeatures; + var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; + + var str = language.sSearch; + str = str.match(/_INPUT_/) ? + str.replace('_INPUT_', input) : + str+input; + + var filter = $('<div/>', { + 'id': ! features.f ? tableId+'_filter' : null, + 'class': classes.sFilter + } ) + .append( $('<label/>' ).append( str ) ); + + var searchFn = function() { + /* Update all other filter input elements for the new display */ + var n = features.f; + var val = !this.value ? "" : this.value; // mental IE8 fix :-( + + /* Now do the filter */ + if ( val != previousSearch.sSearch ) { + _fnFilterComplete( settings, { + "sSearch": val, + "bRegex": previousSearch.bRegex, + "bSmart": previousSearch.bSmart , + "bCaseInsensitive": previousSearch.bCaseInsensitive + } ); + + // Need to redraw, without resorting + settings._iDisplayStart = 0; + _fnDraw( settings ); + } + }; + + var searchDelay = settings.searchDelay !== null ? + settings.searchDelay : + _fnDataSource( settings ) === 'ssp' ? + 400 : + 0; + + var jqFilter = $('input', filter) + .val( previousSearch.sSearch ) + .attr( 'placeholder', language.sSearchPlaceholder ) + .bind( + 'keyup.DT search.DT input.DT paste.DT cut.DT', + searchDelay ? + _fnThrottle( searchFn, searchDelay ) : + searchFn + ) + .bind( 'keypress.DT', function(e) { + /* Prevent form submission */ + if ( e.keyCode == 13 ) { + return false; + } + } ) + .attr('aria-controls', tableId); + + // Update the input elements whenever the table is filtered + $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { + if ( settings === s ) { + // IE9 throws an 'unknown error' if document.activeElement is used + // inside an iframe or frame... + try { + if ( jqFilter[0] !== document.activeElement ) { + jqFilter.val( previousSearch.sSearch ); + } + } + catch ( e ) {} + } + } ); + + return filter[0]; + } + + + /** + * Filter the table using both the global filter and column based filtering + * @param {object} oSettings dataTables settings object + * @param {object} oSearch search information + * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) + * @memberof DataTable#oApi + */ + function _fnFilterComplete ( oSettings, oInput, iForce ) + { + var oPrevSearch = oSettings.oPreviousSearch; + var aoPrevSearch = oSettings.aoPreSearchCols; + var fnSaveFilter = function ( oFilter ) { + /* Save the filtering values */ + oPrevSearch.sSearch = oFilter.sSearch; + oPrevSearch.bRegex = oFilter.bRegex; + oPrevSearch.bSmart = oFilter.bSmart; + oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; + }; + var fnRegex = function ( o ) { + // Backwards compatibility with the bEscapeRegex option + return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; + }; + + // Resolve any column types that are unknown due to addition or invalidation + // @todo As per sort - can this be moved into an event handler? + _fnColumnTypes( oSettings ); + + /* In server-side processing all filtering is done by the server, so no point hanging around here */ + if ( _fnDataSource( oSettings ) != 'ssp' ) + { + /* Global filter */ + _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); + fnSaveFilter( oInput ); + + /* Now do the individual column filter */ + for ( var i=0 ; i<aoPrevSearch.length ; i++ ) + { + _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), + aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); + } + + /* Custom filtering */ + _fnFilterCustom( oSettings ); + } + else + { + fnSaveFilter( oInput ); + } + + /* Tell the draw function we have been filtering */ + oSettings.bFiltered = true; + _fnCallbackFire( oSettings, null, 'search', [oSettings] ); + } + + + /** + * Apply custom filtering functions + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnFilterCustom( settings ) + { + var filters = DataTable.ext.search; + var displayRows = settings.aiDisplay; + var row, rowIdx; + + for ( var i=0, ien=filters.length ; i<ien ; i++ ) { + var rows = []; + + // Loop over each row and see if it should be included + for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { + rowIdx = displayRows[ j ]; + row = settings.aoData[ rowIdx ]; + + if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { + rows.push( rowIdx ); + } + } + + // So the array reference doesn't break set the results into the + // existing array + displayRows.length = 0; + displayRows.push.apply( displayRows, rows ); + } + } + + + /** + * Filter the table on a per-column basis + * @param {object} oSettings dataTables settings object + * @param {string} sInput string to filter on + * @param {int} iColumn column to filter + * @param {bool} bRegex treat search string as a regular expression or not + * @param {bool} bSmart use smart filtering or not + * @param {bool} bCaseInsensitive Do case insenstive matching or not + * @memberof DataTable#oApi + */ + function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) + { + if ( searchStr === '' ) { + return; + } + + var data; + var display = settings.aiDisplay; + var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); + + for ( var i=display.length-1 ; i>=0 ; i-- ) { + data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; + + if ( ! rpSearch.test( data ) ) { + display.splice( i, 1 ); + } + } + } + + + /** + * Filter the data table based on user input and draw the table + * @param {object} settings dataTables settings object + * @param {string} input string to filter on + * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) + * @param {bool} regex treat as a regular expression or not + * @param {bool} smart perform smart filtering or not + * @param {bool} caseInsensitive Do case insenstive matching or not + * @memberof DataTable#oApi + */ + function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) + { + var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); + var prevSearch = settings.oPreviousSearch.sSearch; + var displayMaster = settings.aiDisplayMaster; + var display, invalidated, i; + + // Need to take account of custom filtering functions - always filter + if ( DataTable.ext.search.length !== 0 ) { + force = true; + } + + // Check if any of the rows were invalidated + invalidated = _fnFilterData( settings ); + + // If the input is blank - we just want the full data set + if ( input.length <= 0 ) { + settings.aiDisplay = displayMaster.slice(); + } + else { + // New search - start from the master array + if ( invalidated || + force || + prevSearch.length > input.length || + input.indexOf(prevSearch) !== 0 || + settings.bSorted // On resort, the display master needs to be + // re-filtered since indexes will have changed + ) { + settings.aiDisplay = displayMaster.slice(); + } + + // Search the display array + display = settings.aiDisplay; + + for ( i=display.length-1 ; i>=0 ; i-- ) { + if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { + display.splice( i, 1 ); + } + } + } + } + + + /** + * Build a regular expression object suitable for searching a table + * @param {string} sSearch string to search for + * @param {bool} bRegex treat as a regular expression or not + * @param {bool} bSmart perform smart filtering or not + * @param {bool} bCaseInsensitive Do case insensitive matching or not + * @returns {RegExp} constructed object + * @memberof DataTable#oApi + */ + function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) + { + search = regex ? + search : + _fnEscapeRegex( search ); + + if ( smart ) { + /* For smart filtering we want to allow the search to work regardless of + * word order. We also want double quoted text to be preserved, so word + * order is important - a la google. So this is what we want to + * generate: + * + * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ + */ + var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) { + if ( word.charAt(0) === '"' ) { + var m = word.match( /^"(.*)"$/ ); + word = m ? m[1] : word; + } + + return word.replace('"', ''); + } ); + + search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; + } + + return new RegExp( search, caseInsensitive ? 'i' : '' ); + } + + + /** + * Escape a string such that it can be used in a regular expression + * @param {string} sVal string to escape + * @returns {string} escaped string + * @memberof DataTable#oApi + */ + function _fnEscapeRegex ( sVal ) + { + return sVal.replace( _re_escape_regex, '\\$1' ); + } + + + + var __filter_div = $('<div>')[0]; + var __filter_div_textContent = __filter_div.textContent !== undefined; + + // Update the filtering data for each row if needed (by invalidation or first run) + function _fnFilterData ( settings ) + { + var columns = settings.aoColumns; + var column; + var i, j, ien, jen, filterData, cellData, row; + var fomatters = DataTable.ext.type.search; + var wasInvalidated = false; + + for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { + row = settings.aoData[i]; + + if ( ! row._aFilterData ) { + filterData = []; + + for ( j=0, jen=columns.length ; j<jen ; j++ ) { + column = columns[j]; + + if ( column.bSearchable ) { + cellData = _fnGetCellData( settings, i, j, 'filter' ); + + if ( fomatters[ column.sType ] ) { + cellData = fomatters[ column.sType ]( cellData ); + } + + // Search in DataTables 1.10 is string based. In 1.11 this + // should be altered to also allow strict type checking. + if ( cellData === null ) { + cellData = ''; + } + + if ( typeof cellData !== 'string' && cellData.toString ) { + cellData = cellData.toString(); + } + } + else { + cellData = ''; + } + + // If it looks like there is an HTML entity in the string, + // attempt to decode it so sorting works as expected. Note that + // we could use a single line of jQuery to do this, but the DOM + // method used here is much faster http://jsperf.com/html-decode + if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { + __filter_div.innerHTML = cellData; + cellData = __filter_div_textContent ? + __filter_div.textContent : + __filter_div.innerText; + } + + if ( cellData.replace ) { + cellData = cellData.replace(/[\r\n]/g, ''); + } + + filterData.push( cellData ); + } + + row._aFilterData = filterData; + row._sFilterRow = filterData.join(' '); + wasInvalidated = true; + } + } + + return wasInvalidated; + } + + + /** + * Convert from the internal Hungarian notation to camelCase for external + * interaction + * @param {object} obj Object to convert + * @returns {object} Inverted object + * @memberof DataTable#oApi + */ + function _fnSearchToCamel ( obj ) + { + return { + search: obj.sSearch, + smart: obj.bSmart, + regex: obj.bRegex, + caseInsensitive: obj.bCaseInsensitive + }; + } + + + + /** + * Convert from camelCase notation to the internal Hungarian. We could use the + * Hungarian convert function here, but this is cleaner + * @param {object} obj Object to convert + * @returns {object} Inverted object + * @memberof DataTable#oApi + */ + function _fnSearchToHung ( obj ) + { + return { + sSearch: obj.search, + bSmart: obj.smart, + bRegex: obj.regex, + bCaseInsensitive: obj.caseInsensitive + }; + } + + /** + * Generate the node required for the info display + * @param {object} oSettings dataTables settings object + * @returns {node} Information element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlInfo ( settings ) + { + var + tid = settings.sTableId, + nodes = settings.aanFeatures.i, + n = $('<div/>', { + 'class': settings.oClasses.sInfo, + 'id': ! nodes ? tid+'_info' : null + } ); + + if ( ! nodes ) { + // Update display on each draw + settings.aoDrawCallback.push( { + "fn": _fnUpdateInfo, + "sName": "information" + } ); + + n + .attr( 'role', 'status' ) + .attr( 'aria-live', 'polite' ); + + // Table is described by our info div + $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); + } + + return n[0]; + } + + + /** + * Update the information elements in the display + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnUpdateInfo ( settings ) + { + /* Show information about the table */ + var nodes = settings.aanFeatures.i; + if ( nodes.length === 0 ) { + return; + } + + var + lang = settings.oLanguage, + start = settings._iDisplayStart+1, + end = settings.fnDisplayEnd(), + max = settings.fnRecordsTotal(), + total = settings.fnRecordsDisplay(), + out = total ? + lang.sInfo : + lang.sInfoEmpty; + + if ( total !== max ) { + /* Record set after filtering */ + out += ' ' + lang.sInfoFiltered; + } + + // Convert the macros + out += lang.sInfoPostFix; + out = _fnInfoMacros( settings, out ); + + var callback = lang.fnInfoCallback; + if ( callback !== null ) { + out = callback.call( settings.oInstance, + settings, start, end, max, total, out + ); + } + + $(nodes).html( out ); + } + + + function _fnInfoMacros ( settings, str ) + { + // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only + // internally + var + formatter = settings.fnFormatNumber, + start = settings._iDisplayStart+1, + len = settings._iDisplayLength, + vis = settings.fnRecordsDisplay(), + all = len === -1; + + return str. + replace(/_START_/g, formatter.call( settings, start ) ). + replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). + replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). + replace(/_TOTAL_/g, formatter.call( settings, vis ) ). + replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). + replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); + } + + + + /** + * Draw the table for the first time, adding all required features + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnInitialise ( settings ) + { + var i, iLen, iAjaxStart=settings.iInitDisplayStart; + var columns = settings.aoColumns, column; + var features = settings.oFeatures; + + /* Ensure that the table data is fully initialised */ + if ( ! settings.bInitialised ) { + setTimeout( function(){ _fnInitialise( settings ); }, 200 ); + return; + } + + /* Show the display HTML options */ + _fnAddOptionsHtml( settings ); + + /* Build and draw the header / footer for the table */ + _fnBuildHead( settings ); + _fnDrawHead( settings, settings.aoHeader ); + _fnDrawHead( settings, settings.aoFooter ); + + /* Okay to show that something is going on now */ + _fnProcessingDisplay( settings, true ); + + /* Calculate sizes for columns */ + if ( features.bAutoWidth ) { + _fnCalculateColumnWidths( settings ); + } + + for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { + column = columns[i]; + + if ( column.sWidth ) { + column.nTh.style.width = _fnStringToCss( column.sWidth ); + } + } + + // If there is default sorting required - let's do it. The sort function + // will do the drawing for us. Otherwise we draw the table regardless of the + // Ajax source - this allows the table to look initialised for Ajax sourcing + // data (show 'loading' message possibly) + _fnReDraw( settings ); + + // Server-side processing init complete is done by _fnAjaxUpdateDraw + var dataSrc = _fnDataSource( settings ); + if ( dataSrc != 'ssp' ) { + // if there is an ajax source load the data + if ( dataSrc == 'ajax' ) { + _fnBuildAjax( settings, [], function(json) { + var aData = _fnAjaxDataSrc( settings, json ); + + // Got the data - add it to the table + for ( i=0 ; i<aData.length ; i++ ) { + _fnAddData( settings, aData[i] ); + } + + // Reset the init display for cookie saving. We've already done + // a filter, and therefore cleared it before. So we need to make + // it appear 'fresh' + settings.iInitDisplayStart = iAjaxStart; + + _fnReDraw( settings ); + + _fnProcessingDisplay( settings, false ); + _fnInitComplete( settings, json ); + }, settings ); + } + else { + _fnProcessingDisplay( settings, false ); + _fnInitComplete( settings ); + } + } + } + + + /** + * Draw the table for the first time, adding all required features + * @param {object} oSettings dataTables settings object + * @param {object} [json] JSON from the server that completed the table, if using Ajax source + * with client-side processing (optional) + * @memberof DataTable#oApi + */ + function _fnInitComplete ( settings, json ) + { + settings._bInitComplete = true; + + // On an Ajax load we now have data and therefore want to apply the column + // sizing + if ( json ) { + _fnAdjustColumnSizing( settings ); + } + + _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); + } + + + function _fnLengthChange ( settings, val ) + { + var len = parseInt( val, 10 ); + settings._iDisplayLength = len; + + _fnLengthOverflow( settings ); + + // Fire length change event + _fnCallbackFire( settings, null, 'length', [settings, len] ); + } + + + /** + * Generate the node required for user display length changing + * @param {object} settings dataTables settings object + * @returns {node} Display length feature node + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlLength ( settings ) + { + var + classes = settings.oClasses, + tableId = settings.sTableId, + menu = settings.aLengthMenu, + d2 = $.isArray( menu[0] ), + lengths = d2 ? menu[0] : menu, + language = d2 ? menu[1] : menu; + + var select = $('<select/>', { + 'name': tableId+'_length', + 'aria-controls': tableId, + 'class': classes.sLengthSelect + } ); + + for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { + select[0][ i ] = new Option( language[i], lengths[i] ); + } + + var div = $('<div><label/></div>').addClass( classes.sLength ); + if ( ! settings.aanFeatures.l ) { + div[0].id = tableId+'_length'; + } + + div.children().append( + settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) + ); + + // Can't use `select` variable as user might provide their own and the + // reference is broken by the use of outerHTML + $('select', div) + .val( settings._iDisplayLength ) + .bind( 'change.DT', function(e) { + _fnLengthChange( settings, $(this).val() ); + _fnDraw( settings ); + } ); + + // Update node value whenever anything changes the table's length + $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) { + if ( settings === s ) { + $('select', div).val( len ); + } + } ); + + return div[0]; + } + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Note that most of the paging logic is done in + * DataTable.ext.pager + */ + + /** + * Generate the node required for default pagination + * @param {object} oSettings dataTables settings object + * @returns {node} Pagination feature node + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlPaginate ( settings ) + { + var + type = settings.sPaginationType, + plugin = DataTable.ext.pager[ type ], + modern = typeof plugin === 'function', + redraw = function( settings ) { + _fnDraw( settings ); + }, + node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], + features = settings.aanFeatures; + + if ( ! modern ) { + plugin.fnInit( settings, node, redraw ); + } + + /* Add a draw callback for the pagination on first instance, to update the paging display */ + if ( ! features.p ) + { + node.id = settings.sTableId+'_paginate'; + + settings.aoDrawCallback.push( { + "fn": function( settings ) { + if ( modern ) { + var + start = settings._iDisplayStart, + len = settings._iDisplayLength, + visRecords = settings.fnRecordsDisplay(), + all = len === -1, + page = all ? 0 : Math.ceil( start / len ), + pages = all ? 1 : Math.ceil( visRecords / len ), + buttons = plugin(page, pages), + i, ien; + + for ( i=0, ien=features.p.length ; i<ien ; i++ ) { + _fnRenderer( settings, 'pageButton' )( + settings, features.p[i], i, buttons, page, pages + ); + } + } + else { + plugin.fnUpdate( settings, redraw ); + } + }, + "sName": "pagination" + } ); + } + + return node; + } + + + /** + * Alter the display settings to change the page + * @param {object} settings DataTables settings object + * @param {string|int} action Paging action to take: "first", "previous", + * "next" or "last" or page number to jump to (integer) + * @param [bool] redraw Automatically draw the update or not + * @returns {bool} true page has changed, false - no change + * @memberof DataTable#oApi + */ + function _fnPageChange ( settings, action, redraw ) + { + var + start = settings._iDisplayStart, + len = settings._iDisplayLength, + records = settings.fnRecordsDisplay(); + + if ( records === 0 || len === -1 ) + { + start = 0; + } + else if ( typeof action === "number" ) + { + start = action * len; + + if ( start > records ) + { + start = 0; + } + } + else if ( action == "first" ) + { + start = 0; + } + else if ( action == "previous" ) + { + start = len >= 0 ? + start - len : + 0; + + if ( start < 0 ) + { + start = 0; + } + } + else if ( action == "next" ) + { + if ( start + len < records ) + { + start += len; + } + } + else if ( action == "last" ) + { + start = Math.floor( (records-1) / len) * len; + } + else + { + _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); + } + + var changed = settings._iDisplayStart !== start; + settings._iDisplayStart = start; + + if ( changed ) { + _fnCallbackFire( settings, null, 'page', [settings] ); + + if ( redraw ) { + _fnDraw( settings ); + } + } + + return changed; + } + + + + /** + * Generate the node required for the processing node + * @param {object} settings dataTables settings object + * @returns {node} Processing element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlProcessing ( settings ) + { + return $('<div/>', { + 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, + 'class': settings.oClasses.sProcessing + } ) + .html( settings.oLanguage.sProcessing ) + .insertBefore( settings.nTable )[0]; + } + + + /** + * Display or hide the processing indicator + * @param {object} settings dataTables settings object + * @param {bool} show Show the processing indicator (true) or not (false) + * @memberof DataTable#oApi + */ + function _fnProcessingDisplay ( settings, show ) + { + if ( settings.oFeatures.bProcessing ) { + $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); + } + + _fnCallbackFire( settings, null, 'processing', [settings, show] ); + } + + /** + * Add any control elements for the table - specifically scrolling + * @param {object} settings dataTables settings object + * @returns {node} Node to add to the DOM + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlTable ( settings ) + { + var table = $(settings.nTable); + + // Add the ARIA grid role to the table + table.attr( 'role', 'grid' ); + + // Scrolling from here on in + var scroll = settings.oScroll; + + if ( scroll.sX === '' && scroll.sY === '' ) { + return settings.nTable; + } + + var scrollX = scroll.sX; + var scrollY = scroll.sY; + var classes = settings.oClasses; + var caption = table.children('caption'); + var captionSide = caption.length ? caption[0]._captionSide : null; + var headerClone = $( table[0].cloneNode(false) ); + var footerClone = $( table[0].cloneNode(false) ); + var footer = table.children('tfoot'); + var _div = '<div/>'; + var size = function ( s ) { + return !s ? null : _fnStringToCss( s ); + }; + + // This is fairly messy, but with x scrolling enabled, if the table has a + // width attribute, regardless of any width applied using the column width + // options, the browser will shrink or grow the table as needed to fit into + // that 100%. That would make the width options useless. So we remove it. + // This is okay, under the assumption that width:100% is applied to the + // table in CSS (it is in the default stylesheet) which will set the table + // width as appropriate (the attribute and css behave differently...) + if ( scroll.sX && table.attr('width') === '100%' ) { + table.removeAttr('width'); + } + + if ( ! footer.length ) { + footer = null; + } + + /* + * The HTML structure that we want to generate in this function is: + * div - scroller + * div - scroll head + * div - scroll head inner + * table - scroll head table + * thead - thead + * div - scroll body + * table - table (master table) + * thead - thead clone for sizing + * tbody - tbody + * div - scroll foot + * div - scroll foot inner + * table - scroll foot table + * tfoot - tfoot + */ + var scroller = $( _div, { 'class': classes.sScrollWrapper } ) + .append( + $(_div, { 'class': classes.sScrollHead } ) + .css( { + overflow: 'hidden', + position: 'relative', + border: 0, + width: scrollX ? size(scrollX) : '100%' + } ) + .append( + $(_div, { 'class': classes.sScrollHeadInner } ) + .css( { + 'box-sizing': 'content-box', + width: scroll.sXInner || '100%' + } ) + .append( + headerClone + .removeAttr('id') + .css( 'margin-left', 0 ) + .append( captionSide === 'top' ? caption : null ) + .append( + table.children('thead') + ) + ) + ) + ) + .append( + $(_div, { 'class': classes.sScrollBody } ) + .css( { + overflow: 'auto', + height: size( scrollY ), + width: size( scrollX ) + } ) + .append( table ) + ); + + if ( footer ) { + scroller.append( + $(_div, { 'class': classes.sScrollFoot } ) + .css( { + overflow: 'hidden', + border: 0, + width: scrollX ? size(scrollX) : '100%' + } ) + .append( + $(_div, { 'class': classes.sScrollFootInner } ) + .append( + footerClone + .removeAttr('id') + .css( 'margin-left', 0 ) + .append( captionSide === 'bottom' ? caption : null ) + .append( + table.children('tfoot') + ) + ) + ) + ); + } + + var children = scroller.children(); + var scrollHead = children[0]; + var scrollBody = children[1]; + var scrollFoot = footer ? children[2] : null; + + // When the body is scrolled, then we also want to scroll the headers + if ( scrollX ) { + $(scrollBody).scroll( function (e) { + var scrollLeft = this.scrollLeft; + + scrollHead.scrollLeft = scrollLeft; + + if ( footer ) { + scrollFoot.scrollLeft = scrollLeft; + } + } ); + } + + settings.nScrollHead = scrollHead; + settings.nScrollBody = scrollBody; + settings.nScrollFoot = scrollFoot; + + // On redraw - align columns + settings.aoDrawCallback.push( { + "fn": _fnScrollDraw, + "sName": "scrolling" + } ); + + return scroller[0]; + } + + + + /** + * Update the header, footer and body tables for resizing - i.e. column + * alignment. + * + * Welcome to the most horrible function DataTables. The process that this + * function follows is basically: + * 1. Re-create the table inside the scrolling div + * 2. Take live measurements from the DOM + * 3. Apply the measurements to align the columns + * 4. Clean up + * + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnScrollDraw ( settings ) + { + // Given that this is such a monster function, a lot of variables are use + // to try and keep the minimised size as small as possible + var + scroll = settings.oScroll, + scrollX = scroll.sX, + scrollXInner = scroll.sXInner, + scrollY = scroll.sY, + barWidth = scroll.iBarWidth, + divHeader = $(settings.nScrollHead), + divHeaderStyle = divHeader[0].style, + divHeaderInner = divHeader.children('div'), + divHeaderInnerStyle = divHeaderInner[0].style, + divHeaderTable = divHeaderInner.children('table'), + divBodyEl = settings.nScrollBody, + divBody = $(divBodyEl), + divBodyStyle = divBodyEl.style, + divFooter = $(settings.nScrollFoot), + divFooterInner = divFooter.children('div'), + divFooterTable = divFooterInner.children('table'), + header = $(settings.nTHead), + table = $(settings.nTable), + tableEl = table[0], + tableStyle = tableEl.style, + footer = settings.nTFoot ? $(settings.nTFoot) : null, + browser = settings.oBrowser, + ie67 = browser.bScrollOversize, + headerTrgEls, footerTrgEls, + headerSrcEls, footerSrcEls, + headerCopy, footerCopy, + headerWidths=[], footerWidths=[], + headerContent=[], + idx, correction, sanityWidth, + zeroOut = function(nSizer) { + var style = nSizer.style; + style.paddingTop = "0"; + style.paddingBottom = "0"; + style.borderTopWidth = "0"; + style.borderBottomWidth = "0"; + style.height = 0; + }; + + /* + * 1. Re-create the table inside the scrolling div + */ + + // Remove the old minimised thead and tfoot elements in the inner table + table.children('thead, tfoot').remove(); + + // Clone the current header and footer elements and then place it into the inner table + headerCopy = header.clone().prependTo( table ); + headerTrgEls = header.find('tr'); // original header is in its own table + headerSrcEls = headerCopy.find('tr'); + headerCopy.find('th, td').removeAttr('tabindex'); + + if ( footer ) { + footerCopy = footer.clone().prependTo( table ); + footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized + footerSrcEls = footerCopy.find('tr'); + } + + + /* + * 2. Take live measurements from the DOM - do not alter the DOM itself! + */ + + // Remove old sizing and apply the calculated column widths + // Get the unique column headers in the newly created (cloned) header. We want to apply the + // calculated sizes to this header + if ( ! scrollX ) + { + divBodyStyle.width = '100%'; + divHeader[0].style.width = '100%'; + } + + $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { + idx = _fnVisibleToColumnIndex( settings, i ); + el.style.width = settings.aoColumns[idx].sWidth; + } ); + + if ( footer ) { + _fnApplyToChildren( function(n) { + n.style.width = ""; + }, footerSrcEls ); + } + + // If scroll collapse is enabled, when we put the headers back into the body for sizing, we + // will end up forcing the scrollbar to appear, making our measurements wrong for when we + // then hide it (end of this function), so add the header height to the body scroller. + if ( scroll.bCollapse && scrollY !== "" ) { + divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px"; + } + + // Size the table as a whole + sanityWidth = table.outerWidth(); + if ( scrollX === "" ) { + // No x scrolling + tableStyle.width = "100%"; + + // IE7 will make the width of the table when 100% include the scrollbar + // - which is shouldn't. When there is a scrollbar we need to take this + // into account. + if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || + divBody.css('overflow-y') == "scroll") + ) { + tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); + } + } + else + { + // x scrolling + if ( scrollXInner !== "" ) { + // x scroll inner has been given - use it + tableStyle.width = _fnStringToCss(scrollXInner); + } + else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) { + // There is y-scrolling - try to take account of the y scroll bar + tableStyle.width = _fnStringToCss( sanityWidth-barWidth ); + if ( table.outerWidth() > sanityWidth-barWidth ) { + // Not possible to take account of it + tableStyle.width = _fnStringToCss( sanityWidth ); + } + } + else { + // When all else fails + tableStyle.width = _fnStringToCss( sanityWidth ); + } + } + + // Recalculate the sanity width - now that we've applied the required width, + // before it was a temporary variable. This is required because the column + // width calculation is done before this table DOM is created. + sanityWidth = table.outerWidth(); + + // Hidden header should have zero height, so remove padding and borders. Then + // set the width based on the real headers + + // Apply all styles in one pass + _fnApplyToChildren( zeroOut, headerSrcEls ); + + // Read all widths in next pass + _fnApplyToChildren( function(nSizer) { + headerContent.push( nSizer.innerHTML ); + headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); + }, headerSrcEls ); + + // Apply all widths in final pass + _fnApplyToChildren( function(nToSize, i) { + nToSize.style.width = headerWidths[i]; + }, headerTrgEls ); + + $(headerSrcEls).height(0); + + /* Same again with the footer if we have one */ + if ( footer ) + { + _fnApplyToChildren( zeroOut, footerSrcEls ); + + _fnApplyToChildren( function(nSizer) { + footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); + }, footerSrcEls ); + + _fnApplyToChildren( function(nToSize, i) { + nToSize.style.width = footerWidths[i]; + }, footerTrgEls ); + + $(footerSrcEls).height(0); + } + + + /* + * 3. Apply the measurements + */ + + // "Hide" the header and footer that we used for the sizing. We need to keep + // the content of the cell so that the width applied to the header and body + // both match, but we want to hide it completely. We want to also fix their + // width to what they currently are + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; + nSizer.style.width = headerWidths[i]; + }, headerSrcEls ); + + if ( footer ) + { + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = ""; + nSizer.style.width = footerWidths[i]; + }, footerSrcEls ); + } + + // Sanity check that the table is of a sensible width. If not then we are going to get + // misalignment - try to prevent this by not allowing the table to shrink below its min width + if ( table.outerWidth() < sanityWidth ) + { + // The min width depends upon if we have a vertical scrollbar visible or not */ + correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || + divBody.css('overflow-y') == "scroll")) ? + sanityWidth+barWidth : + sanityWidth; + + // IE6/7 are a law unto themselves... + if ( ie67 && (divBodyEl.scrollHeight > + divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") + ) { + tableStyle.width = _fnStringToCss( correction-barWidth ); + } + + // And give the user a warning that we've stopped the table getting too small + if ( scrollX === "" || scrollXInner !== "" ) { + _fnLog( settings, 1, 'Possible column misalignment', 6 ); + } + } + else + { + correction = '100%'; + } + + // Apply to the container elements + divBodyStyle.width = _fnStringToCss( correction ); + divHeaderStyle.width = _fnStringToCss( correction ); + + if ( footer ) { + settings.nScrollFoot.style.width = _fnStringToCss( correction ); + } + + + /* + * 4. Clean up + */ + if ( ! scrollY ) { + /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting + * the scrollbar height from the visible display, rather than adding it on. We need to + * set the height in order to sort this. Don't want to do it in any other browsers. + */ + if ( ie67 ) { + divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); + } + } + + if ( scrollY && scroll.bCollapse ) { + divBodyStyle.height = _fnStringToCss( scrollY ); + + var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ? + barWidth : + 0; + + if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) { + divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra ); + } + } + + /* Finally set the width's of the header and footer tables */ + var iOuterWidth = table.outerWidth(); + divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); + divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); + + // Figure out if there are scrollbar present - if so then we need a the header and footer to + // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) + var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; + var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); + divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; + + if ( footer ) { + divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); + divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); + divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; + } + + /* Adjust the position of the header in case we loose the y-scrollbar */ + divBody.scroll(); + + // If sorting or filtering has occurred, jump the scrolling back to the top + // only if we aren't holding the position + if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { + divBodyEl.scrollTop = 0; + } + } + + + + /** + * Apply a given function to the display child nodes of an element array (typically + * TD children of TR rows + * @param {function} fn Method to apply to the objects + * @param array {nodes} an1 List of elements to look through for display children + * @param array {nodes} an2 Another list (identical structure to the first) - optional + * @memberof DataTable#oApi + */ + function _fnApplyToChildren( fn, an1, an2 ) + { + var index=0, i=0, iLen=an1.length; + var nNode1, nNode2; + + while ( i < iLen ) { + nNode1 = an1[i].firstChild; + nNode2 = an2 ? an2[i].firstChild : null; + + while ( nNode1 ) { + if ( nNode1.nodeType === 1 ) { + if ( an2 ) { + fn( nNode1, nNode2, index ); + } + else { + fn( nNode1, index ); + } + + index++; + } + + nNode1 = nNode1.nextSibling; + nNode2 = an2 ? nNode2.nextSibling : null; + } + + i++; + } + } + + + + var __re_html_remove = /<.*?>/g; + + + /** + * Calculate the width of columns for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnCalculateColumnWidths ( oSettings ) + { + var + table = oSettings.nTable, + columns = oSettings.aoColumns, + scroll = oSettings.oScroll, + scrollY = scroll.sY, + scrollX = scroll.sX, + scrollXInner = scroll.sXInner, + columnCount = columns.length, + visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), + headerCells = $('th', oSettings.nTHead), + tableWidthAttr = table.getAttribute('width'), + tableContainer = table.parentNode, + userInputs = false, + i, column, columnIdx, width, outerWidth; + + /* Convert any user input sizes into pixel sizes */ + for ( i=0 ; i<visibleColumns.length ; i++ ) { + column = columns[ visibleColumns[i] ]; + + if ( column.sWidth !== null ) { + column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); + + userInputs = true; + } + } + + /* If the number of columns in the DOM equals the number that we have to + * process in DataTables, then we can use the offsets that are created by + * the web- browser. No custom sizes can be set in order for this to happen, + * nor scrolling used + */ + if ( ! userInputs && ! scrollX && ! scrollY && + columnCount == _fnVisbleColumns( oSettings ) && + columnCount == headerCells.length + ) { + for ( i=0 ; i<columnCount ; i++ ) { + columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() ); + } + } + else + { + // Otherwise construct a single row table with the widest node in the + // data, assign any user defined widths, then insert it into the DOM and + // allow the browser to do all the hard work of calculating table widths + var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table + .empty() + .css( 'visibility', 'hidden' ) + .removeAttr( 'id' ) + .append( $(oSettings.nTHead).clone( false ) ) + .append( $(oSettings.nTFoot).clone( false ) ) + .append( $('<tbody><tr/></tbody>') ); + + // Remove any assigned widths from the footer (from scrolling) + tmpTable.find('tfoot th, tfoot td').css('width', ''); + + var tr = tmpTable.find( 'tbody tr' ); + + // Apply custom sizing to the cloned header + headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); + + for ( i=0 ; i<visibleColumns.length ; i++ ) { + column = columns[ visibleColumns[i] ]; + + headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? + _fnStringToCss( column.sWidthOrig ) : + ''; + } + + // Find the widest cell for each column and put it into the table + if ( oSettings.aoData.length ) { + for ( i=0 ; i<visibleColumns.length ; i++ ) { + columnIdx = visibleColumns[i]; + column = columns[ columnIdx ]; + + $( _fnGetWidestNode( oSettings, columnIdx ) ) + .clone( false ) + .append( column.sContentPadding ) + .appendTo( tr ); + } + } + + // Table has been built, attach to the document so we can work with it + tmpTable.appendTo( tableContainer ); + + // When scrolling (X or Y) we want to set the width of the table as + // appropriate. However, when not scrolling leave the table width as it + // is. This results in slightly different, but I think correct behaviour + if ( scrollX && scrollXInner ) { + tmpTable.width( scrollXInner ); + } + else if ( scrollX ) { + tmpTable.css( 'width', 'auto' ); + + if ( tmpTable.width() < tableContainer.offsetWidth ) { + tmpTable.width( tableContainer.offsetWidth ); + } + } + else if ( scrollY ) { + tmpTable.width( tableContainer.offsetWidth ); + } + else if ( tableWidthAttr ) { + tmpTable.width( tableWidthAttr ); + } + + // Take into account the y scrollbar + _fnScrollingWidthAdjust( oSettings, tmpTable[0] ); + + // Browsers need a bit of a hand when a width is assigned to any columns + // when x-scrolling as they tend to collapse the table to the min-width, + // even if we sent the column widths. So we need to keep track of what + // the table width should be by summing the user given values, and the + // automatic values + if ( scrollX ) + { + var total = 0; + + for ( i=0 ; i<visibleColumns.length ; i++ ) { + column = columns[ visibleColumns[i] ]; + outerWidth = $(headerCells[i]).outerWidth(); + + total += column.sWidthOrig === null ? + outerWidth : + parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width(); + } + + tmpTable.width( _fnStringToCss( total ) ); + table.style.width = _fnStringToCss( total ); + } + + // Get the width of each column in the constructed table + for ( i=0 ; i<visibleColumns.length ; i++ ) { + column = columns[ visibleColumns[i] ]; + width = $(headerCells[i]).width(); + + if ( width ) { + column.sWidth = _fnStringToCss( width ); + } + } + + table.style.width = _fnStringToCss( tmpTable.css('width') ); + + // Finished with the table - ditch it + tmpTable.remove(); + } + + // If there is a width attr, we want to attach an event listener which + // allows the table sizing to automatically adjust when the window is + // resized. Use the width attr rather than CSS, since we can't know if the + // CSS is a relative value or absolute - DOM read is always px. + if ( tableWidthAttr ) { + table.style.width = _fnStringToCss( tableWidthAttr ); + } + + if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { + $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { + _fnAdjustColumnSizing( oSettings ); + } ) ); + + oSettings._reszEvt = true; + } + } + + + /** + * Throttle the calls to a function. Arguments and context are maintained for + * the throttled function + * @param {function} fn Function to be called + * @param {int} [freq=200] call frequency in mS + * @returns {function} wrapped function + * @memberof DataTable#oApi + */ + function _fnThrottle( fn, freq ) { + var + frequency = freq !== undefined ? freq : 200, + last, + timer; + + return function () { + var + that = this, + now = +new Date(), + args = arguments; + + if ( last && now < last + frequency ) { + clearTimeout( timer ); + + timer = setTimeout( function () { + last = undefined; + fn.apply( that, args ); + }, frequency ); + } + else if ( last ) { + last = now; + fn.apply( that, args ); + } + else { + last = now; + } + }; + } + + + /** + * Convert a CSS unit width to pixels (e.g. 2em) + * @param {string} width width to be converted + * @param {node} parent parent to get the with for (required for relative widths) - optional + * @returns {int} width in pixels + * @memberof DataTable#oApi + */ + function _fnConvertToWidth ( width, parent ) + { + if ( ! width ) { + return 0; + } + + var n = $('<div/>') + .css( 'width', _fnStringToCss( width ) ) + .appendTo( parent || document.body ); + + var val = n[0].offsetWidth; + n.remove(); + + return val; + } + + + /** + * Adjust a table's width to take account of vertical scroll bar + * @param {object} oSettings dataTables settings object + * @param {node} n table node + * @memberof DataTable#oApi + */ + + function _fnScrollingWidthAdjust ( settings, n ) + { + var scroll = settings.oScroll; + + if ( scroll.sX || scroll.sY ) { + // When y-scrolling only, we want to remove the width of the scroll bar + // so the table + scroll bar will fit into the area available, otherwise + // we fix the table at its current size with no adjustment + var correction = ! scroll.sX ? scroll.iBarWidth : 0; + n.style.width = _fnStringToCss( $(n).outerWidth() - correction ); + } + } + + + /** + * Get the widest node + * @param {object} settings dataTables settings object + * @param {int} colIdx column of interest + * @returns {node} widest table node + * @memberof DataTable#oApi + */ + function _fnGetWidestNode( settings, colIdx ) + { + var idx = _fnGetMaxLenString( settings, colIdx ); + if ( idx < 0 ) { + return null; + } + + var data = settings.aoData[ idx ]; + return ! data.nTr ? // Might not have been created when deferred rendering + $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : + data.anCells[ colIdx ]; + } + + + /** + * Get the maximum strlen for each data column + * @param {object} settings dataTables settings object + * @param {int} colIdx column of interest + * @returns {string} max string length for each column + * @memberof DataTable#oApi + */ + function _fnGetMaxLenString( settings, colIdx ) + { + var s, max=-1, maxIdx = -1; + + for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { + s = _fnGetCellData( settings, i, colIdx, 'display' )+''; + s = s.replace( __re_html_remove, '' ); + + if ( s.length > max ) { + max = s.length; + maxIdx = i; + } + } + + return maxIdx; + } + + + /** + * Append a CSS unit (only if required) to a string + * @param {string} value to css-ify + * @returns {string} value with css unit + * @memberof DataTable#oApi + */ + function _fnStringToCss( s ) + { + if ( s === null ) { + return '0px'; + } + + if ( typeof s == 'number' ) { + return s < 0 ? + '0px' : + s+'px'; + } + + // Check it has a unit character already + return s.match(/\d$/) ? + s+'px' : + s; + } + + + /** + * Get the width of a scroll bar in this browser being used + * @returns {int} width in pixels + * @memberof DataTable#oApi + */ + function _fnScrollBarWidth () + { + // On first run a static variable is set, since this is only needed once. + // Subsequent runs will just use the previously calculated value + if ( ! DataTable.__scrollbarWidth ) { + var inner = $('<p/>').css( { + width: '100%', + height: 200, + padding: 0 + } )[0]; + + var outer = $('<div/>') + .css( { + position: 'absolute', + top: 0, + left: 0, + width: 200, + height: 150, + padding: 0, + overflow: 'hidden', + visibility: 'hidden' + } ) + .append( inner ) + .appendTo( 'body' ); + + var w1 = inner.offsetWidth; + outer.css( 'overflow', 'scroll' ); + var w2 = inner.offsetWidth; + + if ( w1 === w2 ) { + w2 = outer[0].clientWidth; + } + + outer.remove(); + + DataTable.__scrollbarWidth = w1 - w2; + } + + return DataTable.__scrollbarWidth; + } + + + + function _fnSortFlatten ( settings ) + { + var + i, iLen, k, kLen, + aSort = [], + aiOrig = [], + aoColumns = settings.aoColumns, + aDataSort, iCol, sType, srcCol, + fixed = settings.aaSortingFixed, + fixedObj = $.isPlainObject( fixed ), + nestedSort = [], + add = function ( a ) { + if ( a.length && ! $.isArray( a[0] ) ) { + // 1D array + nestedSort.push( a ); + } + else { + // 2D array + nestedSort.push.apply( nestedSort, a ); + } + }; + + // Build the sort array, with pre-fix and post-fix options if they have been + // specified + if ( $.isArray( fixed ) ) { + add( fixed ); + } + + if ( fixedObj && fixed.pre ) { + add( fixed.pre ); + } + + add( settings.aaSorting ); + + if (fixedObj && fixed.post ) { + add( fixed.post ); + } + + for ( i=0 ; i<nestedSort.length ; i++ ) + { + srcCol = nestedSort[i][0]; + aDataSort = aoColumns[ srcCol ].aDataSort; + + for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) + { + iCol = aDataSort[k]; + sType = aoColumns[ iCol ].sType || 'string'; + + if ( nestedSort[i]._idx === undefined ) { + nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); + } + + aSort.push( { + src: srcCol, + col: iCol, + dir: nestedSort[i][1], + index: nestedSort[i]._idx, + type: sType, + formatter: DataTable.ext.type.order[ sType+"-pre" ] + } ); + } + } + + return aSort; + } + + /** + * Change the order of the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + * @todo This really needs split up! + */ + function _fnSort ( oSettings ) + { + var + i, ien, iLen, j, jLen, k, kLen, + sDataType, nTh, + aiOrig = [], + oExtSort = DataTable.ext.type.order, + aoData = oSettings.aoData, + aoColumns = oSettings.aoColumns, + aDataSort, data, iCol, sType, oSort, + formatters = 0, + sortCol, + displayMaster = oSettings.aiDisplayMaster, + aSort; + + // Resolve any column types that are unknown due to addition or invalidation + // @todo Can this be moved into a 'data-ready' handler which is called when + // data is going to be used in the table? + _fnColumnTypes( oSettings ); + + aSort = _fnSortFlatten( oSettings ); + + for ( i=0, ien=aSort.length ; i<ien ; i++ ) { + sortCol = aSort[i]; + + // Track if we can use the fast sort algorithm + if ( sortCol.formatter ) { + formatters++; + } + + // Load the data needed for the sort, for each cell + _fnSortData( oSettings, sortCol.col ); + } + + /* No sorting required if server-side or no sorting array */ + if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) + { + // Create a value - key array of the current row positions such that we can use their + // current position during the sort, if values match, in order to perform stable sorting + for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { + aiOrig[ displayMaster[i] ] = i; + } + + /* Do the sort - here we want multi-column sorting based on a given data source (column) + * and sorting function (from oSort) in a certain direction. It's reasonably complex to + * follow on it's own, but this is what we want (example two column sorting): + * fnLocalSorting = function(a,b){ + * var iTest; + * iTest = oSort['string-asc']('data11', 'data12'); + * if (iTest !== 0) + * return iTest; + * iTest = oSort['numeric-desc']('data21', 'data22'); + * if (iTest !== 0) + * return iTest; + * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); + * } + * Basically we have a test for each sorting column, if the data in that column is equal, + * test the next column. If all columns match, then we use a numeric sort on the row + * positions in the original data array to provide a stable sort. + * + * Note - I know it seems excessive to have two sorting methods, but the first is around + * 15% faster, so the second is only maintained for backwards compatibility with sorting + * methods which do not have a pre-sort formatting function. + */ + if ( formatters === aSort.length ) { + // All sort types have formatting functions + displayMaster.sort( function ( a, b ) { + var + x, y, k, test, sort, + len=aSort.length, + dataA = aoData[a]._aSortData, + dataB = aoData[b]._aSortData; + + for ( k=0 ; k<len ; k++ ) { + sort = aSort[k]; + + x = dataA[ sort.col ]; + y = dataB[ sort.col ]; + + test = x<y ? -1 : x>y ? 1 : 0; + if ( test !== 0 ) { + return sort.dir === 'asc' ? test : -test; + } + } + + x = aiOrig[a]; + y = aiOrig[b]; + return x<y ? -1 : x>y ? 1 : 0; + } ); + } + else { + // Depreciated - remove in 1.11 (providing a plug-in option) + // Not all sort types have formatting methods, so we have to call their sorting + // methods. + displayMaster.sort( function ( a, b ) { + var + x, y, k, l, test, sort, fn, + len=aSort.length, + dataA = aoData[a]._aSortData, + dataB = aoData[b]._aSortData; + + for ( k=0 ; k<len ; k++ ) { + sort = aSort[k]; + + x = dataA[ sort.col ]; + y = dataB[ sort.col ]; + + fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; + test = fn( x, y ); + if ( test !== 0 ) { + return test; + } + } + + x = aiOrig[a]; + y = aiOrig[b]; + return x<y ? -1 : x>y ? 1 : 0; + } ); + } + } + + /* Tell the draw function that we have sorted the data */ + oSettings.bSorted = true; + } + + + function _fnSortAria ( settings ) + { + var label; + var nextSort; + var columns = settings.aoColumns; + var aSort = _fnSortFlatten( settings ); + var oAria = settings.oLanguage.oAria; + + // ARIA attributes - need to loop all columns, to update all (removing old + // attributes as needed) + for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) + { + var col = columns[i]; + var asSorting = col.asSorting; + var sTitle = col.sTitle.replace( /<.*?>/g, "" ); + var th = col.nTh; + + // IE7 is throwing an error when setting these properties with jQuery's + // attr() and removeAttr() methods... + th.removeAttribute('aria-sort'); + + /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ + if ( col.bSortable ) { + if ( aSort.length > 0 && aSort[0].col == i ) { + th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); + nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; + } + else { + nextSort = asSorting[0]; + } + + label = sTitle + ( nextSort === "asc" ? + oAria.sSortAscending : + oAria.sSortDescending + ); + } + else { + label = sTitle; + } + + th.setAttribute('aria-label', label); + } + } + + + /** + * Function to run on user sort request + * @param {object} settings dataTables settings object + * @param {node} attachTo node to attach the handler to + * @param {int} colIdx column sorting index + * @param {boolean} [append=false] Append the requested sort to the existing + * sort if true (i.e. multi-column sort) + * @param {function} [callback] callback function + * @memberof DataTable#oApi + */ + function _fnSortListener ( settings, colIdx, append, callback ) + { + var col = settings.aoColumns[ colIdx ]; + var sorting = settings.aaSorting; + var asSorting = col.asSorting; + var nextSortIdx; + var next = function ( a, overflow ) { + var idx = a._idx; + if ( idx === undefined ) { + idx = $.inArray( a[1], asSorting ); + } + + return idx+1 < asSorting.length ? + idx+1 : + overflow ? + null : + 0; + }; + + // Convert to 2D array if needed + if ( typeof sorting[0] === 'number' ) { + sorting = settings.aaSorting = [ sorting ]; + } + + // If appending the sort then we are multi-column sorting + if ( append && settings.oFeatures.bSortMulti ) { + // Are we already doing some kind of sort on this column? + var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); + + if ( sortIdx !== -1 ) { + // Yes, modify the sort + nextSortIdx = next( sorting[sortIdx], true ); + + if ( nextSortIdx === null ) { + sorting.splice( sortIdx, 1 ); + } + else { + sorting[sortIdx][1] = asSorting[ nextSortIdx ]; + sorting[sortIdx]._idx = nextSortIdx; + } + } + else { + // No sort on this column yet + sorting.push( [ colIdx, asSorting[0], 0 ] ); + sorting[sorting.length-1]._idx = 0; + } + } + else if ( sorting.length && sorting[0][0] == colIdx ) { + // Single column - already sorting on this column, modify the sort + nextSortIdx = next( sorting[0] ); + + sorting.length = 1; + sorting[0][1] = asSorting[ nextSortIdx ]; + sorting[0]._idx = nextSortIdx; + } + else { + // Single column - sort only on this column + sorting.length = 0; + sorting.push( [ colIdx, asSorting[0] ] ); + sorting[0]._idx = 0; + } + + // Run the sort by calling a full redraw + _fnReDraw( settings ); + + // callback used for async user interaction + if ( typeof callback == 'function' ) { + callback( settings ); + } + } + + + /** + * Attach a sort handler (click) to a node + * @param {object} settings dataTables settings object + * @param {node} attachTo node to attach the handler to + * @param {int} colIdx column sorting index + * @param {function} [callback] callback function + * @memberof DataTable#oApi + */ + function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) + { + var col = settings.aoColumns[ colIdx ]; + + _fnBindAction( attachTo, {}, function (e) { + /* If the column is not sortable - don't to anything */ + if ( col.bSortable === false ) { + return; + } + + // If processing is enabled use a timeout to allow the processing + // display to be shown - otherwise to it synchronously + if ( settings.oFeatures.bProcessing ) { + _fnProcessingDisplay( settings, true ); + + setTimeout( function() { + _fnSortListener( settings, colIdx, e.shiftKey, callback ); + + // In server-side processing, the draw callback will remove the + // processing display + if ( _fnDataSource( settings ) !== 'ssp' ) { + _fnProcessingDisplay( settings, false ); + } + }, 0 ); + } + else { + _fnSortListener( settings, colIdx, e.shiftKey, callback ); + } + } ); + } + + + /** + * Set the sorting classes on table's body, Note: it is safe to call this function + * when bSort and bSortClasses are false + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnSortingClasses( settings ) + { + var oldSort = settings.aLastSort; + var sortClass = settings.oClasses.sSortColumn; + var sort = _fnSortFlatten( settings ); + var features = settings.oFeatures; + var i, ien, colIdx; + + if ( features.bSort && features.bSortClasses ) { + // Remove old sorting classes + for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { + colIdx = oldSort[i].src; + + // Remove column sorting + $( _pluck( settings.aoData, 'anCells', colIdx ) ) + .removeClass( sortClass + (i<2 ? i+1 : 3) ); + } + + // Add new column sorting + for ( i=0, ien=sort.length ; i<ien ; i++ ) { + colIdx = sort[i].src; + + $( _pluck( settings.aoData, 'anCells', colIdx ) ) + .addClass( sortClass + (i<2 ? i+1 : 3) ); + } + } + + settings.aLastSort = sort; + } + + + // Get the data to sort a column, be it from cache, fresh (populating the + // cache), or from a sort formatter + function _fnSortData( settings, idx ) + { + // Custom sorting function - provided by the sort data type + var column = settings.aoColumns[ idx ]; + var customSort = DataTable.ext.order[ column.sSortDataType ]; + var customData; + + if ( customSort ) { + customData = customSort.call( settings.oInstance, settings, idx, + _fnColumnIndexToVisible( settings, idx ) + ); + } + + // Use / populate cache + var row, cellData; + var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; + + for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { + row = settings.aoData[i]; + + if ( ! row._aSortData ) { + row._aSortData = []; + } + + if ( ! row._aSortData[idx] || customSort ) { + cellData = customSort ? + customData[i] : // If there was a custom sort function, use data from there + _fnGetCellData( settings, i, idx, 'sort' ); + + row._aSortData[ idx ] = formatter ? + formatter( cellData ) : + cellData; + } + } + } + + + + /** + * Save the state of a table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnSaveState ( settings ) + { + if ( !settings.oFeatures.bStateSave || settings.bDestroying ) + { + return; + } + + /* Store the interesting variables */ + var state = { + time: +new Date(), + start: settings._iDisplayStart, + length: settings._iDisplayLength, + order: $.extend( true, [], settings.aaSorting ), + search: _fnSearchToCamel( settings.oPreviousSearch ), + columns: $.map( settings.aoColumns, function ( col, i ) { + return { + visible: col.bVisible, + search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) + }; + } ) + }; + + _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); + + settings.oSavedState = state; + settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); + } + + + /** + * Attempt to load a saved table state + * @param {object} oSettings dataTables settings object + * @param {object} oInit DataTables init object so we can override settings + * @memberof DataTable#oApi + */ + function _fnLoadState ( settings, oInit ) + { + var i, ien; + var columns = settings.aoColumns; + + if ( ! settings.oFeatures.bStateSave ) { + return; + } + + var state = settings.fnStateLoadCallback.call( settings.oInstance, settings ); + if ( ! state || ! state.time ) { + return; + } + + /* Allow custom and plug-in manipulation functions to alter the saved data set and + * cancelling of loading by returning false + */ + var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] ); + if ( $.inArray( false, abStateLoad ) !== -1 ) { + return; + } + + /* Reject old data */ + var duration = settings.iStateDuration; + if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { + return; + } + + // Number of columns have changed - all bets are off, no restore of settings + if ( columns.length !== state.columns.length ) { + return; + } + + // Store the saved state so it might be accessed at any time + settings.oLoadedState = $.extend( true, {}, state ); + + // Restore key features - todo - for 1.11 this needs to be done by + // subscribed events + settings._iDisplayStart = state.start; + settings.iInitDisplayStart = state.start; + settings._iDisplayLength = state.length; + settings.aaSorting = []; + + // Order + $.each( state.order, function ( i, col ) { + settings.aaSorting.push( col[0] >= columns.length ? + [ 0, col[1] ] : + col + ); + } ); + + // Search + $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) ); + + // Columns + for ( i=0, ien=state.columns.length ; i<ien ; i++ ) { + var col = state.columns[i]; + + // Visibility + columns[i].bVisible = col.visible; + + // Search + $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); + } + + _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] ); + } + + + /** + * Return the settings object for a particular table + * @param {node} table table we are using as a dataTable + * @returns {object} Settings object - or null if not found + * @memberof DataTable#oApi + */ + function _fnSettingsFromNode ( table ) + { + var settings = DataTable.settings; + var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); + + return idx !== -1 ? + settings[ idx ] : + null; + } + + + /** + * Log an error message + * @param {object} settings dataTables settings object + * @param {int} level log error messages, or display them to the user + * @param {string} msg error message + * @param {int} tn Technical note id to get more information about the error. + * @memberof DataTable#oApi + */ + function _fnLog( settings, level, msg, tn ) + { + msg = 'DataTables warning: '+ + (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg; + + if ( tn ) { + msg += '. For more information about this error, please see '+ + 'http://datatables.net/tn/'+tn; + } + + if ( ! level ) { + // Backwards compatibility pre 1.10 + var ext = DataTable.ext; + var type = ext.sErrMode || ext.errMode; + + if ( type == 'alert' ) { + alert( msg ); + } + else { + throw new Error(msg); + } + } + else if ( window.console && console.log ) { + console.log( msg ); + } + } + + + /** + * See if a property is defined on one object, if so assign it to the other object + * @param {object} ret target object + * @param {object} src source object + * @param {string} name property + * @param {string} [mappedName] name to map too - optional, name used if not given + * @memberof DataTable#oApi + */ + function _fnMap( ret, src, name, mappedName ) + { + if ( $.isArray( name ) ) { + $.each( name, function (i, val) { + if ( $.isArray( val ) ) { + _fnMap( ret, src, val[0], val[1] ); + } + else { + _fnMap( ret, src, val ); + } + } ); + + return; + } + + if ( mappedName === undefined ) { + mappedName = name; + } + + if ( src[name] !== undefined ) { + ret[mappedName] = src[name]; + } + } + + + /** + * Extend objects - very similar to jQuery.extend, but deep copy objects, and + * shallow copy arrays. The reason we need to do this, is that we don't want to + * deep copy array init values (such as aaSorting) since the dev wouldn't be + * able to override them, but we do want to deep copy arrays. + * @param {object} out Object to extend + * @param {object} extender Object from which the properties will be applied to + * out + * @param {boolean} breakRefs If true, then arrays will be sliced to take an + * independent copy with the exception of the `data` or `aaData` parameters + * if they are present. This is so you can pass in a collection to + * DataTables and have that used as your data source without breaking the + * references + * @returns {object} out Reference, just for convenience - out === the return. + * @memberof DataTable#oApi + * @todo This doesn't take account of arrays inside the deep copied objects. + */ + function _fnExtend( out, extender, breakRefs ) + { + var val; + + for ( var prop in extender ) { + if ( extender.hasOwnProperty(prop) ) { + val = extender[prop]; + + if ( $.isPlainObject( val ) ) { + if ( ! $.isPlainObject( out[prop] ) ) { + out[prop] = {}; + } + $.extend( true, out[prop], val ); + } + else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { + out[prop] = val.slice(); + } + else { + out[prop] = val; + } + } + } + + return out; + } + + + /** + * Bind an event handers to allow a click or return key to activate the callback. + * This is good for accessibility since a return on the keyboard will have the + * same effect as a click, if the element has focus. + * @param {element} n Element to bind the action to + * @param {object} oData Data object to pass to the triggered function + * @param {function} fn Callback function for when the event is triggered + * @memberof DataTable#oApi + */ + function _fnBindAction( n, oData, fn ) + { + $(n) + .bind( 'click.DT', oData, function (e) { + n.blur(); // Remove focus outline for mouse users + fn(e); + } ) + .bind( 'keypress.DT', oData, function (e){ + if ( e.which === 13 ) { + e.preventDefault(); + fn(e); + } + } ) + .bind( 'selectstart.DT', function () { + /* Take the brutal approach to cancelling text selection */ + return false; + } ); + } + + + /** + * Register a callback function. Easily allows a callback function to be added to + * an array store of callback functions that can then all be called together. + * @param {object} oSettings dataTables settings object + * @param {string} sStore Name of the array storage for the callbacks in oSettings + * @param {function} fn Function to be called back + * @param {string} sName Identifying name for the callback (i.e. a label) + * @memberof DataTable#oApi + */ + function _fnCallbackReg( oSettings, sStore, fn, sName ) + { + if ( fn ) + { + oSettings[sStore].push( { + "fn": fn, + "sName": sName + } ); + } + } + + + /** + * Fire callback functions and trigger events. Note that the loop over the + * callback array store is done backwards! Further note that you do not want to + * fire off triggers in time sensitive applications (for example cell creation) + * as its slow. + * @param {object} settings dataTables settings object + * @param {string} callbackArr Name of the array storage for the callbacks in + * oSettings + * @param {string} event Name of the jQuery custom event to trigger. If null no + * trigger is fired + * @param {array} args Array of arguments to pass to the callback function / + * trigger + * @memberof DataTable#oApi + */ + function _fnCallbackFire( settings, callbackArr, e, args ) + { + var ret = []; + + if ( callbackArr ) { + ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { + return val.fn.apply( settings.oInstance, args ); + } ); + } + + if ( e !== null ) { + $(settings.nTable).trigger( e+'.dt', args ); + } + + return ret; + } + + + function _fnLengthOverflow ( settings ) + { + var + start = settings._iDisplayStart, + end = settings.fnDisplayEnd(), + len = settings._iDisplayLength; + + /* If we have space to show extra rows (backing up from the end point - then do so */ + if ( start >= end ) + { + start = end - len; + } + + // Keep the start record on the current page + start -= (start % len); + + if ( len === -1 || start < 0 ) + { + start = 0; + } + + settings._iDisplayStart = start; + } + + + function _fnRenderer( settings, type ) + { + var renderer = settings.renderer; + var host = DataTable.ext.renderer[type]; + + if ( $.isPlainObject( renderer ) && renderer[type] ) { + // Specific renderer for this type. If available use it, otherwise use + // the default. + return host[renderer[type]] || host._; + } + else if ( typeof renderer === 'string' ) { + // Common renderer - if there is one available for this type use it, + // otherwise use the default + return host[renderer] || host._; + } + + // Use the default + return host._; + } + + + /** + * Detect the data source being used for the table. Used to simplify the code + * a little (ajax) and to make it compress a little smaller. + * + * @param {object} settings dataTables settings object + * @returns {string} Data source + * @memberof DataTable#oApi + */ + function _fnDataSource ( settings ) + { + if ( settings.oFeatures.bServerSide ) { + return 'ssp'; + } + else if ( settings.ajax || settings.sAjaxSource ) { + return 'ajax'; + } + return 'dom'; + } + + + DataTable = function( options ) + { + /** + * Perform a jQuery selector action on the table's TR elements (from the tbody) and + * return the resulting jQuery object. + * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on + * @param {object} [oOpts] Optional parameters for modifying the rows to be included + * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter + * criterion ("applied") or all TR elements (i.e. no filter). + * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. + * Can be either 'current', whereby the current sorting of the table is used, or + * 'original' whereby the original order the data was read into the table is used. + * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page + * ("current") or not ("all"). If 'current' is given, then order is assumed to be + * 'current' and filter is 'applied', regardless of what they might be given as. + * @returns {object} jQuery object, filtered by the given selector. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Highlight every second row + * oTable.$('tr:odd').css('backgroundColor', 'blue'); + * } ); + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Filter to rows with 'Webkit' in them, add a background colour and then + * // remove the filter, thus highlighting the 'Webkit' rows only. + * oTable.fnFilter('Webkit'); + * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); + * oTable.fnFilter(''); + * } ); + */ + this.$ = function ( sSelector, oOpts ) + { + return this.api(true).$( sSelector, oOpts ); + }; + + + /** + * Almost identical to $ in operation, but in this case returns the data for the matched + * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes + * rather than any descendants, so the data can be obtained for the row/cell. If matching + * rows are found, the data returned is the original data array/object that was used to + * create the row (or a generated array if from a DOM source). + * + * This method is often useful in-combination with $ where both functions are given the + * same parameters and the array indexes will match identically. + * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on + * @param {object} [oOpts] Optional parameters for modifying the rows to be included + * @param {string} [oOpts.filter=none] Select elements that meet the current filter + * criterion ("applied") or all elements (i.e. no filter). + * @param {string} [oOpts.order=current] Order of the data in the processed array. + * Can be either 'current', whereby the current sorting of the table is used, or + * 'original' whereby the original order the data was read into the table is used. + * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page + * ("current") or not ("all"). If 'current' is given, then order is assumed to be + * 'current' and filter is 'applied', regardless of what they might be given as. + * @returns {array} Data for the matched elements. If any elements, as a result of the + * selector, were not TR, TD or TH elements in the DataTable, they will have a null + * entry in the array. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Get the data from the first row in the table + * var data = oTable._('tr:first'); + * + * // Do something useful with the data + * alert( "First cell is: "+data[0] ); + * } ); + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Filter to 'Webkit' and get all data for + * oTable.fnFilter('Webkit'); + * var data = oTable._('tr', {"search": "applied"}); + * + * // Do something with the data + * alert( data.length+" rows matched the search" ); + * } ); + */ + this._ = function ( sSelector, oOpts ) + { + return this.api(true).rows( sSelector, oOpts ).data(); + }; + + + /** + * Create a DataTables Api instance, with the currently selected tables for + * the Api's context. + * @param {boolean} [traditional=false] Set the API instance's context to be + * only the table referred to by the `DataTable.ext.iApiIndex` option, as was + * used in the API presented by DataTables 1.9- (i.e. the traditional mode), + * or if all tables captured in the jQuery object should be used. + * @return {DataTables.Api} + */ + this.api = function ( traditional ) + { + return traditional ? + new _Api( + _fnSettingsFromNode( this[ _ext.iApiIndex ] ) + ) : + new _Api( this ); + }; + + + /** + * Add a single new row or multiple rows of data to the table. Please note + * that this is suitable for client-side processing only - if you are using + * server-side processing (i.e. "bServerSide": true), then to add data, you + * must add it to the data source, i.e. the server-side, through an Ajax call. + * @param {array|object} data The data to be added to the table. This can be: + * <ul> + * <li>1D array of data - add a single row with the data provided</li> + * <li>2D array of arrays - add multiple rows in a single call</li> + * <li>object - data object when using <i>mData</i></li> + * <li>array of objects - multiple data objects when using <i>mData</i></li> + * </ul> + * @param {bool} [redraw=true] redraw the table or not + * @returns {array} An array of integers, representing the list of indexes in + * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to + * the table. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * // Global var for counter + * var giCount = 2; + * + * $(document).ready(function() { + * $('#example').dataTable(); + * } ); + * + * function fnClickAddRow() { + * $('#example').dataTable().fnAddData( [ + * giCount+".1", + * giCount+".2", + * giCount+".3", + * giCount+".4" ] + * ); + * + * giCount++; + * } + */ + this.fnAddData = function( data, redraw ) + { + var api = this.api( true ); + + /* Check if we want to add multiple rows or not */ + var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? + api.rows.add( data ) : + api.row.add( data ); + + if ( redraw === undefined || redraw ) { + api.draw(); + } + + return rows.flatten().toArray(); + }; + + + /** + * This function will make DataTables recalculate the column sizes, based on the data + * contained in the table and the sizes applied to the columns (in the DOM, CSS or + * through the sWidth parameter). This can be useful when the width of the table's + * parent element changes (for example a window resize). + * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * + * $(window).bind('resize', function () { + * oTable.fnAdjustColumnSizing(); + * } ); + * } ); + */ + this.fnAdjustColumnSizing = function ( bRedraw ) + { + var api = this.api( true ).columns.adjust(); + var settings = api.settings()[0]; + var scroll = settings.oScroll; + + if ( bRedraw === undefined || bRedraw ) { + api.draw( false ); + } + else if ( scroll.sX !== "" || scroll.sY !== "" ) { + /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ + _fnScrollDraw( settings ); + } + }; + + + /** + * Quickly and simply clear a table + * @param {bool} [bRedraw=true] redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) + * oTable.fnClearTable(); + * } ); + */ + this.fnClearTable = function( bRedraw ) + { + var api = this.api( true ).clear(); + + if ( bRedraw === undefined || bRedraw ) { + api.draw(); + } + }; + + + /** + * The exact opposite of 'opening' a row, this function will close any rows which + * are currently 'open'. + * @param {node} nTr the table row to 'close' + * @returns {int} 0 on success, or 1 if failed (can't find the row) + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnClose = function( nTr ) + { + this.api( true ).row( nTr ).child.hide(); + }; + + + /** + * Remove a row for the table + * @param {mixed} target The index of the row from aoData to be deleted, or + * the TR element you want to delete + * @param {function|null} [callBack] Callback function + * @param {bool} [redraw=true] Redraw the table or not + * @returns {array} The row that was deleted + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Immediately remove the first row + * oTable.fnDeleteRow( 0 ); + * } ); + */ + this.fnDeleteRow = function( target, callback, redraw ) + { + var api = this.api( true ); + var rows = api.rows( target ); + var settings = rows.settings()[0]; + var data = settings.aoData[ rows[0][0] ]; + + rows.remove(); + + if ( callback ) { + callback.call( this, settings, data ); + } + + if ( redraw === undefined || redraw ) { + api.draw(); + } + + return data; + }; + + + /** + * Restore the table to it's original state in the DOM by removing all of DataTables + * enhancements, alterations to the DOM structure of the table and event listeners. + * @param {boolean} [remove=false] Completely remove the table from the DOM + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * // This example is fairly pointless in reality, but shows how fnDestroy can be used + * var oTable = $('#example').dataTable(); + * oTable.fnDestroy(); + * } ); + */ + this.fnDestroy = function ( remove ) + { + this.api( true ).destroy( remove ); + }; + + + /** + * Redraw the table + * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) + * oTable.fnDraw(); + * } ); + */ + this.fnDraw = function( complete ) + { + // Note that this isn't an exact match to the old call to _fnDraw - it takes + // into account the new data, but can old position. + this.api( true ).draw( ! complete ); + }; + + + /** + * Filter the input based on data + * @param {string} sInput String to filter the table on + * @param {int|null} [iColumn] Column to limit filtering to + * @param {bool} [bRegex=false] Treat as regular expression or not + * @param {bool} [bSmart=true] Perform smart filtering or not + * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) + * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sometime later - filter... + * oTable.fnFilter( 'test string' ); + * } ); + */ + this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) + { + var api = this.api( true ); + + if ( iColumn === null || iColumn === undefined ) { + api.search( sInput, bRegex, bSmart, bCaseInsensitive ); + } + else { + api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); + } + + api.draw(); + }; + + + /** + * Get the data for the whole table, an individual row or an individual cell based on the + * provided parameters. + * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as + * a TR node then the data source for the whole row will be returned. If given as a + * TD/TH cell node then iCol will be automatically calculated and the data for the + * cell returned. If given as an integer, then this is treated as the aoData internal + * data index for the row (see fnGetPosition) and the data for that row used. + * @param {int} [col] Optional column index that you want the data of. + * @returns {array|object|string} If mRow is undefined, then the data for all rows is + * returned. If mRow is defined, just data for that row, and is iCol is + * defined, only data for the designated cell is returned. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * // Row data + * $(document).ready(function() { + * oTable = $('#example').dataTable(); + * + * oTable.$('tr').click( function () { + * var data = oTable.fnGetData( this ); + * // ... do something with the array / object of data for the row + * } ); + * } ); + * + * @example + * // Individual cell data + * $(document).ready(function() { + * oTable = $('#example').dataTable(); + * + * oTable.$('td').click( function () { + * var sData = oTable.fnGetData( this ); + * alert( 'The cell clicked on had the value of '+sData ); + * } ); + * } ); + */ + this.fnGetData = function( src, col ) + { + var api = this.api( true ); + + if ( src !== undefined ) { + var type = src.nodeName ? src.nodeName.toLowerCase() : ''; + + return col !== undefined || type == 'td' || type == 'th' ? + api.cell( src, col ).data() : + api.row( src ).data() || null; + } + + return api.data().toArray(); + }; + + + /** + * Get an array of the TR nodes that are used in the table's body. Note that you will + * typically want to use the '$' API method in preference to this as it is more + * flexible. + * @param {int} [iRow] Optional row index for the TR element you want + * @returns {array|node} If iRow is undefined, returns an array of all TR elements + * in the table's body, or iRow is defined, just the TR element requested. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Get the nodes from the table + * var nNodes = oTable.fnGetNodes( ); + * } ); + */ + this.fnGetNodes = function( iRow ) + { + var api = this.api( true ); + + return iRow !== undefined ? + api.row( iRow ).node() : + api.rows().nodes().flatten().toArray(); + }; + + + /** + * Get the array indexes of a particular cell from it's DOM element + * and column index including hidden columns + * @param {node} node this can either be a TR, TD or TH in the table's body + * @returns {int} If nNode is given as a TR, then a single index is returned, or + * if given as a cell, an array of [row index, column index (visible), + * column index (all)] is given. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * $('#example tbody td').click( function () { + * // Get the position of the current data from the node + * var aPos = oTable.fnGetPosition( this ); + * + * // Get the data array for this row + * var aData = oTable.fnGetData( aPos[0] ); + * + * // Update the data array and return the value + * aData[ aPos[1] ] = 'clicked'; + * this.innerHTML = 'clicked'; + * } ); + * + * // Init DataTables + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnGetPosition = function( node ) + { + var api = this.api( true ); + var nodeName = node.nodeName.toUpperCase(); + + if ( nodeName == 'TR' ) { + return api.row( node ).index(); + } + else if ( nodeName == 'TD' || nodeName == 'TH' ) { + var cell = api.cell( node ).index(); + + return [ + cell.row, + cell.columnVisible, + cell.column + ]; + } + return null; + }; + + + /** + * Check to see if a row is 'open' or not. + * @param {node} nTr the table row to check + * @returns {boolean} true if the row is currently open, false otherwise + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnIsOpen = function( nTr ) + { + return this.api( true ).row( nTr ).child.isShown(); + }; + + + /** + * This function will place a new row directly after a row which is currently + * on display on the page, with the HTML contents that is passed into the + * function. This can be used, for example, to ask for confirmation that a + * particular record should be deleted. + * @param {node} nTr The table row to 'open' + * @param {string|node|jQuery} mHtml The HTML to put into the row + * @param {string} sClass Class to give the new TD cell + * @returns {node} The row opened. Note that if the table row passed in as the + * first parameter, is not found in the table, this method will silently + * return. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnOpen = function( nTr, mHtml, sClass ) + { + return this.api( true ) + .row( nTr ) + .child( mHtml, sClass ) + .show() + .child()[0]; + }; + + + /** + * Change the pagination - provides the internal logic for pagination in a simple API + * function. With this function you can have a DataTables table go to the next, + * previous, first or last pages. + * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" + * or page number to jump to (integer), note that page 0 is the first page. + * @param {bool} [bRedraw=true] Redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * oTable.fnPageChange( 'next' ); + * } ); + */ + this.fnPageChange = function ( mAction, bRedraw ) + { + var api = this.api( true ).page( mAction ); + + if ( bRedraw === undefined || bRedraw ) { + api.draw(false); + } + }; + + + /** + * Show a particular column + * @param {int} iCol The column whose display should be changed + * @param {bool} bShow Show (true) or hide (false) the column + * @param {bool} [bRedraw=true] Redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Hide the second column after initialisation + * oTable.fnSetColumnVis( 1, false ); + * } ); + */ + this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) + { + var api = this.api( true ).column( iCol ).visible( bShow ); + + if ( bRedraw === undefined || bRedraw ) { + api.columns.adjust().draw(); + } + }; + + + /** + * Get the settings for a particular table for external manipulation + * @returns {object} DataTables settings object. See + * {@link DataTable.models.oSettings} + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * var oSettings = oTable.fnSettings(); + * + * // Show an example parameter from the settings + * alert( oSettings._iDisplayStart ); + * } ); + */ + this.fnSettings = function() + { + return _fnSettingsFromNode( this[_ext.iApiIndex] ); + }; + + + /** + * Sort the table by a particular column + * @param {int} iCol the data index to sort on. Note that this will not match the + * 'display index' if you have hidden data entries + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sort immediately with columns 0 and 1 + * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); + * } ); + */ + this.fnSort = function( aaSort ) + { + this.api( true ).order( aaSort ).draw(); + }; + + + /** + * Attach a sort listener to an element for a given column + * @param {node} nNode the element to attach the sort listener to + * @param {int} iColumn the column that a click on this node will sort on + * @param {function} [fnCallback] callback function when sort is run + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sort on column 1, when 'sorter' is clicked on + * oTable.fnSortListener( document.getElementById('sorter'), 1 ); + * } ); + */ + this.fnSortListener = function( nNode, iColumn, fnCallback ) + { + this.api( true ).order.listener( nNode, iColumn, fnCallback ); + }; + + + /** + * Update a table cell or row - this method will accept either a single value to + * update the cell with, an array of values with one element for each column or + * an object in the same format as the original data source. The function is + * self-referencing in order to make the multi column updates easier. + * @param {object|array|string} mData Data to update the cell/row with + * @param {node|int} mRow TR element you want to update or the aoData index + * @param {int} [iColumn] The column to update, give as null or undefined to + * update a whole row. + * @param {bool} [bRedraw=true] Redraw the table or not + * @param {bool} [bAction=true] Perform pre-draw actions or not + * @returns {int} 0 on success, 1 on error + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell + * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row + * } ); + */ + this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) + { + var api = this.api( true ); + + if ( iColumn === undefined || iColumn === null ) { + api.row( mRow ).data( mData ); + } + else { + api.cell( mRow, iColumn ).data( mData ); + } + + if ( bAction === undefined || bAction ) { + api.columns.adjust(); + } + + if ( bRedraw === undefined || bRedraw ) { + api.draw(); + } + return 0; + }; + + + /** + * Provide a common method for plug-ins to check the version of DataTables being used, in order + * to ensure compatibility. + * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the + * formats "X" and "X.Y" are also acceptable. + * @returns {boolean} true if this version of DataTables is greater or equal to the required + * version, or false if this version of DataTales is not suitable + * @method + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * alert( oTable.fnVersionCheck( '1.9.0' ) ); + * } ); + */ + this.fnVersionCheck = _ext.fnVersionCheck; + + + var _that = this; + var emptyInit = options === undefined; + var len = this.length; + + if ( emptyInit ) { + options = {}; + } + + this.oApi = this.internal = _ext.internal; + + // Extend with old style plug-in API methods + for ( var fn in DataTable.ext.internal ) { + if ( fn ) { + this[fn] = _fnExternApiFunc(fn); + } + } + + this.each(function() { + // For each initialisation we want to give it a clean initialisation + // object that can be bashed around + var o = {}; + var oInit = len > 1 ? // optimisation for single table case + _fnExtend( o, options, true ) : + options; + + /*global oInit,_that,emptyInit*/ + var i=0, iLen, j, jLen, k, kLen; + var sId = this.getAttribute( 'id' ); + var bInitHandedOff = false; + var defaults = DataTable.defaults; + + + /* Sanity check */ + if ( this.nodeName.toLowerCase() != 'table' ) + { + _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); + return; + } + + /* Backwards compatibility for the defaults */ + _fnCompatOpts( defaults ); + _fnCompatCols( defaults.column ); + + /* Convert the camel-case defaults to Hungarian */ + _fnCamelToHungarian( defaults, defaults, true ); + _fnCamelToHungarian( defaults.column, defaults.column, true ); + + /* Setting up the initialisation object */ + _fnCamelToHungarian( defaults, oInit ); + + /* Check to see if we are re-initialising a table */ + var allSettings = DataTable.settings; + for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) + { + /* Base check on table node */ + if ( allSettings[i].nTable == this ) + { + var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; + var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; + + if ( emptyInit || bRetrieve ) + { + return allSettings[i].oInstance; + } + else if ( bDestroy ) + { + allSettings[i].oInstance.fnDestroy(); + break; + } + else + { + _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 ); + return; + } + } + + /* If the element we are initialising has the same ID as a table which was previously + * initialised, but the table nodes don't match (from before) then we destroy the old + * instance by simply deleting it. This is under the assumption that the table has been + * destroyed by other methods. Anyone using non-id selectors will need to do this manually + */ + if ( allSettings[i].sTableId == this.id ) + { + allSettings.splice( i, 1 ); + break; + } + } + + /* Ensure the table has an ID - required for accessibility */ + if ( sId === null || sId === "" ) + { + sId = "DataTables_Table_"+(DataTable.ext._unique++); + this.id = sId; + } + + /* Create the settings object for this table and set some of the default parameters */ + var oSettings = $.extend( true, {}, DataTable.models.oSettings, { + "nTable": this, + "oApi": _that.internal, + "oInit": oInit, + "sDestroyWidth": $(this)[0].style.width, + "sInstance": sId, + "sTableId": sId + } ); + allSettings.push( oSettings ); + + // Need to add the instance after the instance after the settings object has been added + // to the settings array, so we can self reference the table instance if more than one + oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable(); + + // Backwards compatibility, before we apply all the defaults + _fnCompatOpts( oInit ); + + if ( oInit.oLanguage ) + { + _fnLanguageCompat( oInit.oLanguage ); + } + + // If the length menu is given, but the init display length is not, use the length menu + if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) + { + oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? + oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; + } + + // Apply the defaults and init options to make a single init object will all + // options defined from defaults and instance options. + oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); + + + // Map the initialisation options onto the settings object + _fnMap( oSettings.oFeatures, oInit, [ + "bPaginate", + "bLengthChange", + "bFilter", + "bSort", + "bSortMulti", + "bInfo", + "bProcessing", + "bAutoWidth", + "bSortClasses", + "bServerSide", + "bDeferRender" + ] ); + _fnMap( oSettings, oInit, [ + "asStripeClasses", + "ajax", + "fnServerData", + "fnFormatNumber", + "sServerMethod", + "aaSorting", + "aaSortingFixed", + "aLengthMenu", + "sPaginationType", + "sAjaxSource", + "sAjaxDataProp", + "iStateDuration", + "sDom", + "bSortCellsTop", + "iTabIndex", + "fnStateLoadCallback", + "fnStateSaveCallback", + "renderer", + "searchDelay", + [ "iCookieDuration", "iStateDuration" ], // backwards compat + [ "oSearch", "oPreviousSearch" ], + [ "aoSearchCols", "aoPreSearchCols" ], + [ "iDisplayLength", "_iDisplayLength" ], + [ "bJQueryUI", "bJUI" ] + ] ); + _fnMap( oSettings.oScroll, oInit, [ + [ "sScrollX", "sX" ], + [ "sScrollXInner", "sXInner" ], + [ "sScrollY", "sY" ], + [ "bScrollCollapse", "bCollapse" ] + ] ); + _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); + + /* Callback functions which are array driven */ + _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); + _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); + _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); + _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); + _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); + _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); + _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); + _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); + _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); + _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); + _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); + + var oClasses = oSettings.oClasses; + + // @todo Remove in 1.11 + if ( oInit.bJQueryUI ) + { + /* Use the JUI classes object for display. You could clone the oStdClasses object if + * you want to have multiple tables with multiple independent classes + */ + $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses ); + + if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" ) + { + /* Set the DOM to use a layout suitable for jQuery UI's theming */ + oSettings.sDom = '<"H"lfr>t<"F"ip>'; + } + + if ( ! oSettings.renderer ) { + oSettings.renderer = 'jqueryui'; + } + else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) { + oSettings.renderer.header = 'jqueryui'; + } + } + else + { + $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); + } + $(this).addClass( oClasses.sTable ); + + /* Calculate the scroll bar width and cache it for use later on */ + if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) + { + oSettings.oScroll.iBarWidth = _fnScrollBarWidth(); + } + if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling + oSettings.oScroll.sX = '100%'; + } + + if ( oSettings.iInitDisplayStart === undefined ) + { + /* Display start point, taking into account the save saving */ + oSettings.iInitDisplayStart = oInit.iDisplayStart; + oSettings._iDisplayStart = oInit.iDisplayStart; + } + + if ( oInit.iDeferLoading !== null ) + { + oSettings.bDeferLoading = true; + var tmp = $.isArray( oInit.iDeferLoading ); + oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; + oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; + } + + /* Language definitions */ + var oLanguage = oSettings.oLanguage; + $.extend( true, oLanguage, oInit.oLanguage ); + + if ( oLanguage.sUrl !== "" ) + { + /* Get the language definitions from a file - because this Ajax call makes the language + * get async to the remainder of this function we use bInitHandedOff to indicate that + * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor + */ + $.ajax( { + dataType: 'json', + url: oLanguage.sUrl, + success: function ( json ) { + _fnLanguageCompat( json ); + _fnCamelToHungarian( defaults.oLanguage, json ); + $.extend( true, oLanguage, json ); + _fnInitialise( oSettings ); + }, + error: function () { + // Error occurred loading language file, continue on as best we can + _fnInitialise( oSettings ); + } + } ); + bInitHandedOff = true; + } + + /* + * Stripes + */ + if ( oInit.asStripeClasses === null ) + { + oSettings.asStripeClasses =[ + oClasses.sStripeOdd, + oClasses.sStripeEven + ]; + } + + /* Remove row stripe classes if they are already on the table row */ + var stripeClasses = oSettings.asStripeClasses; + var rowOne = $('tbody tr:eq(0)', this); + if ( $.inArray( true, $.map( stripeClasses, function(el, i) { + return rowOne.hasClass(el); + } ) ) !== -1 ) { + $('tbody tr', this).removeClass( stripeClasses.join(' ') ); + oSettings.asDestroyStripes = stripeClasses.slice(); + } + + /* + * Columns + * See if we should load columns automatically or use defined ones + */ + var anThs = []; + var aoColumnsInit; + var nThead = this.getElementsByTagName('thead'); + if ( nThead.length !== 0 ) + { + _fnDetectHeader( oSettings.aoHeader, nThead[0] ); + anThs = _fnGetUniqueThs( oSettings ); + } + + /* If not given a column array, generate one with nulls */ + if ( oInit.aoColumns === null ) + { + aoColumnsInit = []; + for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) + { + aoColumnsInit.push( null ); + } + } + else + { + aoColumnsInit = oInit.aoColumns; + } + + /* Add the columns */ + for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) + { + _fnAddColumn( oSettings, anThs ? anThs[i] : null ); + } + + /* Apply the column definitions */ + _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { + _fnColumnOptions( oSettings, iCol, oDef ); + } ); + + /* HTML5 attribute detection - build an mData object automatically if the + * attributes are found + */ + if ( rowOne.length ) { + var a = function ( cell, name ) { + return cell.getAttribute( 'data-'+name ) ? name : null; + }; + + $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) { + var col = oSettings.aoColumns[i]; + + if ( col.mData === i ) { + var sort = a( cell, 'sort' ) || a( cell, 'order' ); + var filter = a( cell, 'filter' ) || a( cell, 'search' ); + + if ( sort !== null || filter !== null ) { + col.mData = { + _: i+'.display', + sort: sort !== null ? i+'.@data-'+sort : undefined, + type: sort !== null ? i+'.@data-'+sort : undefined, + filter: filter !== null ? i+'.@data-'+filter : undefined + }; + + _fnColumnOptions( oSettings, i ); + } + } + } ); + } + + var features = oSettings.oFeatures; + + /* Must be done after everything which can be overridden by the state saving! */ + if ( oInit.bStateSave ) + { + features.bStateSave = true; + _fnLoadState( oSettings, oInit ); + _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); + } + + + /* + * Sorting + * @todo For modularisation (1.11) this needs to do into a sort start up handler + */ + + // If aaSorting is not defined, then we use the first indicator in asSorting + // in case that has been altered, so the default sort reflects that option + if ( oInit.aaSorting === undefined ) + { + var sorting = oSettings.aaSorting; + for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) + { + sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; + } + } + + /* Do a first pass on the sorting classes (allows any size changes to be taken into + * account, and also will apply sorting disabled classes if disabled + */ + _fnSortingClasses( oSettings ); + + if ( features.bSort ) + { + _fnCallbackReg( oSettings, 'aoDrawCallback', function () { + if ( oSettings.bSorted ) { + var aSort = _fnSortFlatten( oSettings ); + var sortedColumns = {}; + + $.each( aSort, function (i, val) { + sortedColumns[ val.src ] = val.dir; + } ); + + _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); + _fnSortAria( oSettings ); + } + } ); + } + + _fnCallbackReg( oSettings, 'aoDrawCallback', function () { + if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { + _fnSortingClasses( oSettings ); + } + }, 'sc' ); + + + /* + * Final init + * Cache the header, body and footer as required, creating them if needed + */ + + /* Browser support detection */ + _fnBrowserDetect( oSettings ); + + // Work around for Webkit bug 83867 - store the caption-side before removing from doc + var captions = $(this).children('caption').each( function () { + this._captionSide = $(this).css('caption-side'); + } ); + + var thead = $(this).children('thead'); + if ( thead.length === 0 ) + { + thead = $('<thead/>').appendTo(this); + } + oSettings.nTHead = thead[0]; + + var tbody = $(this).children('tbody'); + if ( tbody.length === 0 ) + { + tbody = $('<tbody/>').appendTo(this); + } + oSettings.nTBody = tbody[0]; + + var tfoot = $(this).children('tfoot'); + if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) + { + // If we are a scrolling table, and no footer has been given, then we need to create + // a tfoot element for the caption element to be appended to + tfoot = $('<tfoot/>').appendTo(this); + } + + if ( tfoot.length === 0 || tfoot.children().length === 0 ) { + $(this).addClass( oClasses.sNoFooter ); + } + else if ( tfoot.length > 0 ) { + oSettings.nTFoot = tfoot[0]; + _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); + } + + /* Check if there is data passing into the constructor */ + if ( oInit.aaData ) + { + for ( i=0 ; i<oInit.aaData.length ; i++ ) + { + _fnAddData( oSettings, oInit.aaData[ i ] ); + } + } + else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) + { + /* Grab the data from the page - only do this when deferred loading or no Ajax + * source since there is no point in reading the DOM data if we are then going + * to replace it with Ajax data + */ + _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); + } + + /* Copy the data index array */ + oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); + + /* Initialisation complete - table can be drawn */ + oSettings.bInitialised = true; + + /* Check if we need to initialise the table (it might not have been handed off to the + * language processor) + */ + if ( bInitHandedOff === false ) + { + _fnInitialise( oSettings ); + } + } ); + _that = null; + return this; + }; + + + + /** + * Computed structure of the DataTables API, defined by the options passed to + * `DataTable.Api.register()` when building the API. + * + * The structure is built in order to speed creation and extension of the Api + * objects since the extensions are effectively pre-parsed. + * + * The array is an array of objects with the following structure, where this + * base array represents the Api prototype base: + * + * [ + * { + * name: 'data' -- string - Property name + * val: function () {}, -- function - Api method (or undefined if just an object + * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result + * propExt: [ ... ] -- array - Array of Api object definitions to extend the property + * }, + * { + * name: 'row' + * val: {}, + * methodExt: [ ... ], + * propExt: [ + * { + * name: 'data' + * val: function () {}, + * methodExt: [ ... ], + * propExt: [ ... ] + * }, + * ... + * ] + * } + * ] + * + * @type {Array} + * @ignore + */ + var __apiStruct = []; + + + /** + * `Array.prototype` reference. + * + * @type object + * @ignore + */ + var __arrayProto = Array.prototype; + + + /** + * Abstraction for `context` parameter of the `Api` constructor to allow it to + * take several different forms for ease of use. + * + * Each of the input parameter types will be converted to a DataTables settings + * object where possible. + * + * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one + * of: + * + * * `string` - jQuery selector. Any DataTables' matching the given selector + * with be found and used. + * * `node` - `TABLE` node which has already been formed into a DataTable. + * * `jQuery` - A jQuery object of `TABLE` nodes. + * * `object` - DataTables settings object + * * `DataTables.Api` - API instance + * @return {array|null} Matching DataTables settings objects. `null` or + * `undefined` is returned if no matching DataTable is found. + * @ignore + */ + var _toSettings = function ( mixed ) + { + var idx, jq; + var settings = DataTable.settings; + var tables = $.map( settings, function (el, i) { + return el.nTable; + } ); + + if ( ! mixed ) { + return []; + } + else if ( mixed.nTable && mixed.oApi ) { + // DataTables settings object + return [ mixed ]; + } + else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { + // Table node + idx = $.inArray( mixed, tables ); + return idx !== -1 ? [ settings[idx] ] : null; + } + else if ( mixed && typeof mixed.settings === 'function' ) { + return mixed.settings().toArray(); + } + else if ( typeof mixed === 'string' ) { + // jQuery selector + jq = $(mixed); + } + else if ( mixed instanceof $ ) { + // jQuery object (also DataTables instance) + jq = mixed; + } + + if ( jq ) { + return jq.map( function(i) { + idx = $.inArray( this, tables ); + return idx !== -1 ? settings[idx] : null; + } ).toArray(); + } + }; + + + /** + * DataTables API class - used to control and interface with one or more + * DataTables enhanced tables. + * + * The API class is heavily based on jQuery, presenting a chainable interface + * that you can use to interact with tables. Each instance of the API class has + * a "context" - i.e. the tables that it will operate on. This could be a single + * table, all tables on a page or a sub-set thereof. + * + * Additionally the API is designed to allow you to easily work with the data in + * the tables, retrieving and manipulating it as required. This is done by + * presenting the API class as an array like interface. The contents of the + * array depend upon the actions requested by each method (for example + * `rows().nodes()` will return an array of nodes, while `rows().data()` will + * return an array of objects or arrays depending upon your table's + * configuration). The API object has a number of array like methods (`push`, + * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, + * `unique` etc) to assist your working with the data held in a table. + * + * Most methods (those which return an Api instance) are chainable, which means + * the return from a method call also has all of the methods available that the + * top level object had. For example, these two calls are equivalent: + * + * // Not chained + * api.row.add( {...} ); + * api.draw(); + * + * // Chained + * api.row.add( {...} ).draw(); + * + * @class DataTable.Api + * @param {array|object|string|jQuery} context DataTable identifier. This is + * used to define which DataTables enhanced tables this API will operate on. + * Can be one of: + * + * * `string` - jQuery selector. Any DataTables' matching the given selector + * with be found and used. + * * `node` - `TABLE` node which has already been formed into a DataTable. + * * `jQuery` - A jQuery object of `TABLE` nodes. + * * `object` - DataTables settings object + * @param {array} [data] Data to initialise the Api instance with. + * + * @example + * // Direct initialisation during DataTables construction + * var api = $('#example').DataTable(); + * + * @example + * // Initialisation using a DataTables jQuery object + * var api = $('#example').dataTable().api(); + * + * @example + * // Initialisation as a constructor + * var api = new $.fn.DataTable.Api( 'table.dataTable' ); + */ + _Api = function ( context, data ) + { + if ( ! this instanceof _Api ) { + throw 'DT API must be constructed as a new object'; + // or should it do the 'new' for the caller? + // return new _Api.apply( this, arguments ); + } + + var settings = []; + var ctxSettings = function ( o ) { + var a = _toSettings( o ); + if ( a ) { + settings.push.apply( settings, a ); + } + }; + + if ( $.isArray( context ) ) { + for ( var i=0, ien=context.length ; i<ien ; i++ ) { + ctxSettings( context[i] ); + } + } + else { + ctxSettings( context ); + } + + // Remove duplicates + this.context = _unique( settings ); + + // Initial data + if ( data ) { + this.push.apply( this, data.toArray ? data.toArray() : data ); + } + + // selector + this.selector = { + rows: null, + cols: null, + opts: null + }; + + _Api.extend( this, this, __apiStruct ); + }; + + DataTable.Api = _Api; + + _Api.prototype = /** @lends DataTables.Api */{ + /** + * Return a new Api instance, comprised of the data held in the current + * instance, join with the other array(s) and/or value(s). + * + * An alias for `Array.prototype.concat`. + * + * @type method + * @param {*} value1 Arrays and/or values to concatenate. + * @param {*} [...] Additional arrays and/or values to concatenate. + * @returns {DataTables.Api} New API instance, comprising of the combined + * array. + */ + concat: __arrayProto.concat, + + + context: [], // array of table settings objects + + + each: function ( fn ) + { + for ( var i=0, ien=this.length ; i<ien; i++ ) { + fn.call( this, this[i], i, this ); + } + + return this; + }, + + + eq: function ( idx ) + { + var ctx = this.context; + + return ctx.length > idx ? + new _Api( ctx[idx], this[idx] ) : + null; + }, + + + filter: function ( fn ) + { + var a = []; + + if ( __arrayProto.filter ) { + a = __arrayProto.filter.call( this, fn, this ); + } + else { + // Compatibility for browsers without EMCA-252-5 (JS 1.6) + for ( var i=0, ien=this.length ; i<ien ; i++ ) { + if ( fn.call( this, this[i], i, this ) ) { + a.push( this[i] ); + } + } + } + + return new _Api( this.context, a ); + }, + + + flatten: function () + { + var a = []; + return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); + }, + + + join: __arrayProto.join, + + + indexOf: __arrayProto.indexOf || function (obj, start) + { + for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { + if ( this[i] === obj ) { + return i; + } + } + return -1; + }, + + // Note that `alwaysNew` is internal - use iteratorNew externally + iterator: function ( flatten, type, fn, alwaysNew ) { + var + a = [], ret, + i, ien, j, jen, + context = this.context, + rows, items, item, + selector = this.selector; + + // Argument shifting + if ( typeof flatten === 'string' ) { + alwaysNew = fn; + fn = type; + type = flatten; + flatten = false; + } + + for ( i=0, ien=context.length ; i<ien ; i++ ) { + var apiInst = new _Api( context[i] ); + + if ( type === 'table' ) { + ret = fn.call( apiInst, context[i], i ); + + if ( ret !== undefined ) { + a.push( ret ); + } + } + else if ( type === 'columns' || type === 'rows' ) { + // this has same length as context - one entry for each table + ret = fn.call( apiInst, context[i], this[i], i ); + + if ( ret !== undefined ) { + a.push( ret ); + } + } + else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { + // columns and rows share the same structure. + // 'this' is an array of column indexes for each context + items = this[i]; + + if ( type === 'column-rows' ) { + rows = _selector_row_indexes( context[i], selector.opts ); + } + + for ( j=0, jen=items.length ; j<jen ; j++ ) { + item = items[j]; + + if ( type === 'cell' ) { + ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); + } + else { + ret = fn.call( apiInst, context[i], item, i, j, rows ); + } + + if ( ret !== undefined ) { + a.push( ret ); + } + } + } + } + + if ( a.length || alwaysNew ) { + var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); + var apiSelector = api.selector; + apiSelector.rows = selector.rows; + apiSelector.cols = selector.cols; + apiSelector.opts = selector.opts; + return api; + } + return this; + }, + + + lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) + { + // Bit cheeky... + return this.indexOf.apply( this.toArray.reverse(), arguments ); + }, + + + length: 0, + + + map: function ( fn ) + { + var a = []; + + if ( __arrayProto.map ) { + a = __arrayProto.map.call( this, fn, this ); + } + else { + // Compatibility for browsers without EMCA-252-5 (JS 1.6) + for ( var i=0, ien=this.length ; i<ien ; i++ ) { + a.push( fn.call( this, this[i], i ) ); + } + } + + return new _Api( this.context, a ); + }, + + + pluck: function ( prop ) + { + return this.map( function ( el ) { + return el[ prop ]; + } ); + }, + + pop: __arrayProto.pop, + + + push: __arrayProto.push, + + + // Does not return an API instance + reduce: __arrayProto.reduce || function ( fn, init ) + { + return _fnReduce( this, fn, init, 0, this.length, 1 ); + }, + + + reduceRight: __arrayProto.reduceRight || function ( fn, init ) + { + return _fnReduce( this, fn, init, this.length-1, -1, -1 ); + }, + + + reverse: __arrayProto.reverse, + + + // Object with rows, columns and opts + selector: null, + + + shift: __arrayProto.shift, + + + sort: __arrayProto.sort, // ? name - order? + + + splice: __arrayProto.splice, + + + toArray: function () + { + return __arrayProto.slice.call( this ); + }, + + + to$: function () + { + return $( this ); + }, + + + toJQuery: function () + { + return $( this ); + }, + + + unique: function () + { + return new _Api( this.context, _unique(this) ); + }, + + + unshift: __arrayProto.unshift + }; + + + _Api.extend = function ( scope, obj, ext ) + { + // Only extend API instances and static properties of the API + if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { + return; + } + + var + i, ien, + j, jen, + struct, inner, + methodScoping = function ( scope, fn, struc ) { + return function () { + var ret = fn.apply( scope, arguments ); + + // Method extension + _Api.extend( ret, ret, struc.methodExt ); + return ret; + }; + }; + + for ( i=0, ien=ext.length ; i<ien ; i++ ) { + struct = ext[i]; + + // Value + obj[ struct.name ] = typeof struct.val === 'function' ? + methodScoping( scope, struct.val, struct ) : + $.isPlainObject( struct.val ) ? + {} : + struct.val; + + obj[ struct.name ].__dt_wrapper = true; + + // Property extension + _Api.extend( scope, obj[ struct.name ], struct.propExt ); + } + }; + + + // @todo - Is there need for an augment function? + // _Api.augment = function ( inst, name ) + // { + // // Find src object in the structure from the name + // var parts = name.split('.'); + + // _Api.extend( inst, obj ); + // }; + + + // [ + // { + // name: 'data' -- string - Property name + // val: function () {}, -- function - Api method (or undefined if just an object + // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result + // propExt: [ ... ] -- array - Array of Api object definitions to extend the property + // }, + // { + // name: 'row' + // val: {}, + // methodExt: [ ... ], + // propExt: [ + // { + // name: 'data' + // val: function () {}, + // methodExt: [ ... ], + // propExt: [ ... ] + // }, + // ... + // ] + // } + // ] + + _Api.register = _api_register = function ( name, val ) + { + if ( $.isArray( name ) ) { + for ( var j=0, jen=name.length ; j<jen ; j++ ) { + _Api.register( name[j], val ); + } + return; + } + + var + i, ien, + heir = name.split('.'), + struct = __apiStruct, + key, method; + + var find = function ( src, name ) { + for ( var i=0, ien=src.length ; i<ien ; i++ ) { + if ( src[i].name === name ) { + return src[i]; + } + } + return null; + }; + + for ( i=0, ien=heir.length ; i<ien ; i++ ) { + method = heir[i].indexOf('()') !== -1; + key = method ? + heir[i].replace('()', '') : + heir[i]; + + var src = find( struct, key ); + if ( ! src ) { + src = { + name: key, + val: {}, + methodExt: [], + propExt: [] + }; + struct.push( src ); + } + + if ( i === ien-1 ) { + src.val = val; + } + else { + struct = method ? + src.methodExt : + src.propExt; + } + } + }; + + + _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { + _Api.register( pluralName, val ); + + _Api.register( singularName, function () { + var ret = val.apply( this, arguments ); + + if ( ret === this ) { + // Returned item is the API instance that was passed in, return it + return this; + } + else if ( ret instanceof _Api ) { + // New API instance returned, want the value from the first item + // in the returned array for the singular result. + return ret.length ? + $.isArray( ret[0] ) ? + new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' + ret[0] : + undefined; + } + + // Non-API return - just fire it back + return ret; + } ); + }; + + + /** + * Selector for HTML tables. Apply the given selector to the give array of + * DataTables settings objects. + * + * @param {string|integer} [selector] jQuery selector string or integer + * @param {array} Array of DataTables settings objects to be filtered + * @return {array} + * @ignore + */ + var __table_selector = function ( selector, a ) + { + // Integer is used to pick out a table by index + if ( typeof selector === 'number' ) { + return [ a[ selector ] ]; + } + + // Perform a jQuery selector on the table nodes + var nodes = $.map( a, function (el, i) { + return el.nTable; + } ); + + return $(nodes) + .filter( selector ) + .map( function (i) { + // Need to translate back from the table node to the settings + var idx = $.inArray( this, nodes ); + return a[ idx ]; + } ) + .toArray(); + }; + + + + /** + * Context selector for the API's context (i.e. the tables the API instance + * refers to. + * + * @name DataTable.Api#tables + * @param {string|integer} [selector] Selector to pick which tables the iterator + * should operate on. If not given, all tables in the current context are + * used. This can be given as a jQuery selector (for example `':gt(0)'`) to + * select multiple tables or as an integer to select a single table. + * @returns {DataTable.Api} Returns a new API instance if a selector is given. + */ + _api_register( 'tables()', function ( selector ) { + // A new instance is created if there was a selector specified + return selector ? + new _Api( __table_selector( selector, this.context ) ) : + this; + } ); + + + _api_register( 'table()', function ( selector ) { + var tables = this.tables( selector ); + var ctx = tables.context; + + // Truncate to the first matched table + return ctx.length ? + new _Api( ctx[0] ) : + tables; + } ); + + + _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { + return this.iterator( 'table', function ( ctx ) { + return ctx.nTable; + }, 1 ); + } ); + + + _api_registerPlural( 'tables().body()', 'table().body()' , function () { + return this.iterator( 'table', function ( ctx ) { + return ctx.nTBody; + }, 1 ); + } ); + + + _api_registerPlural( 'tables().header()', 'table().header()' , function () { + return this.iterator( 'table', function ( ctx ) { + return ctx.nTHead; + }, 1 ); + } ); + + + _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { + return this.iterator( 'table', function ( ctx ) { + return ctx.nTFoot; + }, 1 ); + } ); + + + _api_registerPlural( 'tables().containers()', 'table().container()' , function () { + return this.iterator( 'table', function ( ctx ) { + return ctx.nTableWrapper; + }, 1 ); + } ); + + + + /** + * Redraw the tables in the current context. + * + * @param {boolean} [reset=true] Reset (default) or hold the current paging + * position. A full re-sort and re-filter is performed when this method is + * called, which is why the pagination reset is the default action. + * @returns {DataTables.Api} this + */ + _api_register( 'draw()', function ( resetPaging ) { + return this.iterator( 'table', function ( settings ) { + _fnReDraw( settings, resetPaging===false ); + } ); + } ); + + + + /** + * Get the current page index. + * + * @return {integer} Current page index (zero based) + *//** + * Set the current page. + * + * Note that if you attempt to show a page which does not exist, DataTables will + * not throw an error, but rather reset the paging. + * + * @param {integer|string} action The paging action to take. This can be one of: + * * `integer` - The page index to jump to + * * `string` - An action to take: + * * `first` - Jump to first page. + * * `next` - Jump to the next page + * * `previous` - Jump to previous page + * * `last` - Jump to the last page. + * @returns {DataTables.Api} this + */ + _api_register( 'page()', function ( action ) { + if ( action === undefined ) { + return this.page.info().page; // not an expensive call + } + + // else, have an action to take on all tables + return this.iterator( 'table', function ( settings ) { + _fnPageChange( settings, action ); + } ); + } ); + + + /** + * Paging information for the first table in the current context. + * + * If you require paging information for another table, use the `table()` method + * with a suitable selector. + * + * @return {object} Object with the following properties set: + * * `page` - Current page index (zero based - i.e. the first page is `0`) + * * `pages` - Total number of pages + * * `start` - Display index for the first record shown on the current page + * * `end` - Display index for the last record shown on the current page + * * `length` - Display length (number of records). Note that generally `start + * + length = end`, but this is not always true, for example if there are + * only 2 records to show on the final page, with a length of 10. + * * `recordsTotal` - Full data set length + * * `recordsDisplay` - Data set length once the current filtering criterion + * are applied. + */ + _api_register( 'page.info()', function ( action ) { + if ( this.context.length === 0 ) { + return undefined; + } + + var + settings = this.context[0], + start = settings._iDisplayStart, + len = settings._iDisplayLength, + visRecords = settings.fnRecordsDisplay(), + all = len === -1; + + return { + "page": all ? 0 : Math.floor( start / len ), + "pages": all ? 1 : Math.ceil( visRecords / len ), + "start": start, + "end": settings.fnDisplayEnd(), + "length": len, + "recordsTotal": settings.fnRecordsTotal(), + "recordsDisplay": visRecords + }; + } ); + + + /** + * Get the current page length. + * + * @return {integer} Current page length. Note `-1` indicates that all records + * are to be shown. + *//** + * Set the current page length. + * + * @param {integer} Page length to set. Use `-1` to show all records. + * @returns {DataTables.Api} this + */ + _api_register( 'page.len()', function ( len ) { + // Note that we can't call this function 'length()' because `length` + // is a Javascript property of functions which defines how many arguments + // the function expects. + if ( len === undefined ) { + return this.context.length !== 0 ? + this.context[0]._iDisplayLength : + undefined; + } + + // else, set the page length + return this.iterator( 'table', function ( settings ) { + _fnLengthChange( settings, len ); + } ); + } ); + + + + var __reload = function ( settings, holdPosition, callback ) { + if ( _fnDataSource( settings ) == 'ssp' ) { + _fnReDraw( settings, holdPosition ); + } + else { + // Trigger xhr + _fnProcessingDisplay( settings, true ); + + _fnBuildAjax( settings, [], function( json ) { + _fnClearTable( settings ); + + var data = _fnAjaxDataSrc( settings, json ); + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + _fnAddData( settings, data[i] ); + } + + _fnReDraw( settings, holdPosition ); + _fnProcessingDisplay( settings, false ); + } ); + } + + // Use the draw event to trigger a callback, regardless of if it is an async + // or sync draw + if ( callback ) { + var api = new _Api( settings ); + + api.one( 'draw', function () { + callback( api.ajax.json() ); + } ); + } + }; + + + /** + * Get the JSON response from the last Ajax request that DataTables made to the + * server. Note that this returns the JSON from the first table in the current + * context. + * + * @return {object} JSON received from the server. + */ + _api_register( 'ajax.json()', function () { + var ctx = this.context; + + if ( ctx.length > 0 ) { + return ctx[0].json; + } + + // else return undefined; + } ); + + + /** + * Get the data submitted in the last Ajax request + */ + _api_register( 'ajax.params()', function () { + var ctx = this.context; + + if ( ctx.length > 0 ) { + return ctx[0].oAjaxData; + } + + // else return undefined; + } ); + + + /** + * Reload tables from the Ajax data source. Note that this function will + * automatically re-draw the table when the remote data has been loaded. + * + * @param {boolean} [reset=true] Reset (default) or hold the current paging + * position. A full re-sort and re-filter is performed when this method is + * called, which is why the pagination reset is the default action. + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.reload()', function ( callback, resetPaging ) { + return this.iterator( 'table', function (settings) { + __reload( settings, resetPaging===false, callback ); + } ); + } ); + + + /** + * Get the current Ajax URL. Note that this returns the URL from the first + * table in the current context. + * + * @return {string} Current Ajax source URL + *//** + * Set the Ajax URL. Note that this will set the URL for all tables in the + * current context. + * + * @param {string} url URL to set. + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.url()', function ( url ) { + var ctx = this.context; + + if ( url === undefined ) { + // get + if ( ctx.length === 0 ) { + return undefined; + } + ctx = ctx[0]; + + return ctx.ajax ? + $.isPlainObject( ctx.ajax ) ? + ctx.ajax.url : + ctx.ajax : + ctx.sAjaxSource; + } + + // set + return this.iterator( 'table', function ( settings ) { + if ( $.isPlainObject( settings.ajax ) ) { + settings.ajax.url = url; + } + else { + settings.ajax = url; + } + // No need to consider sAjaxSource here since DataTables gives priority + // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any + // value of `sAjaxSource` redundant. + } ); + } ); + + + /** + * Load data from the newly set Ajax URL. Note that this method is only + * available when `ajax.url()` is used to set a URL. Additionally, this method + * has the same effect as calling `ajax.reload()` but is provided for + * convenience when setting a new URL. Like `ajax.reload()` it will + * automatically redraw the table once the remote data has been loaded. + * + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { + // Same as a reload, but makes sense to present it for easy access after a + // url change + return this.iterator( 'table', function ( ctx ) { + __reload( ctx, resetPaging===false, callback ); + } ); + } ); + + + + + var _selector_run = function ( selector, select ) + { + var + out = [], res, + a, i, ien, j, jen, + selectorType = typeof selector; + + // Can't just check for isArray here, as an API or jQuery instance might be + // given with their array like look + if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { + selector = [ selector ]; + } + + for ( i=0, ien=selector.length ; i<ien ; i++ ) { + a = selector[i] && selector[i].split ? + selector[i].split(',') : + [ selector[i] ]; + + for ( j=0, jen=a.length ; j<jen ; j++ ) { + res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] ); + + if ( res && res.length ) { + out.push.apply( out, res ); + } + } + } + + return out; + }; + + + var _selector_opts = function ( opts ) + { + if ( ! opts ) { + opts = {}; + } + + // Backwards compatibility for 1.9- which used the terminology filter rather + // than search + if ( opts.filter && ! opts.search ) { + opts.search = opts.filter; + } + + return { + search: opts.search || 'none', + order: opts.order || 'current', + page: opts.page || 'all' + }; + }; + + + var _selector_first = function ( inst ) + { + // Reduce the API instance to the first item found + for ( var i=0, ien=inst.length ; i<ien ; i++ ) { + if ( inst[i].length > 0 ) { + // Assign the first element to the first item in the instance + // and truncate the instance and context + inst[0] = inst[i]; + inst.length = 1; + inst.context = [ inst.context[i] ]; + + return inst; + } + } + + // Not found - return an empty instance + inst.length = 0; + return inst; + }; + + + var _selector_row_indexes = function ( settings, opts ) + { + var + i, ien, tmp, a=[], + displayFiltered = settings.aiDisplay, + displayMaster = settings.aiDisplayMaster; + + var + search = opts.search, // none, applied, removed + order = opts.order, // applied, current, index (original - compatibility with 1.9) + page = opts.page; // all, current + + if ( _fnDataSource( settings ) == 'ssp' ) { + // In server-side processing mode, most options are irrelevant since + // rows not shown don't exist and the index order is the applied order + // Removed is a special case - for consistency just return an empty + // array + return search === 'removed' ? + [] : + _range( 0, displayMaster.length ); + } + else if ( page == 'current' ) { + // Current page implies that order=current and fitler=applied, since it is + // fairly senseless otherwise, regardless of what order and search actually + // are + for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { + a.push( displayFiltered[i] ); + } + } + else if ( order == 'current' || order == 'applied' ) { + a = search == 'none' ? + displayMaster.slice() : // no search + search == 'applied' ? + displayFiltered.slice() : // applied search + $.map( displayMaster, function (el, i) { // removed search + return $.inArray( el, displayFiltered ) === -1 ? el : null; + } ); + } + else if ( order == 'index' || order == 'original' ) { + for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { + if ( search == 'none' ) { + a.push( i ); + } + else { // applied | removed + tmp = $.inArray( i, displayFiltered ); + + if ((tmp === -1 && search == 'removed') || + (tmp >= 0 && search == 'applied') ) + { + a.push( i ); + } + } + } + } + + return a; + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Rows + * + * {} - no selector - use all available rows + * {integer} - row aoData index + * {node} - TR node + * {string} - jQuery selector to apply to the TR elements + * {array} - jQuery array of nodes, or simply an array of TR nodes + * + */ + + + var __row_selector = function ( settings, selector, opts ) + { + return _selector_run( selector, function ( sel ) { + var selInt = _intVal( sel ); + var i, ien; + + // Short cut - selector is a number and no options provided (default is + // all records, so no need to check if the index is in there, since it + // must be - dev error if the index doesn't exist). + if ( selInt !== null && ! opts ) { + return [ selInt ]; + } + + var rows = _selector_row_indexes( settings, opts ); + + if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { + // Selector - integer + return [ selInt ]; + } + else if ( ! sel ) { + // Selector - none + return rows; + } + + // Selector - function + if ( typeof sel === 'function' ) { + return $.map( rows, function (idx) { + var row = settings.aoData[ idx ]; + return sel( idx, row._aData, row.nTr ) ? idx : null; + } ); + } + + // Get nodes in the order from the `rows` array with null values removed + var nodes = _removeEmpty( + _pluck_order( settings.aoData, rows, 'nTr' ) + ); + + // Selector - node + if ( sel.nodeName ) { + if ( $.inArray( sel, nodes ) !== -1 ) { + return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table + // and DataTables adds a prop for fast lookup + } + } + + // Selector - jQuery selector string, array of nodes or jQuery object/ + // As jQuery's .filter() allows jQuery objects to be passed in filter, + // it also allows arrays, so this will cope with all three options + return $(nodes) + .filter( sel ) + .map( function () { + return this._DT_RowIndex; + } ) + .toArray(); + } ); + }; + + + /** + * + */ + _api_register( 'rows()', function ( selector, opts ) { + // argument shifting + if ( selector === undefined ) { + selector = ''; + } + else if ( $.isPlainObject( selector ) ) { + opts = selector; + selector = ''; + } + + opts = _selector_opts( opts ); + + var inst = this.iterator( 'table', function ( settings ) { + return __row_selector( settings, selector, opts ); + }, 1 ); + + // Want argument shifting here and in __row_selector? + inst.selector.rows = selector; + inst.selector.opts = opts; + + return inst; + } ); + + + _api_register( 'rows().nodes()', function () { + return this.iterator( 'row', function ( settings, row ) { + return settings.aoData[ row ].nTr || undefined; + }, 1 ); + } ); + + _api_register( 'rows().data()', function () { + return this.iterator( true, 'rows', function ( settings, rows ) { + return _pluck_order( settings.aoData, rows, '_aData' ); + }, 1 ); + } ); + + _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { + return this.iterator( 'row', function ( settings, row ) { + var r = settings.aoData[ row ]; + return type === 'search' ? r._aFilterData : r._aSortData; + }, 1 ); + } ); + + _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { + return this.iterator( 'row', function ( settings, row ) { + _fnInvalidate( settings, row, src ); + } ); + } ); + + _api_registerPlural( 'rows().indexes()', 'row().index()', function () { + return this.iterator( 'row', function ( settings, row ) { + return row; + }, 1 ); + } ); + + _api_registerPlural( 'rows().remove()', 'row().remove()', function () { + var that = this; + + return this.iterator( 'row', function ( settings, row, thatIdx ) { + var data = settings.aoData; + + data.splice( row, 1 ); + + // Update the _DT_RowIndex parameter on all rows in the table + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + if ( data[i].nTr !== null ) { + data[i].nTr._DT_RowIndex = i; + } + } + + // Remove the target row from the search array + var displayIndex = $.inArray( row, settings.aiDisplay ); + + // Delete from the display arrays + _fnDeleteIndex( settings.aiDisplayMaster, row ); + _fnDeleteIndex( settings.aiDisplay, row ); + _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes + + // Check for an 'overflow' they case for displaying the table + _fnLengthOverflow( settings ); + } ); + } ); + + + _api_register( 'rows.add()', function ( rows ) { + var newRows = this.iterator( 'table', function ( settings ) { + var row, i, ien; + var out = []; + + for ( i=0, ien=rows.length ; i<ien ; i++ ) { + row = rows[i]; + + if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { + out.push( _fnAddTr( settings, row )[0] ); + } + else { + out.push( _fnAddData( settings, row ) ); + } + } + + return out; + }, 1 ); + + // Return an Api.rows() extended instance, so rows().nodes() etc can be used + var modRows = this.rows( -1 ); + modRows.pop(); + modRows.push.apply( modRows, newRows.toArray() ); + + return modRows; + } ); + + + + + + /** + * + */ + _api_register( 'row()', function ( selector, opts ) { + return _selector_first( this.rows( selector, opts ) ); + } ); + + + _api_register( 'row().data()', function ( data ) { + var ctx = this.context; + + if ( data === undefined ) { + // Get + return ctx.length && this.length ? + ctx[0].aoData[ this[0] ]._aData : + undefined; + } + + // Set + ctx[0].aoData[ this[0] ]._aData = data; + + // Automatically invalidate + _fnInvalidate( ctx[0], this[0], 'data' ); + + return this; + } ); + + + _api_register( 'row().node()', function () { + var ctx = this.context; + + return ctx.length && this.length ? + ctx[0].aoData[ this[0] ].nTr || null : + null; + } ); + + + _api_register( 'row.add()', function ( row ) { + // Allow a jQuery object to be passed in - only a single row is added from + // it though - the first element in the set + if ( row instanceof $ && row.length ) { + row = row[0]; + } + + var rows = this.iterator( 'table', function ( settings ) { + if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { + return _fnAddTr( settings, row )[0]; + } + return _fnAddData( settings, row ); + } ); + + // Return an Api.rows() extended instance, with the newly added row selected + return this.row( rows[0] ); + } ); + + + + var __details_add = function ( ctx, row, data, klass ) + { + // Convert to array of TR elements + var rows = []; + var addRow = function ( r, k ) { + // If we get a TR element, then just add it directly - up to the dev + // to add the correct number of columns etc + if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { + rows.push( r ); + } + else { + // Otherwise create a row with a wrapper + var created = $('<tr><td/></tr>').addClass( k ); + $('td', created) + .addClass( k ) + .html( r ) + [0].colSpan = _fnVisbleColumns( ctx ); + + rows.push( created[0] ); + } + }; + + if ( $.isArray( data ) || data instanceof $ ) { + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + addRow( data[i], klass ); + } + } + else { + addRow( data, klass ); + } + + if ( row._details ) { + row._details.remove(); + } + + row._details = $(rows); + + // If the children were already shown, that state should be retained + if ( row._detailsShow ) { + row._details.insertAfter( row.nTr ); + } + }; + + + var __details_remove = function ( api, idx ) + { + var ctx = api.context; + + if ( ctx.length ) { + var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; + + if ( row._details ) { + row._details.remove(); + + row._detailsShow = undefined; + row._details = undefined; + } + } + }; + + + var __details_display = function ( api, show ) { + var ctx = api.context; + + if ( ctx.length && api.length ) { + var row = ctx[0].aoData[ api[0] ]; + + if ( row._details ) { + row._detailsShow = show; + + if ( show ) { + row._details.insertAfter( row.nTr ); + } + else { + row._details.detach(); + } + + __details_events( ctx[0] ); + } + } + }; + + + var __details_events = function ( settings ) + { + var api = new _Api( settings ); + var namespace = '.dt.DT_details'; + var drawEvent = 'draw'+namespace; + var colvisEvent = 'column-visibility'+namespace; + var destroyEvent = 'destroy'+namespace; + var data = settings.aoData; + + api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); + + if ( _pluck( data, '_details' ).length > 0 ) { + // On each draw, insert the required elements into the document + api.on( drawEvent, function ( e, ctx ) { + if ( settings !== ctx ) { + return; + } + + api.rows( {page:'current'} ).eq(0).each( function (idx) { + // Internal data grab + var row = data[ idx ]; + + if ( row._detailsShow ) { + row._details.insertAfter( row.nTr ); + } + } ); + } ); + + // Column visibility change - update the colspan + api.on( colvisEvent, function ( e, ctx, idx, vis ) { + if ( settings !== ctx ) { + return; + } + + // Update the colspan for the details rows (note, only if it already has + // a colspan) + var row, visible = _fnVisbleColumns( ctx ); + + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + row = data[i]; + + if ( row._details ) { + row._details.children('td[colspan]').attr('colspan', visible ); + } + } + } ); + + // Table destroyed - nuke any child rows + api.on( destroyEvent, function ( e, ctx ) { + if ( settings !== ctx ) { + return; + } + + for ( var i=0, ien=data.length ; i<ien ; i++ ) { + if ( data[i]._details ) { + __details_remove( api, i ); + } + } + } ); + } + }; + + // Strings for the method names to help minification + var _emp = ''; + var _child_obj = _emp+'row().child'; + var _child_mth = _child_obj+'()'; + + // data can be: + // tr + // string + // jQuery or array of any of the above + _api_register( _child_mth, function ( data, klass ) { + var ctx = this.context; + + if ( data === undefined ) { + // get + return ctx.length && this.length ? + ctx[0].aoData[ this[0] ]._details : + undefined; + } + else if ( data === true ) { + // show + this.child.show(); + } + else if ( data === false ) { + // remove + __details_remove( this ); + } + else if ( ctx.length && this.length ) { + // set + __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); + } + + return this; + } ); + + + _api_register( [ + _child_obj+'.show()', + _child_mth+'.show()' // only when `child()` was called with parameters (without + ], function ( show ) { // it returns an object and this method is not executed) + __details_display( this, true ); + return this; + } ); + + + _api_register( [ + _child_obj+'.hide()', + _child_mth+'.hide()' // only when `child()` was called with parameters (without + ], function () { // it returns an object and this method is not executed) + __details_display( this, false ); + return this; + } ); + + + _api_register( [ + _child_obj+'.remove()', + _child_mth+'.remove()' // only when `child()` was called with parameters (without + ], function () { // it returns an object and this method is not executed) + __details_remove( this ); + return this; + } ); + + + _api_register( _child_obj+'.isShown()', function () { + var ctx = this.context; + + if ( ctx.length && this.length ) { + // _detailsShown as false or undefined will fall through to return false + return ctx[0].aoData[ this[0] ]._detailsShow || false; + } + return false; + } ); + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Columns + * + * {integer} - column index (>=0 count from left, <0 count from right) + * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) + * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) + * "{string}:name" - column name + * "{string}" - jQuery selector on column header nodes + * + */ + + // can be an array of these items, comma separated list, or an array of comma + // separated lists + + var __re_column_selector = /^(.+):(name|visIdx|visible)$/; + + + // r1 and r2 are redundant - but it means that the parameters match for the + // iterator callback in columns().data() + var __columnData = function ( settings, column, r1, r2, rows ) { + var a = []; + for ( var row=0, ien=rows.length ; row<ien ; row++ ) { + a.push( _fnGetCellData( settings, rows[row], column ) ); + } + return a; + }; + + + var __column_selector = function ( settings, selector, opts ) + { + var + columns = settings.aoColumns, + names = _pluck( columns, 'sName' ), + nodes = _pluck( columns, 'nTh' ); + + return _selector_run( selector, function ( s ) { + var selInt = _intVal( s ); + + // Selector - all + if ( s === '' ) { + return _range( columns.length ); + } + + // Selector - index + if ( selInt !== null ) { + return [ selInt >= 0 ? + selInt : // Count from left + columns.length + selInt // Count from right (+ because its a negative value) + ]; + } + + // Selector = function + if ( typeof s === 'function' ) { + var rows = _selector_row_indexes( settings, opts ); + + return $.map( columns, function (col, idx) { + return s( + idx, + __columnData( settings, idx, 0, 0, rows ), + nodes[ idx ] + ) ? idx : null; + } ); + } + + // jQuery or string selector + var match = typeof s === 'string' ? + s.match( __re_column_selector ) : + ''; + + if ( match ) { + switch( match[2] ) { + case 'visIdx': + case 'visible': + var idx = parseInt( match[1], 10 ); + // Visible index given, convert to column index + if ( idx < 0 ) { + // Counting from the right + var visColumns = $.map( columns, function (col,i) { + return col.bVisible ? i : null; + } ); + return [ visColumns[ visColumns.length + idx ] ]; + } + // Counting from the left + return [ _fnVisibleToColumnIndex( settings, idx ) ]; + + case 'name': + // match by name. `names` is column index complete and in order + return $.map( names, function (name, i) { + return name === match[1] ? i : null; + } ); + } + } + else { + // jQuery selector on the TH elements for the columns + return $( nodes ) + .filter( s ) + .map( function () { + return $.inArray( this, nodes ); // `nodes` is column index complete and in order + } ) + .toArray(); + } + } ); + }; + + + var __setColumnVis = function ( settings, column, vis, recalc ) { + var + cols = settings.aoColumns, + col = cols[ column ], + data = settings.aoData, + row, cells, i, ien, tr; + + // Get + if ( vis === undefined ) { + return col.bVisible; + } + + // Set + // No change + if ( col.bVisible === vis ) { + return; + } + + if ( vis ) { + // Insert column + // Need to decide if we should use appendChild or insertBefore + var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); + + for ( i=0, ien=data.length ; i<ien ; i++ ) { + tr = data[i].nTr; + cells = data[i].anCells; + + if ( tr ) { + // insertBefore can act like appendChild if 2nd arg is null + tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); + } + } + } + else { + // Remove column + $( _pluck( settings.aoData, 'anCells', column ) ).detach(); + } + + // Common actions + col.bVisible = vis; + _fnDrawHead( settings, settings.aoHeader ); + _fnDrawHead( settings, settings.aoFooter ); + + if ( recalc === undefined || recalc ) { + // Automatically adjust column sizing + _fnAdjustColumnSizing( settings ); + + // Realign columns for scrolling + if ( settings.oScroll.sX || settings.oScroll.sY ) { + _fnScrollDraw( settings ); + } + } + + _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] ); + + _fnSaveState( settings ); + }; + + + /** + * + */ + _api_register( 'columns()', function ( selector, opts ) { + // argument shifting + if ( selector === undefined ) { + selector = ''; + } + else if ( $.isPlainObject( selector ) ) { + opts = selector; + selector = ''; + } + + opts = _selector_opts( opts ); + + var inst = this.iterator( 'table', function ( settings ) { + return __column_selector( settings, selector, opts ); + }, 1 ); + + // Want argument shifting here and in _row_selector? + inst.selector.cols = selector; + inst.selector.opts = opts; + + return inst; + } ); + + + /** + * + */ + _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { + return this.iterator( 'column', function ( settings, column ) { + return settings.aoColumns[column].nTh; + }, 1 ); + } ); + + + /** + * + */ + _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { + return this.iterator( 'column', function ( settings, column ) { + return settings.aoColumns[column].nTf; + }, 1 ); + } ); + + + /** + * + */ + _api_registerPlural( 'columns().data()', 'column().data()', function () { + return this.iterator( 'column-rows', __columnData, 1 ); + } ); + + + _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { + return this.iterator( 'column', function ( settings, column ) { + return settings.aoColumns[column].mData; + }, 1 ); + } ); + + + _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { + return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { + return _pluck_order( settings.aoData, rows, + type === 'search' ? '_aFilterData' : '_aSortData', column + ); + }, 1 ); + } ); + + + _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { + return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { + return _pluck_order( settings.aoData, rows, 'anCells', column ) ; + }, 1 ); + } ); + + + + _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { + return this.iterator( 'column', function ( settings, column ) { + if ( vis === undefined ) { + return settings.aoColumns[ column ].bVisible; + } // else + __setColumnVis( settings, column, vis, calc ); + } ); + } ); + + + + _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { + return this.iterator( 'column', function ( settings, column ) { + return type === 'visible' ? + _fnColumnIndexToVisible( settings, column ) : + column; + }, 1 ); + } ); + + + // _api_register( 'columns().show()', function () { + // var selector = this.selector; + // return this.columns( selector.cols, selector.opts ).visible( true ); + // } ); + + + // _api_register( 'columns().hide()', function () { + // var selector = this.selector; + // return this.columns( selector.cols, selector.opts ).visible( false ); + // } ); + + + + _api_register( 'columns.adjust()', function () { + return this.iterator( 'table', function ( settings ) { + _fnAdjustColumnSizing( settings ); + }, 1 ); + } ); + + + // Convert from one column index type, to another type + _api_register( 'column.index()', function ( type, idx ) { + if ( this.context.length !== 0 ) { + var ctx = this.context[0]; + + if ( type === 'fromVisible' || type === 'toData' ) { + return _fnVisibleToColumnIndex( ctx, idx ); + } + else if ( type === 'fromData' || type === 'toVisible' ) { + return _fnColumnIndexToVisible( ctx, idx ); + } + } + } ); + + + _api_register( 'column()', function ( selector, opts ) { + return _selector_first( this.columns( selector, opts ) ); + } ); + + + + + var __cell_selector = function ( settings, selector, opts ) + { + var data = settings.aoData; + var rows = _selector_row_indexes( settings, opts ); + var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); + var allCells = $( [].concat.apply([], cells) ); + var row; + var columns = settings.aoColumns.length; + var a, i, ien, j, o, host; + + return _selector_run( selector, function ( s ) { + var fnSelector = typeof s === 'function'; + + if ( s === null || s === undefined || fnSelector ) { + // All cells and function selectors + a = []; + + for ( i=0, ien=rows.length ; i<ien ; i++ ) { + row = rows[i]; + + for ( j=0 ; j<columns ; j++ ) { + o = { + row: row, + column: j + }; + + if ( fnSelector ) { + // Selector - function + host = settings.aoData[ row ]; + + if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) { + a.push( o ); + } + } + else { + // Selector - all + a.push( o ); + } + } + } + + return a; + } + + // Selector - index + if ( $.isPlainObject( s ) ) { + return [s]; + } + + // Selector - jQuery filtered cells + return allCells + .filter( s ) + .map( function (i, el) { + row = el.parentNode._DT_RowIndex; + + return { + row: row, + column: $.inArray( el, data[ row ].anCells ) + }; + } ) + .toArray(); + } ); + }; + + + + + _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { + // Argument shifting + if ( $.isPlainObject( rowSelector ) ) { + // Indexes + if ( typeof rowSelector.row !== undefined ) { + opts = columnSelector; + columnSelector = null; + } + else { + opts = rowSelector; + rowSelector = null; + } + } + if ( $.isPlainObject( columnSelector ) ) { + opts = columnSelector; + columnSelector = null; + } + + // Cell selector + if ( columnSelector === null || columnSelector === undefined ) { + return this.iterator( 'table', function ( settings ) { + return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); + } ); + } + + // Row + column selector + var columns = this.columns( columnSelector, opts ); + var rows = this.rows( rowSelector, opts ); + var a, i, ien, j, jen; + + var cells = this.iterator( 'table', function ( settings, idx ) { + a = []; + + for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { + for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { + a.push( { + row: rows[idx][i], + column: columns[idx][j] + } ); + } + } + + return a; + }, 1 ); + + $.extend( cells.selector, { + cols: columnSelector, + rows: rowSelector, + opts: opts + } ); + + return cells; + } ); + + + _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { + return this.iterator( 'cell', function ( settings, row, column ) { + var cells = settings.aoData[ row ].anCells; + return cells ? + cells[ column ] : + undefined; + }, 1 ); + } ); + + + _api_register( 'cells().data()', function () { + return this.iterator( 'cell', function ( settings, row, column ) { + return _fnGetCellData( settings, row, column ); + }, 1 ); + } ); + + + _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { + type = type === 'search' ? '_aFilterData' : '_aSortData'; + + return this.iterator( 'cell', function ( settings, row, column ) { + return settings.aoData[ row ][ type ][ column ]; + }, 1 ); + } ); + + + _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { + return this.iterator( 'cell', function ( settings, row, column ) { + return _fnGetCellData( settings, row, column, type ); + }, 1 ); + } ); + + + _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { + return this.iterator( 'cell', function ( settings, row, column ) { + return { + row: row, + column: column, + columnVisible: _fnColumnIndexToVisible( settings, column ) + }; + }, 1 ); + } ); + + + _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { + return this.iterator( 'cell', function ( settings, row, column ) { + _fnInvalidate( settings, row, src, column ); + } ); + } ); + + + + _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { + return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); + } ); + + + _api_register( 'cell().data()', function ( data ) { + var ctx = this.context; + var cell = this[0]; + + if ( data === undefined ) { + // Get + return ctx.length && cell.length ? + _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : + undefined; + } + + // Set + _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); + _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); + + return this; + } ); + + + + /** + * Get current ordering (sorting) that has been applied to the table. + * + * @returns {array} 2D array containing the sorting information for the first + * table in the current context. Each element in the parent array represents + * a column being sorted upon (i.e. multi-sorting with two columns would have + * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is + * the column index that the sorting condition applies to, the second is the + * direction of the sort (`desc` or `asc`) and, optionally, the third is the + * index of the sorting order from the `column.sorting` initialisation array. + *//** + * Set the ordering for the table. + * + * @param {integer} order Column index to sort upon. + * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) + * @returns {DataTables.Api} this + *//** + * Set the ordering for the table. + * + * @param {array} order 1D array of sorting information to be applied. + * @param {array} [...] Optional additional sorting conditions + * @returns {DataTables.Api} this + *//** + * Set the ordering for the table. + * + * @param {array} order 2D array of sorting information to be applied. + * @returns {DataTables.Api} this + */ + _api_register( 'order()', function ( order, dir ) { + var ctx = this.context; + + if ( order === undefined ) { + // get + return ctx.length !== 0 ? + ctx[0].aaSorting : + undefined; + } + + // set + if ( typeof order === 'number' ) { + // Simple column / direction passed in + order = [ [ order, dir ] ]; + } + else if ( ! $.isArray( order[0] ) ) { + // Arguments passed in (list of 1D arrays) + order = Array.prototype.slice.call( arguments ); + } + // otherwise a 2D array was passed in + + return this.iterator( 'table', function ( settings ) { + settings.aaSorting = order.slice(); + } ); + } ); + + + /** + * Attach a sort listener to an element for a given column + * + * @param {node|jQuery|string} node Identifier for the element(s) to attach the + * listener to. This can take the form of a single DOM node, a jQuery + * collection of nodes or a jQuery selector which will identify the node(s). + * @param {integer} column the column that a click on this node will sort on + * @param {function} [callback] callback function when sort is run + * @returns {DataTables.Api} this + */ + _api_register( 'order.listener()', function ( node, column, callback ) { + return this.iterator( 'table', function ( settings ) { + _fnSortAttachListener( settings, node, column, callback ); + } ); + } ); + + + // Order by the selected column(s) + _api_register( [ + 'columns().order()', + 'column().order()' + ], function ( dir ) { + var that = this; + + return this.iterator( 'table', function ( settings, i ) { + var sort = []; + + $.each( that[i], function (j, col) { + sort.push( [ col, dir ] ); + } ); + + settings.aaSorting = sort; + } ); + } ); + + + + _api_register( 'search()', function ( input, regex, smart, caseInsen ) { + var ctx = this.context; + + if ( input === undefined ) { + // get + return ctx.length !== 0 ? + ctx[0].oPreviousSearch.sSearch : + undefined; + } + + // set + return this.iterator( 'table', function ( settings ) { + if ( ! settings.oFeatures.bFilter ) { + return; + } + + _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { + "sSearch": input+"", + "bRegex": regex === null ? false : regex, + "bSmart": smart === null ? true : smart, + "bCaseInsensitive": caseInsen === null ? true : caseInsen + } ), 1 ); + } ); + } ); + + + _api_registerPlural( + 'columns().search()', + 'column().search()', + function ( input, regex, smart, caseInsen ) { + return this.iterator( 'column', function ( settings, column ) { + var preSearch = settings.aoPreSearchCols; + + if ( input === undefined ) { + // get + return preSearch[ column ].sSearch; + } + + // set + if ( ! settings.oFeatures.bFilter ) { + return; + } + + $.extend( preSearch[ column ], { + "sSearch": input+"", + "bRegex": regex === null ? false : regex, + "bSmart": smart === null ? true : smart, + "bCaseInsensitive": caseInsen === null ? true : caseInsen + } ); + + _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); + } ); + } + ); + + /* + * State API methods + */ + + _api_register( 'state()', function () { + return this.context.length ? + this.context[0].oSavedState : + null; + } ); + + + _api_register( 'state.clear()', function () { + return this.iterator( 'table', function ( settings ) { + // Save an empty object + settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); + } ); + } ); + + + _api_register( 'state.loaded()', function () { + return this.context.length ? + this.context[0].oLoadedState : + null; + } ); + + + _api_register( 'state.save()', function () { + return this.iterator( 'table', function ( settings ) { + _fnSaveState( settings ); + } ); + } ); + + + + /** + * Provide a common method for plug-ins to check the version of DataTables being + * used, in order to ensure compatibility. + * + * @param {string} version Version string to check for, in the format "X.Y.Z". + * Note that the formats "X" and "X.Y" are also acceptable. + * @returns {boolean} true if this version of DataTables is greater or equal to + * the required version, or false if this version of DataTales is not + * suitable + * @static + * @dtopt API-Static + * + * @example + * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); + */ + DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) + { + var aThis = DataTable.version.split('.'); + var aThat = version.split('.'); + var iThis, iThat; + + for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { + iThis = parseInt( aThis[i], 10 ) || 0; + iThat = parseInt( aThat[i], 10 ) || 0; + + // Parts are the same, keep comparing + if (iThis === iThat) { + continue; + } + + // Parts are different, return immediately + return iThis > iThat; + } + + return true; + }; + + + /** + * Check if a `<table>` node is a DataTable table already or not. + * + * @param {node|jquery|string} table Table node, jQuery object or jQuery + * selector for the table to test. Note that if more than more than one + * table is passed on, only the first will be checked + * @returns {boolean} true the table given is a DataTable, or false otherwise + * @static + * @dtopt API-Static + * + * @example + * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { + * $('#example').dataTable(); + * } + */ + DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) + { + var t = $(table).get(0); + var is = false; + + $.each( DataTable.settings, function (i, o) { + if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) { + is = true; + } + } ); + + return is; + }; + + + /** + * Get all DataTable tables that have been initialised - optionally you can + * select to get only currently visible tables. + * + * @param {boolean} [visible=false] Flag to indicate if you want all (default) + * or visible tables only. + * @returns {array} Array of `table` nodes (not DataTable instances) which are + * DataTables + * @static + * @dtopt API-Static + * + * @example + * $.each( $.fn.dataTable.tables(true), function () { + * $(table).DataTable().columns.adjust(); + * } ); + */ + DataTable.tables = DataTable.fnTables = function ( visible ) + { + return $.map( DataTable.settings, function (o) { + if ( !visible || (visible && $(o.nTable).is(':visible')) ) { + return o.nTable; + } + } ); + }; + + + /** + * DataTables utility methods + * + * This namespace provides helper methods that DataTables uses internally to + * create a DataTable, but which are not exclusively used only for DataTables. + * These methods can be used by extension authors to save the duplication of + * code. + * + * @namespace + */ + DataTable.util = { + /** + * Throttle the calls to a function. Arguments and context are maintained + * for the throttled function. + * + * @param {function} fn Function to be called + * @param {integer} freq Call frequency in mS + * @return {function} Wrapped function + */ + throttle: _fnThrottle, + + + /** + * Escape a string such that it can be used in a regular expression + * + * @param {string} sVal string to escape + * @returns {string} escaped string + */ + escapeRegex: _fnEscapeRegex + }; + + + /** + * Convert from camel case parameters to Hungarian notation. This is made public + * for the extensions to provide the same ability as DataTables core to accept + * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase + * parameters. + * + * @param {object} src The model object which holds all parameters that can be + * mapped. + * @param {object} user The object to convert from camel case to Hungarian. + * @param {boolean} force When set to `true`, properties which already have a + * Hungarian value in the `user` object will be overwritten. Otherwise they + * won't be. + */ + DataTable.camelToHungarian = _fnCamelToHungarian; + + + + /** + * + */ + _api_register( '$()', function ( selector, opts ) { + var + rows = this.rows( opts ).nodes(), // Get all rows + jqRows = $(rows); + + return $( [].concat( + jqRows.filter( selector ).toArray(), + jqRows.find( selector ).toArray() + ) ); + } ); + + + // jQuery functions to operate on the tables + $.each( [ 'on', 'one', 'off' ], function (i, key) { + _api_register( key+'()', function ( /* event, handler */ ) { + var args = Array.prototype.slice.call(arguments); + + // Add the `dt` namespace automatically if it isn't already present + if ( ! args[0].match(/\.dt\b/) ) { + args[0] += '.dt'; + } + + var inst = $( this.tables().nodes() ); + inst[key].apply( inst, args ); + return this; + } ); + } ); + + + _api_register( 'clear()', function () { + return this.iterator( 'table', function ( settings ) { + _fnClearTable( settings ); + } ); + } ); + + + _api_register( 'settings()', function () { + return new _Api( this.context, this.context ); + } ); + + + _api_register( 'data()', function () { + return this.iterator( 'table', function ( settings ) { + return _pluck( settings.aoData, '_aData' ); + } ).flatten(); + } ); + + + _api_register( 'destroy()', function ( remove ) { + remove = remove || false; + + return this.iterator( 'table', function ( settings ) { + var orig = settings.nTableWrapper.parentNode; + var classes = settings.oClasses; + var table = settings.nTable; + var tbody = settings.nTBody; + var thead = settings.nTHead; + var tfoot = settings.nTFoot; + var jqTable = $(table); + var jqTbody = $(tbody); + var jqWrapper = $(settings.nTableWrapper); + var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); + var i, ien; + + // Flag to note that the table is currently being destroyed - no action + // should be taken + settings.bDestroying = true; + + // Fire off the destroy callbacks for plug-ins etc + _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); + + // If not being removed from the document, make all columns visible + if ( ! remove ) { + new _Api( settings ).columns().visible( true ); + } + + // Blitz all `DT` namespaced events (these are internal events, the + // lowercase, `dt` events are user subscribed and they are responsible + // for removing them + jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT'); + $(window).unbind('.DT-'+settings.sInstance); + + // When scrolling we had to break the table up - restore it + if ( table != thead.parentNode ) { + jqTable.children('thead').detach(); + jqTable.append( thead ); + } + + if ( tfoot && table != tfoot.parentNode ) { + jqTable.children('tfoot').detach(); + jqTable.append( tfoot ); + } + + // Remove the DataTables generated nodes, events and classes + jqTable.detach(); + jqWrapper.detach(); + + settings.aaSorting = []; + settings.aaSortingFixed = []; + _fnSortingClasses( settings ); + + $( rows ).removeClass( settings.asStripeClasses.join(' ') ); + + $('th, td', thead).removeClass( classes.sSortable+' '+ + classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone + ); + + if ( settings.bJUI ) { + $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); + $('th, td', thead).each( function () { + var wrapper = $('div.'+classes.sSortJUIWrapper, this); + $(this).append( wrapper.contents() ); + wrapper.detach(); + } ); + } + + if ( ! remove && orig ) { + // insertBefore acts like appendChild if !arg[1] + orig.insertBefore( table, settings.nTableReinsertBefore ); + } + + // Add the TR elements back into the table in their original order + jqTbody.children().detach(); + jqTbody.append( rows ); + + // Restore the width of the original table - was read from the style property, + // so we can restore directly to that + jqTable + .css( 'width', settings.sDestroyWidth ) + .removeClass( classes.sTable ); + + // If the were originally stripe classes - then we add them back here. + // Note this is not fool proof (for example if not all rows had stripe + // classes - but it's a good effort without getting carried away + ien = settings.asDestroyStripes.length; + + if ( ien ) { + jqTbody.children().each( function (i) { + $(this).addClass( settings.asDestroyStripes[i % ien] ); + } ); + } + + /* Remove the settings object from the settings array */ + var idx = $.inArray( settings, DataTable.settings ); + if ( idx !== -1 ) { + DataTable.settings.splice( idx, 1 ); + } + } ); + } ); + + + /** + * Version string for plug-ins to check compatibility. Allowed format is + * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used + * only for non-release builds. See http://semver.org/ for more information. + * @member + * @type string + * @default Version number + */ + DataTable.version = "1.10.4"; + + /** + * Private data store, containing all of the settings objects that are + * created for the tables on a given page. + * + * Note that the `DataTable.settings` object is aliased to + * `jQuery.fn.dataTableExt` through which it may be accessed and + * manipulated, or `jQuery.fn.dataTable.settings`. + * @member + * @type array + * @default [] + * @private + */ + DataTable.settings = []; + + /** + * Object models container, for the various models that DataTables has + * available to it. These models define the objects that are used to hold + * the active state and configuration of the table. + * @namespace + */ + DataTable.models = {}; + + + + /** + * Template object for the way in which DataTables holds information about + * search information for the global filter and individual column filters. + * @namespace + */ + DataTable.models.oSearch = { + /** + * Flag to indicate if the filtering should be case insensitive or not + * @type boolean + * @default true + */ + "bCaseInsensitive": true, + + /** + * Applied search term + * @type string + * @default <i>Empty string</i> + */ + "sSearch": "", + + /** + * Flag to indicate if the search term should be interpreted as a + * regular expression (true) or not (false) and therefore and special + * regex characters escaped. + * @type boolean + * @default false + */ + "bRegex": false, + + /** + * Flag to indicate if DataTables is to use its smart filtering or not. + * @type boolean + * @default true + */ + "bSmart": true + }; + + + + + /** + * Template object for the way in which DataTables holds information about + * each individual row. This is the object format used for the settings + * aoData array. + * @namespace + */ + DataTable.models.oRow = { + /** + * TR element for the row + * @type node + * @default null + */ + "nTr": null, + + /** + * Array of TD elements for each row. This is null until the row has been + * created. + * @type array nodes + * @default [] + */ + "anCells": null, + + /** + * Data object from the original data source for the row. This is either + * an array if using the traditional form of DataTables, or an object if + * using mData options. The exact type will depend on the passed in + * data from the data source, or will be an array if using DOM a data + * source. + * @type array|object + * @default [] + */ + "_aData": [], + + /** + * Sorting data cache - this array is ostensibly the same length as the + * number of columns (although each index is generated only as it is + * needed), and holds the data that is used for sorting each column in the + * row. We do this cache generation at the start of the sort in order that + * the formatting of the sort data need be done only once for each cell + * per sort. This array should not be read from or written to by anything + * other than the master sorting methods. + * @type array + * @default null + * @private + */ + "_aSortData": null, + + /** + * Per cell filtering data cache. As per the sort data cache, used to + * increase the performance of the filtering in DataTables + * @type array + * @default null + * @private + */ + "_aFilterData": null, + + /** + * Filtering data cache. This is the same as the cell filtering cache, but + * in this case a string rather than an array. This is easily computed with + * a join on `_aFilterData`, but is provided as a cache so the join isn't + * needed on every search (memory traded for performance) + * @type array + * @default null + * @private + */ + "_sFilterRow": null, + + /** + * Cache of the class name that DataTables has applied to the row, so we + * can quickly look at this variable rather than needing to do a DOM check + * on className for the nTr property. + * @type string + * @default <i>Empty string</i> + * @private + */ + "_sRowStripe": "", + + /** + * Denote if the original data source was from the DOM, or the data source + * object. This is used for invalidating data, so DataTables can + * automatically read data from the original source, unless uninstructed + * otherwise. + * @type string + * @default null + * @private + */ + "src": null + }; + + + /** + * Template object for the column information object in DataTables. This object + * is held in the settings aoColumns array and contains all the information that + * DataTables needs about each individual column. + * + * Note that this object is related to {@link DataTable.defaults.column} + * but this one is the internal data store for DataTables's cache of columns. + * It should NOT be manipulated outside of DataTables. Any configuration should + * be done through the initialisation options. + * @namespace + */ + DataTable.models.oColumn = { + /** + * Column index. This could be worked out on-the-fly with $.inArray, but it + * is faster to just hold it as a variable + * @type integer + * @default null + */ + "idx": null, + + /** + * A list of the columns that sorting should occur on when this column + * is sorted. That this property is an array allows multi-column sorting + * to be defined for a column (for example first name / last name columns + * would benefit from this). The values are integers pointing to the + * columns to be sorted on (typically it will be a single integer pointing + * at itself, but that doesn't need to be the case). + * @type array + */ + "aDataSort": null, + + /** + * Define the sorting directions that are applied to the column, in sequence + * as the column is repeatedly sorted upon - i.e. the first value is used + * as the sorting direction when the column if first sorted (clicked on). + * Sort it again (click again) and it will move on to the next index. + * Repeat until loop. + * @type array + */ + "asSorting": null, + + /** + * Flag to indicate if the column is searchable, and thus should be included + * in the filtering or not. + * @type boolean + */ + "bSearchable": null, + + /** + * Flag to indicate if the column is sortable or not. + * @type boolean + */ + "bSortable": null, + + /** + * Flag to indicate if the column is currently visible in the table or not + * @type boolean + */ + "bVisible": null, + + /** + * Store for manual type assignment using the `column.type` option. This + * is held in store so we can manipulate the column's `sType` property. + * @type string + * @default null + * @private + */ + "_sManualType": null, + + /** + * Flag to indicate if HTML5 data attributes should be used as the data + * source for filtering or sorting. True is either are. + * @type boolean + * @default false + * @private + */ + "_bAttrSrc": false, + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to mRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available. + * @type function + * @param {element} nTd The TD node that has been created + * @param {*} sData The Data for the cell + * @param {array|object} oData The data for the whole row + * @param {int} iRow The row index for the aoData data store + * @default null + */ + "fnCreatedCell": null, + + /** + * Function to get data from a cell in a column. You should <b>never</b> + * access data directly through _aData internally in DataTables - always use + * the method attached to this property. It allows mData to function as + * required. This function is automatically assigned by the column + * initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {string} sSpecific The specific data type you want to get - + * 'display', 'type' 'filter' 'sort' + * @returns {*} The data for the cell from the given row's data + * @default null + */ + "fnGetData": null, + + /** + * Function to set data for a cell in the column. You should <b>never</b> + * set the data directly to _aData internally in DataTables - always use + * this method. It allows mData to function as required. This function + * is automatically assigned by the column initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {*} sValue Value to set + * @default null + */ + "fnSetData": null, + + /** + * Property to read the value for the cells in the column from the data + * source array / object. If null, then the default content is used, if a + * function is given then the return from the function is used. + * @type function|int|string|null + * @default null + */ + "mData": null, + + /** + * Partner property to mData which is used (only when defined) to get + * the data - i.e. it is basically the same as mData, but without the + * 'set' option, and also the data fed to it is the result from mData. + * This is the rendering method to match the data method of mData. + * @type function|int|string|null + * @default null + */ + "mRender": null, + + /** + * Unique header TH/TD element for this column - this is what the sorting + * listener is attached to (if sorting is enabled.) + * @type node + * @default null + */ + "nTh": null, + + /** + * Unique footer TH/TD element for this column (if there is one). Not used + * in DataTables as such, but can be used for plug-ins to reference the + * footer for each column. + * @type node + * @default null + */ + "nTf": null, + + /** + * The class to apply to all TD elements in the table's TBODY for the column + * @type string + * @default null + */ + "sClass": null, + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * @type string + */ + "sContentPadding": null, + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because mData + * is set to null, or because the data source itself is null). + * @type string + * @default null + */ + "sDefaultContent": null, + + /** + * Name for the column, allowing reference to the column by name as well as + * by index (needs a lookup to work by name). + * @type string + */ + "sName": null, + + /** + * Custom sorting data type - defines which of the available plug-ins in + * afnSortData the custom sorting will use - if any is defined. + * @type string + * @default std + */ + "sSortDataType": 'std', + + /** + * Class to be applied to the header element when sorting on this column + * @type string + * @default null + */ + "sSortingClass": null, + + /** + * Class to be applied to the header element when sorting on this column - + * when jQuery UI theming is used. + * @type string + * @default null + */ + "sSortingClassJUI": null, + + /** + * Title of the column - what is seen in the TH element (nTh). + * @type string + */ + "sTitle": null, + + /** + * Column sorting and filtering type + * @type string + * @default null + */ + "sType": null, + + /** + * Width of the column + * @type string + * @default null + */ + "sWidth": null, + + /** + * Width of the column when it was first "encountered" + * @type string + * @default null + */ + "sWidthOrig": null + }; + + + /* + * Developer note: The properties of the object below are given in Hungarian + * notation, that was used as the interface for DataTables prior to v1.10, however + * from v1.10 onwards the primary interface is camel case. In order to avoid + * breaking backwards compatibility utterly with this change, the Hungarian + * version is still, internally the primary interface, but is is not documented + * - hence the @name tags in each doc comment. This allows a Javascript function + * to create a map from Hungarian notation to camel case (going the other direction + * would require each property to be listed, which would at around 3K to the size + * of DataTables, while this method is about a 0.5K hit. + * + * Ultimately this does pave the way for Hungarian notation to be dropped + * completely, but that is a massive amount of work and will break current + * installs (therefore is on-hold until v2). + */ + + /** + * Initialisation options that can be given to DataTables at initialisation + * time. + * @namespace + */ + DataTable.defaults = { + /** + * An array of data to use for the table, passed in at initialisation which + * will be used in preference to any data which is already in the DOM. This is + * particularly useful for constructing tables purely in Javascript, for + * example with a custom Ajax call. + * @type array + * @default null + * + * @dtopt Option + * @name DataTable.defaults.data + * + * @example + * // Using a 2D array data source + * $(document).ready( function () { + * $('#example').dataTable( { + * "data": [ + * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], + * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], + * ], + * "columns": [ + * { "title": "Engine" }, + * { "title": "Browser" }, + * { "title": "Platform" }, + * { "title": "Version" }, + * { "title": "Grade" } + * ] + * } ); + * } ); + * + * @example + * // Using an array of objects as a data source (`data`) + * $(document).ready( function () { + * $('#example').dataTable( { + * "data": [ + * { + * "engine": "Trident", + * "browser": "Internet Explorer 4.0", + * "platform": "Win 95+", + * "version": 4, + * "grade": "X" + * }, + * { + * "engine": "Trident", + * "browser": "Internet Explorer 5.0", + * "platform": "Win 95+", + * "version": 5, + * "grade": "C" + * } + * ], + * "columns": [ + * { "title": "Engine", "data": "engine" }, + * { "title": "Browser", "data": "browser" }, + * { "title": "Platform", "data": "platform" }, + * { "title": "Version", "data": "version" }, + * { "title": "Grade", "data": "grade" } + * ] + * } ); + * } ); + */ + "aaData": null, + + + /** + * If ordering is enabled, then DataTables will perform a first pass sort on + * initialisation. You can define which column(s) the sort is performed + * upon, and the sorting direction, with this variable. The `sorting` array + * should contain an array for each column to be sorted initially containing + * the column's index and a direction string ('asc' or 'desc'). + * @type array + * @default [[0,'asc']] + * + * @dtopt Option + * @name DataTable.defaults.order + * + * @example + * // Sort by 3rd column first, and then 4th column + * $(document).ready( function() { + * $('#example').dataTable( { + * "order": [[2,'asc'], [3,'desc']] + * } ); + * } ); + * + * // No initial sorting + * $(document).ready( function() { + * $('#example').dataTable( { + * "order": [] + * } ); + * } ); + */ + "aaSorting": [[0,'asc']], + + + /** + * This parameter is basically identical to the `sorting` parameter, but + * cannot be overridden by user interaction with the table. What this means + * is that you could have a column (visible or hidden) which the sorting + * will always be forced on first - any sorting after that (from the user) + * will then be performed as required. This can be useful for grouping rows + * together. + * @type array + * @default null + * + * @dtopt Option + * @name DataTable.defaults.orderFixed + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "orderFixed": [[0,'asc']] + * } ); + * } ) + */ + "aaSortingFixed": [], + + + /** + * DataTables can be instructed to load data to display in the table from a + * Ajax source. This option defines how that Ajax call is made and where to. + * + * The `ajax` property has three different modes of operation, depending on + * how it is defined. These are: + * + * * `string` - Set the URL from where the data should be loaded from. + * * `object` - Define properties for `jQuery.ajax`. + * * `function` - Custom data get function + * + * `string` + * -------- + * + * As a string, the `ajax` property simply defines the URL from which + * DataTables will load data. + * + * `object` + * -------- + * + * As an object, the parameters in the object are passed to + * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control + * of the Ajax request. DataTables has a number of default parameters which + * you can override using this option. Please refer to the jQuery + * documentation for a full description of the options available, although + * the following parameters provide additional options in DataTables or + * require special consideration: + * + * * `data` - As with jQuery, `data` can be provided as an object, but it + * can also be used as a function to manipulate the data DataTables sends + * to the server. The function takes a single parameter, an object of + * parameters with the values that DataTables has readied for sending. An + * object may be returned which will be merged into the DataTables + * defaults, or you can add the items to the object that was passed in and + * not return anything from the function. This supersedes `fnServerParams` + * from DataTables 1.9-. + * + * * `dataSrc` - By default DataTables will look for the property `data` (or + * `aaData` for compatibility with DataTables 1.9-) when obtaining data + * from an Ajax source or for server-side processing - this parameter + * allows that property to be changed. You can use Javascript dotted + * object notation to get a data source for multiple levels of nesting, or + * it my be used as a function. As a function it takes a single parameter, + * the JSON returned from the server, which can be manipulated as + * required, with the returned value being that used by DataTables as the + * data source for the table. This supersedes `sAjaxDataProp` from + * DataTables 1.9-. + * + * * `success` - Should not be overridden it is used internally in + * DataTables. To manipulate / transform the data returned by the server + * use `ajax.dataSrc`, or use `ajax` as a function (see below). + * + * `function` + * ---------- + * + * As a function, making the Ajax call is left up to yourself allowing + * complete control of the Ajax request. Indeed, if desired, a method other + * than Ajax could be used to obtain the required data, such as Web storage + * or an AIR database. + * + * The function is given four parameters and no return is required. The + * parameters are: + * + * 1. _object_ - Data to send to the server + * 2. _function_ - Callback function that must be executed when the required + * data has been obtained. That data should be passed into the callback + * as the only parameter + * 3. _object_ - DataTables settings object for the table + * + * Note that this supersedes `fnServerData` from DataTables 1.9-. + * + * @type string|object|function + * @default null + * + * @dtopt Option + * @name DataTable.defaults.ajax + * @since 1.10.0 + * + * @example + * // Get JSON data from a file via Ajax. + * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). + * $('#example').dataTable( { + * "ajax": "data.json" + * } ); + * + * @example + * // Get JSON data from a file via Ajax, using `dataSrc` to change + * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) + * $('#example').dataTable( { + * "ajax": { + * "url": "data.json", + * "dataSrc": "tableData" + * } + * } ); + * + * @example + * // Get JSON data from a file via Ajax, using `dataSrc` to read data + * // from a plain array rather than an array in an object + * $('#example').dataTable( { + * "ajax": { + * "url": "data.json", + * "dataSrc": "" + * } + * } ); + * + * @example + * // Manipulate the data returned from the server - add a link to data + * // (note this can, should, be done using `render` for the column - this + * // is just a simple example of how the data can be manipulated). + * $('#example').dataTable( { + * "ajax": { + * "url": "data.json", + * "dataSrc": function ( json ) { + * for ( var i=0, ien=json.length ; i<ien ; i++ ) { + * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; + * } + * return json; + * } + * } + * } ); + * + * @example + * // Add data to the request + * $('#example').dataTable( { + * "ajax": { + * "url": "data.json", + * "data": function ( d ) { + * return { + * "extra_search": $('#extra').val() + * }; + * } + * } + * } ); + * + * @example + * // Send request as POST + * $('#example').dataTable( { + * "ajax": { + * "url": "data.json", + * "type": "POST" + * } + * } ); + * + * @example + * // Get the data from localStorage (could interface with a form for + * // adding, editing and removing rows). + * $('#example').dataTable( { + * "ajax": function (data, callback, settings) { + * callback( + * JSON.parse( localStorage.getItem('dataTablesData') ) + * ); + * } + * } ); + */ + "ajax": null, + + + /** + * This parameter allows you to readily specify the entries in the length drop + * down menu that DataTables shows when pagination is enabled. It can be + * either a 1D array of options which will be used for both the displayed + * option and the value, or a 2D array which will use the array in the first + * position as the value, and the array in the second position as the + * displayed options (useful for language strings such as 'All'). + * + * Note that the `pageLength` property will be automatically set to the + * first value given in this array, unless `pageLength` is also provided. + * @type array + * @default [ 10, 25, 50, 100 ] + * + * @dtopt Option + * @name DataTable.defaults.lengthMenu + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] + * } ); + * } ); + */ + "aLengthMenu": [ 10, 25, 50, 100 ], + + + /** + * The `columns` option in the initialisation parameter allows you to define + * details about the way individual columns behave. For a full list of + * column options that can be set, please see + * {@link DataTable.defaults.column}. Note that if you use `columns` to + * define your columns, you must have an entry in the array for every single + * column that you have in your table (these can be null if you don't which + * to specify any options). + * @member + * + * @name DataTable.defaults.column + */ + "aoColumns": null, + + /** + * Very similar to `columns`, `columnDefs` allows you to target a specific + * column, multiple columns, or all columns, using the `targets` property of + * each object in the array. This allows great flexibility when creating + * tables, as the `columnDefs` arrays can be of any length, targeting the + * columns you specifically want. `columnDefs` may use any of the column + * options available: {@link DataTable.defaults.column}, but it _must_ + * have `targets` defined in each object in the array. Values in the `targets` + * array may be: + * <ul> + * <li>a string - class name will be matched on the TH for the column</li> + * <li>0 or a positive integer - column index counting from the left</li> + * <li>a negative integer - column index counting from the right</li> + * <li>the string "_all" - all columns (i.e. assign a default)</li> + * </ul> + * @member + * + * @name DataTable.defaults.columnDefs + */ + "aoColumnDefs": null, + + + /** + * Basically the same as `search`, this parameter defines the individual column + * filtering state at initialisation time. The array must be of the same size + * as the number of columns, and each element be an object with the parameters + * `search` and `escapeRegex` (the latter is optional). 'null' is also + * accepted and the default will be used. + * @type array + * @default [] + * + * @dtopt Option + * @name DataTable.defaults.searchCols + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "searchCols": [ + * null, + * { "search": "My filter" }, + * null, + * { "search": "^[0-9]", "escapeRegex": false } + * ] + * } ); + * } ) + */ + "aoSearchCols": [], + + + /** + * An array of CSS classes that should be applied to displayed rows. This + * array may be of any length, and DataTables will apply each class + * sequentially, looping when required. + * @type array + * @default null <i>Will take the values determined by the `oClasses.stripe*` + * options</i> + * + * @dtopt Option + * @name DataTable.defaults.stripeClasses + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] + * } ); + * } ) + */ + "asStripeClasses": null, + + + /** + * Enable or disable automatic column width calculation. This can be disabled + * as an optimisation (it takes some time to calculate the widths) if the + * tables widths are passed in using `columns`. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.autoWidth + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "autoWidth": false + * } ); + * } ); + */ + "bAutoWidth": true, + + + /** + * Deferred rendering can provide DataTables with a huge speed boost when you + * are using an Ajax or JS data source for the table. This option, when set to + * true, will cause DataTables to defer the creation of the table elements for + * each row until they are needed for a draw - saving a significant amount of + * time. + * @type boolean + * @default false + * + * @dtopt Features + * @name DataTable.defaults.deferRender + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "ajax": "sources/arrays.txt", + * "deferRender": true + * } ); + * } ); + */ + "bDeferRender": false, + + + /** + * Replace a DataTable which matches the given selector and replace it with + * one which has the properties of the new initialisation object passed. If no + * table matches the selector, then the new DataTable will be constructed as + * per normal. + * @type boolean + * @default false + * + * @dtopt Options + * @name DataTable.defaults.destroy + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "srollY": "200px", + * "paginate": false + * } ); + * + * // Some time later.... + * $('#example').dataTable( { + * "filter": false, + * "destroy": true + * } ); + * } ); + */ + "bDestroy": false, + + + /** + * Enable or disable filtering of data. Filtering in DataTables is "smart" in + * that it allows the end user to input multiple words (space separated) and + * will match a row containing those words, even if not in the order that was + * specified (this allow matching across multiple columns). Note that if you + * wish to use filtering in DataTables this must remain 'true' - to remove the + * default filtering input box and retain filtering abilities, please use + * {@link DataTable.defaults.dom}. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.searching + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "searching": false + * } ); + * } ); + */ + "bFilter": true, + + + /** + * Enable or disable the table information display. This shows information + * about the data that is currently visible on the page, including information + * about filtered data if that action is being performed. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.info + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "info": false + * } ); + * } ); + */ + "bInfo": true, + + + /** + * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some + * slightly different and additional mark-up from what DataTables has + * traditionally used). + * @type boolean + * @default false + * + * @dtopt Features + * @name DataTable.defaults.jQueryUI + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "jQueryUI": true + * } ); + * } ); + */ + "bJQueryUI": false, + + + /** + * Allows the end user to select the size of a formatted page from a select + * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.lengthChange + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "lengthChange": false + * } ); + * } ); + */ + "bLengthChange": true, + + + /** + * Enable or disable pagination. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.paging + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "paging": false + * } ); + * } ); + */ + "bPaginate": true, + + + /** + * Enable or disable the display of a 'processing' indicator when the table is + * being processed (e.g. a sort). This is particularly useful for tables with + * large amounts of data where it can take a noticeable amount of time to sort + * the entries. + * @type boolean + * @default false + * + * @dtopt Features + * @name DataTable.defaults.processing + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "processing": true + * } ); + * } ); + */ + "bProcessing": false, + + + /** + * Retrieve the DataTables object for the given selector. Note that if the + * table has already been initialised, this parameter will cause DataTables + * to simply return the object that has already been set up - it will not take + * account of any changes you might have made to the initialisation object + * passed to DataTables (setting this parameter to true is an acknowledgement + * that you understand this). `destroy` can be used to reinitialise a table if + * you need. + * @type boolean + * @default false + * + * @dtopt Options + * @name DataTable.defaults.retrieve + * + * @example + * $(document).ready( function() { + * initTable(); + * tableActions(); + * } ); + * + * function initTable () + * { + * return $('#example').dataTable( { + * "scrollY": "200px", + * "paginate": false, + * "retrieve": true + * } ); + * } + * + * function tableActions () + * { + * var table = initTable(); + * // perform API operations with oTable + * } + */ + "bRetrieve": false, + + + /** + * When vertical (y) scrolling is enabled, DataTables will force the height of + * the table's viewport to the given height at all times (useful for layout). + * However, this can look odd when filtering data down to a small data set, + * and the footer is left "floating" further down. This parameter (when + * enabled) will cause DataTables to collapse the table's viewport down when + * the result set will fit within the given Y height. + * @type boolean + * @default false + * + * @dtopt Options + * @name DataTable.defaults.scrollCollapse + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "scrollY": "200", + * "scrollCollapse": true + * } ); + * } ); + */ + "bScrollCollapse": false, + + + /** + * Configure DataTables to use server-side processing. Note that the + * `ajax` parameter must also be given in order to give DataTables a + * source to obtain the required data for each draw. + * @type boolean + * @default false + * + * @dtopt Features + * @dtopt Server-side + * @name DataTable.defaults.serverSide + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "serverSide": true, + * "ajax": "xhr.php" + * } ); + * } ); + */ + "bServerSide": false, + + + /** + * Enable or disable sorting of columns. Sorting of individual columns can be + * disabled by the `sortable` option for each column. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.ordering + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "ordering": false + * } ); + * } ); + */ + "bSort": true, + + + /** + * Enable or display DataTables' ability to sort multiple columns at the + * same time (activated by shift-click by the user). + * @type boolean + * @default true + * + * @dtopt Options + * @name DataTable.defaults.orderMulti + * + * @example + * // Disable multiple column sorting ability + * $(document).ready( function () { + * $('#example').dataTable( { + * "orderMulti": false + * } ); + * } ); + */ + "bSortMulti": true, + + + /** + * Allows control over whether DataTables should use the top (true) unique + * cell that is found for a single column, or the bottom (false - default). + * This is useful when using complex headers. + * @type boolean + * @default false + * + * @dtopt Options + * @name DataTable.defaults.orderCellsTop + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "orderCellsTop": true + * } ); + * } ); + */ + "bSortCellsTop": false, + + + /** + * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and + * `sorting\_3` to the columns which are currently being sorted on. This is + * presented as a feature switch as it can increase processing time (while + * classes are removed and added) so for large data sets you might want to + * turn this off. + * @type boolean + * @default true + * + * @dtopt Features + * @name DataTable.defaults.orderClasses + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "orderClasses": false + * } ); + * } ); + */ + "bSortClasses": true, + + + /** + * Enable or disable state saving. When enabled HTML5 `localStorage` will be + * used to save table display information such as pagination information, + * display length, filtering and sorting. As such when the end user reloads + * the page the display display will match what thy had previously set up. + * + * Due to the use of `localStorage` the default state saving is not supported + * in IE6 or 7. If state saving is required in those browsers, use + * `stateSaveCallback` to provide a storage solution such as cookies. + * @type boolean + * @default false + * + * @dtopt Features + * @name DataTable.defaults.stateSave + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "stateSave": true + * } ); + * } ); + */ + "bStateSave": false, + + + /** + * This function is called when a TR element is created (and all TD child + * elements have been inserted), or registered if using a DOM source, allowing + * manipulation of the TR element (adding classes etc). + * @type function + * @param {node} row "TR" element for the current row + * @param {array} data Raw data array for this row + * @param {int} dataIndex The index of this row in the internal aoData array + * + * @dtopt Callbacks + * @name DataTable.defaults.createdRow + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "createdRow": function( row, data, dataIndex ) { + * // Bold the grade for all 'A' grade browsers + * if ( data[4] == "A" ) + * { + * $('td:eq(4)', row).html( '<b>A</b>' ); + * } + * } + * } ); + * } ); + */ + "fnCreatedRow": null, + + + /** + * This function is called on every 'draw' event, and allows you to + * dynamically modify any aspect you want about the created DOM. + * @type function + * @param {object} settings DataTables settings object + * + * @dtopt Callbacks + * @name DataTable.defaults.drawCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "drawCallback": function( settings ) { + * alert( 'DataTables has redrawn the table' ); + * } + * } ); + * } ); + */ + "fnDrawCallback": null, + + + /** + * Identical to fnHeaderCallback() but for the table footer this function + * allows you to modify the table footer on every 'draw' event. + * @type function + * @param {node} foot "TR" element for the footer + * @param {array} data Full table data (as derived from the original HTML) + * @param {int} start Index for the current display starting point in the + * display array + * @param {int} end Index for the current display ending point in the + * display array + * @param {array int} display Index array to translate the visual position + * to the full data array + * + * @dtopt Callbacks + * @name DataTable.defaults.footerCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "footerCallback": function( tfoot, data, start, end, display ) { + * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; + * } + * } ); + * } ) + */ + "fnFooterCallback": null, + + + /** + * When rendering large numbers in the information element for the table + * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers + * to have a comma separator for the 'thousands' units (e.g. 1 million is + * rendered as "1,000,000") to help readability for the end user. This + * function will override the default method DataTables uses. + * @type function + * @member + * @param {int} toFormat number to be formatted + * @returns {string} formatted string for DataTables to show the number + * + * @dtopt Callbacks + * @name DataTable.defaults.formatNumber + * + * @example + * // Format a number using a single quote for the separator (note that + * // this can also be done with the language.thousands option) + * $(document).ready( function() { + * $('#example').dataTable( { + * "formatNumber": function ( toFormat ) { + * return toFormat.toString().replace( + * /\B(?=(\d{3})+(?!\d))/g, "'" + * ); + * }; + * } ); + * } ); + */ + "fnFormatNumber": function ( toFormat ) { + return toFormat.toString().replace( + /\B(?=(\d{3})+(?!\d))/g, + this.oLanguage.sThousands + ); + }, + + + /** + * This function is called on every 'draw' event, and allows you to + * dynamically modify the header row. This can be used to calculate and + * display useful information about the table. + * @type function + * @param {node} head "TR" element for the header + * @param {array} data Full table data (as derived from the original HTML) + * @param {int} start Index for the current display starting point in the + * display array + * @param {int} end Index for the current display ending point in the + * display array + * @param {array int} display Index array to translate the visual position + * to the full data array + * + * @dtopt Callbacks + * @name DataTable.defaults.headerCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fheaderCallback": function( head, data, start, end, display ) { + * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; + * } + * } ); + * } ) + */ + "fnHeaderCallback": null, + + + /** + * The information element can be used to convey information about the current + * state of the table. Although the internationalisation options presented by + * DataTables are quite capable of dealing with most customisations, there may + * be times where you wish to customise the string further. This callback + * allows you to do exactly that. + * @type function + * @param {object} oSettings DataTables settings object + * @param {int} start Starting position in data for the draw + * @param {int} end End position in data for the draw + * @param {int} max Total number of rows in the table (regardless of + * filtering) + * @param {int} total Total number of rows in the data set, after filtering + * @param {string} pre The string that DataTables has formatted using it's + * own rules + * @returns {string} The string to be displayed in the information element. + * + * @dtopt Callbacks + * @name DataTable.defaults.infoCallback + * + * @example + * $('#example').dataTable( { + * "infoCallback": function( settings, start, end, max, total, pre ) { + * return start +" to "+ end; + * } + * } ); + */ + "fnInfoCallback": null, + + + /** + * Called when the table has been initialised. Normally DataTables will + * initialise sequentially and there will be no need for this function, + * however, this does not hold true when using external language information + * since that is obtained using an async XHR call. + * @type function + * @param {object} settings DataTables settings object + * @param {object} json The JSON object request from the server - only + * present if client-side Ajax sourced data is used + * + * @dtopt Callbacks + * @name DataTable.defaults.initComplete + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "initComplete": function(settings, json) { + * alert( 'DataTables has finished its initialisation.' ); + * } + * } ); + * } ) + */ + "fnInitComplete": null, + + + /** + * Called at the very start of each table draw and can be used to cancel the + * draw by returning false, any other return (including undefined) results in + * the full draw occurring). + * @type function + * @param {object} settings DataTables settings object + * @returns {boolean} False will cancel the draw, anything else (including no + * return) will allow it to complete. + * + * @dtopt Callbacks + * @name DataTable.defaults.preDrawCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "preDrawCallback": function( settings ) { + * if ( $('#test').val() == 1 ) { + * return false; + * } + * } + * } ); + * } ); + */ + "fnPreDrawCallback": null, + + + /** + * This function allows you to 'post process' each row after it have been + * generated for each table draw, but before it is rendered on screen. This + * function might be used for setting the row class name etc. + * @type function + * @param {node} row "TR" element for the current row + * @param {array} data Raw data array for this row + * @param {int} displayIndex The display index for the current table draw + * @param {int} displayIndexFull The index of the data in the full list of + * rows (after filtering) + * + * @dtopt Callbacks + * @name DataTable.defaults.rowCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { + * // Bold the grade for all 'A' grade browsers + * if ( data[4] == "A" ) { + * $('td:eq(4)', row).html( '<b>A</b>' ); + * } + * } + * } ); + * } ); + */ + "fnRowCallback": null, + + + /** + * __Deprecated__ The functionality provided by this parameter has now been + * superseded by that provided through `ajax`, which should be used instead. + * + * This parameter allows you to override the default function which obtains + * the data from the server so something more suitable for your application. + * For example you could use POST data, or pull information from a Gears or + * AIR database. + * @type function + * @member + * @param {string} source HTTP source to obtain the data from (`ajax`) + * @param {array} data A key/value pair object containing the data to send + * to the server + * @param {function} callback to be called on completion of the data get + * process that will draw the data on the page. + * @param {object} settings DataTables settings object + * + * @dtopt Callbacks + * @dtopt Server-side + * @name DataTable.defaults.serverData + * + * @deprecated 1.10. Please use `ajax` for this functionality now. + */ + "fnServerData": null, + + + /** + * __Deprecated__ The functionality provided by this parameter has now been + * superseded by that provided through `ajax`, which should be used instead. + * + * It is often useful to send extra data to the server when making an Ajax + * request - for example custom filtering information, and this callback + * function makes it trivial to send extra information to the server. The + * passed in parameter is the data set that has been constructed by + * DataTables, and you can add to this or modify it as you require. + * @type function + * @param {array} data Data array (array of objects which are name/value + * pairs) that has been constructed by DataTables and will be sent to the + * server. In the case of Ajax sourced data with server-side processing + * this will be an empty array, for server-side processing there will be a + * significant number of parameters! + * @returns {undefined} Ensure that you modify the data array passed in, + * as this is passed by reference. + * + * @dtopt Callbacks + * @dtopt Server-side + * @name DataTable.defaults.serverParams + * + * @deprecated 1.10. Please use `ajax` for this functionality now. + */ + "fnServerParams": null, + + + /** + * Load the table state. With this function you can define from where, and how, the + * state of a table is loaded. By default DataTables will load from `localStorage` + * but you might wish to use a server-side database or cookies. + * @type function + * @member + * @param {object} settings DataTables settings object + * @return {object} The DataTables state object to be loaded + * + * @dtopt Callbacks + * @name DataTable.defaults.stateLoadCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateLoadCallback": function (settings) { + * var o; + * + * // Send an Ajax request to the server to get the data. Note that + * // this is a synchronous request. + * $.ajax( { + * "url": "/state_load", + * "async": false, + * "dataType": "json", + * "success": function (json) { + * o = json; + * } + * } ); + * + * return o; + * } + * } ); + * } ); + */ + "fnStateLoadCallback": function ( settings ) { + try { + return JSON.parse( + (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( + 'DataTables_'+settings.sInstance+'_'+location.pathname + ) + ); + } catch (e) {} + }, + + + /** + * Callback which allows modification of the saved state prior to loading that state. + * This callback is called when the table is loading state from the stored data, but + * prior to the settings object being modified by the saved state. Note that for + * plug-in authors, you should use the `stateLoadParams` event to load parameters for + * a plug-in. + * @type function + * @param {object} settings DataTables settings object + * @param {object} data The state object that is to be loaded + * + * @dtopt Callbacks + * @name DataTable.defaults.stateLoadParams + * + * @example + * // Remove a saved filter, so filtering is never loaded + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateLoadParams": function (settings, data) { + * data.oSearch.sSearch = ""; + * } + * } ); + * } ); + * + * @example + * // Disallow state loading by returning false + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateLoadParams": function (settings, data) { + * return false; + * } + * } ); + * } ); + */ + "fnStateLoadParams": null, + + + /** + * Callback that is called when the state has been loaded from the state saving method + * and the DataTables settings object has been modified as a result of the loaded state. + * @type function + * @param {object} settings DataTables settings object + * @param {object} data The state object that was loaded + * + * @dtopt Callbacks + * @name DataTable.defaults.stateLoaded + * + * @example + * // Show an alert with the filtering value that was saved + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateLoaded": function (settings, data) { + * alert( 'Saved filter was: '+data.oSearch.sSearch ); + * } + * } ); + * } ); + */ + "fnStateLoaded": null, + + + /** + * Save the table state. This function allows you to define where and how the state + * information for the table is stored By default DataTables will use `localStorage` + * but you might wish to use a server-side database or cookies. + * @type function + * @member + * @param {object} settings DataTables settings object + * @param {object} data The state object to be saved + * + * @dtopt Callbacks + * @name DataTable.defaults.stateSaveCallback + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateSaveCallback": function (settings, data) { + * // Send an Ajax request to the server with the state object + * $.ajax( { + * "url": "/state_save", + * "data": data, + * "dataType": "json", + * "method": "POST" + * "success": function () {} + * } ); + * } + * } ); + * } ); + */ + "fnStateSaveCallback": function ( settings, data ) { + try { + (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( + 'DataTables_'+settings.sInstance+'_'+location.pathname, + JSON.stringify( data ) + ); + } catch (e) {} + }, + + + /** + * Callback which allows modification of the state to be saved. Called when the table + * has changed state a new state save is required. This method allows modification of + * the state saving object prior to actually doing the save, including addition or + * other state properties or modification. Note that for plug-in authors, you should + * use the `stateSaveParams` event to save parameters for a plug-in. + * @type function + * @param {object} settings DataTables settings object + * @param {object} data The state object to be saved + * + * @dtopt Callbacks + * @name DataTable.defaults.stateSaveParams + * + * @example + * // Remove a saved filter, so filtering is never saved + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateSave": true, + * "stateSaveParams": function (settings, data) { + * data.oSearch.sSearch = ""; + * } + * } ); + * } ); + */ + "fnStateSaveParams": null, + + + /** + * Duration for which the saved state information is considered valid. After this period + * has elapsed the state will be returned to the default. + * Value is given in seconds. + * @type int + * @default 7200 <i>(2 hours)</i> + * + * @dtopt Options + * @name DataTable.defaults.stateDuration + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "stateDuration": 60*60*24; // 1 day + * } ); + * } ) + */ + "iStateDuration": 7200, + + + /** + * When enabled DataTables will not make a request to the server for the first + * page draw - rather it will use the data already on the page (no sorting etc + * will be applied to it), thus saving on an XHR at load time. `deferLoading` + * is used to indicate that deferred loading is required, but it is also used + * to tell DataTables how many records there are in the full table (allowing + * the information element and pagination to be displayed correctly). In the case + * where a filtering is applied to the table on initial load, this can be + * indicated by giving the parameter as an array, where the first element is + * the number of records available after filtering and the second element is the + * number of records without filtering (allowing the table information element + * to be shown correctly). + * @type int | array + * @default null + * + * @dtopt Options + * @name DataTable.defaults.deferLoading + * + * @example + * // 57 records available in the table, no filtering applied + * $(document).ready( function() { + * $('#example').dataTable( { + * "serverSide": true, + * "ajax": "scripts/server_processing.php", + * "deferLoading": 57 + * } ); + * } ); + * + * @example + * // 57 records after filtering, 100 without filtering (an initial filter applied) + * $(document).ready( function() { + * $('#example').dataTable( { + * "serverSide": true, + * "ajax": "scripts/server_processing.php", + * "deferLoading": [ 57, 100 ], + * "search": { + * "search": "my_filter" + * } + * } ); + * } ); + */ + "iDeferLoading": null, + + + /** + * Number of rows to display on a single page when using pagination. If + * feature enabled (`lengthChange`) then the end user will be able to override + * this to a custom setting using a pop-up menu. + * @type int + * @default 10 + * + * @dtopt Options + * @name DataTable.defaults.pageLength + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "pageLength": 50 + * } ); + * } ) + */ + "iDisplayLength": 10, + + + /** + * Define the starting point for data display when using DataTables with + * pagination. Note that this parameter is the number of records, rather than + * the page number, so if you have 10 records per page and want to start on + * the third page, it should be "20". + * @type int + * @default 0 + * + * @dtopt Options + * @name DataTable.defaults.displayStart + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "displayStart": 20 + * } ); + * } ) + */ + "iDisplayStart": 0, + + + /** + * By default DataTables allows keyboard navigation of the table (sorting, paging, + * and filtering) by adding a `tabindex` attribute to the required elements. This + * allows you to tab through the controls and press the enter key to activate them. + * The tabindex is default 0, meaning that the tab follows the flow of the document. + * You can overrule this using this parameter if you wish. Use a value of -1 to + * disable built-in keyboard navigation. + * @type int + * @default 0 + * + * @dtopt Options + * @name DataTable.defaults.tabIndex + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "tabIndex": 1 + * } ); + * } ); + */ + "iTabIndex": 0, + + + /** + * Classes that DataTables assigns to the various components and features + * that it adds to the HTML table. This allows classes to be configured + * during initialisation in addition to through the static + * {@link DataTable.ext.oStdClasses} object). + * @namespace + * @name DataTable.defaults.classes + */ + "oClasses": {}, + + + /** + * All strings that DataTables uses in the user interface that it creates + * are defined in this object, allowing you to modified them individually or + * completely replace them all as required. + * @namespace + * @name DataTable.defaults.language + */ + "oLanguage": { + /** + * Strings that are used for WAI-ARIA labels and controls only (these are not + * actually visible on the page, but will be read by screenreaders, and thus + * must be internationalised as well). + * @namespace + * @name DataTable.defaults.language.aria + */ + "oAria": { + /** + * ARIA label that is added to the table headers when the column may be + * sorted ascending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * + * @dtopt Language + * @name DataTable.defaults.language.aria.sortAscending + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "aria": { + * "sortAscending": " - click/return to sort ascending" + * } + * } + * } ); + * } ); + */ + "sSortAscending": ": activate to sort column ascending", + + /** + * ARIA label that is added to the table headers when the column may be + * sorted descending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * + * @dtopt Language + * @name DataTable.defaults.language.aria.sortDescending + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "aria": { + * "sortDescending": " - click/return to sort descending" + * } + * } + * } ); + * } ); + */ + "sSortDescending": ": activate to sort column descending" + }, + + /** + * Pagination string used by DataTables for the built-in pagination + * control types. + * @namespace + * @name DataTable.defaults.language.paginate + */ + "oPaginate": { + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the first page. + * @type string + * @default First + * + * @dtopt Language + * @name DataTable.defaults.language.paginate.first + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "paginate": { + * "first": "First page" + * } + * } + * } ); + * } ); + */ + "sFirst": "First", + + + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the last page. + * @type string + * @default Last + * + * @dtopt Language + * @name DataTable.defaults.language.paginate.last + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "paginate": { + * "last": "Last page" + * } + * } + * } ); + * } ); + */ + "sLast": "Last", + + + /** + * Text to use for the 'next' pagination button (to take the user to the + * next page). + * @type string + * @default Next + * + * @dtopt Language + * @name DataTable.defaults.language.paginate.next + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "paginate": { + * "next": "Next page" + * } + * } + * } ); + * } ); + */ + "sNext": "Next", + + + /** + * Text to use for the 'previous' pagination button (to take the user to + * the previous page). + * @type string + * @default Previous + * + * @dtopt Language + * @name DataTable.defaults.language.paginate.previous + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "paginate": { + * "previous": "Previous page" + * } + * } + * } ); + * } ); + */ + "sPrevious": "Previous" + }, + + /** + * This string is shown in preference to `zeroRecords` when the table is + * empty of data (regardless of filtering). Note that this is an optional + * parameter - if it is not given, the value of `zeroRecords` will be used + * instead (either the default or given value). + * @type string + * @default No data available in table + * + * @dtopt Language + * @name DataTable.defaults.language.emptyTable + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "emptyTable": "No data available in table" + * } + * } ); + * } ); + */ + "sEmptyTable": "No data available in table", + + + /** + * This string gives information to the end user about the information + * that is current on display on the page. The following tokens can be + * used in the string and will be dynamically replaced as the table + * display updates. This tokens can be placed anywhere in the string, or + * removed as needed by the language requires: + * + * * `\_START\_` - Display index of the first record on the current page + * * `\_END\_` - Display index of the last record on the current page + * * `\_TOTAL\_` - Number of records in the table after filtering + * * `\_MAX\_` - Number of records in the table without filtering + * * `\_PAGE\_` - Current page number + * * `\_PAGES\_` - Total number of pages of data in the table + * + * @type string + * @default Showing _START_ to _END_ of _TOTAL_ entries + * + * @dtopt Language + * @name DataTable.defaults.language.info + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "info": "Showing page _PAGE_ of _PAGES_" + * } + * } ); + * } ); + */ + "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", + + + /** + * Display information string for when the table is empty. Typically the + * format of this string should match `info`. + * @type string + * @default Showing 0 to 0 of 0 entries + * + * @dtopt Language + * @name DataTable.defaults.language.infoEmpty + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "infoEmpty": "No entries to show" + * } + * } ); + * } ); + */ + "sInfoEmpty": "Showing 0 to 0 of 0 entries", + + + /** + * When a user filters the information in a table, this string is appended + * to the information (`info`) to give an idea of how strong the filtering + * is. The variable _MAX_ is dynamically updated. + * @type string + * @default (filtered from _MAX_ total entries) + * + * @dtopt Language + * @name DataTable.defaults.language.infoFiltered + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "infoFiltered": " - filtering from _MAX_ records" + * } + * } ); + * } ); + */ + "sInfoFiltered": "(filtered from _MAX_ total entries)", + + + /** + * If can be useful to append extra information to the info string at times, + * and this variable does exactly that. This information will be appended to + * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are + * being used) at all times. + * @type string + * @default <i>Empty string</i> + * + * @dtopt Language + * @name DataTable.defaults.language.infoPostFix + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "infoPostFix": "All records shown are derived from real information." + * } + * } ); + * } ); + */ + "sInfoPostFix": "", + + + /** + * This decimal place operator is a little different from the other + * language options since DataTables doesn't output floating point + * numbers, so it won't ever use this for display of a number. Rather, + * what this parameter does is modify the sort methods of the table so + * that numbers which are in a format which has a character other than + * a period (`.`) as a decimal place will be sorted numerically. + * + * Note that numbers with different decimal places cannot be shown in + * the same table and still be sortable, the table must be consistent. + * However, multiple different tables on the page can use different + * decimal place characters. + * @type string + * @default + * + * @dtopt Language + * @name DataTable.defaults.language.decimal + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "decimal": "," + * "thousands": "." + * } + * } ); + * } ); + */ + "sDecimal": "", + + + /** + * DataTables has a build in number formatter (`formatNumber`) which is + * used to format large numbers that are used in the table information. + * By default a comma is used, but this can be trivially changed to any + * character you wish with this parameter. + * @type string + * @default , + * + * @dtopt Language + * @name DataTable.defaults.language.thousands + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "thousands": "'" + * } + * } ); + * } ); + */ + "sThousands": ",", + + + /** + * Detail the action that will be taken when the drop down menu for the + * pagination length option is changed. The '_MENU_' variable is replaced + * with a default select list of 10, 25, 50 and 100, and can be replaced + * with a custom select box if required. + * @type string + * @default Show _MENU_ entries + * + * @dtopt Language + * @name DataTable.defaults.language.lengthMenu + * + * @example + * // Language change only + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "lengthMenu": "Display _MENU_ records" + * } + * } ); + * } ); + * + * @example + * // Language and options change + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "lengthMenu": 'Display <select>'+ + * '<option value="10">10</option>'+ + * '<option value="20">20</option>'+ + * '<option value="30">30</option>'+ + * '<option value="40">40</option>'+ + * '<option value="50">50</option>'+ + * '<option value="-1">All</option>'+ + * '</select> records' + * } + * } ); + * } ); + */ + "sLengthMenu": "Show _MENU_ entries", + + + /** + * When using Ajax sourced data and during the first draw when DataTables is + * gathering the data, this message is shown in an empty row in the table to + * indicate to the end user the the data is being loaded. Note that this + * parameter is not used when loading data by server-side processing, just + * Ajax sourced data with client-side processing. + * @type string + * @default Loading... + * + * @dtopt Language + * @name DataTable.defaults.language.loadingRecords + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "loadingRecords": "Please wait - loading..." + * } + * } ); + * } ); + */ + "sLoadingRecords": "Loading...", + + + /** + * Text which is displayed when the table is processing a user action + * (usually a sort command or similar). + * @type string + * @default Processing... + * + * @dtopt Language + * @name DataTable.defaults.language.processing + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "processing": "DataTables is currently busy" + * } + * } ); + * } ); + */ + "sProcessing": "Processing...", + + + /** + * Details the actions that will be taken when the user types into the + * filtering input text box. The variable "_INPUT_", if used in the string, + * is replaced with the HTML text box for the filtering input allowing + * control over where it appears in the string. If "_INPUT_" is not given + * then the input box is appended to the string automatically. + * @type string + * @default Search: + * + * @dtopt Language + * @name DataTable.defaults.language.search + * + * @example + * // Input text box will be appended at the end automatically + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "search": "Filter records:" + * } + * } ); + * } ); + * + * @example + * // Specify where the filter should appear + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "search": "Apply filter _INPUT_ to table" + * } + * } ); + * } ); + */ + "sSearch": "Search:", + + + /** + * Assign a `placeholder` attribute to the search `input` element + * @type string + * @default + * + * @dtopt Language + * @name DataTable.defaults.language.searchPlaceholder + */ + "sSearchPlaceholder": "", + + + /** + * All of the language information can be stored in a file on the + * server-side, which DataTables will look up if this parameter is passed. + * It must store the URL of the language file, which is in a JSON format, + * and the object has the same properties as the oLanguage object in the + * initialiser object (i.e. the above parameters). Please refer to one of + * the example language files to see how this works in action. + * @type string + * @default <i>Empty string - i.e. disabled</i> + * + * @dtopt Language + * @name DataTable.defaults.language.url + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" + * } + * } ); + * } ); + */ + "sUrl": "", + + + /** + * Text shown inside the table records when the is no information to be + * displayed after filtering. `emptyTable` is shown when there is simply no + * information in the table at all (regardless of filtering). + * @type string + * @default No matching records found + * + * @dtopt Language + * @name DataTable.defaults.language.zeroRecords + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "language": { + * "zeroRecords": "No records to display" + * } + * } ); + * } ); + */ + "sZeroRecords": "No matching records found" + }, + + + /** + * This parameter allows you to have define the global filtering state at + * initialisation time. As an object the `search` parameter must be + * defined, but all other parameters are optional. When `regex` is true, + * the search string will be treated as a regular expression, when false + * (default) it will be treated as a straight string. When `smart` + * DataTables will use it's smart filtering methods (to word match at + * any point in the data), when false this will not be done. + * @namespace + * @extends DataTable.models.oSearch + * + * @dtopt Options + * @name DataTable.defaults.search + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "search": {"search": "Initial search"} + * } ); + * } ) + */ + "oSearch": $.extend( {}, DataTable.models.oSearch ), + + + /** + * __Deprecated__ The functionality provided by this parameter has now been + * superseded by that provided through `ajax`, which should be used instead. + * + * By default DataTables will look for the property `data` (or `aaData` for + * compatibility with DataTables 1.9-) when obtaining data from an Ajax + * source or for server-side processing - this parameter allows that + * property to be changed. You can use Javascript dotted object notation to + * get a data source for multiple levels of nesting. + * @type string + * @default data + * + * @dtopt Options + * @dtopt Server-side + * @name DataTable.defaults.ajaxDataProp + * + * @deprecated 1.10. Please use `ajax` for this functionality now. + */ + "sAjaxDataProp": "data", + + + /** + * __Deprecated__ The functionality provided by this parameter has now been + * superseded by that provided through `ajax`, which should be used instead. + * + * You can instruct DataTables to load data from an external + * source using this parameter (use aData if you want to pass data in you + * already have). Simply provide a url a JSON object can be obtained from. + * @type string + * @default null + * + * @dtopt Options + * @dtopt Server-side + * @name DataTable.defaults.ajaxSource + * + * @deprecated 1.10. Please use `ajax` for this functionality now. + */ + "sAjaxSource": null, + + + /** + * This initialisation variable allows you to specify exactly where in the + * DOM you want DataTables to inject the various controls it adds to the page + * (for example you might want the pagination controls at the top of the + * table). DIV elements (with or without a custom class) can also be added to + * aid styling. The follow syntax is used: + * <ul> + * <li>The following options are allowed: + * <ul> + * <li>'l' - Length changing</li> + * <li>'f' - Filtering input</li> + * <li>'t' - The table!</li> + * <li>'i' - Information</li> + * <li>'p' - Pagination</li> + * <li>'r' - pRocessing</li> + * </ul> + * </li> + * <li>The following constants are allowed: + * <ul> + * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> + * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> + * </ul> + * </li> + * <li>The following syntax is expected: + * <ul> + * <li>'<' and '>' - div elements</li> + * <li>'<"class" and '>' - div with a class</li> + * <li>'<"#id" and '>' - div with an ID</li> + * </ul> + * </li> + * <li>Examples: + * <ul> + * <li>'<"wrapper"flipt>'</li> + * <li>'<lf<t>ip>'</li> + * </ul> + * </li> + * </ul> + * @type string + * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> + * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> + * + * @dtopt Options + * @name DataTable.defaults.dom + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "dom": '<"top"i>rt<"bottom"flp><"clear">' + * } ); + * } ); + */ + "sDom": "lfrtip", + + + /** + * Search delay option. This will throttle full table searches that use the + * DataTables provided search input element (it does not effect calls to + * `dt-api search()`, providing a delay before the search is made. + * @type integer + * @default 0 + * + * @dtopt Options + * @name DataTable.defaults.searchDelay + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "searchDelay": 200 + * } ); + * } ) + */ + "searchDelay": null, + + + /** + * DataTables features four different built-in options for the buttons to + * display for pagination control: + * + * * `simple` - 'Previous' and 'Next' buttons only + * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers + * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons + * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus + * page numbers + * + * Further methods can be added using {@link DataTable.ext.oPagination}. + * @type string + * @default simple_numbers + * + * @dtopt Options + * @name DataTable.defaults.pagingType + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "pagingType": "full_numbers" + * } ); + * } ) + */ + "sPaginationType": "simple_numbers", + + + /** + * Enable horizontal scrolling. When a table is too wide to fit into a + * certain layout, or you have a large number of columns in the table, you + * can enable x-scrolling to show the table in a viewport, which can be + * scrolled. This property can be `true` which will allow the table to + * scroll horizontally when needed, or any CSS unit, or a number (in which + * case it will be treated as a pixel measurement). Setting as simply `true` + * is recommended. + * @type boolean|string + * @default <i>blank string - i.e. disabled</i> + * + * @dtopt Features + * @name DataTable.defaults.scrollX + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "scrollX": true, + * "scrollCollapse": true + * } ); + * } ); + */ + "sScrollX": "", + + + /** + * This property can be used to force a DataTable to use more width than it + * might otherwise do when x-scrolling is enabled. For example if you have a + * table which requires to be well spaced, this parameter is useful for + * "over-sizing" the table, and thus forcing scrolling. This property can by + * any CSS unit, or a number (in which case it will be treated as a pixel + * measurement). + * @type string + * @default <i>blank string - i.e. disabled</i> + * + * @dtopt Options + * @name DataTable.defaults.scrollXInner + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "scrollX": "100%", + * "scrollXInner": "110%" + * } ); + * } ); + */ + "sScrollXInner": "", + + + /** + * Enable vertical scrolling. Vertical scrolling will constrain the DataTable + * to the given height, and enable scrolling for any data which overflows the + * current viewport. This can be used as an alternative to paging to display + * a lot of data in a small area (although paging and scrolling can both be + * enabled at the same time). This property can be any CSS unit, or a number + * (in which case it will be treated as a pixel measurement). + * @type string + * @default <i>blank string - i.e. disabled</i> + * + * @dtopt Features + * @name DataTable.defaults.scrollY + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "scrollY": "200px", + * "paginate": false + * } ); + * } ); + */ + "sScrollY": "", + + + /** + * __Deprecated__ The functionality provided by this parameter has now been + * superseded by that provided through `ajax`, which should be used instead. + * + * Set the HTTP method that is used to make the Ajax call for server-side + * processing or Ajax sourced data. + * @type string + * @default GET + * + * @dtopt Options + * @dtopt Server-side + * @name DataTable.defaults.serverMethod + * + * @deprecated 1.10. Please use `ajax` for this functionality now. + */ + "sServerMethod": "GET", + + + /** + * DataTables makes use of renderers when displaying HTML elements for + * a table. These renderers can be added or modified by plug-ins to + * generate suitable mark-up for a site. For example the Bootstrap + * integration plug-in for DataTables uses a paging button renderer to + * display pagination buttons in the mark-up required by Bootstrap. + * + * For further information about the renderers available see + * DataTable.ext.renderer + * @type string|object + * @default null + * + * @name DataTable.defaults.renderer + * + */ + "renderer": null + }; + + _fnHungarianMap( DataTable.defaults ); + + + + /* + * Developer note - See note in model.defaults.js about the use of Hungarian + * notation and camel case. + */ + + /** + * Column options that can be given to DataTables at initialisation time. + * @namespace + */ + DataTable.defaults.column = { + /** + * Define which column(s) an order will occur on for this column. This + * allows a column's ordering to take multiple columns into account when + * doing a sort or use the data from a different column. For example first + * name / last name columns make sense to do a multi-column sort over the + * two columns. + * @type array|int + * @default null <i>Takes the value of the column index automatically</i> + * + * @name DataTable.defaults.column.orderData + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, + * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, + * { "orderData": 2, "targets": [ 2 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "orderData": [ 0, 1 ] }, + * { "orderData": [ 1, 0 ] }, + * { "orderData": 2 }, + * null, + * null + * ] + * } ); + * } ); + */ + "aDataSort": null, + "iDataSort": -1, + + + /** + * You can control the default ordering direction, and even alter the + * behaviour of the sort handler (i.e. only allow ascending ordering etc) + * using this parameter. + * @type array + * @default [ 'asc', 'desc' ] + * + * @name DataTable.defaults.column.orderSequence + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, + * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, + * { "orderSequence": [ "desc" ], "targets": [ 3 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * null, + * { "orderSequence": [ "asc" ] }, + * { "orderSequence": [ "desc", "asc", "asc" ] }, + * { "orderSequence": [ "desc" ] }, + * null + * ] + * } ); + * } ); + */ + "asSorting": [ 'asc', 'desc' ], + + + /** + * Enable or disable filtering on the data in this column. + * @type boolean + * @default true + * + * @name DataTable.defaults.column.searchable + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "searchable": false, "targets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "searchable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSearchable": true, + + + /** + * Enable or disable ordering on this column. + * @type boolean + * @default true + * + * @name DataTable.defaults.column.orderable + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "orderable": false, "targets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "orderable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSortable": true, + + + /** + * Enable or disable the display of this column. + * @type boolean + * @default true + * + * @name DataTable.defaults.column.visible + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "visible": false, "targets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "visible": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bVisible": true, + + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to mRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available. + * @type function + * @param {element} td The TD node that has been created + * @param {*} cellData The Data for the cell + * @param {array|object} rowData The data for the whole row + * @param {int} row The row index for the aoData data store + * @param {int} col The column index for aoColumns + * + * @name DataTable.defaults.column.createdCell + * @dtopt Columns + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [3], + * "createdCell": function (td, cellData, rowData, row, col) { + * if ( cellData == "1.7" ) { + * $(td).css('color', 'blue') + * } + * } + * } ] + * }); + * } ); + */ + "fnCreatedCell": null, + + + /** + * This parameter has been replaced by `data` in DataTables to ensure naming + * consistency. `dataProp` can still be used, as there is backwards + * compatibility in DataTables for this option, but it is strongly + * recommended that you use `data` in preference to `dataProp`. + * @name DataTable.defaults.column.dataProp + */ + + + /** + * This property can be used to read data from any data source property, + * including deeply nested objects / properties. `data` can be given in a + * number of different ways which effect its behaviour: + * + * * `integer` - treated as an array index for the data source. This is the + * default that DataTables uses (incrementally increased for each column). + * * `string` - read an object property from the data source. There are + * three 'special' options that can be used in the string to alter how + * DataTables reads the data from the source object: + * * `.` - Dotted Javascript notation. Just as you use a `.` in + * Javascript to read from nested objects, so to can the options + * specified in `data`. For example: `browser.version` or + * `browser.name`. If your object parameter name contains a period, use + * `\\` to escape it - i.e. `first\\.name`. + * * `[]` - Array notation. DataTables can automatically combine data + * from and array source, joining the data with the characters provided + * between the two brackets. For example: `name[, ]` would provide a + * comma-space separated list from the source array. If no characters + * are provided between the brackets, the original array source is + * returned. + * * `()` - Function notation. Adding `()` to the end of a parameter will + * execute a function of the name given. For example: `browser()` for a + * simple function on the data source, `browser.version()` for a + * function in a nested property or even `browser().version` to get an + * object property if the function called returns an object. Note that + * function notation is recommended for use in `render` rather than + * `data` as it is much simpler to use as a renderer. + * * `null` - use the original data source for the row rather than plucking + * data directly from it. This action has effects on two other + * initialisation options: + * * `defaultContent` - When null is given as the `data` option and + * `defaultContent` is specified for the column, the value defined by + * `defaultContent` will be used for the cell. + * * `render` - When null is used for the `data` option and the `render` + * option is specified for the column, the whole data source for the + * row is used for the renderer. + * * `function` - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function + * takes three parameters: + * * Parameters: + * * `{array|object}` The data source for the row + * * `{string}` The type call data requested - this will be 'set' when + * setting data or 'filter', 'display', 'type', 'sort' or undefined + * when gathering data. Note that when `undefined` is given for the + * type DataTables expects to get the raw data for the object back< + * * `{*}` Data to set when the second parameter is 'set'. + * * Return: + * * The return value from the function is not required when 'set' is + * the type of call, but otherwise the return is what will be used + * for the data requested. + * + * Note that `data` is a getter and setter option. If you just require + * formatting of data for output, you will likely want to use `render` which + * is simply a getter and thus simpler to use. + * + * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The + * name change reflects the flexibility of this property and is consistent + * with the naming of mRender. If 'mDataProp' is given, then it will still + * be used by DataTables, as it automatically maps the old name to the new + * if required. + * + * @type string|int|function|null + * @default null <i>Use automatically calculated column index</i> + * + * @name DataTable.defaults.column.data + * @dtopt Columns + * + * @example + * // Read table data from objects + * // JSON structure for each row: + * // { + * // "engine": {value}, + * // "browser": {value}, + * // "platform": {value}, + * // "version": {value}, + * // "grade": {value} + * // } + * $(document).ready( function() { + * $('#example').dataTable( { + * "ajaxSource": "sources/objects.txt", + * "columns": [ + * { "data": "engine" }, + * { "data": "browser" }, + * { "data": "platform" }, + * { "data": "version" }, + * { "data": "grade" } + * ] + * } ); + * } ); + * + * @example + * // Read information from deeply nested objects + * // JSON structure for each row: + * // { + * // "engine": {value}, + * // "browser": {value}, + * // "platform": { + * // "inner": {value} + * // }, + * // "details": [ + * // {value}, {value} + * // ] + * // } + * $(document).ready( function() { + * $('#example').dataTable( { + * "ajaxSource": "sources/deep.txt", + * "columns": [ + * { "data": "engine" }, + * { "data": "browser" }, + * { "data": "platform.inner" }, + * { "data": "platform.details.0" }, + * { "data": "platform.details.1" } + * ] + * } ); + * } ); + * + * @example + * // Using `data` as a function to provide different information for + * // sorting, filtering and display. In this case, currency (price) + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": function ( source, type, val ) { + * if (type === 'set') { + * source.price = val; + * // Store the computed dislay and filter values for efficiency + * source.price_display = val=="" ? "" : "$"+numberFormat(val); + * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; + * return; + * } + * else if (type === 'display') { + * return source.price_display; + * } + * else if (type === 'filter') { + * return source.price_filter; + * } + * // 'sort', 'type' and undefined all just use the integer + * return source.price; + * } + * } ] + * } ); + * } ); + * + * @example + * // Using default content + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": null, + * "defaultContent": "Click to edit" + * } ] + * } ); + * } ); + * + * @example + * // Using array notation - outputting a list from an array + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": "name[, ]" + * } ] + * } ); + * } ); + * + */ + "mData": null, + + + /** + * This property is the rendering partner to `data` and it is suggested that + * when you want to manipulate data for display (including filtering, + * sorting etc) without altering the underlying data for the table, use this + * property. `render` can be considered to be the the read only companion to + * `data` which is read / write (then as such more complex). Like `data` + * this option can be given in a number of different ways to effect its + * behaviour: + * + * * `integer` - treated as an array index for the data source. This is the + * default that DataTables uses (incrementally increased for each column). + * * `string` - read an object property from the data source. There are + * three 'special' options that can be used in the string to alter how + * DataTables reads the data from the source object: + * * `.` - Dotted Javascript notation. Just as you use a `.` in + * Javascript to read from nested objects, so to can the options + * specified in `data`. For example: `browser.version` or + * `browser.name`. If your object parameter name contains a period, use + * `\\` to escape it - i.e. `first\\.name`. + * * `[]` - Array notation. DataTables can automatically combine data + * from and array source, joining the data with the characters provided + * between the two brackets. For example: `name[, ]` would provide a + * comma-space separated list from the source array. If no characters + * are provided between the brackets, the original array source is + * returned. + * * `()` - Function notation. Adding `()` to the end of a parameter will + * execute a function of the name given. For example: `browser()` for a + * simple function on the data source, `browser.version()` for a + * function in a nested property or even `browser().version` to get an + * object property if the function called returns an object. + * * `object` - use different data for the different data types requested by + * DataTables ('filter', 'display', 'type' or 'sort'). The property names + * of the object is the data type the property refers to and the value can + * defined using an integer, string or function using the same rules as + * `render` normally does. Note that an `_` option _must_ be specified. + * This is the default value to use if you haven't specified a value for + * the data type requested by DataTables. + * * `function` - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function + * takes three parameters: + * * Parameters: + * * {array|object} The data source for the row (based on `data`) + * * {string} The type call data requested - this will be 'filter', + * 'display', 'type' or 'sort'. + * * {array|object} The full data source for the row (not based on + * `data`) + * * Return: + * * The return value from the function is what will be used for the + * data requested. + * + * @type string|int|function|object|null + * @default null Use the data source value. + * + * @name DataTable.defaults.column.render + * @dtopt Columns + * + * @example + * // Create a comma separated list from an array of objects + * $(document).ready( function() { + * $('#example').dataTable( { + * "ajaxSource": "sources/deep.txt", + * "columns": [ + * { "data": "engine" }, + * { "data": "browser" }, + * { + * "data": "platform", + * "render": "[, ].name" + * } + * ] + * } ); + * } ); + * + * @example + * // Execute a function to obtain data + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": null, // Use the full data source object for the renderer's source + * "render": "browserName()" + * } ] + * } ); + * } ); + * + * @example + * // As an object, extracting different data for the different types + * // This would be used with a data source such as: + * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } + * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` + * // (which has both forms) is used for filtering for if a user inputs either format, while + * // the formatted phone number is the one that is shown in the table. + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": null, // Use the full data source object for the renderer's source + * "render": { + * "_": "phone", + * "filter": "phone_filter", + * "display": "phone_display" + * } + * } ] + * } ); + * } ); + * + * @example + * // Use as a function to create a link from the data source + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": "download_link", + * "render": function ( data, type, full ) { + * return '<a href="'+data+'">Download</a>'; + * } + * } ] + * } ); + * } ); + */ + "mRender": null, + + + /** + * Change the cell type created for the column - either TD cells or TH cells. This + * can be useful as TH cells have semantic meaning in the table body, allowing them + * to act as a header for a row (you may wish to add scope='row' to the TH elements). + * @type string + * @default td + * + * @name DataTable.defaults.column.cellType + * @dtopt Columns + * + * @example + * // Make the first column use TH cells + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "cellType": "th" + * } ] + * } ); + * } ); + */ + "sCellType": "td", + + + /** + * Class to give to each cell in this column. + * @type string + * @default <i>Empty string</i> + * + * @name DataTable.defaults.column.class + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "class": "my_class", "targets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "class": "my_class" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sClass": "", + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * Generally you shouldn't need this! + * @type string + * @default <i>Empty string<i> + * + * @name DataTable.defaults.column.contentPadding + * @dtopt Columns + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * null, + * null, + * null, + * { + * "contentPadding": "mmm" + * } + * ] + * } ); + * } ); + */ + "sContentPadding": "", + + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because `data` + * is set to null, or because the data source itself is null). + * @type string + * @default null + * + * @name DataTable.defaults.column.defaultContent + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { + * "data": null, + * "defaultContent": "Edit", + * "targets": [ -1 ] + * } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * null, + * null, + * null, + * { + * "data": null, + * "defaultContent": "Edit" + * } + * ] + * } ); + * } ); + */ + "sDefaultContent": null, + + + /** + * This parameter is only used in DataTables' server-side processing. It can + * be exceptionally useful to know what columns are being displayed on the + * client side, and to map these to database fields. When defined, the names + * also allow DataTables to reorder information from the server if it comes + * back in an unexpected order (i.e. if you switch your columns around on the + * client-side, your server-side code does not also need updating). + * @type string + * @default <i>Empty string</i> + * + * @name DataTable.defaults.column.name + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "name": "engine", "targets": [ 0 ] }, + * { "name": "browser", "targets": [ 1 ] }, + * { "name": "platform", "targets": [ 2 ] }, + * { "name": "version", "targets": [ 3 ] }, + * { "name": "grade", "targets": [ 4 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "name": "engine" }, + * { "name": "browser" }, + * { "name": "platform" }, + * { "name": "version" }, + * { "name": "grade" } + * ] + * } ); + * } ); + */ + "sName": "", + + + /** + * Defines a data source type for the ordering which can be used to read + * real-time information from the table (updating the internally cached + * version) prior to ordering. This allows ordering to occur on user + * editable elements such as form inputs. + * @type string + * @default std + * + * @name DataTable.defaults.column.orderDataType + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, + * { "type": "numeric", "targets": [ 3 ] }, + * { "orderDataType": "dom-select", "targets": [ 4 ] }, + * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * null, + * null, + * { "orderDataType": "dom-text" }, + * { "orderDataType": "dom-text", "type": "numeric" }, + * { "orderDataType": "dom-select" }, + * { "orderDataType": "dom-checkbox" } + * ] + * } ); + * } ); + */ + "sSortDataType": "std", + + + /** + * The title of this column. + * @type string + * @default null <i>Derived from the 'TH' value for this column in the + * original HTML table.</i> + * + * @name DataTable.defaults.column.title + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "title": "My column title", "targets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "title": "My column title" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sTitle": null, + + + /** + * The type allows you to specify how the data for this column will be + * ordered. Four types (string, numeric, date and html (which will strip + * HTML tags before ordering)) are currently available. Note that only date + * formats understood by Javascript's Date() object will be accepted as type + * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', + * 'numeric', 'date' or 'html' (by default). Further types can be adding + * through plug-ins. + * @type string + * @default null <i>Auto-detected from raw data</i> + * + * @name DataTable.defaults.column.type + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "type": "html", "targets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "type": "html" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sType": null, + + + /** + * Defining the width of the column, this parameter may take any CSS value + * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not + * been given a specific width through this interface ensuring that the table + * remains readable. + * @type string + * @default null <i>Automatic</i> + * + * @name DataTable.defaults.column.width + * @dtopt Columns + * + * @example + * // Using `columnDefs` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ + * { "width": "20%", "targets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using `columns` + * $(document).ready( function() { + * $('#example').dataTable( { + * "columns": [ + * { "width": "20%" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sWidth": null + }; + + _fnHungarianMap( DataTable.defaults.column ); + + + + /** + * DataTables settings object - this holds all the information needed for a + * given table, including configuration, data and current application of the + * table options. DataTables does not have a single instance for each DataTable + * with the settings attached to that instance, but rather instances of the + * DataTable "class" are created on-the-fly as needed (typically by a + * $().dataTable() call) and the settings object is then applied to that + * instance. + * + * Note that this object is related to {@link DataTable.defaults} but this + * one is the internal data store for DataTables's cache of columns. It should + * NOT be manipulated outside of DataTables. Any configuration should be done + * through the initialisation options. + * @namespace + * @todo Really should attach the settings object to individual instances so we + * don't need to create new instances on each $().dataTable() call (if the + * table already exists). It would also save passing oSettings around and + * into every single function. However, this is a very significant + * architecture change for DataTables and will almost certainly break + * backwards compatibility with older installations. This is something that + * will be done in 2.0. + */ + DataTable.models.oSettings = { + /** + * Primary features of DataTables and their enablement state. + * @namespace + */ + "oFeatures": { + + /** + * Flag to say if DataTables should automatically try to calculate the + * optimum table and columns widths (true) or not (false). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bAutoWidth": null, + + /** + * Delay the creation of TR and TD elements until they are actually + * needed by a driven page draw. This can give a significant speed + * increase for Ajax source and Javascript source data, but makes no + * difference at all fro DOM and server-side processing tables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bDeferRender": null, + + /** + * Enable filtering on the table or not. Note that if this is disabled + * then there is no filtering at all on the table, including fnFilter. + * To just remove the filtering input use sDom and remove the 'f' option. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bFilter": null, + + /** + * Table information element (the 'Showing x of y records' div) enable + * flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bInfo": null, + + /** + * Present a user control allowing the end user to change the page size + * when pagination is enabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bLengthChange": null, + + /** + * Pagination enabled or not. Note that if this is disabled then length + * changing must also be disabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bPaginate": null, + + /** + * Processing indicator enable flag whenever DataTables is enacting a + * user request - typically an Ajax request for server-side processing. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bProcessing": null, + + /** + * Server-side processing enabled flag - when enabled DataTables will + * get all data from the server for every draw - there is no filtering, + * sorting or paging done on the client-side. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bServerSide": null, + + /** + * Sorting enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSort": null, + + /** + * Multi-column sorting + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortMulti": null, + + /** + * Apply a class to the columns which are being sorted to provide a + * visual highlight or not. This can slow things down when enabled since + * there is a lot of DOM interaction. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortClasses": null, + + /** + * State saving enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bStateSave": null + }, + + + /** + * Scrolling settings for a table. + * @namespace + */ + "oScroll": { + /** + * When the table is shorter in height than sScrollY, collapse the + * table container down to the height of the table (when true). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bCollapse": null, + + /** + * Width of the scrollbar for the web-browser's platform. Calculated + * during table initialisation. + * @type int + * @default 0 + */ + "iBarWidth": 0, + + /** + * Viewport width for horizontal scrolling. Horizontal scrolling is + * disabled if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sX": null, + + /** + * Width to expand the table to when using x-scrolling. Typically you + * should not need to use this. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @deprecated + */ + "sXInner": null, + + /** + * Viewport height for vertical scrolling. Vertical scrolling is disabled + * if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sY": null + }, + + /** + * Language information for the table. + * @namespace + * @extends DataTable.defaults.oLanguage + */ + "oLanguage": { + /** + * Information callback function. See + * {@link DataTable.defaults.fnInfoCallback} + * @type function + * @default null + */ + "fnInfoCallback": null + }, + + /** + * Browser support parameters + * @namespace + */ + "oBrowser": { + /** + * Indicate if the browser incorrectly calculates width:100% inside a + * scrolling element (IE6/7) + * @type boolean + * @default false + */ + "bScrollOversize": false, + + /** + * Determine if the vertical scrollbar is on the right or left of the + * scrolling container - needed for rtl language layout, although not + * all browsers move the scrollbar (Safari). + * @type boolean + * @default false + */ + "bScrollbarLeft": false + }, + + + "ajax": null, + + + /** + * Array referencing the nodes which are used for the features. The + * parameters of this object match what is allowed by sDom - i.e. + * <ul> + * <li>'l' - Length changing</li> + * <li>'f' - Filtering input</li> + * <li>'t' - The table!</li> + * <li>'i' - Information</li> + * <li>'p' - Pagination</li> + * <li>'r' - pRocessing</li> + * </ul> + * @type array + * @default [] + */ + "aanFeatures": [], + + /** + * Store data information - see {@link DataTable.models.oRow} for detailed + * information. + * @type array + * @default [] + */ + "aoData": [], + + /** + * Array of indexes which are in the current display (after filtering etc) + * @type array + * @default [] + */ + "aiDisplay": [], + + /** + * Array of indexes for display - no filtering + * @type array + * @default [] + */ + "aiDisplayMaster": [], + + /** + * Store information about each column that is in use + * @type array + * @default [] + */ + "aoColumns": [], + + /** + * Store information about the table's header + * @type array + * @default [] + */ + "aoHeader": [], + + /** + * Store information about the table's footer + * @type array + * @default [] + */ + "aoFooter": [], + + /** + * Store the applied global search information in case we want to force a + * research or compare the old search to a new one. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @namespace + * @extends DataTable.models.oSearch + */ + "oPreviousSearch": {}, + + /** + * Store the applied search for each column - see + * {@link DataTable.models.oSearch} for the format that is used for the + * filtering information for each column. + * @type array + * @default [] + */ + "aoPreSearchCols": [], + + /** + * Sorting that is applied to the table. Note that the inner arrays are + * used in the following manner: + * <ul> + * <li>Index 0 - column number</li> + * <li>Index 1 - current sorting direction</li> + * </ul> + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @todo These inner arrays should really be objects + */ + "aaSorting": null, + + /** + * Sorting that is always applied to the table (i.e. prefixed in front of + * aaSorting). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "aaSortingFixed": [], + + /** + * Classes to use for the striping of a table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "asStripeClasses": null, + + /** + * If restoring a table - we should restore its striping classes as well + * @type array + * @default [] + */ + "asDestroyStripes": [], + + /** + * If restoring a table - we should restore its width + * @type int + * @default 0 + */ + "sDestroyWidth": 0, + + /** + * Callback functions array for every time a row is inserted (i.e. on a draw). + * @type array + * @default [] + */ + "aoRowCallback": [], + + /** + * Callback functions for the header on each draw. + * @type array + * @default [] + */ + "aoHeaderCallback": [], + + /** + * Callback function for the footer on each draw. + * @type array + * @default [] + */ + "aoFooterCallback": [], + + /** + * Array of callback functions for draw callback functions + * @type array + * @default [] + */ + "aoDrawCallback": [], + + /** + * Array of callback functions for row created function + * @type array + * @default [] + */ + "aoRowCreatedCallback": [], + + /** + * Callback functions for just before the table is redrawn. A return of + * false will be used to cancel the draw. + * @type array + * @default [] + */ + "aoPreDrawCallback": [], + + /** + * Callback functions for when the table has been initialised. + * @type array + * @default [] + */ + "aoInitComplete": [], + + + /** + * Callbacks for modifying the settings to be stored for state saving, prior to + * saving state. + * @type array + * @default [] + */ + "aoStateSaveParams": [], + + /** + * Callbacks for modifying the settings that have been stored for state saving + * prior to using the stored values to restore the state. + * @type array + * @default [] + */ + "aoStateLoadParams": [], + + /** + * Callbacks for operating on the settings object once the saved state has been + * loaded + * @type array + * @default [] + */ + "aoStateLoaded": [], + + /** + * Cache the table ID for quick access + * @type string + * @default <i>Empty string</i> + */ + "sTableId": "", + + /** + * The TABLE node for the main table + * @type node + * @default null + */ + "nTable": null, + + /** + * Permanent ref to the thead element + * @type node + * @default null + */ + "nTHead": null, + + /** + * Permanent ref to the tfoot element - if it exists + * @type node + * @default null + */ + "nTFoot": null, + + /** + * Permanent ref to the tbody element + * @type node + * @default null + */ + "nTBody": null, + + /** + * Cache the wrapper node (contains all DataTables controlled elements) + * @type node + * @default null + */ + "nTableWrapper": null, + + /** + * Indicate if when using server-side processing the loading of data + * should be deferred until the second draw. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + * @default false + */ + "bDeferLoading": false, + + /** + * Indicate if all required information has been read in + * @type boolean + * @default false + */ + "bInitialised": false, + + /** + * Information about open rows. Each object in the array has the parameters + * 'nTr' and 'nParent' + * @type array + * @default [] + */ + "aoOpenRows": [], + + /** + * Dictate the positioning of DataTables' control elements - see + * {@link DataTable.model.oInit.sDom}. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sDom": null, + + /** + * Search delay (in mS) + * @type integer + * @default null + */ + "searchDelay": null, + + /** + * Which type of pagination should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default two_button + */ + "sPaginationType": "two_button", + + /** + * The state duration (for `stateSave`) in seconds. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type int + * @default 0 + */ + "iStateDuration": 0, + + /** + * Array of callback functions for state saving. Each array element is an + * object with the following parameters: + * <ul> + * <li>function:fn - function to call. Takes two parameters, oSettings + * and the JSON string to save that has been thus far created. Returns + * a JSON string to be inserted into a json object + * (i.e. '"param": [ 0, 1, 2]')</li> + * <li>string:sName - name of callback</li> + * </ul> + * @type array + * @default [] + */ + "aoStateSave": [], + + /** + * Array of callback functions for state loading. Each array element is an + * object with the following parameters: + * <ul> + * <li>function:fn - function to call. Takes two parameters, oSettings + * and the object stored. May return false to cancel state loading</li> + * <li>string:sName - name of callback</li> + * </ul> + * @type array + * @default [] + */ + "aoStateLoad": [], + + /** + * State that was saved. Useful for back reference + * @type object + * @default null + */ + "oSavedState": null, + + /** + * State that was loaded. Useful for back reference + * @type object + * @default null + */ + "oLoadedState": null, + + /** + * Source url for AJAX data for the table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sAjaxSource": null, + + /** + * Property from a given object from which to read the table data from. This + * can be an empty string (when not server-side processing), in which case + * it is assumed an an array is given directly. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sAjaxDataProp": null, + + /** + * Note if draw should be blocked while getting data + * @type boolean + * @default true + */ + "bAjaxDataGet": true, + + /** + * The last jQuery XHR object that was used for server-side data gathering. + * This can be used for working with the XHR information in one of the + * callbacks + * @type object + * @default null + */ + "jqXHR": null, + + /** + * JSON returned from the server in the last Ajax request + * @type object + * @default undefined + */ + "json": undefined, + + /** + * Data submitted as part of the last Ajax request + * @type object + * @default undefined + */ + "oAjaxData": undefined, + + /** + * Function to get the server-side data. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnServerData": null, + + /** + * Functions which are called prior to sending an Ajax request so extra + * parameters can easily be sent to the server + * @type array + * @default [] + */ + "aoServerParams": [], + + /** + * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if + * required). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sServerMethod": null, + + /** + * Format numbers for display. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnFormatNumber": null, + + /** + * List of options that can be used for the user selectable length menu. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "aLengthMenu": null, + + /** + * Counter for the draws that the table does. Also used as a tracker for + * server-side processing + * @type int + * @default 0 + */ + "iDraw": 0, + + /** + * Indicate if a redraw is being done - useful for Ajax + * @type boolean + * @default false + */ + "bDrawing": false, + + /** + * Draw index (iDraw) of the last error when parsing the returned data + * @type int + * @default -1 + */ + "iDrawError": -1, + + /** + * Paging display length + * @type int + * @default 10 + */ + "_iDisplayLength": 10, + + /** + * Paging start point - aiDisplay index + * @type int + * @default 0 + */ + "_iDisplayStart": 0, + + /** + * Server-side processing - number of records in the result set + * (i.e. before filtering), Use fnRecordsTotal rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type int + * @default 0 + * @private + */ + "_iRecordsTotal": 0, + + /** + * Server-side processing - number of records in the current display set + * (i.e. after filtering). Use fnRecordsDisplay rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type boolean + * @default 0 + * @private + */ + "_iRecordsDisplay": 0, + + /** + * Flag to indicate if jQuery UI marking and classes should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bJUI": null, + + /** + * The classes to use for the table + * @type object + * @default {} + */ + "oClasses": {}, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if filtering has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bFiltered": false, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if sorting has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bSorted": false, + + /** + * Indicate that if multiple rows are in the header and there is more than + * one unique cell per column, if the top one (true) or bottom one (false) + * should be used for sorting / title by DataTables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortCellsTop": null, + + /** + * Initialisation object that is used for the table + * @type object + * @default null + */ + "oInit": null, + + /** + * Destroy callback functions - for plug-ins to attach themselves to the + * destroy so they can clean up markup and events. + * @type array + * @default [] + */ + "aoDestroyCallback": [], + + + /** + * Get the number of records in the current record set, before filtering + * @type function + */ + "fnRecordsTotal": function () + { + return _fnDataSource( this ) == 'ssp' ? + this._iRecordsTotal * 1 : + this.aiDisplayMaster.length; + }, + + /** + * Get the number of records in the current record set, after filtering + * @type function + */ + "fnRecordsDisplay": function () + { + return _fnDataSource( this ) == 'ssp' ? + this._iRecordsDisplay * 1 : + this.aiDisplay.length; + }, + + /** + * Get the display end point - aiDisplay index + * @type function + */ + "fnDisplayEnd": function () + { + var + len = this._iDisplayLength, + start = this._iDisplayStart, + calc = start + len, + records = this.aiDisplay.length, + features = this.oFeatures, + paginate = features.bPaginate; + + if ( features.bServerSide ) { + return paginate === false || len === -1 ? + start + records : + Math.min( start+len, this._iRecordsDisplay ); + } + else { + return ! paginate || calc>records || len===-1 ? + records : + calc; + } + }, + + /** + * The DataTables object for this table + * @type object + * @default null + */ + "oInstance": null, + + /** + * Unique identifier for each instance of the DataTables object. If there + * is an ID on the table node, then it takes that value, otherwise an + * incrementing internal counter is used. + * @type string + * @default null + */ + "sInstance": null, + + /** + * tabindex attribute value that is added to DataTables control elements, allowing + * keyboard navigation of the table and its controls. + */ + "iTabIndex": 0, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollHead": null, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollFoot": null, + + /** + * Last applied sort + * @type array + * @default [] + */ + "aLastSort": [], + + /** + * Stored plug-in instances + * @type object + * @default {} + */ + "oPlugins": {} + }; + + /** + * Extension object for DataTables that is used to provide all extension + * options. + * + * Note that the `DataTable.ext` object is available through + * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is + * also aliased to `jQuery.fn.dataTableExt` for historic reasons. + * @namespace + * @extends DataTable.models.ext + */ + + + /** + * DataTables extensions + * + * This namespace acts as a collection area for plug-ins that can be used to + * extend DataTables capabilities. Indeed many of the build in methods + * use this method to provide their own capabilities (sorting methods for + * example). + * + * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy + * reasons + * + * @namespace + */ + DataTable.ext = _ext = { + /** + * Element class names + * + * @type object + * @default {} + */ + classes: {}, + + + /** + * Error reporting. + * + * How should DataTables report an error. Can take the value 'alert' or + * 'throw' + * + * @type string + * @default alert + */ + errMode: "alert", + + + /** + * Feature plug-ins. + * + * This is an array of objects which describe the feature plug-ins that are + * available to DataTables. These feature plug-ins are then available for + * use through the `dom` initialisation option. + * + * Each feature plug-in is described by an object which must have the + * following properties: + * + * * `fnInit` - function that is used to initialise the plug-in, + * * `cFeature` - a character so the feature can be enabled by the `dom` + * instillation option. This is case sensitive. + * + * The `fnInit` function has the following input parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * + * And the following return is expected: + * + * * {node|null} The element which contains your feature. Note that the + * return may also be void if your plug-in does not require to inject any + * DOM elements into DataTables control (`dom`) - for example this might + * be useful when developing a plug-in which allows table control via + * keyboard entry + * + * @type array + * + * @example + * $.fn.dataTable.ext.features.push( { + * "fnInit": function( oSettings ) { + * return new TableTools( { "oDTSettings": oSettings } ); + * }, + * "cFeature": "T" + * } ); + */ + feature: [], + + + /** + * Row searching. + * + * This method of searching is complimentary to the default type based + * searching, and a lot more comprehensive as it allows you complete control + * over the searching logic. Each element in this array is a function + * (parameters described below) that is called for every row in the table, + * and your logic decides if it should be included in the searching data set + * or not. + * + * Searching functions have the following input parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{array|object}` Data for the row to be processed (same as the + * original format that was passed in as the data source, or an array + * from a DOM data source + * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which + * can be useful to retrieve the `TR` element if you need DOM interaction. + * + * And the following return is expected: + * + * * {boolean} Include the row in the searched result set (true) or not + * (false) + * + * Note that as with the main search ability in DataTables, technically this + * is "filtering", since it is subtractive. However, for consistency in + * naming we call it searching here. + * + * @type array + * @default [] + * + * @example + * // The following example shows custom search being applied to the + * // fourth column (i.e. the data[3] index) based on two input values + * // from the end-user, matching the data in a certain range. + * $.fn.dataTable.ext.search.push( + * function( settings, data, dataIndex ) { + * var min = document.getElementById('min').value * 1; + * var max = document.getElementById('max').value * 1; + * var version = data[3] == "-" ? 0 : data[3]*1; + * + * if ( min == "" && max == "" ) { + * return true; + * } + * else if ( min == "" && version < max ) { + * return true; + * } + * else if ( min < version && "" == max ) { + * return true; + * } + * else if ( min < version && version < max ) { + * return true; + * } + * return false; + * } + * ); + */ + search: [], + + + /** + * Internal functions, exposed for used in plug-ins. + * + * Please note that you should not need to use the internal methods for + * anything other than a plug-in (and even then, try to avoid if possible). + * The internal function may change between releases. + * + * @type object + * @default {} + */ + internal: {}, + + + /** + * Legacy configuration options. Enable and disable legacy options that + * are available in DataTables. + * + * @type object + */ + legacy: { + /** + * Enable / disable DataTables 1.9 compatible server-side processing + * requests + * + * @type boolean + * @default null + */ + ajax: null + }, + + + /** + * Pagination plug-in methods. + * + * Each entry in this object is a function and defines which buttons should + * be shown by the pagination rendering method that is used for the table: + * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the + * buttons are displayed in the document, while the functions here tell it + * what buttons to display. This is done by returning an array of button + * descriptions (what each button will do). + * + * Pagination types (the four built in options and any additional plug-in + * options defined here) can be used through the `paginationType` + * initialisation parameter. + * + * The functions defined take two parameters: + * + * 1. `{int} page` The current page index + * 2. `{int} pages` The number of pages in the table + * + * Each function is expected to return an array where each element of the + * array can be one of: + * + * * `first` - Jump to first page when activated + * * `last` - Jump to last page when activated + * * `previous` - Show previous page when activated + * * `next` - Show next page when activated + * * `{int}` - Show page of the index given + * * `{array}` - A nested array containing the above elements to add a + * containing 'DIV' element (might be useful for styling). + * + * Note that DataTables v1.9- used this object slightly differently whereby + * an object with two functions would be defined for each plug-in. That + * ability is still supported by DataTables 1.10+ to provide backwards + * compatibility, but this option of use is now decremented and no longer + * documented in DataTables 1.10+. + * + * @type object + * @default {} + * + * @example + * // Show previous, next and current page buttons only + * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { + * return [ 'previous', page, 'next' ]; + * }; + */ + pager: {}, + + + renderer: { + pageButton: {}, + header: {} + }, + + + /** + * Ordering plug-ins - custom data source + * + * The extension options for ordering of data available here is complimentary + * to the default type based ordering that DataTables typically uses. It + * allows much greater control over the the data that is being used to + * order a column, but is necessarily therefore more complex. + * + * This type of ordering is useful if you want to do ordering based on data + * live from the DOM (for example the contents of an 'input' element) rather + * than just the static string that DataTables knows of. + * + * The way these plug-ins work is that you create an array of the values you + * wish to be ordering for the column in question and then return that + * array. The data in the array much be in the index order of the rows in + * the table (not the currently ordering order!). Which order data gathering + * function is run here depends on the `dt-init columns.orderDataType` + * parameter that is used for the column (if any). + * + * The functions defined take two parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{int}` Target column index + * + * Each function is expected to return an array: + * + * * `{array}` Data for the column to be ordering upon + * + * @type array + * + * @example + * // Ordering using `input` node values + * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) + * { + * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { + * return $('input', td).val(); + * } ); + * } + */ + order: {}, + + + /** + * Type based plug-ins. + * + * Each column in DataTables has a type assigned to it, either by automatic + * detection or by direct assignment using the `type` option for the column. + * The type of a column will effect how it is ordering and search (plug-ins + * can also make use of the column type if required). + * + * @namespace + */ + type: { + /** + * Type detection functions. + * + * The functions defined in this object are used to automatically detect + * a column's type, making initialisation of DataTables super easy, even + * when complex data is in the table. + * + * The functions defined take two parameters: + * + * 1. `{*}` Data from the column cell to be analysed + * 2. `{settings}` DataTables settings object. This can be used to + * perform context specific type detection - for example detection + * based on language settings such as using a comma for a decimal + * place. Generally speaking the options from the settings will not + * be required + * + * Each function is expected to return: + * + * * `{string|null}` Data type detected, or null if unknown (and thus + * pass it on to the other type detection functions. + * + * @type array + * + * @example + * // Currency type detection plug-in: + * $.fn.dataTable.ext.type.detect.push( + * function ( data, settings ) { + * // Check the numeric part + * if ( ! $.isNumeric( data.substring(1) ) ) { + * return null; + * } + * + * // Check prefixed by currency + * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { + * return 'currency'; + * } + * return null; + * } + * ); + */ + detect: [], + + + /** + * Type based search formatting. + * + * The type based searching functions can be used to pre-format the + * data to be search on. For example, it can be used to strip HTML + * tags or to de-format telephone numbers for numeric only searching. + * + * Note that is a search is not defined for a column of a given type, + * no search formatting will be performed. + * + * Pre-processing of searching data plug-ins - When you assign the sType + * for a column (or have it automatically detected for you by DataTables + * or a type detection plug-in), you will typically be using this for + * custom sorting, but it can also be used to provide custom searching + * by allowing you to pre-processing the data and returning the data in + * the format that should be searched upon. This is done by adding + * functions this object with a parameter name which matches the sType + * for that target column. This is the corollary of <i>afnSortData</i> + * for searching data. + * + * The functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for searching + * + * Each function is expected to return: + * + * * `{string|null}` Formatted string that will be used for the searching. + * + * @type object + * @default {} + * + * @example + * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { + * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); + * } + */ + search: {}, + + + /** + * Type based ordering. + * + * The column type tells DataTables what ordering to apply to the table + * when a column is sorted upon. The order for each type that is defined, + * is defined by the functions available in this object. + * + * Each ordering option can be described by three properties added to + * this object: + * + * * `{type}-pre` - Pre-formatting function + * * `{type}-asc` - Ascending order function + * * `{type}-desc` - Descending order function + * + * All three can be used together, only `{type}-pre` or only + * `{type}-asc` and `{type}-desc` together. It is generally recommended + * that only `{type}-pre` is used, as this provides the optimal + * implementation in terms of speed, although the others are provided + * for compatibility with existing Javascript sort functions. + * + * `{type}-pre`: Functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for ordering + * + * And return: + * + * * `{*}` Data to be sorted upon + * + * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort + * functions, taking two parameters: + * + * 1. `{*}` Data to compare to the second parameter + * 2. `{*}` Data to compare to the first parameter + * + * And returning: + * + * * `{*}` Ordering match: <0 if first parameter should be sorted lower + * than the second parameter, ===0 if the two parameters are equal and + * >0 if the first parameter should be sorted height than the second + * parameter. + * + * @type object + * @default {} + * + * @example + * // Numeric ordering of formatted numbers with a pre-formatter + * $.extend( $.fn.dataTable.ext.type.order, { + * "string-pre": function(x) { + * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); + * return parseFloat( a ); + * } + * } ); + * + * @example + * // Case-sensitive string ordering, with no pre-formatting method + * $.extend( $.fn.dataTable.ext.order, { + * "string-case-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-case-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + */ + order: {} + }, + + /** + * Unique DataTables instance counter + * + * @type int + * @private + */ + _unique: 0, + + + // + // Depreciated + // The following properties are retained for backwards compatiblity only. + // The should not be used in new projects and will be removed in a future + // version + // + + /** + * Version check function. + * @type function + * @depreciated Since 1.10 + */ + fnVersionCheck: DataTable.fnVersionCheck, + + + /** + * Index for what 'this' index API functions should use + * @type int + * @deprecated Since v1.10 + */ + iApiIndex: 0, + + + /** + * jQuery UI class container + * @type object + * @deprecated Since v1.10 + */ + oJUIClasses: {}, + + + /** + * Software version + * @type string + * @deprecated Since v1.10 + */ + sVersion: DataTable.version + }; + + + // + // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts + // + $.extend( _ext, { + afnFiltering: _ext.search, + aTypes: _ext.type.detect, + ofnSearch: _ext.type.search, + oSort: _ext.type.order, + afnSortData: _ext.order, + aoFeatures: _ext.feature, + oApi: _ext.internal, + oStdClasses: _ext.classes, + oPagination: _ext.pager + } ); + + + $.extend( DataTable.ext.classes, { + "sTable": "dataTable", + "sNoFooter": "no-footer", + + /* Paging buttons */ + "sPageButton": "paginate_button", + "sPageButtonActive": "current", + "sPageButtonDisabled": "disabled", + + /* Striping classes */ + "sStripeOdd": "odd", + "sStripeEven": "even", + + /* Empty row */ + "sRowEmpty": "dataTables_empty", + + /* Features */ + "sWrapper": "dataTables_wrapper", + "sFilter": "dataTables_filter", + "sInfo": "dataTables_info", + "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ + "sLength": "dataTables_length", + "sProcessing": "dataTables_processing", + + /* Sorting */ + "sSortAsc": "sorting_asc", + "sSortDesc": "sorting_desc", + "sSortable": "sorting", /* Sortable in both directions */ + "sSortableAsc": "sorting_asc_disabled", + "sSortableDesc": "sorting_desc_disabled", + "sSortableNone": "sorting_disabled", + "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ + + /* Filtering */ + "sFilterInput": "", + + /* Page length */ + "sLengthSelect": "", + + /* Scrolling */ + "sScrollWrapper": "dataTables_scroll", + "sScrollHead": "dataTables_scrollHead", + "sScrollHeadInner": "dataTables_scrollHeadInner", + "sScrollBody": "dataTables_scrollBody", + "sScrollFoot": "dataTables_scrollFoot", + "sScrollFootInner": "dataTables_scrollFootInner", + + /* Misc */ + "sHeaderTH": "", + "sFooterTH": "", + + // Deprecated + "sSortJUIAsc": "", + "sSortJUIDesc": "", + "sSortJUI": "", + "sSortJUIAscAllowed": "", + "sSortJUIDescAllowed": "", + "sSortJUIWrapper": "", + "sSortIcon": "", + "sJUIHeader": "", + "sJUIFooter": "" + } ); + + + (function() { + + // Reused strings for better compression. Closure compiler appears to have a + // weird edge case where it is trying to expand strings rather than use the + // variable version. This results in about 200 bytes being added, for very + // little preference benefit since it this run on script load only. + var _empty = ''; + _empty = ''; + + var _stateDefault = _empty + 'ui-state-default'; + var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; + var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; + + $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { + /* Full numbers paging buttons */ + "sPageButton": "fg-button ui-button "+_stateDefault, + "sPageButtonActive": "ui-state-disabled", + "sPageButtonDisabled": "ui-state-disabled", + + /* Features */ + "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ + "ui-buttonset-multi paging_", /* Note that the type is postfixed */ + + /* Sorting */ + "sSortAsc": _stateDefault+" sorting_asc", + "sSortDesc": _stateDefault+" sorting_desc", + "sSortable": _stateDefault+" sorting", + "sSortableAsc": _stateDefault+" sorting_asc_disabled", + "sSortableDesc": _stateDefault+" sorting_desc_disabled", + "sSortableNone": _stateDefault+" sorting_disabled", + "sSortJUIAsc": _sortIcon+"triangle-1-n", + "sSortJUIDesc": _sortIcon+"triangle-1-s", + "sSortJUI": _sortIcon+"carat-2-n-s", + "sSortJUIAscAllowed": _sortIcon+"carat-1-n", + "sSortJUIDescAllowed": _sortIcon+"carat-1-s", + "sSortJUIWrapper": "DataTables_sort_wrapper", + "sSortIcon": "DataTables_sort_icon", + + /* Scrolling */ + "sScrollHead": "dataTables_scrollHead "+_stateDefault, + "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, + + /* Misc */ + "sHeaderTH": _stateDefault, + "sFooterTH": _stateDefault, + "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", + "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" + } ); + + }()); + + + + var extPagination = DataTable.ext.pager; + + function _numbers ( page, pages ) { + var + numbers = [], + buttons = extPagination.numbers_length, + half = Math.floor( buttons / 2 ), + i = 1; + + if ( pages <= buttons ) { + numbers = _range( 0, pages ); + } + else if ( page <= half ) { + numbers = _range( 0, buttons-2 ); + numbers.push( 'ellipsis' ); + numbers.push( pages-1 ); + } + else if ( page >= pages - 1 - half ) { + numbers = _range( pages-(buttons-2), pages ); + numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 + numbers.splice( 0, 0, 0 ); + } + else { + numbers = _range( page-1, page+2 ); + numbers.push( 'ellipsis' ); + numbers.push( pages-1 ); + numbers.splice( 0, 0, 'ellipsis' ); + numbers.splice( 0, 0, 0 ); + } + + numbers.DT_el = 'span'; + return numbers; + } + + + $.extend( extPagination, { + simple: function ( page, pages ) { + return [ 'previous', 'next' ]; + }, + + full: function ( page, pages ) { + return [ 'first', 'previous', 'next', 'last' ]; + }, + + simple_numbers: function ( page, pages ) { + return [ 'previous', _numbers(page, pages), 'next' ]; + }, + + full_numbers: function ( page, pages ) { + return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; + }, + + // For testing and plug-ins to use + _numbers: _numbers, + numbers_length: 7 + } ); + + + $.extend( true, DataTable.ext.renderer, { + pageButton: { + _: function ( settings, host, idx, buttons, page, pages ) { + var classes = settings.oClasses; + var lang = settings.oLanguage.oPaginate; + var btnDisplay, btnClass, counter=0; + + var attach = function( container, buttons ) { + var i, ien, node, button; + var clickHandler = function ( e ) { + _fnPageChange( settings, e.data.action, true ); + }; + + for ( i=0, ien=buttons.length ; i<ien ; i++ ) { + button = buttons[i]; + + if ( $.isArray( button ) ) { + var inner = $( '<'+(button.DT_el || 'div')+'/>' ) + .appendTo( container ); + attach( inner, button ); + } + else { + btnDisplay = ''; + btnClass = ''; + + switch ( button ) { + case 'ellipsis': + //RhodeCode fixed, added class paginate_button + container.append('<span class=\"paginate_button\">…</span>'); + break; + + case 'first': + btnDisplay = lang.sFirst; + btnClass = button + (page > 0 ? + '' : ' '+classes.sPageButtonDisabled); + break; + + case 'previous': + btnDisplay = lang.sPrevious; + btnClass = button + (page > 0 ? + '' : ' '+classes.sPageButtonDisabled); + break; + + case 'next': + btnDisplay = lang.sNext; + btnClass = button + (page < pages-1 ? + '' : ' '+classes.sPageButtonDisabled); + break; + + case 'last': + btnDisplay = lang.sLast; + btnClass = button + (page < pages-1 ? + '' : ' '+classes.sPageButtonDisabled); + break; + + default: + btnDisplay = button + 1; + btnClass = page === button ? + classes.sPageButtonActive : ''; + break; + } + + if ( btnDisplay ) { + node = $('<a>', { + 'class': classes.sPageButton+' '+btnClass, + 'aria-controls': settings.sTableId, + 'data-dt-idx': counter, + 'tabindex': settings.iTabIndex, + 'id': idx === 0 && typeof button === 'string' ? + settings.sTableId +'_'+ button : + null + } ) + .html( btnDisplay ) + .appendTo( container ); + + _fnBindAction( + node, {action: button}, clickHandler + ); + + counter++; + } + } + } + }; + + // IE9 throws an 'unknown error' if document.activeElement is used + // inside an iframe or frame. Try / catch the error. Not good for + // accessibility, but neither are frames. + try { + // Because this approach is destroying and recreating the paging + // elements, focus is lost on the select button which is bad for + // accessibility. So we want to restore focus once the draw has + // completed + var activeEl = $(document.activeElement).data('dt-idx'); + + attach( $(host).empty(), buttons ); + + if ( activeEl !== null ) { + $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); + } + } + catch (e) {} + } + } + } ); + + + + // Built in type detection. See model.ext.aTypes for information about + // what is required from this methods. + $.extend( DataTable.ext.type.detect, [ + // Plain numbers - first since V8 detects some plain numbers as dates + // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). + function ( d, settings ) + { + var decimal = settings.oLanguage.sDecimal; + return _isNumber( d, decimal ) ? 'num'+decimal : null; + }, + + // Dates (only those recognised by the browser's Date.parse) + function ( d, settings ) + { + // V8 will remove any unknown characters at the start and end of the + // expression, leading to false matches such as `$245.12` or `10%` being + // a valid date. See forum thread 18941 for detail. + if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) { + return null; + } + var parsed = Date.parse(d); + return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; + }, + + // Formatted numbers + function ( d, settings ) + { + var decimal = settings.oLanguage.sDecimal; + return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; + }, + + // HTML numeric + function ( d, settings ) + { + var decimal = settings.oLanguage.sDecimal; + return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; + }, + + // HTML numeric, formatted + function ( d, settings ) + { + var decimal = settings.oLanguage.sDecimal; + return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; + }, + + // HTML (this is strict checking - there must be html) + function ( d, settings ) + { + return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? + 'html' : null; + } + ] ); + + + + // Filter formatting functions. See model.ext.ofnSearch for information about + // what is required from these methods. + // + // Note that additional search methods are added for the html numbers and + // html formatted numbers by `_addNumericSort()` when we know what the decimal + // place is + + + $.extend( DataTable.ext.type.search, { + html: function ( data ) { + return _empty(data) ? + data : + typeof data === 'string' ? + data + .replace( _re_new_lines, " " ) + .replace( _re_html, "" ) : + ''; + }, + + string: function ( data ) { + return _empty(data) ? + data : + typeof data === 'string' ? + data.replace( _re_new_lines, " " ) : + data; + } + } ); + + + + var __numericReplace = function ( d, decimalPlace, re1, re2 ) { + if ( d !== 0 && (!d || d === '-') ) { + return -Infinity; + } + + // If a decimal place other than `.` is used, it needs to be given to the + // function so we can detect it and replace with a `.` which is the only + // decimal place Javascript recognises - it is not locale aware. + if ( decimalPlace ) { + d = _numToDecimal( d, decimalPlace ); + } + + if ( d.replace ) { + if ( re1 ) { + d = d.replace( re1, '' ); + } + + if ( re2 ) { + d = d.replace( re2, '' ); + } + } + + return d * 1; + }; + + + // Add the numeric 'deformatting' functions for sorting and search. This is done + // in a function to provide an easy ability for the language options to add + // additional methods if a non-period decimal place is used. + function _addNumericSort ( decimalPlace ) { + $.each( + { + // Plain numbers + "num": function ( d ) { + return __numericReplace( d, decimalPlace ); + }, + + // Formatted numbers + "num-fmt": function ( d ) { + return __numericReplace( d, decimalPlace, _re_formatted_numeric ); + }, + + // HTML numeric + "html-num": function ( d ) { + return __numericReplace( d, decimalPlace, _re_html ); + }, + + // HTML numeric, formatted + "html-num-fmt": function ( d ) { + return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); + } + }, + function ( key, fn ) { + // Add the ordering method + _ext.type.order[ key+decimalPlace+'-pre' ] = fn; + + // For HTML types add a search formatter that will strip the HTML + if ( key.match(/^html\-/) ) { + _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; + } + } + ); + } + + + // Default sort methods + $.extend( _ext.type.order, { + // Dates + "date-pre": function ( d ) { + return Date.parse( d ) || 0; + }, + + // html + "html-pre": function ( a ) { + return _empty(a) ? + '' : + a.replace ? + a.replace( /<.*?>/g, "" ).toLowerCase() : + a+''; + }, + + // string + "string-pre": function ( a ) { + // This is a little complex, but faster than always calling toString, + // http://jsperf.com/tostring-v-check + return _empty(a) ? + '' : + typeof a === 'string' ? + a.toLowerCase() : + ! a.toString ? + '' : + a.toString(); + }, + + // string-asc and -desc are retained only for compatibility with the old + // sort methods + "string-asc": function ( x, y ) { + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + }, + + "string-desc": function ( x, y ) { + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + } + } ); + + + // Numeric sorting types - order doesn't matter here + _addNumericSort( '' ); + + + $.extend( true, DataTable.ext.renderer, { + header: { + _: function ( settings, cell, column, classes ) { + // No additional mark-up required + // Attach a sort listener to update on sort - note that using the + // `DT` namespace will allow the event to be removed automatically + // on destroy, while the `dt` namespaced event is the one we are + // listening for + $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { + if ( settings !== ctx ) { // need to check this this is the host + return; // table, not a nested one + } + + var colIdx = column.idx; + + cell + .removeClass( + column.sSortingClass +' '+ + classes.sSortAsc +' '+ + classes.sSortDesc + ) + .addClass( columns[ colIdx ] == 'asc' ? + classes.sSortAsc : columns[ colIdx ] == 'desc' ? + classes.sSortDesc : + column.sSortingClass + ); + } ); + }, + + jqueryui: function ( settings, cell, column, classes ) { + $('<div/>') + .addClass( classes.sSortJUIWrapper ) + .append( cell.contents() ) + .append( $('<span/>') + .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) + ) + .appendTo( cell ); + + // Attach a sort listener to update on sort + $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { + if ( settings !== ctx ) { + return; + } + + var colIdx = column.idx; + + cell + .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) + .addClass( columns[ colIdx ] == 'asc' ? + classes.sSortAsc : columns[ colIdx ] == 'desc' ? + classes.sSortDesc : + column.sSortingClass + ); + + cell + .find( 'span.'+classes.sSortIcon ) + .removeClass( + classes.sSortJUIAsc +" "+ + classes.sSortJUIDesc +" "+ + classes.sSortJUI +" "+ + classes.sSortJUIAscAllowed +" "+ + classes.sSortJUIDescAllowed + ) + .addClass( columns[ colIdx ] == 'asc' ? + classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? + classes.sSortJUIDesc : + column.sSortingClassJUI + ); + } ); + } + } + } ); + + /* + * Public helper functions. These aren't used internally by DataTables, or + * called by any of the options passed into DataTables, but they can be used + * externally by developers working with DataTables. They are helper functions + * to make working with DataTables a little bit easier. + */ + + /** + * Helpers for `columns.render`. + * + * The options defined here can be used with the `columns.render` initialisation + * option to provide a display renderer. The following functions are defined: + * + * * `number` - Will format numeric data (defined by `columns.data`) for + * display, retaining the original unformatted data for sorting and filtering. + * It takes 4 parameters: + * * `string` - Thousands grouping separator + * * `string` - Decimal point indicator + * * `integer` - Number of decimal points to show + * * `string` (optional) - Prefix. + * + * @example + * // Column definition using the number renderer + * { + * data: "salary", + * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) + * } + * + * @namespace + */ + DataTable.render = { + number: function ( thousands, decimal, precision, prefix ) { + return { + display: function ( d ) { + var negative = d < 0 ? '-' : ''; + d = Math.abs( parseFloat( d ) ); + + var intPart = parseInt( d, 10 ); + var floatPart = precision ? + decimal+(d - intPart).toFixed( precision ).substring( 2 ): + ''; + + return negative + (prefix||'') + + intPart.toString().replace( + /\B(?=(\d{3})+(?!\d))/g, thousands + ) + + floatPart; + } + }; + } + }; + + + /* + * This is really a good bit rubbish this method of exposing the internal methods + * publicly... - To be fixed in 2.0 using methods on the prototype + */ + + + /** + * Create a wrapper function for exporting an internal functions to an external API. + * @param {string} fn API function name + * @returns {function} wrapped function + * @memberof DataTable#internal + */ + function _fnExternApiFunc (fn) + { + return function() { + var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( + Array.prototype.slice.call(arguments) + ); + return DataTable.ext.internal[fn].apply( this, args ); + }; + } + + + /** + * Reference to internal functions for use by plug-in developers. Note that + * these methods are references to internal functions and are considered to be + * private. If you use these methods, be aware that they are liable to change + * between versions. + * @namespace + */ + $.extend( DataTable.ext.internal, { + _fnExternApiFunc: _fnExternApiFunc, + _fnBuildAjax: _fnBuildAjax, + _fnAjaxUpdate: _fnAjaxUpdate, + _fnAjaxParameters: _fnAjaxParameters, + _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, + _fnAjaxDataSrc: _fnAjaxDataSrc, + _fnAddColumn: _fnAddColumn, + _fnColumnOptions: _fnColumnOptions, + _fnAdjustColumnSizing: _fnAdjustColumnSizing, + _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, + _fnColumnIndexToVisible: _fnColumnIndexToVisible, + _fnVisbleColumns: _fnVisbleColumns, + _fnGetColumns: _fnGetColumns, + _fnColumnTypes: _fnColumnTypes, + _fnApplyColumnDefs: _fnApplyColumnDefs, + _fnHungarianMap: _fnHungarianMap, + _fnCamelToHungarian: _fnCamelToHungarian, + _fnLanguageCompat: _fnLanguageCompat, + _fnBrowserDetect: _fnBrowserDetect, + _fnAddData: _fnAddData, + _fnAddTr: _fnAddTr, + _fnNodeToDataIndex: _fnNodeToDataIndex, + _fnNodeToColumnIndex: _fnNodeToColumnIndex, + _fnGetCellData: _fnGetCellData, + _fnSetCellData: _fnSetCellData, + _fnSplitObjNotation: _fnSplitObjNotation, + _fnGetObjectDataFn: _fnGetObjectDataFn, + _fnSetObjectDataFn: _fnSetObjectDataFn, + _fnGetDataMaster: _fnGetDataMaster, + _fnClearTable: _fnClearTable, + _fnDeleteIndex: _fnDeleteIndex, + _fnInvalidate: _fnInvalidate, + _fnGetRowElements: _fnGetRowElements, + _fnCreateTr: _fnCreateTr, + _fnBuildHead: _fnBuildHead, + _fnDrawHead: _fnDrawHead, + _fnDraw: _fnDraw, + _fnReDraw: _fnReDraw, + _fnAddOptionsHtml: _fnAddOptionsHtml, + _fnDetectHeader: _fnDetectHeader, + _fnGetUniqueThs: _fnGetUniqueThs, + _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, + _fnFilterComplete: _fnFilterComplete, + _fnFilterCustom: _fnFilterCustom, + _fnFilterColumn: _fnFilterColumn, + _fnFilter: _fnFilter, + _fnFilterCreateSearch: _fnFilterCreateSearch, + _fnEscapeRegex: _fnEscapeRegex, + _fnFilterData: _fnFilterData, + _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, + _fnUpdateInfo: _fnUpdateInfo, + _fnInfoMacros: _fnInfoMacros, + _fnInitialise: _fnInitialise, + _fnInitComplete: _fnInitComplete, + _fnLengthChange: _fnLengthChange, + _fnFeatureHtmlLength: _fnFeatureHtmlLength, + _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, + _fnPageChange: _fnPageChange, + _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, + _fnProcessingDisplay: _fnProcessingDisplay, + _fnFeatureHtmlTable: _fnFeatureHtmlTable, + _fnScrollDraw: _fnScrollDraw, + _fnApplyToChildren: _fnApplyToChildren, + _fnCalculateColumnWidths: _fnCalculateColumnWidths, + _fnThrottle: _fnThrottle, + _fnConvertToWidth: _fnConvertToWidth, + _fnScrollingWidthAdjust: _fnScrollingWidthAdjust, + _fnGetWidestNode: _fnGetWidestNode, + _fnGetMaxLenString: _fnGetMaxLenString, + _fnStringToCss: _fnStringToCss, + _fnScrollBarWidth: _fnScrollBarWidth, + _fnSortFlatten: _fnSortFlatten, + _fnSort: _fnSort, + _fnSortAria: _fnSortAria, + _fnSortListener: _fnSortListener, + _fnSortAttachListener: _fnSortAttachListener, + _fnSortingClasses: _fnSortingClasses, + _fnSortData: _fnSortData, + _fnSaveState: _fnSaveState, + _fnLoadState: _fnLoadState, + _fnSettingsFromNode: _fnSettingsFromNode, + _fnLog: _fnLog, + _fnMap: _fnMap, + _fnBindAction: _fnBindAction, + _fnCallbackReg: _fnCallbackReg, + _fnCallbackFire: _fnCallbackFire, + _fnLengthOverflow: _fnLengthOverflow, + _fnRenderer: _fnRenderer, + _fnDataSource: _fnDataSource, + _fnRowAttributes: _fnRowAttributes, + _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant + // in 1.10, so this dead-end function is + // added to prevent errors + } ); + + + // jQuery access + $.fn.dataTable = DataTable; + + // Legacy aliases + $.fn.dataTableSettings = DataTable.settings; + $.fn.dataTableExt = DataTable.ext; + + // With a capital `D` we return a DataTables API instance rather than a + // jQuery object + $.fn.DataTable = function ( opts ) { + return $(this).dataTable( opts ).api(); + }; + + // All properties that are available to $.fn.dataTable should also be + // available on $.fn.DataTable + $.each( DataTable, function ( prop, val ) { + $.fn.DataTable[ prop ] = val; + } ); + + + // Information about events fired by DataTables - for documentation. + /** + * Draw event, fired whenever the table is redrawn on the page, at the same + * point as fnDrawCallback. This may be useful for binding events or + * performing calculations when the table is altered at all. + * @name DataTable#draw.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Search event, fired when the searching applied to the table (using the + * built-in global search, or column filters) is altered. + * @name DataTable#search.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Page change event, fired when the paging of the table is altered. + * @name DataTable#page.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Order event, fired when the ordering applied to the table is altered. + * @name DataTable#order.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * DataTables initialisation complete event, fired when the table is fully + * drawn, including Ajax data loaded, if Ajax data is required. + * @name DataTable#init.dt + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The JSON object request from the server - only + * present if client-side Ajax sourced data is used</li></ol> + */ + + /** + * State save event, fired when the table has changed state a new state save + * is required. This event allows modification of the state saving object + * prior to actually doing the save, including addition or other state + * properties (for plug-ins) or modification of a DataTables core property. + * @name DataTable#stateSaveParams.dt + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The state information to be saved + */ + + /** + * State load event, fired when the table is loading state from the stored + * data, but prior to the settings object being modified by the saved state + * - allowing modification of the saved state is required or loading of + * state for a plug-in. + * @name DataTable#stateLoadParams.dt + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * State loaded event, fired when state has been loaded from stored data and + * the settings object has been modified by the loaded data. + * @name DataTable#stateLoaded.dt + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * Processing event, fired when DataTables is doing some kind of processing + * (be it, order, searcg or anything else). It can be used to indicate to + * the end user that there is something happening, or that something has + * finished. + * @name DataTable#processing.dt + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {boolean} bShow Flag for if DataTables is doing processing or not + */ + + /** + * Ajax (XHR) event, fired whenever an Ajax request is completed from a + * request to made to the server for new data. This event is called before + * DataTables processed the returned data, so it can also be used to pre- + * process the data returned from the server, if needed. + * + * Note that this trigger is called in `fnServerData`, if you override + * `fnServerData` and which to use this event, you need to trigger it in you + * success function. + * @name DataTable#xhr.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + * @param {object} json JSON returned from the server + * + * @example + * // Use a custom property returned from the server in another DOM element + * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { + * $('#status').html( json.status ); + * } ); + * + * @example + * // Pre-process the data returned from the server + * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { + * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { + * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; + * } + * // Note no return - manipulate the data directly in the JSON object. + * } ); + */ + + /** + * Destroy event, fired when the DataTable is destroyed by calling fnDestroy + * or passing the bDestroy:true parameter in the initialisation object. This + * can be used to remove bound events, added DOM nodes, etc. + * @name DataTable#destroy.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Page length change event, fired when number of records to show on each + * page (the length) is changed. + * @name DataTable#length.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + * @param {integer} len New length + */ + + /** + * Column sizing has changed. + * @name DataTable#column-sizing.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Column visibility has changed. + * @name DataTable#column-visibility.dt + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + * @param {int} column Column index + * @param {bool} vis `false` if column now hidden, or `true` if visible + */ + + return $.fn.dataTable; +})); + +}(window, document)); + diff --git a/rhodecode/public/js/src/plugins/jquery.debounce.js b/rhodecode/public/js/src/plugins/jquery.debounce.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.debounce.js @@ -0,0 +1,252 @@ +/*! + * jQuery throttle / debounce - v1.1 - 3/7/2010 + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ + +// Script: jQuery throttle / debounce: Sometimes, less is more! +// +// *Version: 1.1, Last updated: 3/7/2010* +// +// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/ +// GitHub - http://github.com/cowboy/jquery-throttle-debounce/ +// Source - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js +// (Minified) - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb) +// +// About: License +// +// Copyright (c) 2010 "Cowboy" Ben Alman, +// Dual licensed under the MIT and GPL licenses. +// http://benalman.com/about/license/ +// +// About: Examples +// +// These working examples, complete with fully commented code, illustrate a few +// ways in which this plugin can be used. +// +// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ +// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/ +// +// About: Support and Testing +// +// Information about what version or versions of jQuery this plugin has been +// tested with, what browsers it has been tested in, and where the unit tests +// reside (so you can test it yourself). +// +// jQuery Versions - none, 1.3.2, 1.4.2 +// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1. +// Unit Tests - http://benalman.com/code/projects/jquery-throttle-debounce/unit/ +// +// About: Release History +// +// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks +// executed later than they should. Reworked a fair amount of internal +// logic as well. +// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over +// from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the +// no_trailing throttle parameter and debounce functionality. +// +// Topic: Note for non-jQuery users +// +// jQuery isn't actually required for this plugin, because nothing internal +// uses any jQuery methods or properties. jQuery is just used as a namespace +// under which these methods can exist. +// +// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist +// when this plugin is loaded, the method described below will be created in +// the `Cowboy` namespace. Usage will be exactly the same, but instead of +// $.method() or jQuery.method(), you'll need to use Cowboy.method(). + +(function(window,undefined){ + '$:nomunge'; // Used by YUI compressor. + + // Since jQuery really isn't required for this plugin, use `jQuery` as the + // namespace only if it already exists, otherwise use the `Cowboy` namespace, + // creating it if necessary. + var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ), + + // Internal method reference. + jq_throttle; + + // Method: jQuery.throttle + // + // Throttle execution of a function. Especially useful for rate limiting + // execution of handlers on events like resize and scroll. If you want to + // rate-limit execution of a function to a single time, see the + // <jQuery.debounce> method. + // + // In this visualization, | is a throttled-function call and X is the actual + // callback execution: + // + // > Throttled with `no_trailing` specified as false or unspecified: + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| + // > X X X X X X X X X X X X + // > + // > Throttled with `no_trailing` specified as true: + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| + // > X X X X X X X X X X + // + // Usage: + // + // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback ); + // > + // > jQuery('selector').bind( 'someevent', throttled ); + // > jQuery('selector').unbind( 'someevent', throttled ); + // + // This also works in jQuery 1.4+: + // + // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) ); + // > jQuery('selector').unbind( 'someevent', callback ); + // + // Arguments: + // + // delay - (Number) A zero-or-greater delay in milliseconds. For event + // callbacks, values around 100 or 250 (or even higher) are most useful. + // no_trailing - (Boolean) Optional, defaults to false. If no_trailing is + // true, callback will only execute every `delay` milliseconds while the + // throttled-function is being called. If no_trailing is false or + // unspecified, callback will be executed one final time after the last + // throttled-function call. (After the throttled-function has not been + // called for `delay` milliseconds, the internal counter is reset) + // callback - (Function) A function to be executed after delay milliseconds. + // The `this` context and all arguments are passed through, as-is, to + // `callback` when the throttled-function is executed. + // + // Returns: + // + // (Function) A new, throttled, function. + + $.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) { + // After wrapper has stopped being called, this timeout ensures that + // `callback` is executed at the proper times in `throttle` and `end` + // debounce modes. + var timeout_id, + + // Keep track of the last time `callback` was executed. + last_exec = 0; + + // `no_trailing` defaults to falsy. + if ( typeof no_trailing !== 'boolean' ) { + debounce_mode = callback; + callback = no_trailing; + no_trailing = undefined; + } + + // The `wrapper` function encapsulates all of the throttling / debouncing + // functionality and when executed will limit the rate at which `callback` + // is executed. + function wrapper() { + var that = this, + elapsed = +new Date() - last_exec, + args = arguments; + + // Execute `callback` and update the `last_exec` timestamp. + function exec() { + last_exec = +new Date(); + callback.apply( that, args ); + }; + + // If `debounce_mode` is true (at_begin) this is used to clear the flag + // to allow future `callback` executions. + function clear() { + timeout_id = undefined; + }; + + if ( debounce_mode && !timeout_id ) { + // Since `wrapper` is being called for the first time and + // `debounce_mode` is true (at_begin), execute `callback`. + exec(); + } + + // Clear any existing timeout. + timeout_id && clearTimeout( timeout_id ); + + if ( debounce_mode === undefined && elapsed > delay ) { + // In throttle mode, if `delay` time has been exceeded, execute + // `callback`. + exec(); + + } else if ( no_trailing !== true ) { + // In trailing throttle mode, since `delay` time has not been + // exceeded, schedule `callback` to execute `delay` ms after most + // recent execution. + // + // If `debounce_mode` is true (at_begin), schedule `clear` to execute + // after `delay` ms. + // + // If `debounce_mode` is false (at end), schedule `callback` to + // execute after `delay` ms. + timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay ); + } + }; + + // Set the guid of `wrapper` function to the same of original callback, so + // it can be removed in jQuery 1.4+ .unbind or .die by using the original + // callback as a reference. + if ( $.guid ) { + wrapper.guid = callback.guid = callback.guid || $.guid++; + } + + // Return the wrapper function. + return wrapper; + }; + + // Method: jQuery.debounce + // + // Debounce execution of a function. Debouncing, unlike throttling, + // guarantees that a function is only executed a single time, either at the + // very beginning of a series of calls, or at the very end. If you want to + // simply rate-limit execution of a function, see the <jQuery.throttle> + // method. + // + // In this visualization, | is a debounced-function call and X is the actual + // callback execution: + // + // > Debounced with `at_begin` specified as false or unspecified: + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| + // > X X + // > + // > Debounced with `at_begin` specified as true: + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| + // > X X + // + // Usage: + // + // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback ); + // > + // > jQuery('selector').bind( 'someevent', debounced ); + // > jQuery('selector').unbind( 'someevent', debounced ); + // + // This also works in jQuery 1.4+: + // + // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) ); + // > jQuery('selector').unbind( 'someevent', callback ); + // + // Arguments: + // + // delay - (Number) A zero-or-greater delay in milliseconds. For event + // callbacks, values around 100 or 250 (or even higher) are most useful. + // at_begin - (Boolean) Optional, defaults to false. If at_begin is false or + // unspecified, callback will only be executed `delay` milliseconds after + // the last debounced-function call. If at_begin is true, callback will be + // executed only at the first debounced-function call. (After the + // throttled-function has not been called for `delay` milliseconds, the + // internal counter is reset) + // callback - (Function) A function to be executed after delay milliseconds. + // The `this` context and all arguments are passed through, as-is, to + // `callback` when the debounced-function is executed. + // + // Returns: + // + // (Function) A new, debounced, function. + + $.debounce = function( delay, at_begin, callback ) { + return callback === undefined + ? jq_throttle( delay, at_begin, false ) + : jq_throttle( delay, callback, at_begin !== false ); + }; + +})(this); \ No newline at end of file diff --git a/rhodecode/public/js/src/plugins/jquery.pjax.js b/rhodecode/public/js/src/plugins/jquery.pjax.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.pjax.js @@ -0,0 +1,925 @@ +/*! + * Copyright 2012, Chris Wanstrath + * Released under the MIT License + * https://github.com/defunkt/jquery-pjax + */ + +(function($){ + +// When called on a container with a selector, fetches the href with +// ajax into the container or with the data-pjax attribute on the link +// itself. +// +// Tries to make sure the back button and ctrl+click work the way +// you'd expect. +// +// Exported as $.fn.pjax +// +// Accepts a jQuery ajax options object that may include these +// pjax specific options: +// +// +// container - Where to stick the response body. Usually a String selector. +// $(container).html(xhr.responseBody) +// (default: current jquery context) +// push - Whether to pushState the URL. Defaults to true (of course). +// replace - Want to use replaceState instead? That's cool. +// +// For convenience the second parameter can be either the container or +// the options object. +// +// Returns the jQuery object +function fnPjax(selector, container, options) { + var context = this + return this.on('click.pjax', selector, function(event) { + var opts = $.extend({}, optionsFor(container, options)) + if (!opts.container) + opts.container = $(this).attr('data-pjax') || context + handleClick(event, opts) + }) +} + +// Public: pjax on click handler +// +// Exported as $.pjax.click. +// +// event - "click" jQuery.Event +// options - pjax options +// +// Examples +// +// $(document).on('click', 'a', $.pjax.click) +// // is the same as +// $(document).pjax('a') +// +// $(document).on('click', 'a', function(event) { +// var container = $(this).closest('[data-pjax-container]') +// $.pjax.click(event, container) +// }) +// +// Returns nothing. +function handleClick(event, container, options) { + options = optionsFor(container, options) + + var link = event.currentTarget + + if (link.tagName.toUpperCase() !== 'A') + throw "$.fn.pjax or $.pjax.click requires an anchor element" + + // Middle click, cmd click, and ctrl click should open + // links in a new tab as normal. + if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) + return + + // Ignore cross origin links + if ( location.protocol !== link.protocol || location.hostname !== link.hostname ) + return + + // Ignore case when a hash is being tacked on the current URL + if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) ) + return + + // Ignore event with default prevented + if (event.isDefaultPrevented()) + return + + var defaults = { + url: link.href, + container: $(link).attr('data-pjax'), + target: link + } + + var opts = $.extend({}, defaults, options) + var clickEvent = $.Event('pjax:click') + $(link).trigger(clickEvent, [opts]) + + if (!clickEvent.isDefaultPrevented()) { + pjax(opts) + event.preventDefault() + $(link).trigger('pjax:clicked', [opts]) + } +} + +// Public: pjax on form submit handler +// +// Exported as $.pjax.submit +// +// event - "click" jQuery.Event +// options - pjax options +// +// Examples +// +// $(document).on('submit', 'form', function(event) { +// var container = $(this).closest('[data-pjax-container]') +// $.pjax.submit(event, container) +// }) +// +// Returns nothing. +function handleSubmit(event, container, options) { + options = optionsFor(container, options) + + var form = event.currentTarget + var $form = $(form) + + if (form.tagName.toUpperCase() !== 'FORM') + throw "$.pjax.submit requires a form element" + + var defaults = { + type: ($form.attr('method') || 'GET').toUpperCase(), + url: $form.attr('action'), + container: $form.attr('data-pjax'), + target: form + } + + if (defaults.type !== 'GET' && window.FormData !== undefined) { + defaults.data = new FormData(form); + defaults.processData = false; + defaults.contentType = false; + } else { + // Can't handle file uploads, exit + if ($(form).find(':file').length) { + return; + } + + // Fallback to manually serializing the fields + defaults.data = $(form).serializeArray(); + } + + pjax($.extend({}, defaults, options)) + + event.preventDefault() +} + +// Loads a URL with ajax, puts the response body inside a container, +// then pushState()'s the loaded URL. +// +// Works just like $.ajax in that it accepts a jQuery ajax +// settings object (with keys like url, type, data, etc). +// +// Accepts these extra keys: +// +// container - Where to stick the response body. +// $(container).html(xhr.responseBody) +// push - Whether to pushState the URL. Defaults to true (of course). +// replace - Want to use replaceState instead? That's cool. +// +// Use it just like $.ajax: +// +// var xhr = $.pjax({ url: this.href, container: '#main' }) +// console.log( xhr.readyState ) +// +// Returns whatever $.ajax returns. +function pjax(options) { + options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options) + + if ($.isFunction(options.url)) { + options.url = options.url() + } + + var target = options.target + + var hash = parseURL(options.url).hash + + var context = options.context = findContainerFor(options.container) + + // We want the browser to maintain two separate internal caches: one + // for pjax'd partial page loads and one for normal page loads. + // Without adding this secret parameter, some browsers will often + // confuse the two. + if (!options.data) options.data = {} + if ($.isArray(options.data)) { + options.data.push({name: '_pjax', value: context.selector}) + } else { + options.data._pjax = context.selector + } + + function fire(type, args, props) { + if (!props) props = {} + props.relatedTarget = target + var event = $.Event(type, props) + context.trigger(event, args) + return !event.isDefaultPrevented() + } + + var timeoutTimer + + options.beforeSend = function(xhr, settings) { + // No timeout for non-GET requests + // Its not safe to request the resource again with a fallback method. + if (settings.type !== 'GET') { + settings.timeout = 0 + } + + xhr.setRequestHeader('X-PJAX', 'true') + xhr.setRequestHeader('X-PJAX-Container', context.selector) + + if (!fire('pjax:beforeSend', [xhr, settings])) + return false + + if (settings.timeout > 0) { + timeoutTimer = setTimeout(function() { + if (fire('pjax:timeout', [xhr, options])) + xhr.abort('timeout') + }, settings.timeout) + + // Clear timeout setting so jquerys internal timeout isn't invoked + settings.timeout = 0 + } + + var url = parseURL(settings.url) + if (hash) url.hash = hash + options.requestUrl = stripInternalParams(url) + } + + options.complete = function(xhr, textStatus) { + if (timeoutTimer) + clearTimeout(timeoutTimer) + + fire('pjax:complete', [xhr, textStatus, options]) + + fire('pjax:end', [xhr, options]) + } + + options.error = function(xhr, textStatus, errorThrown) { + var container = extractContainer("", xhr, options) + + var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options]) + if (options.type == 'GET' && textStatus !== 'abort' && allowed) { + locationReplace(container.url) + } + } + + options.success = function(data, status, xhr) { + var previousState = pjax.state; + + // If $.pjax.defaults.version is a function, invoke it first. + // Otherwise it can be a static string. + var currentVersion = (typeof $.pjax.defaults.version === 'function') ? + $.pjax.defaults.version() : + $.pjax.defaults.version + + var latestVersion = xhr.getResponseHeader('X-PJAX-Version') + + var container = extractContainer(data, xhr, options) + + var url = parseURL(container.url) + if (hash) { + url.hash = hash + container.url = url.href + } + + // If there is a layout version mismatch, hard load the new url + if (currentVersion && latestVersion && currentVersion !== latestVersion) { + locationReplace(container.url) + return + } + + // If the new response is missing a body, hard load the page + if (!container.contents) { + locationReplace(container.url) + return + } + + pjax.state = { + id: options.id || uniqueId(), + url: container.url, + title: container.title, + container: context.selector, + fragment: options.fragment, + timeout: options.timeout + } + + if (options.push || options.replace) { + window.history.replaceState(pjax.state, container.title, container.url) + } + + // Only blur the focus if the focused element is within the container. + var blurFocus = $.contains(options.container, document.activeElement) + + // Clear out any focused controls before inserting new page contents. + if (blurFocus) { + try { + document.activeElement.blur() + } catch (e) { } + } + + if (container.title) document.title = container.title + + fire('pjax:beforeReplace', [container.contents, options], { + state: pjax.state, + previousState: previousState + }) + context.html(container.contents) + + // FF bug: Won't autofocus fields that are inserted via JS. + // This behavior is incorrect. So if theres no current focus, autofocus + // the last field. + // + // http://www.w3.org/html/wg/drafts/html/master/forms.html + var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0] + if (autofocusEl && document.activeElement !== autofocusEl) { + autofocusEl.focus(); + } + + executeScriptTags(container.scripts) + + var scrollTo = options.scrollTo + + // Ensure browser scrolls to the element referenced by the URL anchor + if (hash) { + var name = decodeURIComponent(hash.slice(1)) + var target = document.getElementById(name) || document.getElementsByName(name)[0] + if (target) scrollTo = $(target).offset().top + } + + if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo) + + fire('pjax:success', [data, status, xhr, options]) + } + + + // Initialize pjax.state for the initial page load. Assume we're + // using the container and options of the link we're loading for the + // back button to the initial page. This ensures good back button + // behavior. + if (!pjax.state) { + pjax.state = { + id: uniqueId(), + url: window.location.href, + title: document.title, + container: context.selector, + fragment: options.fragment, + timeout: options.timeout + } + window.history.replaceState(pjax.state, document.title) + } + + // Cancel the current request if we're already pjaxing + abortXHR(pjax.xhr) + + pjax.options = options + var xhr = pjax.xhr = $.ajax(options) + + if (xhr.readyState > 0) { + if (options.push && !options.replace) { + // Cache current container element before replacing it + cachePush(pjax.state.id, cloneContents(context)) + + window.history.pushState(null, "", options.requestUrl) + } + + fire('pjax:start', [xhr, options]) + fire('pjax:send', [xhr, options]) + } + + return pjax.xhr +} + +// Public: Reload current page with pjax. +// +// Returns whatever $.pjax returns. +function pjaxReload(container, options) { + var defaults = { + url: window.location.href, + push: false, + replace: true, + scrollTo: false + } + + return pjax($.extend(defaults, optionsFor(container, options))) +} + +// Internal: Hard replace current state with url. +// +// Work for around WebKit +// https://bugs.webkit.org/show_bug.cgi?id=93506 +// +// Returns nothing. +function locationReplace(url) { + window.history.replaceState(null, "", pjax.state.url) + window.location.replace(url) +} + + +var initialPop = true +var initialURL = window.location.href +var initialState = window.history.state + +// Initialize $.pjax.state if possible +// Happens when reloading a page and coming forward from a different +// session history. +if (initialState && initialState.container) { + pjax.state = initialState +} + +// Non-webkit browsers don't fire an initial popstate event +if ('state' in window.history) { + initialPop = false +} + +// popstate handler takes care of the back and forward buttons +// +// You probably shouldn't use pjax on pages with other pushState +// stuff yet. +function onPjaxPopstate(event) { + + // Hitting back or forward should override any pending PJAX request. + if (!initialPop) { + abortXHR(pjax.xhr) + } + + var previousState = pjax.state + var state = event.state + var direction + + if (state && state.container) { + // When coming forward from a separate history session, will get an + // initial pop with a state we are already at. Skip reloading the current + // page. + if (initialPop && initialURL == state.url) return + + if (previousState) { + // If popping back to the same state, just skip. + // Could be clicking back from hashchange rather than a pushState. + if (previousState.id === state.id) return + + // Since state IDs always increase, we can deduce the navigation direction + direction = previousState.id < state.id ? 'forward' : 'back' + } + + var cache = cacheMapping[state.id] || [] + var container = $(cache[0] || state.container), contents = cache[1] + + if (container.length) { + if (previousState) { + // Cache current container before replacement and inform the + // cache which direction the history shifted. + cachePop(direction, previousState.id, cloneContents(container)) + } + + var popstateEvent = $.Event('pjax:popstate', { + state: state, + direction: direction + }) + container.trigger(popstateEvent) + + var options = { + id: state.id, + url: state.url, + container: container, + push: false, + fragment: state.fragment, + timeout: state.timeout, + scrollTo: false + } + + if (contents) { + container.trigger('pjax:start', [null, options]) + + pjax.state = state + if (state.title) document.title = state.title + var beforeReplaceEvent = $.Event('pjax:beforeReplace', { + state: state, + previousState: previousState + }) + container.trigger(beforeReplaceEvent, [contents, options]) + container.html(contents) + + container.trigger('pjax:end', [null, options]) + } else { + pjax(options) + } + + // Force reflow/relayout before the browser tries to restore the + // scroll position. + container[0].offsetHeight + } else { + locationReplace(location.href) + } + } + initialPop = false +} + +// Fallback version of main pjax function for browsers that don't +// support pushState. +// +// Returns nothing since it retriggers a hard form submission. +function fallbackPjax(options) { + var url = $.isFunction(options.url) ? options.url() : options.url, + method = options.type ? options.type.toUpperCase() : 'GET' + + var form = $('<form>', { + method: method === 'GET' ? 'GET' : 'POST', + action: url, + style: 'display:none' + }) + + if (method !== 'GET' && method !== 'POST') { + form.append($('<input>', { + type: 'hidden', + name: '_method', + value: method.toLowerCase() + })) + } + + var data = options.data + if (typeof data === 'string') { + $.each(data.split('&'), function(index, value) { + var pair = value.split('=') + form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]})) + }) + } else if ($.isArray(data)) { + $.each(data, function(index, value) { + form.append($('<input>', {type: 'hidden', name: value.name, value: value.value})) + }) + } else if (typeof data === 'object') { + var key + for (key in data) + form.append($('<input>', {type: 'hidden', name: key, value: data[key]})) + } + + $(document.body).append(form) + form.submit() +} + +// Internal: Abort an XmlHttpRequest if it hasn't been completed, +// also removing its event handlers. +function abortXHR(xhr) { + if ( xhr && xhr.readyState < 4) { + xhr.onreadystatechange = $.noop + xhr.abort() + } +} + +// Internal: Generate unique id for state object. +// +// Use a timestamp instead of a counter since ids should still be +// unique across page loads. +// +// Returns Number. +function uniqueId() { + return (new Date).getTime() +} + +function cloneContents(container) { + var cloned = container.clone() + // Unmark script tags as already being eval'd so they can get executed again + // when restored from cache. HAXX: Uses jQuery internal method. + cloned.find('script').each(function(){ + if (!this.src) jQuery._data(this, 'globalEval', false) + }) + return [container.selector, cloned.contents()] +} + +// Internal: Strip internal query params from parsed URL. +// +// Returns sanitized url.href String. +function stripInternalParams(url) { + url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '') + return url.href.replace(/\?($|#)/, '$1') +} + +// Internal: Parse URL components and returns a Locationish object. +// +// url - String URL +// +// Returns HTMLAnchorElement that acts like Location. +function parseURL(url) { + var a = document.createElement('a') + a.href = url + return a +} + +// Internal: Return the `href` component of given URL object with the hash +// portion removed. +// +// location - Location or HTMLAnchorElement +// +// Returns String +function stripHash(location) { + return location.href.replace(/#.*/, '') +} + +// Internal: Build options Object for arguments. +// +// For convenience the first parameter can be either the container or +// the options object. +// +// Examples +// +// optionsFor('#container') +// // => {container: '#container'} +// +// optionsFor('#container', {push: true}) +// // => {container: '#container', push: true} +// +// optionsFor({container: '#container', push: true}) +// // => {container: '#container', push: true} +// +// Returns options Object. +function optionsFor(container, options) { + // Both container and options + if ( container && options ) + options.container = container + + // First argument is options Object + else if ( $.isPlainObject(container) ) + options = container + + // Only container + else + options = {container: container} + + // Find and validate container + if (options.container) + options.container = findContainerFor(options.container) + + return options +} + +// Internal: Find container element for a variety of inputs. +// +// Because we can't persist elements using the history API, we must be +// able to find a String selector that will consistently find the Element. +// +// container - A selector String, jQuery object, or DOM Element. +// +// Returns a jQuery object whose context is `document` and has a selector. +function findContainerFor(container) { + container = $(container) + + if ( !container.length ) { + throw "no pjax container for " + container.selector + } else if ( container.selector !== '' && container.context === document ) { + return container + } else if ( container.attr('id') ) { + return $('#' + container.attr('id')) + } else { + throw "cant get selector for pjax container!" + } +} + +// Internal: Filter and find all elements matching the selector. +// +// Where $.fn.find only matches descendants, findAll will test all the +// top level elements in the jQuery object as well. +// +// elems - jQuery object of Elements +// selector - String selector to match +// +// Returns a jQuery object. +function findAll(elems, selector) { + return elems.filter(selector).add(elems.find(selector)); +} + +function parseHTML(html) { + return $.parseHTML(html, document, true) +} + +// Internal: Extracts container and metadata from response. +// +// 1. Extracts X-PJAX-URL header if set +// 2. Extracts inline <title> tags +// 3. Builds response Element and extracts fragment if set +// +// data - String response data +// xhr - XHR response +// options - pjax options Object +// +// Returns an Object with url, title, and contents keys. +function extractContainer(data, xhr, options) { + var obj = {}, fullDocument = /<html/i.test(data) + + // Prefer X-PJAX-URL header if it was set, otherwise fallback to + // using the original requested url. + var serverUrl = xhr.getResponseHeader('X-PJAX-URL') + obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl + + // Attempt to parse response html into elements + if (fullDocument) { + var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])) + var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])) + } else { + var $head = $body = $(parseHTML(data)) + } + + // If response data is empty, return fast + if ($body.length === 0) + return obj + + // If there's a <title> tag in the header, use it as + // the page's title. + obj.title = findAll($head, 'title').last().text() + + if (options.fragment) { + // If they specified a fragment, look for it in the response + // and pull it out. + if (options.fragment === 'body') { + var $fragment = $body + } else { + var $fragment = findAll($body, options.fragment).first() + } + + if ($fragment.length) { + obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents() + + // If there's no title, look for data-title and title attributes + // on the fragment + if (!obj.title) + obj.title = $fragment.attr('title') || $fragment.data('title') + } + + } else if (!fullDocument) { + obj.contents = $body + } + + // Clean up any <title> tags + if (obj.contents) { + // Remove any parent title elements + obj.contents = obj.contents.not(function() { return $(this).is('title') }) + + // Then scrub any titles from their descendants + obj.contents.find('title').remove() + + // Gather all script[src] elements + obj.scripts = findAll(obj.contents, 'script[src]').remove() + obj.contents = obj.contents.not(obj.scripts) + } + + // Trim any whitespace off the title + if (obj.title) obj.title = $.trim(obj.title) + + return obj +} + +// Load an execute scripts using standard script request. +// +// Avoids jQuery's traditional $.getScript which does a XHR request and +// globalEval. +// +// scripts - jQuery object of script Elements +// +// Returns nothing. +function executeScriptTags(scripts) { + if (!scripts) return + + var existingScripts = $('script[src]') + + scripts.each(function() { + var src = this.src + var matchedScripts = existingScripts.filter(function() { + return this.src === src + }) + if (matchedScripts.length) return + + var script = document.createElement('script') + var type = $(this).attr('type') + if (type) script.type = type + script.src = $(this).attr('src') + document.head.appendChild(script) + }) +} + +// Internal: History DOM caching class. +var cacheMapping = {} +var cacheForwardStack = [] +var cacheBackStack = [] + +// Push previous state id and container contents into the history +// cache. Should be called in conjunction with `pushState` to save the +// previous container contents. +// +// id - State ID Number +// value - DOM Element to cache +// +// Returns nothing. +function cachePush(id, value) { + cacheMapping[id] = value + cacheBackStack.push(id) + + // Remove all entries in forward history stack after pushing a new page. + trimCacheStack(cacheForwardStack, 0) + + // Trim back history stack to max cache length. + trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength) +} + +// Shifts cache from directional history cache. Should be +// called on `popstate` with the previous state id and container +// contents. +// +// direction - "forward" or "back" String +// id - State ID Number +// value - DOM Element to cache +// +// Returns nothing. +function cachePop(direction, id, value) { + var pushStack, popStack + cacheMapping[id] = value + + if (direction === 'forward') { + pushStack = cacheBackStack + popStack = cacheForwardStack + } else { + pushStack = cacheForwardStack + popStack = cacheBackStack + } + + pushStack.push(id) + if (id = popStack.pop()) + delete cacheMapping[id] + + // Trim whichever stack we just pushed to to max cache length. + trimCacheStack(pushStack, pjax.defaults.maxCacheLength) +} + +// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no +// longer than the specified length, deleting cached DOM elements as necessary. +// +// stack - Array of state IDs +// length - Maximum length to trim to +// +// Returns nothing. +function trimCacheStack(stack, length) { + while (stack.length > length) + delete cacheMapping[stack.shift()] +} + +// Public: Find version identifier for the initial page load. +// +// Returns String version or undefined. +function findVersion() { + return $('meta').filter(function() { + var name = $(this).attr('http-equiv') + return name && name.toUpperCase() === 'X-PJAX-VERSION' + }).attr('content') +} + +// Install pjax functions on $.pjax to enable pushState behavior. +// +// Does nothing if already enabled. +// +// Examples +// +// $.pjax.enable() +// +// Returns nothing. +function enable() { + $.fn.pjax = fnPjax + $.pjax = pjax + $.pjax.enable = $.noop + $.pjax.disable = disable + $.pjax.click = handleClick + $.pjax.submit = handleSubmit + $.pjax.reload = pjaxReload + $.pjax.defaults = { + timeout: 650, + push: true, + replace: false, + type: 'GET', + dataType: 'html', + scrollTo: 0, + maxCacheLength: 20, + version: findVersion + } + $(window).on('popstate.pjax', onPjaxPopstate) +} + +// Disable pushState behavior. +// +// This is the case when a browser doesn't support pushState. It is +// sometimes useful to disable pushState for debugging on a modern +// browser. +// +// Examples +// +// $.pjax.disable() +// +// Returns nothing. +function disable() { + $.fn.pjax = function() { return this } + $.pjax = fallbackPjax + $.pjax.enable = enable + $.pjax.disable = $.noop + $.pjax.click = $.noop + $.pjax.submit = $.noop + $.pjax.reload = function() { window.location.reload() } + + $(window).off('popstate.pjax', onPjaxPopstate) +} + + +// Add the state property to jQuery's event object so we can use it in +// $(window).bind('popstate') +if ( $.inArray('state', $.event.props) < 0 ) + $.event.props.push('state') + +// Is pjax supported by this browser? +$.support.pjax = + window.history && window.history.pushState && window.history.replaceState && + // pushState isn't reliable on iOS until 5. + !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) + +$.support.pjax ? enable() : disable() + +})(jQuery); \ No newline at end of file diff --git a/rhodecode/public/js/src/plugins/jquery.timeago-extension.js b/rhodecode/public/js/src/plugins/jquery.timeago-extension.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.timeago-extension.js @@ -0,0 +1,205 @@ +// define module +var AgeModule = (function () { + return { + age: function(prevdate, now, show_short_version, show_suffix, short_format) { + + var prevdate = moment(prevdate); + var now = now || moment().utc(); + + var show_short_version = show_short_version || false; + var show_suffix = show_suffix || true; + var short_format = short_format || false; + + // alias for backward compat + var _ = function(s) { + if (_TM.hasOwnProperty(s)) { + return _TM[s]; + } + return s + }; + + var ungettext = function (singular, plural, n) { + if (n === 1){ + return _(singular) + } + return _(plural) + }; + + var _get_relative_delta = function(now, prevdate) { + + var duration = moment.duration(moment(now).diff(prevdate)); + return { + 'year': duration.years(), + 'month': duration.months(), + 'day': duration.days(), + 'hour': duration.hours(), + 'minute': duration.minutes(), + 'second': duration.seconds() + }; + + }; + + var _is_leap_year = function(year){ + return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); + }; + + var get_month = function(prevdate) { + return prevdate.getMonth() + }; + + var get_year = function(prevdate) { + return prevdate.getYear() + }; + + var order = ['year', 'month', 'day', 'hour', 'minute', 'second']; + var deltas = {}; + var future = false; + + if (prevdate > now) { + var now_old = now; + now = prevdate; + prevdate = now_old; + future = true; + } + if (future) { + // ? remove microseconds, we don't have it in JS + } + + // Get date parts deltas + for (part in order) { + var part = order[part]; + var rel_delta = _get_relative_delta(now, prevdate); + deltas[part] = rel_delta[part] + } + + //# Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00, + //# not 1 hour, -59 minutes and -59 seconds) + var offsets = [[5, 60], [4, 60], [3, 24]]; + for (element in offsets) { //# seconds, minutes, hours + var element = offsets[element]; + var num = element[0]; + var length = element[1]; + + var part = order[num]; + var carry_part = order[num - 1]; + + if (deltas[part] < 0){ + deltas[part] += length; + deltas[carry_part] -= 1 + } + + } + + // # Same thing for days except that the increment depends on the (variable) + // # number of days in the month + var month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + if (deltas['day'] < 0) { + if (get_month(prevdate) == 2 && _is_leap_year(get_year(prevdate))) { + deltas['day'] += 29; + } else { + deltas['day'] += month_lengths[get_month(prevdate) - 1]; + } + + deltas['month'] -= 1 + } + + if (deltas['month'] < 0) { + deltas['month'] += 12; + deltas['year'] -= 1; + } + + //# Format the result + if (short_format) { + var fmt_funcs = { + 'year': function(d) {return '{0}y'.format(d)}, + 'month': function(d) {return '{0}m'.format(d)}, + 'day': function(d) {return '{0}d'.format(d)}, + 'hour': function(d) {return '{0}h'.format(d)}, + 'minute': function(d) {return '{0}min'.format(d)}, + 'second': function(d) {return '{0}sec'.format(d)} + } + + } else { + var fmt_funcs = { + 'year': function(d) {return ungettext('{0} year', '{0} years', d).format(d)}, + 'month': function(d) {return ungettext('{0} month', '{0} months', d).format(d)}, + 'day': function(d) {return ungettext('{0} day', '{0} days', d).format(d)}, + 'hour': function(d) {return ungettext('{0} hour', '{0} hours', d).format(d)}, + 'minute': function(d) {return ungettext('{0} min', '{0} min', d).format(d)}, + 'second': function(d) {return ungettext('{0} sec', '{0} sec', d).format(d)} + } + + } + var i = 0; + for (part in order){ + var part = order[part]; + var value = deltas[part]; + if (value !== 0) { + + if (i < 5) { + var sub_part = order[i + 1]; + var sub_value = deltas[sub_part] + } else { + var sub_value = 0 + } + if (sub_value == 0 || show_short_version) { + var _val = fmt_funcs[part](value); + if (future) { + if (show_suffix) { + return _('in {0}').format(_val) + } else { + return _val + } + + } + else { + if (show_suffix) { + return _('{0} ago').format(_val) + } else { + return _val + } + } + } + + var val = fmt_funcs[part](value); + var val_detail = fmt_funcs[sub_part](sub_value); + if (short_format) { + var datetime_tmpl = '{0}, {1}'; + if (show_suffix) { + datetime_tmpl = _('{0}, {1} ago'); + if (future) { + datetime_tmpl = _('in {0}, {1}'); + } + } + } else { + var datetime_tmpl = _('{0} and {1}'); + if (show_suffix) { + datetime_tmpl = _('{0} and {1} ago'); + if (future) { + datetime_tmpl = _('in {0} and {1}') + } + } + } + + return datetime_tmpl.format(val, val_detail) + } + i += 1; + } + + return _('just now') + +}, + createTimeComponent: function(dateTime, text) { + return '<time class="timeago tooltip" title="{1}" datetime="{0}">{1}</time>'.format(dateTime, text); + } + } +})(); + + +jQuery.timeago.settings.localeTitle = false; + +// auto refresh the components every Ns +jQuery.timeago.settings.refreshMillis = templateContext.timeago.refresh_time; + +// Display original dates older than N days +jQuery.timeago.settings.cutoff = templateContext.timeago.cutoff_limit; diff --git a/rhodecode/public/js/src/plugins/jquery.timeago.js b/rhodecode/public/js/src/plugins/jquery.timeago.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/plugins/jquery.timeago.js @@ -0,0 +1,228 @@ +/** + * Timeago is a jQuery plugin that makes it easy to support automatically + * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). + * + * @name timeago + * @version 1.5.2 + * @requires jQuery v1.2.3+ + * @author Ryan McGeary + * @license MIT License - http://www.opensource.org/licenses/mit-license.php + * + * For usage and examples, visit: + * http://timeago.yarp.com/ + * + * Copyright (c) 2008-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && typeof module.exports === 'object') { + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + $.timeago = function(timestamp) { + if (timestamp instanceof Date) { + return inWords(timestamp); + } else if (typeof timestamp === "string") { + return inWords($.timeago.parse(timestamp)); + } else if (typeof timestamp === "number") { + return inWords(new Date(timestamp)); + } else { + return inWords($.timeago.datetime(timestamp)); + } + }; + var $t = $.timeago; + + $.extend($.timeago, { + settings: { + refreshMillis: 60000, + allowPast: true, + allowFuture: false, + localeTitle: false, + cutoff: 0, + autoDispose: true, + strings: { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: "ago", + suffixFromNow: "from now", + inPast: 'any moment now', + seconds: "less than a minute", + minute: "about a minute", + minutes: "%d minutes", + hour: "about an hour", + hours: "about %d hours", + day: "a day", + days: "%d days", + month: "about a month", + months: "%d months", + year: "about a year", + years: "%d years", + wordSeparator: " ", + numbers: [] + } + }, + + inWords: function(distanceMillis) { + if (!this.settings.allowPast && ! this.settings.allowFuture) { + throw 'timeago allowPast and allowFuture settings can not both be set to false.'; + } + + var $l = this.settings.strings; + var prefix = $l.prefixAgo; + var suffix = $l.suffixAgo; + if (this.settings.allowFuture) { + if (distanceMillis < 0) { + prefix = $l.prefixFromNow; + suffix = $l.suffixFromNow; + } + } + + if (!this.settings.allowPast && distanceMillis >= 0) { + return this.settings.strings.inPast; + } + + var seconds = Math.abs(distanceMillis) / 1000; + var minutes = seconds / 60; + var hours = minutes / 60; + var days = hours / 24; + var years = days / 365; + + function substitute(stringOrFunction, number) { + var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; + var value = ($l.numbers && $l.numbers[number]) || number; + return string.replace(/%d/i, value); + } + + var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || + seconds < 90 && substitute($l.minute, 1) || + minutes < 45 && substitute($l.minutes, Math.round(minutes)) || + minutes < 90 && substitute($l.hour, 1) || + hours < 24 && substitute($l.hours, Math.round(hours)) || + hours < 42 && substitute($l.day, 1) || + days < 30 && substitute($l.days, Math.round(days)) || + days < 45 && substitute($l.month, 1) || + days < 365 && substitute($l.months, Math.round(days / 30)) || + years < 1.5 && substitute($l.year, 1) || + substitute($l.years, Math.round(years)); + + var separator = $l.wordSeparator || ""; + if ($l.wordSeparator === undefined) { separator = " "; } + return $.trim([prefix, words, suffix].join(separator)); + }, + + parse: function(iso8601) { + var s = $.trim(iso8601); + s = s.replace(/\.\d+/,""); // remove milliseconds + s = s.replace(/-/,"/").replace(/-/,"/"); + s = s.replace(/T/," ").replace(/Z/," UTC"); + s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 + s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900 + return new Date(s); + }, + datetime: function(elem) { + var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); + return $t.parse(iso8601); + }, + isTime: function(elem) { + // jQuery's `is()` doesn't play well with HTML5 in IE + return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); + } + }); + + // functions that can be called via $(el).timeago('action') + // init is default when no action is given + // functions are called with context of a single element + var functions = { + init: function() { + var refresh_el = $.proxy(refresh, this); + refresh_el(); + var $s = $t.settings; + if ($s.refreshMillis > 0 && this._timeagoInterval == null) { + this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis); + } + }, + update: function(timestamp) { + var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp); + $(this).data('timeago', { datetime: date }); + if ($t.settings.localeTitle) $(this).attr("title", date.toLocaleString()); + refresh.apply(this); + }, + updateFromDOM: function() { + $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) }); + refresh.apply(this); + }, + dispose: function () { + if (this._timeagoInterval) { + window.clearInterval(this._timeagoInterval); + this._timeagoInterval = null; + } + } + }; + + $.fn.timeago = function(action, options) { + var fn = action ? functions[action] : functions.init; + if (!fn) { + throw new Error("Unknown function name '"+ action +"' for timeago"); + } + // each over objects here and call the requested function + this.each(function() { + fn.call(this, options); + }); + return this; + }; + + function refresh() { + var $s = $t.settings; + + //check if it's still visible + if ($s.autoDispose && !$.contains(document.documentElement,this)) { + //stop if it has been removed + $(this).timeago("dispose"); + return this; + } + + var data = prepareData(this); + + if (!isNaN(data.datetime)) { + if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) { + $(this).text(inWords(data.datetime)); + } + } + return this; + } + + function prepareData(element) { + element = $(element); + if (!element.data("timeago")) { + element.data("timeago", { datetime: $t.datetime(element) }); + var text = $.trim(element.text()); + if ($t.settings.localeTitle) { + element.attr("title", element.data('timeago').datetime.toLocaleString()); + } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { + element.attr("title", text); + } + } + return element.data("timeago"); + } + + function inWords(date) { + /* RhodeCode Change */ + return AgeModule.age(date); + return $t.inWords(distance(date)); + } + + function distance(date) { + return (new Date().getTime() - date.getTime()); + } + + // fix for IE6 suckage + document.createElement("abbr"); + document.createElement("time"); +})); + diff --git a/rhodecode/public/js/src/rhodecode.js b/rhodecode/public/js/src/rhodecode.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode.js @@ -0,0 +1,422 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** +RhodeCode JS Files +**/ + +if (typeof console == "undefined" || typeof console.log == "undefined"){ + console = { log: function() {} } +} + + +// alias for backward compat +var _tm = function(s) { + if (_TM.hasOwnProperty(s)) { + return _TM[s]; + } + return s +}; + +// TODO: move the following function to submodules + +/** + * show more + */ +var show_more_event = function(){ + $('table .show_more').click(function(e) { + var cid = e.target.id.substring(1); + var button = $(this); + if (button.hasClass('open')) { + $('#'+cid).hide(); + button.removeClass('open'); + } else { + $('#'+cid).show(); + button.addClass('open one'); + } + }); +}; + +var compare_radio_buttons = function(repo_name, compare_ref_type){ + $('#compare_action').on('click', function(e){ + e.preventDefault(); + + var source = $('input[name=compare_source]:checked').val(); + var target = $('input[name=compare_target]:checked').val(); + if(source && target){ + var url_data = { + repo_name: repo_name, + source_ref: source, + source_ref_type: compare_ref_type, + target_ref: target, + target_ref_type: compare_ref_type, + merge: 1 + }; + window.location = pyroutes.url('compare_url', url_data); + } + }); + $('.compare-radio-button').on('click', function(e){ + var source = $('input[name=compare_source]:checked').val(); + var target = $('input[name=compare_target]:checked').val(); + if(source && target){ + $('#compare_action').removeAttr("disabled"); + $('#compare_action').removeClass("disabled"); + } + }) +}; + +var showRepoSize = function(target, repo_name, commit_id, callback) { + var container = $('#' + target); + var url = pyroutes.url('repo_stats', + {"repo_name": repo_name, "commit_id": commit_id}); + + if (!container.hasClass('loaded')) { + $.ajax({url: url}) + .complete(function (data) { + var responseJSON = data.responseJSON; + container.addClass('loaded'); + container.html(responseJSON.size); + callback(responseJSON.code_stats) + }) + .fail(function (data) { + console.log('failed to load repo stats'); + }); + } + +}; + +var showRepoStats = function(target, data){ + var container = $('#' + target); + + if (container.hasClass('loaded')) { + return + } + + var total = 0; + var no_data = true; + var tbl = document.createElement('table'); + tbl.setAttribute('class', 'trending_language_tbl'); + + $.each(data, function(key, val){ + total += val.count; + }); + + var sortedStats = []; + for (var obj in data){ + sortedStats.push([obj, data[obj]]) + } + var sortedData = sortedStats.sort(function (a, b) { + return b[1].count - a[1].count + }); + var cnt = 0; + $.each(sortedData, function(idx, val){ + cnt += 1; + no_data = false; + + var hide = cnt > 2; + var tr = document.createElement('tr'); + if (hide) { + tr.setAttribute('style', 'display:none'); + tr.setAttribute('class', 'stats_hidden'); + } + + var key = val[0]; + var obj = {"desc": val[1].desc, "count": val[1].count}; + + var percentage = Math.round((obj.count / total * 100), 2); + + var td1 = document.createElement('td'); + td1.width = 300; + var trending_language_label = document.createElement('div'); + trending_language_label.innerHTML = obj.desc + " (.{0})".format(key); + td1.appendChild(trending_language_label); + + var td2 = document.createElement('td'); + var trending_language = document.createElement('div'); + var nr_files = obj.count +" "+ (obj.count === 1 ? _tm('file'): _tm('files')); + + trending_language.title = key + " " + nr_files; + + trending_language.innerHTML = "<span>" + percentage + "% " + nr_files + + "</span><b>" + percentage + "% " + nr_files + "</b>"; + + trending_language.setAttribute("class", 'trending_language'); + $('b', trending_language)[0].style.width = percentage + "%"; + td2.appendChild(trending_language); + + tr.appendChild(td1); + tr.appendChild(td2); + tbl.appendChild(tr); + if (cnt == 3) { + var show_more = document.createElement('tr'); + var td = document.createElement('td'); + lnk = document.createElement('a'); + + lnk.href = '#'; + lnk.innerHTML = _tm('Show more'); + lnk.id = 'code_stats_show_more'; + td.appendChild(lnk); + + show_more.appendChild(td); + show_more.appendChild(document.createElement('td')); + tbl.appendChild(show_more); + } + }); + + $(container).html(tbl); + $(container).addClass('loaded'); + + $('#code_stats_show_more').on('click', function (e) { + e.preventDefault(); + $('.stats_hidden').each(function (idx) { + $(this).css("display", ""); + }); + $('#code_stats_show_more').hide(); + }); + +}; + + +// Toggle Collapsable Content +function collapsableContent() { + + $('.collapsable-content').not('.no-hide').hide(); + + $('.btn-collapse').unbind(); //in case we've been here before + $('.btn-collapse').click(function() { + var button = $(this); + var togglename = $(this).data("toggle"); + $('.collapsable-content[data-toggle='+togglename+']').toggle(); + if ($(this).html()=="Show Less") + $(this).html("Show More"); + else + $(this).html("Show Less"); + }); +}; + +var timeagoActivate = function() { + $("time.timeago").timeago(); +}; + +// Formatting values in a Select2 dropdown of commit references +var formatSelect2SelectionRefs = function(commit_ref){ + var tmpl = ''; + if (!commit_ref.text || commit_ref.type === 'sha'){ + return commit_ref.text; + } + if (commit_ref.type === 'branch'){ + tmpl = tmpl.concat('<i class="icon-branch"></i> '); + } else if (commit_ref.type === 'tag'){ + tmpl = tmpl.concat('<i class="icon-tag"></i> '); + } else if (commit_ref.type === 'book'){ + tmpl = tmpl.concat('<i class="icon-bookmark"></i> '); + } + return tmpl.concat(commit_ref.text); +}; + +// takes a given html element and scrolls it down offset pixels +function offsetScroll(element, offset){ + setTimeout(function(){ + console.log(element); + var location = element.offset().top; + // some browsers use body, some use html + $('html, body').animate({ scrollTop: (location - offset) }); + }, 100); +} + +/** + * global hooks after DOM is loaded + */ +$(document).ready(function() { + firefoxAnchorFix(); + + $('.navigation a.menulink').on('click', function(e){ + var menuitem = $(this).parent('li'); + if (menuitem.hasClass('open')) { + menuitem.removeClass('open'); + } else { + menuitem.addClass('open'); + $(document).on('click', function(event) { + if (!$(event.target).closest(menuitem).length) { + menuitem.removeClass('open'); + } + }); + } + }); + // Add tooltips + $('tr.line .lineno a').attr("title","Click to select line").addClass('tooltip'); + $('tr.line .add-comment-line a').attr("title","Click to comment").addClass('tooltip'); + + // Set colors and styles + $('tr.line .lineno a').hover( + function(){ + $(this).parents('tr.line').addClass('hover'); + }, function(){ + $(this).parents('tr.line').removeClass('hover'); + } + ); + + $('tr.line .lineno a').click( + function(){ + if ($(this).text() != ""){ + $('tr.line').removeClass('selected'); + $(this).parents("tr.line").addClass('selected'); + + // Replace URL without jumping to it if browser supports. + // Default otherwise + if (history.pushState) { + var new_location = location.href + if (location.hash){ + new_location = new_location.replace(location.hash, ""); + } + + // Make new anchor url + var new_location = new_location+$(this).attr('href'); + history.pushState(true, document.title, new_location); + + return false; + } + } + } + ); + + $('tr.line .add-comment-line a').hover( + function(){ + $(this).parents('tr.line').addClass('commenting'); + }, function(){ + $(this).parents('tr.line').removeClass('commenting'); + } + ); + + $('tr.line .add-comment-line a').on('click', function(e){ + var tr = $(e.currentTarget).parents('tr.line')[0]; + injectInlineForm(tr); + return false; + }); + + + $('.collapse_file').on('click', function(e) { + e.stopPropagation(); + if ($(e.target).is('a')) { return; } + var node = $(e.delegateTarget).first(); + var icon = $($(node.children().first()).children().first()); + var id = node.attr('fid'); + var target = $('#'+id); + var tr = $('#tr_'+id); + var diff = $('#diff_'+id); + if(node.hasClass('expand_file')){ + node.removeClass('expand_file'); + icon.removeClass('expand_file_icon'); + node.addClass('collapse_file'); + icon.addClass('collapse_file_icon'); + diff.show(); + tr.show(); + target.show(); + } else { + node.removeClass('collapse_file'); + icon.removeClass('collapse_file_icon'); + node.addClass('expand_file'); + icon.addClass('expand_file_icon'); + diff.hide(); + tr.hide(); + target.hide(); + } + }); + + $('#expand_all_files').click(function() { + $('.expand_file').each(function() { + var node = $(this); + var icon = $($(node.children().first()).children().first()); + var id = $(this).attr('fid'); + var target = $('#'+id); + var tr = $('#tr_'+id); + var diff = $('#diff_'+id); + node.removeClass('expand_file'); + icon.removeClass('expand_file_icon'); + node.addClass('collapse_file'); + icon.addClass('collapse_file_icon'); + diff.show(); + tr.show(); + target.show(); + }); + }); + + $('#collapse_all_files').click(function() { + $('.collapse_file').each(function() { + var node = $(this); + var icon = $($(node.children().first()).children().first()); + var id = $(this).attr('fid'); + var target = $('#'+id); + var tr = $('#tr_'+id); + var diff = $('#diff_'+id); + node.removeClass('collapse_file'); + icon.removeClass('collapse_file_icon'); + node.addClass('expand_file'); + icon.addClass('expand_file_icon'); + diff.hide(); + tr.hide(); + target.hide(); + }); + }); + + // Mouse over behavior for comments and line selection + + // Select the line that comes from the url anchor + // At the time of development, Chrome didn't seem to support jquery's :target + // element, so I had to scroll manually + if (location.hash) { + var splitIx = location.hash.indexOf('/?/'); + if (splitIx !== -1){ + var loc = location.hash.slice(0, splitIx); + var remainder = location.hash.slice(splitIx + 2); + } + else{ + var loc = location.hash; + var remainder = null; + } + if (loc.length > 1){ + var lineno = $(loc+'.lineno'); + if (lineno.length > 0){ + var tr = lineno.parents('tr.line'); + tr.addClass('selected'); + + // once we scrolled into our line, trigger chat app + if (remainder){ + tr.find('.add-comment-line a').trigger( "click" ); + setTimeout(function(){ + var nextNode = $(tr).next(); + if(nextNode.hasClass('inline-comments')){ + nextNode.next().find('.switch-to-chat').trigger( "click" ); + } + else{ + nextNode.find('.switch-to-chat').trigger( "click" ); + } + // trigger scroll into, later so all elements are already loaded + tr[0].scrollIntoView(); + }, 250); + + } + else{ + tr[0].scrollIntoView(); + } + } + } + }; + + collapsableContent(); +}); diff --git a/rhodecode/public/js/src/rhodecode/appenlight.js b/rhodecode/public/js/src/rhodecode/appenlight.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/appenlight.js @@ -0,0 +1,36 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var initAppEnlight = function (config) { + if (config && config.enabled === true && config.key) { + AppEnlight.init({ + apiKey: config.key, + server: config.serverUrl, + windowOnError: 1 // enable to hook to window.onerror + }); + if (config.requestInfo){ + AppEnlight.setRequestInfo(config.requestInfo); + } + } +}; + +(function () { + if (window.APPENLIGHT) { + initAppEnlight(APPENLIGHT) + } +})(); diff --git a/rhodecode/public/js/src/rhodecode/codemirror.js b/rhodecode/public/js/src/rhodecode/codemirror.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/codemirror.js @@ -0,0 +1,530 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * Code Mirror + */ +// global code-mirror logger;, to enable run +// Logger.get('CodeMirror').setLevel(Logger.DEBUG) + +cmLog = Logger.get('CodeMirror'); +cmLog.setLevel(Logger.OFF); + + +//global cache for inline forms +var userHintsCache = {}; + + +var initCodeMirror = function(textAreadId, resetUrl, focus, options) { + var ta = $('#' + textAreadId).get(0); + if (focus === undefined) { + focus = true; + } + + // default options + var codeMirrorOptions = { + mode: "null", + lineNumbers: true, + indentUnit: 4, + autofocus: focus + }; + + if (options !== undefined) { + // extend with custom options + codeMirrorOptions = $.extend(true, codeMirrorOptions, options); + } + + var myCodeMirror = CodeMirror.fromTextArea(ta, codeMirrorOptions); + + $('#reset').on('click', function(e) { + window.location = resetUrl; + }); + + return myCodeMirror; +}; + +var initCommentBoxCodeMirror = function(textAreaId, triggerActions){ + var initialHeight = 100; + + // global timer, used to cancel async loading + var loadUserHintTimer; + + if (typeof userHintsCache === "undefined") { + userHintsCache = {}; + cmLog.debug('Init empty cache for mentions'); + } + if (!$(textAreaId).get(0)) { + cmLog.debug('Element for textarea not found', textAreaId); + return; + } + var escapeRegExChars = function(value) { + return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }; + /** + * Load hints from external source returns an array of objects in a format + * that hinting lib requires + * @returns {Array} + */ + var loadUserHints = function(query, triggerHints) { + cmLog.debug('Loading mentions users via AJAX'); + var _users = []; + $.ajax({ + type: 'GET', + data: {query: query}, + url: pyroutes.url('user_autocomplete_data'), + headers: {'X-PARTIAL-XHR': true}, + async: true + }) + .done(function(data) { + var tmpl = '<img class="gravatar" src="{0}"/>{1}'; + $.each(data.suggestions, function(i) { + var userObj = data.suggestions[i]; + + if (userObj.username !== "default") { + _users.push({ + text: userObj.username + " ", + org_text: userObj.username, + displayText: userObj.value_display, // search that field + // internal caches + _icon_link: userObj.icon_link, + _text: userObj.value_display, + + render: function(elt, data, completion) { + var el = document.createElement('div'); + el.className = "CodeMirror-hint-entry"; + el.innerHTML = tmpl.format( + completion._icon_link, completion._text); + elt.appendChild(el); + } + }); + } + }); + cmLog.debug('Mention users loaded'); + // set to global cache + userHintsCache[query] = _users; + triggerHints(userHintsCache[query]); + }) + .fail(function(data, textStatus, xhr) { + alert("error processing request: " + textStatus); + }); + }; + + /** + * filters the results based on the current context + * @param users + * @param context + * @returns {Array} + */ + var filterUsers = function(users, context) { + var MAX_LIMIT = 10; + var filtered_users = []; + var curWord = context.string; + + cmLog.debug('Filtering users based on query:', curWord); + $.each(users, function(i) { + var match = users[i]; + var searchText = match.displayText; + + if (!curWord || + searchText.toLowerCase().lastIndexOf(curWord) !== -1) { + // reset state + match._text = match.displayText; + if (curWord) { + // do highlighting + var pattern = '(' + escapeRegExChars(curWord) + ')'; + match._text = searchText.replace( + new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); + } + + filtered_users.push(match); + } + // to not return to many results, use limit of filtered results + if (filtered_users.length > MAX_LIMIT) { + return false; + } + }); + + return filtered_users; + }; + + /** + * Filter action based on typed in text + * @param actions + * @param context + * @returns {Array} + */ + + var filterActions = function(actions, context){ + var MAX_LIMIT = 10; + var filtered_actions= []; + var curWord = context.string; + + cmLog.debug('Filtering actions based on query:', curWord); + $.each(actions, function(i) { + var match = actions[i]; + var searchText = match.displayText; + + if (!curWord || + searchText.toLowerCase().lastIndexOf(curWord) !== -1) { + // reset state + match._text = match.displayText; + if (curWord) { + // do highlighting + var pattern = '(' + escapeRegExChars(curWord) + ')'; + match._text = searchText.replace( + new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); + } + + filtered_actions.push(match); + } + // to not return to many results, use limit of filtered results + if (filtered_actions.length > MAX_LIMIT) { + return false; + } + }); + return filtered_actions; + }; + + var completeAfter = function(cm, pred) { + var options = { + completeSingle: false, + async: true, + closeOnUnfocus: true + }; + var cur = cm.getCursor(); + setTimeout(function() { + if (!cm.state.completionActive) { + cmLog.debug('Trigger mentions hinting'); + CodeMirror.showHint(cm, CodeMirror.hint.mentions, options); + } + }, 100); + + // tell CodeMirror we didn't handle the key + // trick to trigger on a char but still complete it + return CodeMirror.Pass; + }; + + var submitForm = function(cm, pred) { + $(cm.display.input.textarea.form).submit(); + return CodeMirror.Pass; + }; + + var completeActions = function(cm, pred) { + var cur = cm.getCursor(); + var options = { + closeOnUnfocus: true + }; + setTimeout(function() { + if (!cm.state.completionActive) { + cmLog.debug('Trigger actions hinting'); + CodeMirror.showHint(cm, CodeMirror.hint.actions, options); + } + }, 100); + }; + + var extraKeys = { + "'@'": completeAfter, + Tab: function(cm) { + // space indent instead of TABS + var spaces = new Array(cm.getOption("indentUnit") + 1).join(" "); + cm.replaceSelection(spaces); + } + }; + // submit form on Meta-Enter + if (OSType === "mac") { + extraKeys["Cmd-Enter"] = submitForm; + } + else { + extraKeys["Ctrl-Enter"] = submitForm; + } + + if (triggerActions) { + extraKeys["Ctrl-Space"] = completeActions; + } + + var cm = CodeMirror.fromTextArea($(textAreaId).get(0), { + lineNumbers: false, + indentUnit: 4, + viewportMargin: 30, + // this is a trick to trigger some logic behind codemirror placeholder + // it influences styling and behaviour. + placeholder: " ", + extraKeys: extraKeys, + lineWrapping: true + }); + + cm.setSize(null, initialHeight); + cm.setOption("mode", DEFAULT_RENDERER); + CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode + cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER); + // start listening on changes to make auto-expanded editor + cm.on("change", function(self) { + var height = initialHeight; + var lines = self.lineCount(); + if ( lines > 6 && lines < 20) { + height = "auto"; + } + else if (lines >= 20){ + zheight = 20*15; + } + self.setSize(null, height); + }); + + var mentionHint = function(editor, callback, options) { + var cur = editor.getCursor(); + var curLine = editor.getLine(cur.line).slice(0, cur.ch); + + // match on @ +1char + var tokenMatch = new RegExp( + '(^@| @)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*)$').exec(curLine); + + var tokenStr = ''; + if (tokenMatch !== null && tokenMatch.length > 0){ + tokenStr = tokenMatch[0].strip(); + } else { + // skip if we didn't match our token + return; + } + + var context = { + start: (cur.ch - tokenStr.length) + 1, + end: cur.ch, + string: tokenStr.slice(1), + type: null + }; + + // case when we put the @sign in fron of a string, + // eg <@ we put it here>sometext then we need to prepend to text + if (context.end > cur.ch) { + context.start = context.start + 1; // we add to the @ sign + context.end = cur.ch; // don't eat front part just append + context.string = context.string.slice(1, cur.ch - context.start); + } + + cmLog.debug('Mention context', context); + + var triggerHints = function(userHints){ + return callback({ + list: filterUsers(userHints, context), + from: CodeMirror.Pos(cur.line, context.start), + to: CodeMirror.Pos(cur.line, context.end) + }); + }; + + var queryBasedHintsCache = undefined; + // if we have something in the cache, try to fetch the query based cache + if (userHintsCache !== {}){ + queryBasedHintsCache = userHintsCache[context.string]; + } + + if (queryBasedHintsCache !== undefined) { + cmLog.debug('Users loaded from cache'); + triggerHints(queryBasedHintsCache); + } else { + // this takes care for async loading, and then displaying results + // and also propagates the userHintsCache + window.clearTimeout(loadUserHintTimer); + loadUserHintTimer = setTimeout(function() { + loadUserHints(context.string, triggerHints); + }, 300); + } + }; + + var actionHint = function(editor, options) { + var cur = editor.getCursor(); + var curLine = editor.getLine(cur.line).slice(0, cur.ch); + + var tokenMatch = new RegExp('[a-zA-Z]{1}[a-zA-Z]*$').exec(curLine); + + var tokenStr = ''; + if (tokenMatch !== null && tokenMatch.length > 0){ + tokenStr = tokenMatch[0].strip(); + } + + var context = { + start: cur.ch - tokenStr.length, + end: cur.ch, + string: tokenStr, + type: null + }; + + var actions = [ + { + text: "approve", + displayText: _TM['Set status to Approved'], + hint: function(CodeMirror, data, completion) { + CodeMirror.replaceRange("", completion.from || data.from, + completion.to || data.to, "complete"); + $('#change_status').select2("val", 'approved').trigger('change'); + }, + render: function(elt, data, completion) { + var el = document.createElement('div'); + el.className = "flag_status flag_status_comment_box approved pull-left"; + elt.appendChild(el); + + el = document.createElement('span'); + el.innerHTML = completion.displayText; + elt.appendChild(el); + } + }, + { + text: "reject", + displayText: _TM['Set status to Rejected'], + hint: function(CodeMirror, data, completion) { + CodeMirror.replaceRange("", completion.from || data.from, + completion.to || data.to, "complete"); + $('#change_status').select2("val", 'rejected').trigger('change'); + }, + render: function(elt, data, completion) { + var el = document.createElement('div'); + el.className = "flag_status flag_status_comment_box rejected pull-left"; + elt.appendChild(el); + + el = document.createElement('span'); + el.innerHTML = completion.displayText; + elt.appendChild(el); + } + } + ]; + + return { + list: filterActions(actions, context), + from: CodeMirror.Pos(cur.line, context.start), + to: CodeMirror.Pos(cur.line, context.end) + }; + }; + CodeMirror.registerHelper("hint", "mentions", mentionHint); + CodeMirror.registerHelper("hint", "actions", actionHint); + return cm; +}; + +var setCodeMirrorMode = function(codeMirrorInstance, mode) { + CodeMirror.autoLoadMode(codeMirrorInstance, mode); + codeMirrorInstance.setOption("mode", mode); +}; + +var setCodeMirrorLineWrap = function(codeMirrorInstance, line_wrap) { + codeMirrorInstance.setOption("lineWrapping", line_wrap); +}; + +var setCodeMirrorModeFromSelect = function( + targetSelect, targetFileInput, codeMirrorInstance, callback){ + + $(targetSelect).on('change', function(e) { + cmLog.debug('codemirror select2 mode change event !'); + var selected = e.currentTarget; + var node = selected.options[selected.selectedIndex]; + var mimetype = node.value; + cmLog.debug('picked mimetype', mimetype); + var new_mode = $(node).attr('mode'); + setCodeMirrorMode(codeMirrorInstance, new_mode); + cmLog.debug('set new mode', new_mode); + + //propose filename from picked mode + cmLog.debug('setting mimetype', mimetype); + var proposed_ext = getExtFromMimeType(mimetype); + cmLog.debug('file input', $(targetFileInput).val()); + var file_data = getFilenameAndExt($(targetFileInput).val()); + var filename = file_data.filename || 'filename1'; + $(targetFileInput).val(filename + proposed_ext); + cmLog.debug('proposed file', filename + proposed_ext); + + + if (typeof(callback) === 'function') { + try { + cmLog.debug('running callback', callback); + callback(filename, mimetype, new_mode); + } catch (err) { + console.log('failed to run callback', callback, err); + } + } + cmLog.debug('finish iteration...'); + }); +}; + +var setCodeMirrorModeFromInput = function( + targetSelect, targetFileInput, codeMirrorInstance, callback) { + + // on type the new filename set mode + $(targetFileInput).on('keyup', function(e) { + var file_data = getFilenameAndExt(this.value); + if (file_data.ext === null) { + return; + } + + var mimetypes = getMimeTypeFromExt(file_data.ext, true); + cmLog.debug('mimetype from file', file_data, mimetypes); + var detected_mode; + var detected_option; + for (var i in mimetypes) { + var mt = mimetypes[i]; + if (!detected_mode) { + detected_mode = detectCodeMirrorMode(this.value, mt); + } + + if (!detected_option) { + cmLog.debug('#mimetype option[value="{0}"]'.format(mt)); + if ($(targetSelect).find('option[value="{0}"]'.format(mt)).length) { + detected_option = mt; + } + } + } + + cmLog.debug('detected mode', detected_mode); + cmLog.debug('detected option', detected_option); + if (detected_mode && detected_option){ + + $(targetSelect).select2("val", detected_option); + setCodeMirrorMode(codeMirrorInstance, detected_mode); + + if(typeof(callback) === 'function'){ + try{ + cmLog.debug('running callback', callback); + var filename = file_data.filename + "." + file_data.ext; + callback(filename, detected_option, detected_mode); + }catch (err){ + console.log('failed to run callback', callback, err); + } + } + } + + }); +}; + +var fillCodeMirrorOptions = function(targetSelect) { + //inject new modes, based on codeMirrors modeInfo object + var modes_select = $(targetSelect); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var m = CodeMirror.modeInfo[i]; + var opt = new Option(m.name, m.mime); + $(opt).attr('mode', m.mode); + modes_select.append(opt); + } +}; + +var CodeMirrorPreviewEnable = function(edit_mode) { + // in case it a preview enabled mode enable the button + if (['markdown', 'rst', 'gfm'].indexOf(edit_mode) !== -1) { + $('#render_preview').removeClass('hidden'); + } + else { + if (!$('#render_preview').hasClass('hidden')) { + $('#render_preview').addClass('hidden'); + } + } +}; diff --git a/rhodecode/public/js/src/rhodecode/comments.js b/rhodecode/public/js/src/rhodecode/comments.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/comments.js @@ -0,0 +1,664 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var firefoxAnchorFix = function() { + // hack to make anchor links behave properly on firefox, in our inline + // comments generation when comments are injected firefox is misbehaving + // when jumping to anchor links + if (location.href.indexOf('#') > -1) { + location.href += ''; + } +}; + +// returns a node from given html; +var fromHTML = function(html){ + var _html = document.createElement('element'); + _html.innerHTML = html; + return _html; +}; + +var tableTr = function(cls, body){ + var _el = document.createElement('div'); + var _body = $(body).attr('id'); + var comment_id = fromHTML(body).children[0].id.split('comment-')[1]; + var id = 'comment-tr-{0}'.format(comment_id); + var _html = ('<table><tbody><tr id="{0}" class="{1}">'+ + '<td class="add-comment-line"><span class="add-comment-content"></span></td>'+ + '<td></td>'+ + '<td></td>'+ + '<td>{2}</td>'+ + '</tr></tbody></table>').format(id, cls, body); + $(_el).html(_html); + return _el.children[0].children[0].children[0]; +}; + +var removeInlineForm = function(form) { + form.parentNode.removeChild(form); +}; + +var createInlineForm = function(parent_tr, f_path, line) { + var tmpl = $('#comment-inline-form-template').html(); + tmpl = tmpl.format(f_path, line); + var form = tableTr('comment-form-inline', tmpl); + var form_hide_button = $(form).find('.hide-inline-form'); + + $(form_hide_button).click(function(e) { + $('.inline-comments').removeClass('hide-comment-button'); + var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode; + if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) { + $(newtr.nextElementSibling).show(); + } + $(newtr).parents('.comment-form-inline').remove(); + $(parent_tr).removeClass('form-open'); + $(parent_tr).removeClass('hl-comment'); + }); + + return form; +}; + +var getLineNo = function(tr) { + var line; + // Try to get the id and return "" (empty string) if it doesn't exist + var o = ($(tr).find('.lineno.old').attr('id')||"").split('_'); + var n = ($(tr).find('.lineno.new').attr('id')||"").split('_'); + if (n.length >= 2) { + line = n[n.length-1]; + } else if (o.length >= 2) { + line = o[o.length-1]; + } + return line; +}; + +/** + * make a single inline comment and place it inside + */ +var renderInlineComment = function(json_data, show_add_button) { + show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; + try { + var html = json_data.rendered_text; + var lineno = json_data.line_no; + var target_id = json_data.target_id; + placeInline(target_id, lineno, html, show_add_button); + } catch (e) { + console.error(e); + } +}; + +function bindDeleteCommentButtons() { + $('.delete-comment').one('click', function() { + var comment_id = $(this).data("comment-id"); + + if (comment_id){ + deleteComment(comment_id); + } + }); +} + +/** + * Inject inline comment for on given TR this tr should be always an .line + * tr containing the line. Code will detect comment, and always put the comment + * block at the very bottom + */ +var injectInlineForm = function(tr){ + if (!$(tr).hasClass('line')) { + return; + } + + var _td = $(tr).find('.code').get(0); + if ($(tr).hasClass('form-open') || + $(tr).hasClass('context') || + $(_td).hasClass('no-comment')) { + return; + } + $(tr).addClass('form-open'); + $(tr).addClass('hl-comment'); + var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0); + var f_path = $(node).attr('path'); + var lineno = getLineNo(tr); + var form = createInlineForm(tr, f_path, lineno); + + var parent = tr; + while (1) { + var n = parent.nextElementSibling; + // next element are comments ! + if ($(n).hasClass('inline-comments')) { + parent = n; + } + else { + break; + } + } + var _parent = $(parent).get(0); + $(_parent).after(form); + $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button'); + var f = $(form).get(0); + + var _form = $(f).find('.inline-form').get(0); + + $('.switch-to-chat', _form).on('click', function(evt){ + var fParent = $(_parent).closest('.injected_diff').parent().prev('*[fid]'); + var fid = fParent.attr('fid'); + + // activate chat and trigger subscription to channels + $.Topic('/chat_controller').publish({ + action:'subscribe_to_channels', + data: ['/chat${0}$/fid/{1}/{2}'.format(templateContext.repo_name, fid, lineno)] + }); + $(_form).closest('td').find('.comment-inline-form').addClass('hidden'); + $(_form).closest('td').find('.chat-holder').removeClass('hidden'); + }); + + var pullRequestId = templateContext.pull_request_data.pull_request_id; + var commitId = templateContext.commit_data.commit_id; + + var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false); + var cm = commentForm.getCmInstance(); + + // set a CUSTOM submit handler for inline comments. + commentForm.setHandleFormSubmit(function(o) { + var text = commentForm.cm.getValue(); + + if (text === "") { + return; + } + + if (lineno === undefined) { + alert('missing line !'); + return; + } + if (f_path === undefined) { + alert('missing file path !'); + return; + } + + var excludeCancelBtn = false; + var submitEvent = true; + commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent); + commentForm.cm.setOption("readOnly", true); + var postData = { + 'text': text, + 'f_path': f_path, + 'line': lineno, + 'csrf_token': CSRF_TOKEN + }; + var submitSuccessCallback = function(o) { + $(tr).removeClass('form-open'); + removeInlineForm(f); + renderInlineComment(o); + $('.inline-comments').removeClass('hide-comment-button'); + + // re trigger the linkification of next/prev navigation + linkifyComments($('.inline-comment-injected')); + timeagoActivate(); + tooltip_activate(); + bindDeleteCommentButtons(); + commentForm.setActionButtonsDisabled(false); + + }; + var submitFailCallback = function(){ + commentForm.resetCommentFormState(text) + }; + commentForm.submitAjaxPOST( + commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback); + }); + + setTimeout(function() { + // callbacks + if (cm !== undefined) { + cm.focus(); + } + }, 10); + +}; + +var deleteComment = function(comment_id) { + var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id); + var postData = { + '_method': 'delete', + 'csrf_token': CSRF_TOKEN + }; + + var success = function(o) { + window.location.reload(); + }; + ajaxPOST(url, postData, success); +}; + +var createInlineAddButton = function(tr){ + var label = _TM['Add another comment']; + var html_el = document.createElement('div'); + $(html_el).addClass('add-comment'); + html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label); + var add = new $(html_el); + add.on('click', function(e) { + injectInlineForm(tr); + }); + return add; +}; + +var placeAddButton = function(target_tr){ + if(!target_tr){ + return; + } + var last_node = target_tr; + // scan + while (1){ + var n = last_node.nextElementSibling; + // next element are comments ! + if($(n).hasClass('inline-comments')){ + last_node = n; + // also remove the comment button from previous + var comment_add_buttons = $(last_node).find('.add-comment'); + for(var i=0; i<comment_add_buttons.length; i++){ + var b = comment_add_buttons[i]; + b.parentNode.removeChild(b); + } + } + else{ + break; + } + } + var add = createInlineAddButton(target_tr); + // get the comment div + var comment_block = $(last_node).find('.comment')[0]; + // attach add button + $(add).insertAfter(comment_block); +}; + +/** + * Places the inline comment into the changeset block in proper line position + */ +var placeInline = function(target_container, lineno, html, show_add_button) { + show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; + + var lineid = "{0}_{1}".format(target_container, lineno); + var target_line = $('#' + lineid).get(0); + var comment = new $(tableTr('inline-comments', html)); + // check if there are comments already ! + var parent_node = target_line.parentNode; + var root_parent = parent_node; + while (1) { + var n = parent_node.nextElementSibling; + // next element are comments ! + if ($(n).hasClass('inline-comments')) { + parent_node = n; + } + else { + break; + } + } + // put in the comment at the bottom + $(comment).insertAfter(parent_node); + $(comment).find('.comment-inline').addClass('inline-comment-injected'); + // scan nodes, and attach add button to last one + if (show_add_button) { + placeAddButton(root_parent); + } + + return target_line; +}; + +var linkifyComments = function(comments) { + + for (var i = 0; i < comments.length; i++) { + var comment_id = $(comments[i]).data('comment-id'); + var prev_comment_id = $(comments[i - 1]).data('comment-id'); + var next_comment_id = $(comments[i + 1]).data('comment-id'); + + // place next/prev links + if (prev_comment_id) { + $('#prev_c_' + comment_id).show(); + $('#prev_c_' + comment_id + " a.arrow_comment_link").attr( + 'href', '#comment-' + prev_comment_id).removeClass('disabled'); + } + if (next_comment_id) { + $('#next_c_' + comment_id).show(); + $('#next_c_' + comment_id + " a.arrow_comment_link").attr( + 'href', '#comment-' + next_comment_id).removeClass('disabled'); + } + // place a first link to the total counter + if (i === 0) { + $('#inline-comments-counter').attr('href', '#comment-' + comment_id); + } + } + +}; + +/** + * Iterates over all the inlines, and places them inside proper blocks of data + */ +var renderInlineComments = function(file_comments, show_add_button) { + show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; + + for (var i = 0; i < file_comments.length; i++) { + var box = file_comments[i]; + + var target_id = $(box).attr('target_id'); + + // actually comments with line numbers + var comments = box.children; + + for (var j = 0; j < comments.length; j++) { + var data = { + 'rendered_text': comments[j].outerHTML, + 'line_no': $(comments[j]).attr('line'), + 'target_id': target_id + }; + renderInlineComment(data, show_add_button); + } + } + + // since order of injection is random, we're now re-iterating + // from correct order and filling in links + linkifyComments($('.inline-comment-injected')); + bindDeleteCommentButtons(); + firefoxAnchorFix(); +}; + + +/* Comment form for main and inline comments */ +var CommentForm = (function() { + "use strict"; + + function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) { + + this.withLineNo = function(selector) { + var lineNo = this.lineNo; + if (lineNo === undefined) { + return selector + } else { + return selector + '_' + lineNo; + } + }; + + this.commitId = commitId; + this.pullRequestId = pullRequestId; + this.lineNo = lineNo; + this.initAutocompleteActions = initAutocompleteActions; + + this.previewButton = this.withLineNo('#preview-btn'); + this.previewContainer = this.withLineNo('#preview-container'); + + this.previewBoxSelector = this.withLineNo('#preview-box'); + + this.editButton = this.withLineNo('#edit-btn'); + this.editContainer = this.withLineNo('#edit-container'); + + this.cancelButton = this.withLineNo('#cancel-btn'); + + this.statusChange = '#change_status'; + this.cmBox = this.withLineNo('#text'); + this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions); + + this.submitForm = formElement; + this.submitButton = $(this.submitForm).find('input[type="submit"]'); + this.submitButtonText = this.submitButton.val(); + + this.previewUrl = pyroutes.url('changeset_comment_preview', + {'repo_name': templateContext.repo_name}); + + // based on commitId, or pullReuqestId decide where do we submit + // out data + if (this.commitId){ + this.submitUrl = pyroutes.url('changeset_comment', + {'repo_name': templateContext.repo_name, + 'revision': this.commitId}); + + } else if (this.pullRequestId) { + this.submitUrl = pyroutes.url('pullrequest_comment', + {'repo_name': templateContext.repo_name, + 'pull_request_id': this.pullRequestId}); + + } else { + throw new Error( + 'CommentForm requires pullRequestId, or commitId to be specified.') + } + + this.getCmInstance = function(){ + return this.cm + }; + + var self = this; + + this.getCommentStatus = function() { + return $(this.submitForm).find(this.statusChange).val(); + }; + + this.isAllowedToSubmit = function() { + return !$(this.submitButton).prop('disabled'); + }; + + this.initStatusChangeSelector = function(){ + var formatChangeStatus = function(state, escapeMarkup) { + var originalOption = state.element; + return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' + + '<span>' + escapeMarkup(state.text) + '</span>'; + }; + var formatResult = function(result, container, query, escapeMarkup) { + return formatChangeStatus(result, escapeMarkup); + }; + + var formatSelection = function(data, container, escapeMarkup) { + return formatChangeStatus(data, escapeMarkup); + }; + + $(this.submitForm).find(this.statusChange).select2({ + placeholder: _TM['Status Review'], + formatResult: formatResult, + formatSelection: formatSelection, + containerCssClass: "drop-menu status_box_menu", + dropdownCssClass: "drop-menu-dropdown", + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }); + $(this.submitForm).find(this.statusChange).on('change', function() { + var status = self.getCommentStatus(); + if (status && !self.lineNo) { + $(self.submitButton).prop('disabled', false); + } + //todo, fix this name + var placeholderText = _TM['Comment text will be set automatically based on currently selected status ({0}) ...'].format(status); + self.cm.setOption('placeholder', placeholderText); + }) + }; + + // reset the comment form into it's original state + this.resetCommentFormState = function(content) { + content = content || ''; + + $(this.editContainer).show(); + $(this.editButton).hide(); + + $(this.previewContainer).hide(); + $(this.previewButton).show(); + + this.setActionButtonsDisabled(true); + self.cm.setValue(content); + self.cm.setOption("readOnly", false); + }; + + this.submitAjaxPOST = function(url, postData, successHandler, failHandler) { + failHandler = failHandler || function() {}; + var postData = toQueryString(postData); + var request = $.ajax({ + url: url, + type: 'POST', + data: postData, + headers: {'X-PARTIAL-XHR': true} + }) + .done(function(data) { + successHandler(data); + }) + .fail(function(data, textStatus, errorThrown){ + alert( + "Error while submitting comment.\n" + + "Error code {0} ({1}).".format(data.status, data.statusText)); + failHandler() + }); + return request; + }; + + // overwrite a submitHandler, we need to do it for inline comments + this.setHandleFormSubmit = function(callback) { + this.handleFormSubmit = callback; + }; + + // default handler for for submit for main comments + this.handleFormSubmit = function() { + var text = self.cm.getValue(); + var status = self.getCommentStatus(); + + if (text === "" && !status) { + return; + } + + var excludeCancelBtn = false; + var submitEvent = true; + self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent); + self.cm.setOption("readOnly", true); + var postData = { + 'text': text, + 'changeset_status': status, + 'csrf_token': CSRF_TOKEN + }; + + var submitSuccessCallback = function(o) { + if (status) { + location.reload(true); + } else { + $('#injected_page_comments').append(o.rendered_text); + self.resetCommentFormState(); + bindDeleteCommentButtons(); + timeagoActivate(); + tooltip_activate(); + } + }; + var submitFailCallback = function(){ + self.resetCommentFormState(text) + }; + self.submitAjaxPOST( + self.submitUrl, postData, submitSuccessCallback, submitFailCallback); + }; + + this.previewSuccessCallback = function(o) { + $(self.previewBoxSelector).html(o); + $(self.previewBoxSelector).removeClass('unloaded'); + + // swap buttons + $(self.previewButton).hide(); + $(self.editButton).show(); + + // unlock buttons + self.setActionButtonsDisabled(false); + }; + + this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) { + excludeCancelBtn = excludeCancelBtn || false; + submitEvent = submitEvent || false; + + $(this.editButton).prop('disabled', state); + $(this.previewButton).prop('disabled', state); + + if (!excludeCancelBtn) { + $(this.cancelButton).prop('disabled', state); + } + + var submitState = state; + if (!submitEvent && this.getCommentStatus() && !this.lineNo) { + // if the value of commit review status is set, we allow + // submit button, but only on Main form, lineNo means inline + submitState = false + } + $(this.submitButton).prop('disabled', submitState); + if (submitEvent) { + $(this.submitButton).val(_TM['Submitting...']); + } else { + $(this.submitButton).val(this.submitButtonText); + } + + }; + + // lock preview/edit/submit buttons on load, but exclude cancel button + var excludeCancelBtn = true; + this.setActionButtonsDisabled(true, excludeCancelBtn); + + // anonymous users don't have access to initialized CM instance + if (this.cm !== undefined){ + this.cm.on('change', function(cMirror) { + if (cMirror.getValue() === "") { + self.setActionButtonsDisabled(true, excludeCancelBtn) + } else { + self.setActionButtonsDisabled(false, excludeCancelBtn) + } + }); + } + + $(this.editButton).on('click', function(e) { + e.preventDefault(); + + $(self.previewButton).show(); + $(self.previewContainer).hide(); + $(self.editButton).hide(); + $(self.editContainer).show(); + + }); + + $(this.previewButton).on('click', function(e) { + e.preventDefault(); + var text = self.cm.getValue(); + + if (text === "") { + return; + } + + var postData = { + 'text': text, + 'renderer': DEFAULT_RENDERER, + 'csrf_token': CSRF_TOKEN + }; + + // lock ALL buttons on preview + self.setActionButtonsDisabled(true); + + $(self.previewBoxSelector).addClass('unloaded'); + $(self.previewBoxSelector).html(_TM['Loading ...']); + $(self.editContainer).hide(); + $(self.previewContainer).show(); + + // by default we reset state of comment preserving the text + var previewFailCallback = function(){ + self.resetCommentFormState(text) + }; + self.submitAjaxPOST( + self.previewUrl, postData, self.previewSuccessCallback, previewFailCallback); + + }); + + $(this.submitForm).submit(function(e) { + e.preventDefault(); + var allowedToSubmit = self.isAllowedToSubmit(); + if (!allowedToSubmit){ + return false; + } + self.handleFormSubmit(); + }); + + } + + return CommentForm; +})(); diff --git a/rhodecode/public/js/src/rhodecode/constants.js b/rhodecode/public/js/src/rhodecode/constants.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/constants.js @@ -0,0 +1,23 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +// ** unified definition of pagination of grids +var DEFAULT_GRID_PAGINATION = { + "previous": "<", + "next": ">" +}; diff --git a/rhodecode/public/js/src/rhodecode/files.js b/rhodecode/public/js/src/rhodecode/files.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/files.js @@ -0,0 +1,309 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * Search file list + */ +// global reference to file-node filter +var _NODEFILTER = {}; + +var fileBrowserListeners = function(node_list_url, url_base){ + var n_filter = $('#node_filter').get(0); + + _NODEFILTER.filterTimeout = null; + var nodes = null; + + _NODEFILTER.fetchNodes = function(callback) { + $.ajax({url: node_list_url, headers: {'X-PARTIAL-XHR': true}}) + .done(function(data){ + nodes = data.nodes; + if (callback) { + callback(); + } + }) + .fail(function(data){ + console.log('failed to load'); + }); + }; + + _NODEFILTER.fetchNodesCallback = function() { + $('#node_filter_box_loading').hide(); + $('#node_filter_box').removeClass('hidden').show(); + n_filter.focus(); + if ($('#node_filter').hasClass('init')){ + n_filter.value = ''; + $('#node_filter').removeClass('init'); + } + }; + + _NODEFILTER.initFilter = function(){ + $('#node_filter_box_loading').removeClass('hidden').show(); + $('#search_activate_id').hide(); + $('#search_deactivate_id').removeClass('hidden').show(); + $('#add_node_id').hide(); + _NODEFILTER.fetchNodes(_NODEFILTER.fetchNodesCallback); + }; + + _NODEFILTER.resetFilter = function(){ + $('#node_filter_box_loading').hide(); + $('#node_filter_box').hide(); + $('#search_activate_id').show(); + $('#search_deactivate_id').hide(); + $('#add_node_id').show(); + $('#tbody').show(); + $('#tbody_filtered').hide(); + $('#node_filter').val(''); + }; + + _NODEFILTER.fuzzy_match = function(filepath, query) { + var highlight = []; + var order = 0; + for (var i = 0; i < query.length; i++) { + var match_position = filepath.indexOf(query[i]); + if (match_position !== -1) { + var prev_match_position = highlight[highlight.length-1]; + if (prev_match_position === undefined) { + highlight.push(match_position); + } else { + var current_match_position = prev_match_position + match_position + 1; + highlight.push(current_match_position); + order = order + current_match_position - prev_match_position; + } + filepath = filepath.substring(match_position+1); + } else { + return false; + } + } + return {'order': order, + 'highlight': highlight}; + }; + + _NODEFILTER.sortPredicate = function(a, b) { + if (a.order < b.order) return -1; + if (a.order > b.order) return 1; + if (a.filepath < b.filepath) return -1; + if (a.filepath > b.filepath) return 1; + return 0; + }; + + _NODEFILTER.updateFilter = function(elem, e) { + return function(){ + // Reset timeout + _NODEFILTER.filterTimeout = null; + var query = elem.value.toLowerCase(); + var match = []; + var matches_max = 20; + if (query !== ""){ + var results = []; + for(var k=0;k<nodes.length;k++){ + var result = _NODEFILTER.fuzzy_match( + nodes[k].name.toLowerCase(), query); + if (result) { + result.type = nodes[k].type; + result.filepath = nodes[k].name; + results.push(result); + } + } + results = results.sort(_NODEFILTER.sortPredicate); + var limit = matches_max; + if (results.length < matches_max) { + limit = results.length; + } + for (var i=0; i<limit; i++){ + if(query && results.length > 0){ + var n = results[i].filepath; + var t = results[i].type; + var n_hl = n.split(""); + var pos = results[i].highlight; + for (var j = 0; j < pos.length; j++) { + n_hl[pos[j]] = "<em>" + n_hl[pos[j]] + "</em>"; + } + n_hl = n_hl.join(""); + var new_url = url_base.replace('__FPATH__',n); + + var typeObj = { + dir: 'icon-folder browser-dir', + file: 'icon-file browser-file' + }; + var typeIcon = '<i class="{0}"></i>'.format(typeObj[t]); + match.push('<tr class="browser-result"><td><a class="browser-{0} pjax-link" href="{1}">{2}{3}</a></td><td colspan="5"></td></tr>'.format(t,new_url,typeIcon, n_hl)); + } + } + if(results.length > limit){ + var truncated_count = results.length - matches_max; + if (truncated_count === 1) { + match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated result'])); + } else { + match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated results'])); + } + } + } + if (query !== ""){ + $('#tbody').hide(); + $('#tbody_filtered').show(); + + if (match.length === 0){ + match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files'])); + } + $('#tbody_filtered').html(match.join("")); + } + else{ + $('#tbody').show(); + $('#tbody_filtered').hide(); + } + + }; + }; + + var scrollDown = function(element){ + var elementBottom = element.offset().top + $(element).outerHeight(); + var windowBottom = window.innerHeight + $(window).scrollTop(); + if (elementBottom > windowBottom) { + var offset = elementBottom - window.innerHeight; + $('html,body').scrollTop(offset); + return false; + } + return true; + }; + + var scrollUp = function(element){ + if (element.offset().top < $(window).scrollTop()) { + $('html,body').scrollTop(element.offset().top); + return false; + } + return true; + }; + + $('#filter_activate').click(function() { + _NODEFILTER.initFilter(); + }); + + $('#filter_deactivate').click(function() { + _NODEFILTER.resetFilter(); + }); + + $(n_filter).click(function() { + if ($('#node_filter').hasClass('init')){ + n_filter.value = ''; + $('#node_filter').removeClass('init'); + } + }); + + $(n_filter).keydown(function(e) { + if (e.keyCode === 40){ // Down + if ($('.browser-highlight').length === 0){ + $('.browser-result').first().addClass('browser-highlight'); + } else { + var next = $('.browser-highlight').next(); + if (next.length !== 0) { + $('.browser-highlight').removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } + scrollDown($('.browser-highlight')); + } + if (e.keyCode === 38){ // Up + e.preventDefault(); + if ($('.browser-highlight').length !== 0){ + var next = $('.browser-highlight').prev(); + if (next.length !== 0) { + $('.browser-highlight').removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } + scrollUp($('.browser-highlight')); + } + if (e.keyCode === 13){ // Enter + if ($('.browser-highlight').length !== 0){ + var url = $('.browser-highlight').find('.pjax-link').attr('href'); + $.pjax({url: url, container: '#pjax-container', timeout: pjaxTimeout}); + } + } + if (e.keyCode === 27){ // Esc + _NODEFILTER.resetFilter(); + $('html,body').scrollTop(0); + } + }); + var capture_keys = [40, 38, 39, 37, 13, 27]; + $(n_filter).keyup(function(e) { + if ($.inArray(e.keyCode, capture_keys) === -1){ + clearTimeout(_NODEFILTER.filterTimeout); + _NODEFILTER.filterTimeout = setTimeout(_NODEFILTER.updateFilter(n_filter, e),200); + } + }); +}; + +var getIdentNode = function(n){ + // iterate through nodes until matched interesting node + if (typeof n === 'undefined'){ + return -1; + } + if(typeof n.id !== "undefined" && n.id.match('L[0-9]+')){ + return n; + } + else{ + return getIdentNode(n.parentNode); + } +}; + +var getSelectionLink = function(e) { + // get selection from start/to nodes + if (typeof window.getSelection !== "undefined") { + s = window.getSelection(); + + from = getIdentNode(s.anchorNode); + till = getIdentNode(s.focusNode); + + f_int = parseInt(from.id.replace('L','')); + t_int = parseInt(till.id.replace('L','')); + + if (f_int > t_int){ + // highlight from bottom + offset = -35; + ranges = [t_int,f_int]; + } + else{ + // highligth from top + offset = 35; + ranges = [f_int,t_int]; + } + // if we select more than 2 lines + if (ranges[0] !== ranges[1]){ + if($('#linktt').length === 0){ + hl_div = document.createElement('div'); + hl_div.id = 'linktt'; + } + hl_div.innerHTML = ''; + + anchor = '#L'+ranges[0]+'-'+ranges[1]; + var link = document.createElement('a'); + link.href = location.href.substring(0,location.href.indexOf('#'))+anchor; + link.innerHTML = _TM['Selection link']; + hl_div.appendChild(link); + $('#codeblock').append(hl_div); + + var xy = $(till).offset(); + $('#linktt').addClass('hl-tip-box tip-box'); + $('#linktt').offset({top: xy.top + offset, left: xy.left}); + $('#linktt').css('visibility','visible'); + } + else{ + $('#linktt').css('visibility','hidden'); + } + } +}; diff --git a/rhodecode/public/js/src/rhodecode/followers.js b/rhodecode/public/js/src/rhodecode/followers.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/followers.js @@ -0,0 +1,74 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var onSuccessFollow = function(target){ + var f = $(target); + var f_cnt = $('#current_followers_count'); + + if(f.hasClass('follow')){ + f.removeClass('follow'); + f.addClass('following'); + f.attr('title', _TM['Stop following this repository']); + $(f).html(_TM['Unfollow']); + if(f_cnt.length){ + var cnt = Number(f_cnt.html())+1; + f_cnt.html(cnt); + } + } + else{ + f.removeClass('following'); + f.addClass('follow'); + f.attr('title', _TM['Start following this repository']); + $(f).html(_TM['Follow']); + if(f_cnt.length){ + var cnt = Number(f_cnt.html())-1; + f_cnt.html(cnt); + } + } +}; + +// TODO:: check if the function is needed. 0 usage found +var toggleFollowingUser = function(target,follows_user_id,token,user_id){ + var args = { + 'follows_user_id': follows_user_id, + 'auth_token': token, + 'csrf_token': CSRF_TOKEN + }; + if(user_id != undefined){ + args.user_id = user_id + } + ajaxPOST(pyroutes.url('toggle_following'), args, function(){ + onSuccessFollow(target); + }); + return false; +}; + +var toggleFollowingRepo = function(target,follows_repo_id,token,user_id){ + var args = { + 'follows_repo_id': follows_repo_id, + 'auth_token': token, + 'csrf_token': CSRF_TOKEN + }; + if(user_id != undefined){ + args.user_id = user_id + } + ajaxPOST(pyroutes.url('toggle_following'), args, function(){ + onSuccessFollow(target); + }); + return false; +}; diff --git a/rhodecode/public/js/src/rhodecode/menus.js b/rhodecode/public/js/src/rhodecode/menus.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/menus.js @@ -0,0 +1,38 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * QUICK REPO MENU, used on repositories to show shortcuts to files, history + * etc. + */ + +var quick_repo_menu = function() { + var hide_quick_repo_menus = function() { + $('.menu_items_container').hide(); + $('.active_quick_repo').removeClass('active_quick_repo'); + }; + $('.quick_repo_menu').hover(function() { + hide_quick_repo_menus(); + if (!$(this).hasClass('active_quick_repo')) { + $('.menu_items_container', this).removeClass("hidden").show(); + $(this).addClass('active_quick_repo'); + } + }, function() { + hide_quick_repo_menus(); + }); +}; \ No newline at end of file diff --git a/rhodecode/public/js/src/rhodecode/notifications.js b/rhodecode/public/js/src/rhodecode/notifications.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/notifications.js @@ -0,0 +1,64 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var _run_callbacks = function(callbacks){ + if (callbacks !== undefined){ + var _l = callbacks.length; + for (var i=0;i<_l;i++){ + var func = callbacks[i]; + if(typeof(func)=='function'){ + try{ + func(); + }catch (err){}; + } + } + } +}; + +var deleteNotification = function(url, notification_id,callbacks){ + var callback = function(o){ + var obj = $("#notification_"+notification_id); + obj.remove(); + _run_callbacks(callbacks); + }; + var postData = {'_method': 'delete', 'csrf_token': CSRF_TOKEN}; + var sUrl = url.replace('__NOTIFICATION_ID__',notification_id); + var request = $.post(sUrl, postData) + .done(callback) + .fail(function(data, textStatus, errorThrown){ + alert("Error while deleting notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); +}; + +var readNotification = function(url, notification_id,callbacks){ + var callback = function(o){ + var obj = $("#notification_"+notification_id); + obj.removeClass('unread'); + var r_button = $('.read-notification',obj)[0]; + r_button.remove(); + + _run_callbacks(callbacks); + }; + var postData = {'_method': 'put', 'csrf_token': CSRF_TOKEN}; + var sUrl = url.replace('__NOTIFICATION_ID__',notification_id); + var request = $.post(sUrl, postData) + .done(callback) + .fail(function(data, textStatus, errorThrown){ + alert("Error while saving notification.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); +}; diff --git a/rhodecode/public/js/src/rhodecode/permissions.js b/rhodecode/public/js/src/rhodecode/permissions.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/permissions.js @@ -0,0 +1,72 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +// creates new permission input box with autocomplete +var addNewPermInput = function(node, permission_type, cur_used_id){ + var _html = '<tr class="new_members" id="add_perm_input_{0}">'+ + '<td class="td-radio"><input type="radio" value="{1}.none" name="perm_new_member_perm_{0}"></td>'+ + '<td class="td-radio"><input type="radio" value="{1}.read" name="perm_new_member_perm_{0}" checked="checked"></td>'+ + '<td class="td-radio"><input type="radio" value="{1}.write" name="perm_new_member_perm_{0}"></td>'+ + '<td class="td-radio"><input type="radio" value="{1}.admin" name="perm_new_member_perm_{0}"></td>'+ + '<td class="ac">'+ + ' <div class="perm_ac" id="perm_ac_{0}">'+ + ' <input class="ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text" autocomplete="off">'+ + ' <input type="hidden" id="perm_new_member_id_{0}" name="perm_new_member_id_{0}" value="">'+ + ' <input type="hidden" id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="">'+ + ' <div id="perm_container_{0}"></div>'+ + ' </div>'+ + '</td>'+ + '<td></td>'+ + '</tr>'; + var _next_id = 'new'+$('.new_members').length; + _html = _html.format(_next_id, permission_type); + $('#add_perm_input').before(_html); + + //autocomplete widget + $('#perm_new_member_name_{0}'.format(_next_id)).autocomplete({ + serviceUrl: pyroutes.url('user_autocomplete_data'), + minChars:2, + maxHeight:400, + width:300, + deferRequestBy: 300, //miliseconds + showNoSuggestionNotice: true, + params: { user_id: cur_used_id, user_groups:true }, + formatResult: autocompleteFormatResult, + lookupFilter: autocompleteFilterResult, + onSelect: function(element, suggestion){ + $('#perm_new_member_id_{0}'.format(_next_id)).val(suggestion['id']); + $('#perm_new_member_type_{0}'.format(_next_id)).val(suggestion['value_type']); + } + }); + +}; + +// marks current input for "revoke" action +var markRevokePermInput = function(node, permission_type){ + var obj_type = $(node).attr('member_type'); + var obj_id = $(node).attr('member'); + var tr = $(node).parent().parent(); + + if(!tr.hasClass('to-delete')){ + tr.css({"text-decoration":"line-through", "opacity": 0.5}); + tr.addClass('to-delete'); + // inject special hidden input that we mark the user for deletion + tr.append($('<input type="hidden" name="perm_del_member_id_{0}" value="{1}"/>'.format(obj_id, obj_id))); + tr.append($('<input type="hidden" name="perm_del_member_type_{0}" value="{1}"/>'.format(obj_id, obj_type))); + } +}; diff --git a/rhodecode/public/js/src/rhodecode/pjax.js b/rhodecode/public/js/src/rhodecode/pjax.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/pjax.js @@ -0,0 +1,29 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * Global Pjax Events + */ + +$(document).on('pjax:send', function(event, xhr, options) { + $(event.target).css('opacity', 0.3); +}); + +$(document).on('pjax:complete', function(event, xhr, options) { + $(event.target).css('opacity', 1); +}); diff --git a/rhodecode/public/js/src/rhodecode/pullrequests.js b/rhodecode/public/js/src/rhodecode/pullrequests.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/pullrequests.js @@ -0,0 +1,206 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * Pull request reviewers + */ +var removeReviewMember = function(reviewer_id, mark_delete){ + var reviewer = $('#reviewer_{0}'.format(reviewer_id)); + + if(typeof(mark_delete) === undefined){ + mark_delete = false; + } + + if(mark_delete === true){ + if (reviewer){ + // mark as to-remove + var obj = $('#reviewer_{0}_name'.format(reviewer_id)); + obj.css("text-decoration", "line-through"); + obj.addClass('to-delete'); + // now delete the input + $('#reviewer_{0}_input'.format(reviewer_id)).remove(); + } + } + else{ + $('#reviewer_{0}'.format(reviewer_id)).remove(); + } +}; + +var addReviewMember = function(id,fname,lname,nname,gravatar_link){ + var members = $('#review_members').get(0); + var tmpl = '<li id="reviewer_{2}">'+ + '<div class="reviewer_status">'+ + '<div class="flag_status not_reviewed pull-left reviewer_member_status"></div>'+ + '</div>'+ + '<img alt="gravatar" class="gravatar" src="{0}"/>'+ + '<span class="reviewer_name user">{1}</span>'+ + '<input type="hidden" value="{2}" name="review_members" />'+ + '<div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">' + + '<i class="icon-remove-sign"></i>'+ + '</div>'+ + '</div>'+ + '</li>' ; + var displayname = "{0} ({1} {2})".format( + nname, escapeHtml(fname), escapeHtml(lname)); + var element = tmpl.format(gravatar_link,displayname,id); + // check if we don't have this ID already in + var ids = []; + var _els = $('#review_members li').toArray(); + for (el in _els){ + ids.push(_els[el].id) + } + if(ids.indexOf('reviewer_'+id) == -1){ + // only add if it's not there + members.innerHTML += element; + } + +}; + +var _updatePullRequest = function(repo_name, pull_request_id, postData) { + var url = pyroutes.url( + 'pullrequest_update', + {"repo_name": repo_name, "pull_request_id": pull_request_id}); + postData.csrf_token = CSRF_TOKEN; + var success = function(o) { + window.location.reload(); + }; + ajaxPOST(url, postData, success); +}; + +var updateReviewers = function(reviewers_ids, repo_name, pull_request_id){ + if (reviewers_ids === undefined){ + var reviewers_ids = []; + var ids = $('#review_members input').toArray(); + for(var i=0; i<ids.length;i++){ + var id = ids[i].value + reviewers_ids.push(id); + } + } + var postData = { + '_method':'put', + 'reviewers_ids': reviewers_ids}; + _updatePullRequest(repo_name, pull_request_id, postData); +}; + +/** + * PULL REQUEST reject & close + */ +var closePullRequest = function(repo_name, pull_request_id) { + var postData = { + '_method': 'put', + 'close_pull_request': true}; + _updatePullRequest(repo_name, pull_request_id, postData); +}; + +/** + * PULL REQUEST update commits + */ +var updateCommits = function(repo_name, pull_request_id) { + var postData = { + '_method': 'put', + 'update_commits': true}; + _updatePullRequest(repo_name, pull_request_id, postData); +}; + + +/** + * PULL REQUEST edit info + */ +var editPullRequest = function(repo_name, pull_request_id, title, description) { + var url = pyroutes.url( + 'pullrequest_update', + {"repo_name": repo_name, "pull_request_id": pull_request_id}); + + var postData = { + '_method': 'put', + 'title': title, + 'description': description, + 'edit_pull_request': true, + 'csrf_token': CSRF_TOKEN + }; + var success = function(o) { + window.location.reload(); + }; + ajaxPOST(url, postData, success); +}; + +var initPullRequestsCodeMirror = function (textAreaId) { + var ta = $(textAreaId).get(0); + var initialHeight = '100px'; + + // default options + var codeMirrorOptions = { + mode: "text", + lineNumbers: false, + indentUnit: 4, + theme: 'rc-input' + }; + + var codeMirrorInstance = CodeMirror.fromTextArea(ta, codeMirrorOptions); + // marker for manually set description + codeMirrorInstance._userDefinedDesc = false; + codeMirrorInstance.setSize(null, initialHeight); + codeMirrorInstance.on("change", function(instance, changeObj) { + var height = initialHeight; + var lines = instance.lineCount(); + if (lines > 6 && lines < 20) { + height = "auto" + } + else if (lines >= 20) { + height = 20 * 15; + } + instance.setSize(null, height); + + // detect if the change was trigger by auto desc, or user input + changeOrigin = changeObj.origin; + + if (changeOrigin === "setValue") { + cmLog.debug('Change triggered by setValue'); + } + else { + cmLog.debug('user triggered change !'); + // set special marker to indicate user has created an input. + instance._userDefinedDesc = true; + } + + }); + + return codeMirrorInstance +}; + +/** + * Reviewer autocomplete + */ +var ReviewerAutoComplete = function(input_id) { + $('#'+input_id).autocomplete({ + serviceUrl: pyroutes.url('user_autocomplete_data'), + minChars:2, + maxHeight:400, + deferRequestBy: 300, //miliseconds + showNoSuggestionNotice: true, + tabDisabled: true, + autoSelectFirst: true, + formatResult: autocompleteFormatResult, + lookupFilter: autocompleteFilterResult, + onSelect: function(suggestion, data){ + addReviewMember(data.id, data.first_name, data.last_name, + data.username, data.icon_link); + $('#'+input_id).val(''); + } + }); +}; diff --git a/rhodecode/public/js/src/rhodecode/pyroutes.js b/rhodecode/public/js/src/rhodecode/pyroutes.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/pyroutes.js @@ -0,0 +1,45 @@ +/* This file is automatically generated. DO NOT change it manually. + * If this file needs to be modified, edit + * rhodecode/utils/file_generation/js_routes_data.py + * and run the script invoke -r scripts/ generate.js-routes . + */ +function registerRCRoutes() { + // routes registration + pyroutes.register('home', '/', []); + pyroutes.register('new_gist', '/_admin/gists/new', []); + pyroutes.register('gists', '/_admin/gists', []); + pyroutes.register('new_repo', '/_admin/create_repository', []); + pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']); + pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']); + pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); + pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); + pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']); + pyroutes.register('user_autocomplete_data', '/_users', []); + pyroutes.register('toggle_following', '/_admin/toggle_following', []); + pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); + pyroutes.register('changeset_info', '/changeset_info/%(repo_name)s/%(revision)s', ['repo_name', 'revision']); + pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); + pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']); + pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']); + pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']); + pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); + pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); + pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); + pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('files_metadata_list_home', '/%(repo_name)s/metadata_list/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']); + pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']); + pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']); + pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']); + pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']); + pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']); + pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']); + pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']); + pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']); +} + +registerRCRoutes(); \ No newline at end of file diff --git a/rhodecode/public/js/src/rhodecode/select2_widgets.js b/rhodecode/public/js/src/rhodecode/select2_widgets.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/select2_widgets.js @@ -0,0 +1,84 @@ +/* COMMON */ +var select2RefFilterResults = function(queryTerm, data) { + var filteredData = {results: []}; + //filter results + $.each(data.results, function() { + var section = this.text; + var children = []; + $.each(this.children, function() { + if (queryTerm.length === 0 || this.text.toUpperCase().indexOf(queryTerm.toUpperCase()) >= 0) { + children.push(this); + } + }); + + if (children.length > 0) { + filteredData.results.push({ + 'text': section, + 'children': children + }); + } + }); + + return filteredData +}; + + +var select2RefBaseSwitcher = function(targetElement, loadUrl, initialData){ + var formatResult = function(result, container, query) { + return formatSelect2SelectionRefs(result); + }; + + var formatSelection = function(data, container) { + return formatSelect2SelectionRefs(data); + }; + + $(targetElement).select2({ + cachedDataSource: {}, + dropdownAutoWidth: true, + formatResult: formatResult, + width: "resolve", + containerCssClass: "drop-menu", + dropdownCssClass: "drop-menu-dropdown", + query: function(query) { + var self = this; + var cacheKey = '__ALLREFS__'; + var cachedData = self.cachedDataSource[cacheKey]; + if (cachedData) { + var data = select2RefFilterResults(query.term, cachedData); + query.callback({results: data.results}); + } else { + $.ajax({ + url: loadUrl, + data: {}, + dataType: 'json', + type: 'GET', + success: function(data) { + self.cachedDataSource[cacheKey] = data; + query.callback({results: data.results}); + } + }); + } + }, + + initSelection: function(element, callback) { + callback(initialData); + }, + + formatSelection: formatSelection + }); + +}; + +/* WIDGETS */ +var select2RefSwitcher = function(targetElement, initialData) { + var loadUrl = pyroutes.url('repo_refs_data', + {'repo_name': templateContext.repo_name}); + select2RefBaseSwitcher(targetElement, loadUrl, initialData); +}; + +var select2FileHistorySwitcher = function(targetElement, initialData, state) { + var loadUrl = pyroutes.url('files_history_home', + {'repo_name': templateContext.repo_name, 'revision': state.rev, + 'f_path': state.f_path}); + select2RefBaseSwitcher(targetElement, loadUrl, initialData); +}; diff --git a/rhodecode/public/js/src/rhodecode/settings.js b/rhodecode/public/js/src/rhodecode/settings.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/settings.js @@ -0,0 +1,28 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var addNewPatternInput = function(pattern, description, url, prefix){ + var _html = $('#add-row-tmpl tbody').html(); + var _next_id = $('.new_pattern').length; + _html = _html.replace(/##UUID##/g, _next_id); + _html = _html.replace(/##DESCRIPTION##/g, description || ''); + _html = _html.replace(/##PATTERN##/g, pattern || ''); + _html = _html.replace(/##URL##/g, url || ''); + _html = _html.replace(/##PREFIX##/g, prefix || ''); + $('#last-row').before(_html); +}; diff --git a/rhodecode/public/js/src/rhodecode/tooltips.js b/rhodecode/public/js/src/rhodecode/tooltips.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/tooltips.js @@ -0,0 +1,126 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * TOOLTIP IMPL. + */ + +var TTIP = {}; + +TTIP.main = { + offset: [15,15], + maxWidth: 600, + + set_listeners: function(tt){ + $(tt).mouseover(tt, yt.show_tip); + $(tt).mousemove(tt, yt.move_tip); + $(tt).mouseout(tt, yt.close_tip); + }, + + init: function(){ + $('#tip-box').remove(); + yt.tipBox = document.createElement('div'); + document.body.appendChild(yt.tipBox); + yt.tipBox.id = 'tip-box'; + + $(yt.tipBox).hide(); + $(yt.tipBox).css('position', 'absolute'); + if(yt.maxWidth !== null){ + $(yt.tipBox).css('max-width', yt.maxWidth+'px'); + } + + var tooltips = $('.tooltip'); + var ttLen = tooltips.length; + + for(i=0;i<ttLen;i++){ + yt.set_listeners(tooltips[i]); + } + }, + + show_tip: function(e, el){ + e.stopPropagation(); + e.preventDefault(); + var el = e.data || el; + if(el.tagName.toLowerCase() === 'img'){ + yt.tipText = el.alt ? el.alt : ''; + } else { + yt.tipText = el.title ? el.title : ''; + } + + if(yt.tipText !== ''){ + // save org title + $(el).attr('tt_title', yt.tipText); + // reset title to not show org tooltips + $(el).attr('title', ''); + + yt.tipBox.innerHTML = yt.tipText; + $(yt.tipBox).show(); + } + }, + + move_tip: function(e, el){ + e.stopPropagation(); + e.preventDefault(); + var el = e.data || el; + var movePos = [e.pageX, e.pageY]; + $(yt.tipBox).css('top', (movePos[1] + yt.offset[1]) + 'px') + $(yt.tipBox).css('left', (movePos[0] + yt.offset[0]) + 'px') + }, + + close_tip: function(e, el){ + e.stopPropagation(); + e.preventDefault(); + var el = e.data || el; + $(yt.tipBox).hide(); + $(el).attr('title', $(el).attr('tt_title')); + $('#tip-box').hide(); + } +}; + +/** + * tooltip activate + */ +var tooltip_activate = function(){ + yt = TTIP.main; + $(document).ready(yt.init); +}; + +/** + * show changeset tooltip + */ +var show_changeset_tooltip = function(){ + $('.lazy-cs').mouseover(function(e) { + var target = e.currentTarget; + var rid = $(target).attr('raw_id'); + var repo_name = $(target).attr('repo_name'); + var ttid = 'tt-'+rid; + var success = function(o){ + $(target).addClass('tooltip') + $(target).attr('title', o['message']); + TTIP.main.show_tip(e, target); + } + if(rid && !$(target).hasClass('tooltip')){ + $(target).attr('id', ttid); + $(target).attr('title', _TM['loading ...']); + TTIP.main.set_listeners(target); + TTIP.main.show_tip(e, target); + var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid}); + ajaxGET(url, success); + } + }); +}; diff --git a/rhodecode/public/js/src/rhodecode/users.js b/rhodecode/public/js/src/rhodecode/users.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/users.js @@ -0,0 +1,49 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var generatePassword = function(length) { + if (length === undefined){ + length = 8 + } + + var charset = "abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + var gen_pass = ""; + + for (var i = 0, n = charset.length; i < length; ++i) { + gen_pass += charset.charAt(Math.floor(Math.random() * n)); + } + return gen_pass; +}; + +/** + * User autocomplete + */ +var UsersAutoComplete = function(input_id, user_id) { + $('#'+input_id).autocomplete({ + serviceUrl: pyroutes.url('user_autocomplete_data'), + minChars:2, + maxHeight:400, + deferRequestBy: 300, //miliseconds + showNoSuggestionNotice: true, + tabDisabled: true, + autoSelectFirst: true, + params: { user_id: user_id }, + formatResult: autocompleteFormatResult, + lookupFilter: autocompleteFilterResult + }); +}; diff --git a/rhodecode/public/js/src/rhodecode/utils/ajax.js b/rhodecode/public/js/src/rhodecode/utils/ajax.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/ajax.js @@ -0,0 +1,59 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** +* turns objects into GET query string +*/ +var toQueryString = function(o) { + if(typeof o !== 'object') { + return false; + } + var _p, _qs = []; + for(_p in o) { + _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p])); + } + return _qs.join('&'); +}; + +/** +* ajax call wrappers +*/ +var ajaxGET = function(url, success) { + var sUrl = url; + var request = $.ajax({url: sUrl, headers: {'X-PARTIAL-XHR': true}}) + .done(function(data){ + success(data); + }) + .fail(function(data, textStatus, xhr){ + alert("error processing request: " + textStatus); + }); + return request; +}; +var ajaxPOST = function(url,postData,success) { + var sUrl = url; + var postData = toQueryString(postData); + var request = $.ajax({type: 'POST', data: postData, url: sUrl, + headers: {'X-PARTIAL-XHR': true}}) + .done(function(data){ + success(data); + }) + .fail(function(data, textStatus, xhr){ + alert("error processing request: " + textStatus); + }); + return request; +}; diff --git a/rhodecode/public/js/src/rhodecode/utils/array.js b/rhodecode/public/js/src/rhodecode/utils/array.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/array.js @@ -0,0 +1,80 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + "use strict"; + if (this === null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 0) { + n = Number(arguments[1]); + if (n !== n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n !== 0 && n !== Infinity && n !== -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; +} + +if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp*/) { + 'use strict'; + + if (this === null) { + throw new TypeError(); + } + + var t = Object(this), + len = t.length >>> 0, + res, thisp, i, val; + if (typeof fun !== 'function') { + throw new TypeError(); + } + + res = []; + thisp = arguments[1]; + for (i = 0; i < len; i++) { + if (i in t) { + val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) { + res.push(val); + } + } + } + + return res; + }; +} \ No newline at end of file diff --git a/rhodecode/public/js/src/rhodecode/utils/autocomplete.js b/rhodecode/public/js/src/rhodecode/utils/autocomplete.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/autocomplete.js @@ -0,0 +1,42 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * autocomplete formatter that uses gravatar + * */ +var autocompleteFormatResult = function(data, value, org_formatter) { + var value_display = data.value_display; + var escapeRegExChars = function (value) { + return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }; + var pattern = '(' + escapeRegExChars(value) + ')'; + value_display = value_display.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); + var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>'; + if (data.icon_link === "") { + tmpl = '<div class="ac-container-wrap">{0}</div>'; + return tmpl.format(value_display); + } + return tmpl.format(data.icon_link, value_display); +}; + +/** + * autocomplete filter that uses display value to filter + */ +var autocompleteFilterResult = function (suggestion, originalQuery, queryLowerCase) { + return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1; +}; diff --git a/rhodecode/public/js/src/rhodecode/utils/colorgenerator.js b/rhodecode/public/js/src/rhodecode/utils/colorgenerator.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/colorgenerator.js @@ -0,0 +1,83 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** +* SmartColorGenerator +* +*usage:: +* var CG = new ColorGenerator(); +* var col = CG.getColor(key); //returns array of RGB +* 'rgb({0})'.format(col.join(',') +* +* @returns {ColorGenerator} +*/ + +// TODO: no usages found. Maybe it's time to remove it +var ColorGenerator = function(){ + this.GOLDEN_RATIO = 0.618033988749895; + this.CURRENT_RATIO = 0.22717784590367374; // this can be random + this.HSV_1 = 0.75;// saturation + this.HSV_2 = 0.95; + this.color; + this.cacheColorMap = {}; +}; + +ColorGenerator.prototype = { + getColor:function(key){ + if(this.cacheColorMap[key] !== undefined){ + return this.cacheColorMap[key]; + } + else{ + this.cacheColorMap[key] = this.generateColor(); + return this.cacheColorMap[key]; + } + }, + _hsvToRgb:function(h,s,v){ + if (s === 0.0) + return [v, v, v]; + i = parseInt(h * 6.0); + f = (h * 6.0) - i; + p = v * (1.0 - s); + q = v * (1.0 - s * f); + t = v * (1.0 - s * (1.0 - f)); + i = i % 6; + if (i === 0) + return [v, t, p]; + if (i === 1) + return [q, v, p]; + if (i === 2) + return [p, v, t]; + if (i === 3) + return [p, q, v]; + if (i === 4) + return [t, p, v]; + if (i === 5) + return [v, p, q]; + }, + generateColor:function(){ + this.CURRENT_RATIO = this.CURRENT_RATIO+this.GOLDEN_RATIO; + this.CURRENT_RATIO = this.CURRENT_RATIO %= 1; + HSV_tuple = [this.CURRENT_RATIO, this.HSV_1, this.HSV_2]; + RGB_tuple = this._hsvToRgb(HSV_tuple[0],HSV_tuple[1],HSV_tuple[2]); + function toRgb(v){ + return ""+parseInt(v*256); + } + return [toRgb(RGB_tuple[0]),toRgb(RGB_tuple[1]),toRgb(RGB_tuple[2])]; + + } +}; diff --git a/rhodecode/public/js/src/rhodecode/utils/ie.js b/rhodecode/public/js/src/rhodecode/utils/ie.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/ie.js @@ -0,0 +1,65 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * detect IE + * returns version of IE or false, if browser is not Internet Explorer + */ +function detectIE() { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // IE 12 => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + + +// TODO: no usages found. Maybe it's time to remove it +// IE doesn't support previousElementSibling +var prevElementSibling = function( el ) { + if( el.previousElementSibling ) { + return el.previousElementSibling; + } else { + while( el === el.previousSibling ) { + if( el.nodeType === 1 ) return el; + } + } +}; + +// TODO: no usages found. Maybe it's time to remove it +var firstElementChild = function(el) { + return (el.firstElementChild||el.firstChild); +}; \ No newline at end of file diff --git a/rhodecode/public/js/src/rhodecode/utils/os.js b/rhodecode/public/js/src/rhodecode/utils/os.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/os.js @@ -0,0 +1,31 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +var OSType = "unknown"; +if (navigator.appVersion.indexOf("Win") !== -1) { + OSType = "win"; +} +else if (navigator.appVersion.indexOf("Mac") !== -1) { + OSType = "mac"; +} +else if (navigator.appVersion.indexOf("X11") !== -1) { + OSType = "unix"; +} +else if (navigator.appVersion.indexOf("Linux") !== -1) { + OSType = "unix"; +} diff --git a/rhodecode/public/js/src/rhodecode/utils/pyroutes.js b/rhodecode/public/js/src/rhodecode/utils/pyroutes.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/pyroutes.js @@ -0,0 +1,227 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** +* Object holding the registered pyroutes. +* Routes will be registered with the generated script +* rhodecode/public/js/rhodecode/base/pyroutes.js +*/ +var PROUTES_MAP = {}; + +/** +* PyRoutesJS +* +* Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id> +*/ +var pyroutes = (function() { + // access global map defined in special file pyroutes + var matchlist = PROUTES_MAP; + var sprintf = (function() { + function get_type(variable) { + return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); + } + function str_repeat(input, multiplier) { + for (var output = []; multiplier > 0; output[--multiplier] = input) { + /* do nothing */ + } + return output.join(''); + } + var str_format = function() { + if (!str_format.cache.hasOwnProperty(arguments[0])) { + str_format.cache[arguments[0]] = str_format.parse(arguments[0]); + } + return str_format.format.call(null, str_format.cache[arguments[0]], arguments); + }; + + str_format.format = function(parse_tree, argv) { + var cursor = 1, + tree_length = parse_tree.length, + node_type = '', + arg, + output = [], + i, k, + match, + pad, + pad_character, + pad_length; + for (i = 0; i < tree_length; i++) { + node_type = get_type(parse_tree[i]); + if (node_type === 'string') { + output.push(parse_tree[i]); + } + else if (node_type === 'array') { + match = parse_tree[i]; // convenience purposes only + if (match[2]) { // keyword argument + arg = argv[cursor]; + for (k = 0; k < match[2].length; k++) { + if (!arg.hasOwnProperty(match[2][k])) { + throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); + } + arg = arg[match[2][k]]; + } + } + else if (match[1]) { // positional argument (explicit) + arg = argv[match[1]]; + } + else { // positional argument (implicit) + arg = argv[cursor++]; + } + + if (/[^s]/.test(match[8]) && (get_type(arg) !== 'number')) { + throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); + } + switch (match[8]) { + case 'b': arg = arg.toString(2); break; + case 'c': arg = String.fromCharCode(arg); break; + case 'd': arg = parseInt(arg, 10); break; + case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; + case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; + case 'o': arg = arg.toString(8); break; + case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); + break; + case 'u': arg = Math.abs(arg); break; + case 'x': arg = arg.toString(16); break; + case 'X': arg = arg.toString(16).toUpperCase(); break; + } + arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); + pad_character = + match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' '; + pad_length = match[6] - String(arg).length; + pad = match[6] ? str_repeat(pad_character, pad_length) : ''; + output.push(match[5] ? arg + pad : pad + arg); + } + } + return output.join(''); + }; + + str_format.cache = {}; + + str_format.parse = function(fmt) { + var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; + while (_fmt) { + if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { + parse_tree.push(match[0]); + } + else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { + parse_tree.push('%'); + } + else if ( + (match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { + if (match[2]) { + arg_names |= 1; + var field_list = [], replacement_field = match[2], field_match = []; + if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { + if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else { + throw('[sprintf] huh?'); + } + } + } + else { + throw('[sprintf] huh?'); + } + match[2] = field_list; + } + else { + arg_names |= 2; + } + if (arg_names === 3) { + throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); + } + parse_tree.push(match); + } + else { + throw('[sprintf] huh?'); + } + _fmt = _fmt.substring(match[0].length); + } + return parse_tree; + }; + return str_format; + })(); + + var vsprintf = function(fmt, argv) { + argv.unshift(fmt); + return sprintf.apply(null, argv); + }; + return { + 'url': function(route_name, params) { + var result = route_name; + if (typeof(params) !== 'object'){ + params = {}; + } + if (matchlist.hasOwnProperty(route_name)) { + var route = matchlist[route_name]; + // param substitution + for(var i=0; i < route[1].length; i++) { + var param_name = route[1][i]; + if (!params.hasOwnProperty(param_name)) + throw new Error( + 'parameter '+ + param_name + + ' is missing in route"' + + route_name + '" generation'); + } + result = sprintf(route[0], params); + + var ret = []; + // extra params => GET + for (var param in params){ + if (route[1].indexOf(param) === -1){ + ret.push(encodeURIComponent(param) + "=" + + encodeURIComponent(params[param])); + } + } + var _parts = ret.join("&"); + if(_parts){ + result = result +'?'+ _parts; + } + if(APPLICATION_URL) { + result = APPLICATION_URL + result; + } + } + + return result; + }, + 'register': function(route_name, route_tmpl, req_params) { + if (typeof(req_params) !== 'object') { + req_params = []; + } + // fix escape + route_tmpl = unescape(route_tmpl); + keys = []; + for(var i=0; i < req_params.length; i++) { + keys.push(req_params[i]); + } + matchlist[route_name] = [ + route_tmpl, + keys + ]; + }, + '_routes': function(){ + return matchlist; + } + }; +})(); diff --git a/rhodecode/public/js/src/rhodecode/utils/string.js b/rhodecode/public/js/src/rhodecode/utils/string.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/utils/string.js @@ -0,0 +1,151 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * INJECT .format function into String + * Usage: "My name is {0} {1}".format("Johny","Bravo") + * Return "My name is Johny Bravo" + * Inspired by https://gist.github.com/1049426 + */ +String.prototype.format = function() { + + function format() { + var str = this; + var len = arguments.length+1; + var safe = undefined; + var arg = undefined; + + // For each {0} {1} {n...} replace with the argument in that position. If + // the argument is an object or an array it will be stringified to JSON. + for (var i=0; i < len; arg = arguments[i++]) { + safe = typeof arg === 'object' ? JSON.stringify(arg) : arg; + str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe); + } + return str; + } + + // Save a reference of what may already exist under the property native. + // Allows for doing something like: if("".format.native) { /* use native */ } + format.native = String.prototype.format; + + // Replace the prototype property + return format; +}(); + +String.prototype.strip = function(char) { + if(char === undefined){ + char = '\\s'; + } + return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), ''); +}; + +String.prototype.lstrip = function(char) { + if(char === undefined){ + char = '\\s'; + } + return this.replace(new RegExp('^'+char+'+'),''); +}; + +String.prototype.rstrip = function(char) { + if(char === undefined){ + char = '\\s'; + } + return this.replace(new RegExp(''+char+'+$'),''); +}; + +String.prototype.capitalizeFirstLetter = function() { + return this.charAt(0).toUpperCase() + this.slice(1); +}; + + +/** + * Escape html characters in string + */ +var entityMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''', + "/": '/' +}; + +function escapeHtml(string) { + return String(string).replace(/[&<>"'\/]/g, function (s) { + return entityMap[s]; + }); +} + +/** encode/decode html special chars**/ +var htmlEnDeCode = (function() { + var charToEntityRegex, + entityToCharRegex, + charToEntity, + entityToChar; + + function resetCharacterEntities() { + charToEntity = {}; + entityToChar = {}; + // add the default set + addCharacterEntities({ + '&' : '&', + '>' : '>', + '<' : '<', + '"' : '"', + ''' : "'" + }); + } + + function addCharacterEntities(newEntities) { + var charKeys = [], + entityKeys = [], + key, echar; + for (key in newEntities) { + echar = newEntities[key]; + entityToChar[key] = echar; + charToEntity[echar] = key; + charKeys.push(echar); + entityKeys.push(key); + } + charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g'); + entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g'); + } + + function htmlEncode(value){ + var htmlEncodeReplaceFn = function(match, capture) { + return charToEntity[capture]; + }; + + return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn); + } + + function htmlDecode(value) { + var htmlDecodeReplaceFn = function(match, capture) { + return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10)); + }; + + return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn); + } + + resetCharacterEntities(); + + return { + htmlEncode: htmlEncode, + htmlDecode: htmlDecode + }; +})(); diff --git a/rhodecode/public/js/src/rhodecode/widgets/multiselect.js b/rhodecode/public/js/src/rhodecode/widgets/multiselect.js new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/src/rhodecode/widgets/multiselect.js @@ -0,0 +1,132 @@ +// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # 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 Affero General Public License +// # along with this program. If not, see <http://www.gnu.org/licenses/>. +// # +// # This program is dual-licensed. If you wish to learn more about the +// # RhodeCode Enterprise Edition, including its added features, Support services, +// # and proprietary license terms, please see https://rhodecode.com/licenses/ + +/** + * Multi select widget + */ +var MultiSelectWidget = function(selected_id, available_id, form_id){ + // definition of containers ID's + var selected_container = selected_id; + var available_container = available_id; + // temp container for selected storage. + var cache = []; + var av_cache = []; + var c = $('#'+selected_container).get(0); + var ac = $('#'+available_container).get(0); + // get only selected options for further fullfilment + for (var i = 0; node = c.options[i]; i++){ + if (node.selected){ + // push selected to my temp storage left overs :) + cache.push(node); + } + } + // get all available options to cache + for (i = 0; node = ac.options[i]; i++){ + // push selected to my temp storage left overs :) + av_cache.push(node); + } + // fill available only with those not in chosen + ac.options.length = 0; + tmp_cache = []; + + for (i = 0; node = av_cache[i]; i++){ + var add = true; + for (var i2 = 0; node_2 = cache[i2]; i2++){ + if (node.value === node_2.value){ + add=false; + break; + } + } + if(add){ + tmp_cache.push(new Option(node.text, node.value, false, false)); + } + } + for (i = 0; node = tmp_cache[i]; i++){ + ac.options[i] = node; + } + function prompts_action_callback(e){ + var chosen = $('#'+selected_container).get(0); + var available = $('#'+available_container).get(0); + // get checked and unchecked options from field + function get_checked(from_field){ + // temp container for storage. + var sel_cache = []; + var oth_cache = []; + + for (i = 0; node = from_field.options[i]; i++){ + if(node.selected){ + // push selected fields :) + sel_cache.push(node); + } + else { + oth_cache.push(node); + } + } + return [sel_cache,oth_cache]; + } + // fill the field with given options + function fill_with(field,options){ + // clear firtst + field.options.length=0; + for (var i = 0; node = options[i]; i++){ + field.options[i] = new Option(node.text, node.value, false, false); + } + } + // adds to current field + function add_to(field,options){ + for (i = 0; node = options[i]; i++){ + field.appendChild(new Option(node.text, node.value, false, false)); + } + } + // add action + if (this.id ==='add_element'){ + var c = get_checked(available); + add_to(chosen,c[0]); + fill_with(available,c[1]); + } + // remove action + if (this.id ==='remove_element'){ + c = get_checked(chosen); + add_to(available,c[0]); + fill_with(chosen,c[1]); + } + // add all elements + if(this.id === 'add_all_elements'){ + for (i=0; node = available.options[i]; i++){ + chosen.appendChild(new Option(node.text, node.value, false, false)); + } + available.options.length = 0; + } + // remove all elements + if (this.id === 'remove_all_elements'){ + for (i=0; node = chosen.options[i]; i++){ + available.appendChild(new Option(node.text, node.value, false, false)); + } + chosen.options.length = 0; + } + } + $('#add_element, #remove_element, #add_all_elements, #remove_all_elements').click(prompts_action_callback); + if (form_id !== undefined) { + $('#'+form_id).submit(function(){ + var chosen = $('#'+selected_container).get(0); + for (i = 0; i < chosen.options.length; i++) { + chosen.options[i].selected = 'selected'; + } + }); + } +}; diff --git a/rhodecode/public/js/src/select2/select2.css b/rhodecode/public/js/src/select2/select2.css new file mode 100755 --- /dev/null +++ b/rhodecode/public/js/src/select2/select2.css @@ -0,0 +1,704 @@ +/* +Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #aaa; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 4px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(to top, #eee 0%, #fff 50%); +} + +html[dir="rtl"] .select2-container .select2-choice { + padding: 0 8px 0 0; +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #aaa; + + border-radius: 0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(to bottom, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; + float: none; + width: auto; +} + +html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { + margin-left: 26px; + margin-right: 0; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('../../images/select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #aaa; + border-top: 0; + + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-active { + border: 1px solid #5897fb; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid #5897fb; +} + +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #aaa; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(to top, #ccc 0%, #eee 60%); +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow { + left: 0; + right: auto; + + border-left: none; + border-right: 1px solid #aaa; + border-radius: 4px 0 0 4px; +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('../../images/select2.png') no-repeat 0 1px; +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow b { + background-position: 2px 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #aaa; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('../../images/select2.png') no-repeat 100% -22px; + background: url('../../images/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../../images/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +html[dir="rtl"] .select2-search input { + padding: 4px 5px 4px 20px; + + background: #fff url('../../images/select2.png') no-repeat -37px -22px; + background: url('../../images/select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../../images/select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff url('../../images/select2-spinner.gif') no-repeat 100%; + background: url('../../images/select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../../images/select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../../images/select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow { + border-right: none; +} + +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -16px 1px; +} + +.select2-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +html[dir="rtl"] .select2-results { + padding: 0 4px 0 0; + margin: 4px 0 4px 4px; +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results-dept-1 .select2-result-label { padding-left: 20px } +.select2-results-dept-2 .select2-result-label { padding-left: 40px } +.select2-results-dept-3 .select2-result-label { padding-left: 60px } +.select2-results-dept-4 .select2-result-label { padding-left: 80px } +.select2-results-dept-5 .select2-result-label { padding-left: 100px } +.select2-results-dept-6 .select2-result-label { padding-left: 110px } +.select2-results-dept-7 .select2-result-label { padding-left: 120px } + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-ajax-error, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; + padding-left: 5px; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 url('../../images/select2-spinner.gif') no-repeat 100%; +} + +.select2-results .select2-ajax-error { + background: rgba(255, 50, 50, .2); +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0 5px 0 0; + position: relative; + + border: 1px solid #aaa; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(to bottom, #eee 1%, #fff 15%); +} + +html[dir="rtl"] .select2-container-multi .select2-choices { + padding: 0 0 0 5px; +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +html[dir="rtl"] .select2-container-multi .select2-choices li +{ + float: right; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff url('../../images/select2-spinner.gif') no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #aaaaaa; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice +{ + margin: 3px 5px 3px 0; + padding: 3px 18px 3px 5px; +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('../../images/select2.png') right top no-repeat; +} +html[dir="rtl"] .select2-search-choice-close { + right: auto; + left: 3px; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +html[dir="rtl"] .select2-container-multi .select2-search-choice-close { + left: auto; + right: 2px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} + +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) { + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b { + background-image: url('../../images/select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/rhodecode/public/js/src/select2/select2.js b/rhodecode/public/js/src/select2/select2.js new file mode 100755 --- /dev/null +++ b/rhodecode/public/js/src/select2/select2.js @@ -0,0 +1,3729 @@ +/* +Copyright 2012 Igor Vaynberg + +Version: 3.5.4 Timestamp: Sun Aug 30 13:30:32 EDT 2015 + +This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU +General Public License version 2 (the "GPL License"). You may choose either license to govern your +use of this software only upon the condition that you accept all of the terms of either the Apache +License or the GPL License. + +You may obtain a copy of the Apache License and the GPL License at: + + http://www.apache.org/licenses/LICENSE-2.0 + http://www.gnu.org/licenses/gpl-2.0.html + +Unless required by applicable law or agreed to in writing, software distributed under the +Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for +the specific language governing permissions and limitations under the Apache License and the GPL License. +*/ +(function ($) { + if(typeof $.fn.each2 == "undefined") { + $.extend($.fn, { + /* + * 4-10 times faster .each replacement + * use it carefully, as it overrides jQuery context of element on each iteration + */ + each2 : function (c) { + var j = $([0]), i = -1, l = this.length; + while ( + ++i < l + && (j.context = j[0] = this[i]) + && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object + ); + return this; + } + }); + } +})(jQuery); + +(function ($, undefined) { + "use strict"; + /*global document, window, jQuery, console */ + + if (window.Select2 !== undefined) { + return; + } + + var AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, + lastMousePosition={x:0,y:0}, $document, scrollBarDimensions, + + KEY = { + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + SHIFT: 16, + CTRL: 17, + ALT: 18, + PAGE_UP: 33, + PAGE_DOWN: 34, + HOME: 36, + END: 35, + BACKSPACE: 8, + DELETE: 46, + isArrow: function (k) { + k = k.which ? k.which : k; + switch (k) { + case KEY.LEFT: + case KEY.RIGHT: + case KEY.UP: + case KEY.DOWN: + return true; + } + return false; + }, + isControl: function (e) { + var k = e.which; + switch (k) { + case KEY.SHIFT: + case KEY.CTRL: + case KEY.ALT: + return true; + } + + if (e.metaKey) return true; + + return false; + }, + isFunctionKey: function (k) { + k = k.which ? k.which : k; + return k >= 112 && k <= 123; + } + }, + MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>", + + DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038A":"\u0399","\u03AA":"\u0399","\u038C":"\u039F","\u038E":"\u03A5","\u03AB":"\u03A5","\u038F":"\u03A9","\u03AC":"\u03B1","\u03AD":"\u03B5","\u03AE":"\u03B7","\u03AF":"\u03B9","\u03CA":"\u03B9","\u0390":"\u03B9","\u03CC":"\u03BF","\u03CD":"\u03C5","\u03CB":"\u03C5","\u03B0":"\u03C5","\u03C9":"\u03C9","\u03C2":"\u03C3"}; + + $document = $(document); + + nextUid=(function() { var counter=1; return function() { return counter++; }; }()); + + + function reinsertElement(element) { + var placeholder = $(document.createTextNode('')); + + element.before(placeholder); + placeholder.before(element); + placeholder.remove(); + } + + function stripDiacritics(str) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return str.replace(/[^\u0000-\u007E]/g, match); + } + + function indexOf(value, array) { + var i = 0, l = array.length; + for (; i < l; i = i + 1) { + if (equal(value, array[i])) return i; + } + return -1; + } + + function measureScrollbar () { + var $template = $( MEASURE_SCROLLBAR_TEMPLATE ); + $template.appendTo(document.body); + + var dim = { + width: $template.width() - $template[0].clientWidth, + height: $template.height() - $template[0].clientHeight + }; + $template.remove(); + + return dim; + } + + /** + * Compares equality of a and b + * @param a + * @param b + */ + function equal(a, b) { + if (a === b) return true; + if (a === undefined || b === undefined) return false; + if (a === null || b === null) return false; + // Check whether 'a' or 'b' is a string (primitive or object). + // The concatenation of an empty string (+'') converts its argument to a string's primitive. + if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object + if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object + return false; + } + + /** + * Splits the string into an array of values, transforming each value. An empty array is returned for nulls or empty + * strings + * @param string + * @param separator + */ + function splitVal(string, separator, transform) { + var val, i, l; + if (string === null || string.length < 1) return []; + val = string.split(separator); + for (i = 0, l = val.length; i < l; i = i + 1) val[i] = transform(val[i]); + return val; + } + + function getSideBorderPadding(element) { + return element.outerWidth(false) - element.width(); + } + + function installKeyUpChangeEvent(element) { + var key="keyup-change-value"; + element.on("keydown", function () { + if ($.data(element, key) === undefined) { + $.data(element, key, element.val()); + } + }); + element.on("keyup", function () { + var val= $.data(element, key); + if (val !== undefined && element.val() !== val) { + $.removeData(element, key); + element.trigger("keyup-change"); + } + }); + } + + + /** + * filters mouse events so an event is fired only if the mouse moved. + * + * filters out mouse events that occur when mouse is stationary but + * the elements under the pointer are scrolled. + */ + function installFilteredMouseMove(element) { + element.on("mousemove", function (e) { + var lastpos = lastMousePosition; + if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { + $(e.target).trigger("mousemove-filtered", e); + } + }); + } + + /** + * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made + * within the last quietMillis milliseconds. + * + * @param quietMillis number of milliseconds to wait before invoking fn + * @param fn function to be debounced + * @param ctx object to be used as this reference within fn + * @return debounced version of fn + */ + function debounce(quietMillis, fn, ctx) { + ctx = ctx || undefined; + var timeout; + return function () { + var args = arguments; + window.clearTimeout(timeout); + timeout = window.setTimeout(function() { + fn.apply(ctx, args); + }, quietMillis); + }; + } + + function installDebouncedScroll(threshold, element) { + var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); + element.on("scroll", function (e) { + if (indexOf(e.target, element.get()) >= 0) notify(e); + }); + } + + function focus($el) { + if ($el[0] === document.activeElement) return; + + /* set the focus in a 0 timeout - that way the focus is set after the processing + of the current event has finished - which seems like the only reliable way + to set focus */ + window.setTimeout(function() { + var el=$el[0], pos=$el.val().length, range; + + $el.focus(); + + /* make sure el received focus so we do not error out when trying to manipulate the caret. + sometimes modals or others listeners may steal it after its set */ + var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0); + if (isVisible && el === document.activeElement) { + + /* after the focus is set move the caret to the end, necessary when we val() + just before setting focus */ + if(el.setSelectionRange) + { + el.setSelectionRange(pos, pos); + } + else if (el.createTextRange) { + range = el.createTextRange(); + range.collapse(false); + range.select(); + } + } + }, 0); + } + + function getCursorInfo(el) { + el = $(el)[0]; + var offset = 0; + var length = 0; + if ('selectionStart' in el) { + offset = el.selectionStart; + length = el.selectionEnd - offset; + } else if ('selection' in document) { + el.focus(); + var sel = document.selection.createRange(); + length = document.selection.createRange().text.length; + sel.moveStart('character', -el.value.length); + offset = sel.text.length - length; + } + return { offset: offset, length: length }; + } + + function killEvent(event) { + event.preventDefault(); + event.stopPropagation(); + } + function killEventImmediately(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + + function measureTextWidth(e) { + if (!sizer){ + var style = e[0].currentStyle || window.getComputedStyle(e[0], null); + sizer = $(document.createElement("div")).css({ + position: "absolute", + left: "-10000px", + top: "-10000px", + display: "none", + fontSize: style.fontSize, + fontFamily: style.fontFamily, + fontStyle: style.fontStyle, + fontWeight: style.fontWeight, + letterSpacing: style.letterSpacing, + textTransform: style.textTransform, + whiteSpace: "nowrap" + }); + sizer.attr("class","select2-sizer"); + $(document.body).append(sizer); + } + sizer.text(e.val()); + return sizer.width(); + } + + function syncCssClasses(dest, src, adapter) { + var classes, replacements = [], adapted; + + classes = $.trim(dest.attr("class")); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each2(function() { + if (this.indexOf("select2-") === 0) { + replacements.push(this); + } + }); + } + + classes = $.trim(src.attr("class")); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each2(function() { + if (this.indexOf("select2-") !== 0) { + adapted = adapter(this); + + if (adapted) { + replacements.push(adapted); + } + } + }); + } + + dest.attr("class", replacements.join(" ")); + } + + + function markMatch(text, term, markup, escapeMarkup) { + var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())), + tl=term.length; + + if (match<0) { + markup.push(escapeMarkup(text)); + return; + } + + markup.push(escapeMarkup(text.substring(0, match))); + markup.push("<span class='select2-match'>"); + markup.push(escapeMarkup(text.substring(match, match + tl))); + markup.push("</span>"); + markup.push(escapeMarkup(text.substring(match + tl, text.length))); + } + + function defaultEscapeMarkup(markup) { + var replace_map = { + '\\': '\', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + "/": '/' + }; + + return String(markup).replace(/[&<>"'\/\\]/g, function (match) { + return replace_map[match]; + }); + } + + /** + * Produces an ajax-based query function + * + * @param options object containing configuration parameters + * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax + * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax + * @param options.url url for the data + * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. + * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified + * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often + * @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2. + * The expected format is an object containing the following keys: + * results array of objects that will be used as choices + * more (optional) boolean indicating whether there are more results available + * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true} + */ + function ajax(options) { + var timeout, // current scheduled but not yet executed request + handler = null, + quietMillis = options.quietMillis || 100, + ajaxUrl = options.url, + self = this; + + return function (query) { + window.clearTimeout(timeout); + timeout = window.setTimeout(function () { + var data = options.data, // ajax data function + url = ajaxUrl, // ajax url string or function + transport = options.transport || $.fn.select2.ajaxDefaults.transport, + // deprecated - to be removed in 4.0 - use params instead + deprecated = { + type: options.type || 'GET', // set type of request (GET or POST) + cache: options.cache || false, + jsonpCallback: options.jsonpCallback||undefined, + dataType: options.dataType||"json" + }, + params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated); + + data = data ? data.call(self, query.term, query.page, query.context) : null; + url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url; + + if (handler && typeof handler.abort === "function") { handler.abort(); } + + if (options.params) { + if ($.isFunction(options.params)) { + $.extend(params, options.params.call(self)); + } else { + $.extend(params, options.params); + } + } + + $.extend(params, { + url: url, + dataType: options.dataType, + data: data, + success: function (data) { + // TODO - replace query.page with query so users have access to term, page, etc. + // added query as third paramter to keep backwards compatibility + var results = options.results(data, query.page, query); + query.callback(results); + }, + error: function(jqXHR, textStatus, errorThrown){ + var results = { + hasError: true, + jqXHR: jqXHR, + textStatus: textStatus, + errorThrown: errorThrown + }; + + query.callback(results); + } + }); + handler = transport.call(self, params); + }, quietMillis); + }; + } + + /** + * Produces a query function that works with a local array + * + * @param options object containing configuration parameters. The options parameter can either be an array or an + * object. + * + * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys. + * + * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain + * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text' + * key can either be a String in which case it is expected that each element in the 'data' array has a key with the + * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract + * the text. + */ + function local(options) { + var data = options, // data elements + dataText, + tmp, + text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search + + if ($.isArray(data)) { + tmp = data; + data = { results: tmp }; + } + + if ($.isFunction(data) === false) { + tmp = data; + data = function() { return tmp; }; + } + + var dataItem = data(); + if (dataItem.text) { + text = dataItem.text; + // if text is not a function we assume it to be a key name + if (!$.isFunction(text)) { + dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available + text = function (item) { return item[dataText]; }; + } + } + + return function (query) { + var t = query.term, filtered = { results: [] }, process; + if (t === "") { + query.callback(data()); + return; + } + + process = function(datum, collection) { + var group, attr; + datum = datum[0]; + if (datum.children) { + group = {}; + for (attr in datum) { + if (datum.hasOwnProperty(attr)) group[attr]=datum[attr]; + } + group.children=[]; + $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); + if (group.children.length || query.matcher(t, text(group), datum)) { + collection.push(group); + } + } else { + if (query.matcher(t, text(datum), datum)) { + collection.push(datum); + } + } + }; + + $(data().results).each2(function(i, datum) { process(datum, filtered.results); }); + query.callback(filtered); + }; + } + + // TODO javadoc + function tags(data) { + var isFunc = $.isFunction(data); + return function (query) { + var t = query.term, filtered = {results: []}; + var result = isFunc ? data(query) : data; + if ($.isArray(result)) { + $(result).each(function () { + var isObject = this.text !== undefined, + text = isObject ? this.text : this; + if (t === "" || query.matcher(t, text)) { + filtered.results.push(isObject ? this : {id: this, text: this}); + } + }); + query.callback(filtered); + } + }; + } + + /** + * Checks if the formatter function should be used. + * + * Throws an error if it is not a function. Returns true if it should be used, + * false if no formatting should be performed. + * + * @param formatter + */ + function checkFormatter(formatter, formatterName) { + if ($.isFunction(formatter)) return true; + if (!formatter) return false; + if (typeof(formatter) === 'string') return true; + throw new Error(formatterName +" must be a string, function, or falsy value"); + } + + /** + * Returns a given value + * If given a function, returns its output + * + * @param val string|function + * @param context value of "this" to be passed to function + * @returns {*} + */ + function evaluate(val, context) { + if ($.isFunction(val)) { + var args = Array.prototype.slice.call(arguments, 2); + return val.apply(context, args); + } + return val; + } + + function countResults(results) { + var count = 0; + $.each(results, function(i, item) { + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + }); + return count; + } + + /** + * Default tokenizer. This function uses breaks the input on substring match of any string from the + * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those + * two options have to be defined in order for the tokenizer to work. + * + * @param input text user has typed so far or pasted into the search field + * @param selection currently selected choices + * @param selectCallback function(choice) callback tho add the choice to selection + * @param opts select2's opts + * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value + */ + function defaultTokenizer(input, selection, selectCallback, opts) { + var original = input, // store the original so we can compare and know if we need to tell the search to update its text + dupe = false, // check for whether a token we extracted represents a duplicate selected choice + token, // token + index, // position at which the separator was found + i, l, // looping variables + separator; // the matched separator + + if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined; + + while (true) { + index = -1; + + for (i = 0, l = opts.tokenSeparators.length; i < l; i++) { + separator = opts.tokenSeparators[i]; + index = input.indexOf(separator); + if (index >= 0) break; + } + + if (index < 0) break; // did not find any token separator in the input string, bail + + token = input.substring(0, index); + input = input.substring(index + separator.length); + + if (token.length > 0) { + token = opts.createSearchChoice.call(this, token, selection); + if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) { + dupe = false; + for (i = 0, l = selection.length; i < l; i++) { + if (equal(opts.id(token), opts.id(selection[i]))) { + dupe = true; break; + } + } + + if (!dupe) selectCallback(token); + } + } + } + + if (original!==input) return input; + } + + function cleanupJQueryElements() { + var self = this; + + $.each(arguments, function (i, element) { + self[element].remove(); + self[element] = null; + }); + } + + /** + * Creates a new class + * + * @param superClass + * @param methods + */ + function clazz(SuperClass, methods) { + var constructor = function () {}; + constructor.prototype = new SuperClass; + constructor.prototype.constructor = constructor; + constructor.prototype.parent = SuperClass.prototype; + constructor.prototype = $.extend(constructor.prototype, methods); + return constructor; + } + + AbstractSelect2 = clazz(Object, { + + // abstract + bind: function (func) { + var self = this; + return function () { + func.apply(self, arguments); + }; + }, + + // abstract + init: function (opts) { + var results, search, resultsSelector = ".select2-results"; + + // prepare options + this.opts = opts = this.prepareOpts(opts); + + this.id=opts.id; + + // destroy if called on an existing component + if (opts.element.data("select2") !== undefined && + opts.element.data("select2") !== null) { + opts.element.data("select2").destroy(); + } + + this.container = this.createContainer(); + + this.liveRegion = $('.select2-hidden-accessible'); + if (this.liveRegion.length == 0) { + this.liveRegion = $("<span>", { + role: "status", + "aria-live": "polite" + }) + .addClass("select2-hidden-accessible") + .appendTo(document.body); + } + + this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()); + this.containerEventName= this.containerId + .replace(/([.])/g, '_') + .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); + this.container.attr("id", this.containerId); + + this.container.attr("title", opts.element.attr("title")); + + this.body = $(document.body); + + syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); + + this.container.attr("style", opts.element.attr("style")); + this.container.css(evaluate(opts.containerCss, this.opts.element)); + this.container.addClass(evaluate(opts.containerCssClass, this.opts.element)); + + this.elementTabIndex = this.opts.element.attr("tabindex"); + + // swap container for the element + this.opts.element + .data("select2", this) + .attr("tabindex", "-1") + .before(this.container) + .on("click.select2", killEvent); // do not leak click events + + this.container.data("select2", this); + + this.dropdown = this.container.find(".select2-drop"); + + syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + + this.dropdown.addClass(evaluate(opts.dropdownCssClass, this.opts.element)); + this.dropdown.data("select2", this); + this.dropdown.on("click", killEvent); + + this.results = results = this.container.find(resultsSelector); + this.search = search = this.container.find("input.select2-input"); + + this.queryCount = 0; + this.resultsPage = 0; + this.context = null; + + // initialize the container + this.initContainer(); + + this.container.on("click", killEvent); + + installFilteredMouseMove(this.results); + + this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent)); + this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) { + this._touchEvent = true; + this.highlightUnderEvent(event); + })); + this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved)); + this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved)); + + // Waiting for a click event on touch devices to select option and hide dropdown + // otherwise click will be triggered on an underlying element + this.dropdown.on('click', this.bind(function (event) { + if (this._touchEvent) { + this._touchEvent = false; + this.selectHighlighted(); + } + })); + + installDebouncedScroll(80, this.results); + this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded)); + + // do not propagate change event from the search field out of the component + $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();}); + $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();}); + + // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel + if ($.fn.mousewheel) { + results.mousewheel(function (e, delta, deltaX, deltaY) { + var top = results.scrollTop(); + if (deltaY > 0 && top - deltaY <= 0) { + results.scrollTop(0); + killEvent(e); + } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { + results.scrollTop(results.get(0).scrollHeight - results.height()); + killEvent(e); + } + }); + } + + installKeyUpChangeEvent(search); + search.on("keyup-change input paste", this.bind(this.updateResults)); + search.on("focus", function () { search.addClass("select2-focused"); }); + search.on("blur", function () { search.removeClass("select2-focused");}); + + this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) { + if ($(e.target).closest(".select2-result-selectable").length > 0) { + this.highlightUnderEvent(e); + this.selectHighlighted(e); + } + })); + + // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening + // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's + // dom it will trigger the popup close, which is not what we want + // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal. + this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); }); + + this.lastSearchTerm = undefined; + + if ($.isFunction(this.opts.initSelection)) { + // initialize selection based on the current value of the source element + this.initSelection(); + + // if the user has provided a function that can set selection based on the value of the source element + // we monitor the change event on the element and trigger it, allowing for two way synchronization + this.monitorSource(); + } + + if (opts.maximumInputLength !== null) { + this.search.attr("maxlength", opts.maximumInputLength); + } + + var disabled = opts.element.prop("disabled"); + if (disabled === undefined) disabled = false; + this.enable(!disabled); + + var readonly = opts.element.prop("readonly"); + if (readonly === undefined) readonly = false; + this.readonly(readonly); + + // Calculate size of scrollbar + scrollBarDimensions = scrollBarDimensions || measureScrollbar(); + + this.autofocus = opts.element.prop("autofocus"); + opts.element.prop("autofocus", false); + if (this.autofocus) this.focus(); + + this.search.attr("placeholder", opts.searchInputPlaceholder); + }, + + // abstract + destroy: function () { + var element=this.opts.element, select2 = element.data("select2"), self = this; + + this.close(); + + if (element.length && element[0].detachEvent && self._sync) { + element.each(function () { + if (self._sync) { + this.detachEvent("onpropertychange", self._sync); + } + }); + } + if (this.propertyObserver) { + this.propertyObserver.disconnect(); + this.propertyObserver = null; + } + this._sync = null; + + if (select2 !== undefined) { + select2.container.remove(); + select2.liveRegion.remove(); + select2.dropdown.remove(); + element.removeData("select2") + .off(".select2"); + if (!element.is("input[type='hidden']")) { + element + .show() + .prop("autofocus", this.autofocus || false); + if (this.elementTabIndex) { + element.attr({tabindex: this.elementTabIndex}); + } else { + element.removeAttr("tabindex"); + } + element.show(); + } else { + element.css("display", ""); + } + } + + cleanupJQueryElements.call(this, + "container", + "liveRegion", + "dropdown", + "results", + "search" + ); + }, + + // abstract + optionToData: function(element) { + if (element.is("option")) { + return { + id:element.prop("value"), + text:element.text(), + element: element.get(), + css: element.attr("class"), + disabled: element.prop("disabled"), + locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true) + }; + } else if (element.is("optgroup")) { + return { + text:element.attr("label"), + children:[], + element: element.get(), + css: element.attr("class") + }; + } + }, + + // abstract + prepareOpts: function (opts) { + var element, select, idKey, ajaxUrl, self = this; + + element = opts.element; + + if (element.get(0).tagName.toLowerCase() === "select") { + this.select = select = opts.element; + } + + if (select) { + // these options are not allowed when attached to a select because they are picked up off the element itself + $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () { + if (this in opts) { + throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element."); + } + }); + } + + opts.debug = opts.debug || $.fn.select2.defaults.debug; + + // Warnings for options renamed/removed in Select2 4.0.0 + // Only when it's enabled through debug mode + if (opts.debug && console && console.warn) { + // id was removed + if (opts.id != null) { + console.warn( + 'Select2: The `id` option has been removed in Select2 4.0.0, ' + + 'consider renaming your `id` property or mapping the property before your data makes it to Select2. ' + + 'You can read more at https://select2.github.io/announcements-4.0.html#changed-id' + ); + } + + // text was removed + if (opts.text != null) { + console.warn( + 'Select2: The `text` option has been removed in Select2 4.0.0, ' + + 'consider renaming your `text` property or mapping the property before your data makes it to Select2. ' + + 'You can read more at https://select2.github.io/announcements-4.0.html#changed-id' + ); + } + + // sortResults was renamed to results + if (opts.sortResults != null) { + console.warn( + 'Select2: the `sortResults` option has been renamed to `sorter` in Select2 4.0.0. ' + ); + } + + // selectOnBlur was renamed to selectOnClose + if (opts.selectOnBlur != null) { + console.warn( + 'Select2: The `selectOnBlur` option has been renamed to `selectOnClose` in Select2 4.0.0.' + ); + } + + // ajax.results was renamed to ajax.processResults + if (opts.ajax != null && opts.ajax.results != null) { + console.warn( + 'Select2: The `ajax.results` option has been renamed to `ajax.processResults` in Select2 4.0.0.' + ); + } + + // format* options were renamed to language.* + if (opts.formatNoResults != null) { + console.warn( + 'Select2: The `formatNoResults` option has been renamed to `language.noResults` in Select2 4.0.0.' + ); + } + if (opts.formatSearching != null) { + console.warn( + 'Select2: The `formatSearching` option has been renamed to `language.searching` in Select2 4.0.0.' + ); + } + if (opts.formatInputTooShort != null) { + console.warn( + 'Select2: The `formatInputTooShort` option has been renamed to `language.inputTooShort` in Select2 4.0.0.' + ); + } + if (opts.formatInputTooLong != null) { + console.warn( + 'Select2: The `formatInputTooLong` option has been renamed to `language.inputTooLong` in Select2 4.0.0.' + ); + } + if (opts.formatLoading != null) { + console.warn( + 'Select2: The `formatLoading` option has been renamed to `language.loadingMore` in Select2 4.0.0.' + ); + } + if (opts.formatSelectionTooBig != null) { + console.warn( + 'Select2: The `formatSelectionTooBig` option has been renamed to `language.maximumSelected` in Select2 4.0.0.' + ); + } + + if (opts.element.data('select2Tags')) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been renamed to `data-tags` in Select2 4.0.0.' + ); + } + } + + // Aliasing options renamed in Select2 4.0.0 + + // data-select2-tags -> data-tags + if (opts.element.data('tags') != null) { + var elemTags = opts.element.data('tags'); + + // data-tags should actually be a boolean + if (!$.isArray(elemTags)) { + elemTags = []; + } + + opts.element.data('select2Tags', elemTags); + } + + // sortResults -> sorter + if (opts.sorter != null) { + opts.sortResults = opts.sorter; + } + + // selectOnBlur -> selectOnClose + if (opts.selectOnClose != null) { + opts.selectOnBlur = opts.selectOnClose; + } + + // ajax.results -> ajax.processResults + if (opts.ajax != null) { + if ($.isFunction(opts.ajax.processResults)) { + opts.ajax.results = opts.ajax.processResults; + } + } + + // Formatters/language options + if (opts.language != null) { + var lang = opts.language; + + // formatNoMatches -> language.noMatches + if ($.isFunction(lang.noMatches)) { + opts.formatNoMatches = lang.noMatches; + } + + // formatSearching -> language.searching + if ($.isFunction(lang.searching)) { + opts.formatSearching = lang.searching; + } + + // formatInputTooShort -> language.inputTooShort + if ($.isFunction(lang.inputTooShort)) { + opts.formatInputTooShort = lang.inputTooShort; + } + + // formatInputTooLong -> language.inputTooLong + if ($.isFunction(lang.inputTooLong)) { + opts.formatInputTooLong = lang.inputTooLong; + } + + // formatLoading -> language.loadingMore + if ($.isFunction(lang.loadingMore)) { + opts.formatLoading = lang.loadingMore; + } + + // formatSelectionTooBig -> language.maximumSelected + if ($.isFunction(lang.maximumSelected)) { + opts.formatSelectionTooBig = lang.maximumSelected; + } + } + + opts = $.extend({}, { + populateResults: function(container, results, query) { + var populate, id=this.opts.id, liveRegion=this.liveRegion; + + populate=function(results, container, depth) { + + var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted; + + results = opts.sortResults(results, container, query); + + // collect the created nodes for bulk append + var nodes = []; + for (i = 0, l = results.length; i < l; i = i + 1) { + + result=results[i]; + + disabled = (result.disabled === true); + selectable = (!disabled) && (id(result) !== undefined); + + compound=result.children && result.children.length > 0; + + node=$("<li></li>"); + node.addClass("select2-results-dept-"+depth); + node.addClass("select2-result"); + node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable"); + if (disabled) { node.addClass("select2-disabled"); } + if (compound) { node.addClass("select2-result-with-children"); } + node.addClass(self.opts.formatResultCssClass(result)); + node.attr("role", "presentation"); + + label=$(document.createElement("div")); + label.addClass("select2-result-label"); + label.attr("id", "select2-result-label-" + nextUid()); + label.attr("role", "option"); + + formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup); + if (formatted!==undefined) { + label.html(formatted); + node.append(label); + } + + + if (compound) { + innerContainer=$("<ul></ul>"); + innerContainer.addClass("select2-result-sub"); + populate(result.children, innerContainer, depth+1); + node.append(innerContainer); + } + + node.data("select2-data", result); + nodes.push(node[0]); + } + + // bulk append the created nodes + container.append(nodes); + liveRegion.text(opts.formatMatches(results.length)); + }; + + populate(results, container, 0); + } + }, $.fn.select2.defaults, opts); + + if (typeof(opts.id) !== "function") { + idKey = opts.id; + opts.id = function (e) { return e[idKey]; }; + } + + if ($.isArray(opts.element.data("select2Tags"))) { + if ("tags" in opts) { + throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id"); + } + opts.tags=opts.element.data("select2Tags"); + } + + if (select) { + opts.query = this.bind(function (query) { + var data = { results: [], more: false }, + term = query.term, + children, placeholderOption, process; + + process=function(element, collection) { + var group; + if (element.is("option")) { + if (query.matcher(term, element.text(), element)) { + collection.push(self.optionToData(element)); + } + } else if (element.is("optgroup")) { + group=self.optionToData(element); + element.children().each2(function(i, elm) { process(elm, group.children); }); + if (group.children.length>0) { + collection.push(group); + } + } + }; + + children=element.children(); + + // ignore the placeholder option if there is one + if (this.getPlaceholder() !== undefined && children.length > 0) { + placeholderOption = this.getPlaceholderOption(); + if (placeholderOption) { + children=children.not(placeholderOption); + } + } + + children.each2(function(i, elm) { process(elm, data.results); }); + + query.callback(data); + }); + // this is needed because inside val() we construct choices from options and their id is hardcoded + opts.id=function(e) { return e.id; }; + } else { + if (!("query" in opts)) { + if ("ajax" in opts) { + ajaxUrl = opts.element.data("ajax-url"); + if (ajaxUrl && ajaxUrl.length > 0) { + opts.ajax.url = ajaxUrl; + } + opts.query = ajax.call(opts.element, opts.ajax); + } else if ("data" in opts) { + opts.query = local(opts.data); + } else if ("tags" in opts) { + opts.query = tags(opts.tags); + if (opts.createSearchChoice === undefined) { + opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; }; + } + if (opts.initSelection === undefined) { + opts.initSelection = function (element, callback) { + var data = []; + $(splitVal(element.val(), opts.separator, opts.transformVal)).each(function () { + var obj = { id: this, text: this }, + tags = opts.tags; + if ($.isFunction(tags)) tags=tags(); + $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } }); + data.push(obj); + }); + + callback(data); + }; + } + } + } + } + if (typeof(opts.query) !== "function") { + throw "query function not defined for Select2 " + opts.element.attr("id"); + } + + if (opts.createSearchChoicePosition === 'top') { + opts.createSearchChoicePosition = function(list, item) { list.unshift(item); }; + } + else if (opts.createSearchChoicePosition === 'bottom') { + opts.createSearchChoicePosition = function(list, item) { list.push(item); }; + } + else if (typeof(opts.createSearchChoicePosition) !== "function") { + throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function"; + } + + return opts; + }, + + /** + * Monitor the original element for changes and update select2 accordingly + */ + // abstract + monitorSource: function () { + var el = this.opts.element, observer, self = this; + + el.on("change.select2", this.bind(function (e) { + if (this.opts.element.data("select2-change-triggered") !== true) { + this.initSelection(); + } + })); + + this._sync = this.bind(function () { + + // sync enabled state + var disabled = el.prop("disabled"); + if (disabled === undefined) disabled = false; + this.enable(!disabled); + + var readonly = el.prop("readonly"); + if (readonly === undefined) readonly = false; + this.readonly(readonly); + + if (this.container) { + syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); + this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element)); + } + + if (this.dropdown) { + syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element)); + } + + }); + + // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener) + if (el.length && el[0].attachEvent) { + el.each(function() { + this.attachEvent("onpropertychange", self._sync); + }); + } + + // safari, chrome, firefox, IE11 + observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver; + if (observer !== undefined) { + if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } + this.propertyObserver = new observer(function (mutations) { + $.each(mutations, self._sync); + }); + this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false }); + } + }, + + // abstract + triggerSelect: function(data) { + var evt = $.Event("select2-selecting", { val: this.id(data), object: data, choice: data }); + this.opts.element.trigger(evt); + return !evt.isDefaultPrevented(); + }, + + /** + * Triggers the change event on the source element + */ + // abstract + triggerChange: function (details) { + + details = details || {}; + details= $.extend({}, details, { type: "change", val: this.val() }); + // prevents recursive triggering + this.opts.element.data("select2-change-triggered", true); + this.opts.element.trigger(details); + this.opts.element.data("select2-change-triggered", false); + + // some validation frameworks ignore the change event and listen instead to keyup, click for selects + // so here we trigger the click event manually + this.opts.element.click(); + + // ValidationEngine ignores the change event and listens instead to blur + // so here we trigger the blur event manually if so desired + if (this.opts.blurOnChange) + this.opts.element.blur(); + }, + + //abstract + isInterfaceEnabled: function() + { + return this.enabledInterface === true; + }, + + // abstract + enableInterface: function() { + var enabled = this._enabled && !this._readonly, + disabled = !enabled; + + if (enabled === this.enabledInterface) return false; + + this.container.toggleClass("select2-container-disabled", disabled); + this.close(); + this.enabledInterface = enabled; + + return true; + }, + + // abstract + enable: function(enabled) { + if (enabled === undefined) enabled = true; + if (this._enabled === enabled) return; + this._enabled = enabled; + + this.opts.element.prop("disabled", !enabled); + this.enableInterface(); + }, + + // abstract + disable: function() { + this.enable(false); + }, + + // abstract + readonly: function(enabled) { + if (enabled === undefined) enabled = false; + if (this._readonly === enabled) return; + this._readonly = enabled; + + this.opts.element.prop("readonly", enabled); + this.enableInterface(); + }, + + // abstract + opened: function () { + return (this.container) ? this.container.hasClass("select2-dropdown-open") : false; + }, + + // abstract + positionDropdown: function() { + var $dropdown = this.dropdown, + container = this.container, + offset = container.offset(), + height = container.outerHeight(false), + width = container.outerWidth(false), + dropHeight = $dropdown.outerHeight(false), + $window = $(window), + windowWidth = $window.width(), + windowHeight = $window.height(), + viewPortRight = $window.scrollLeft() + windowWidth, + viewportBottom = $window.scrollTop() + windowHeight, + dropTop = offset.top + height, + dropLeft = offset.left, + enoughRoomBelow = dropTop + dropHeight <= viewportBottom, + enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(), + dropWidth = $dropdown.outerWidth(false), + enoughRoomOnRight = function() { + return dropLeft + dropWidth <= viewPortRight; + }, + enoughRoomOnLeft = function() { + return offset.left + viewPortRight + container.outerWidth(false) > dropWidth; + }, + aboveNow = $dropdown.hasClass("select2-drop-above"), + bodyOffset, + above, + changeDirection, + css, + resultsListNode; + + // always prefer the current above/below alignment, unless there is not enough room + if (aboveNow) { + above = true; + if (!enoughRoomAbove && enoughRoomBelow) { + changeDirection = true; + above = false; + } + } else { + above = false; + if (!enoughRoomBelow && enoughRoomAbove) { + changeDirection = true; + above = true; + } + } + + //if we are changing direction we need to get positions when dropdown is hidden; + if (changeDirection) { + $dropdown.hide(); + offset = this.container.offset(); + height = this.container.outerHeight(false); + width = this.container.outerWidth(false); + dropHeight = $dropdown.outerHeight(false); + viewPortRight = $window.scrollLeft() + windowWidth; + viewportBottom = $window.scrollTop() + windowHeight; + dropTop = offset.top + height; + dropLeft = offset.left; + dropWidth = $dropdown.outerWidth(false); + $dropdown.show(); + + // fix so the cursor does not move to the left within the search-textbox in IE + this.focusSearch(); + } + + if (this.opts.dropdownAutoWidth) { + resultsListNode = $('.select2-results', $dropdown)[0]; + $dropdown.addClass('select2-drop-auto-width'); + $dropdown.css('width', ''); + // Add scrollbar width to dropdown if vertical scrollbar is present + dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width); + dropWidth > width ? width = dropWidth : dropWidth = width; + dropHeight = $dropdown.outerHeight(false); + } + else { + this.container.removeClass('select2-drop-auto-width'); + } + + //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); + //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove); + + // fix positioning when body has an offset and is not position: static + if (this.body.css('position') !== 'static') { + bodyOffset = this.body.offset(); + dropTop -= bodyOffset.top; + dropLeft -= bodyOffset.left; + } + + if (!enoughRoomOnRight() && enoughRoomOnLeft()) { + dropLeft = offset.left + this.container.outerWidth(false) - dropWidth; + } + + css = { + left: dropLeft, + width: width + }; + + if (above) { + this.container.addClass("select2-drop-above"); + $dropdown.addClass("select2-drop-above"); + dropHeight = $dropdown.outerHeight(false); + css.top = offset.top - dropHeight; + css.bottom = 'auto'; + } + else { + css.top = dropTop; + css.bottom = 'auto'; + this.container.removeClass("select2-drop-above"); + $dropdown.removeClass("select2-drop-above"); + } + css = $.extend(css, evaluate(this.opts.dropdownCss, this.opts.element)); + + $dropdown.css(css); + }, + + // abstract + shouldOpen: function() { + var event; + + if (this.opened()) return false; + + if (this._enabled === false || this._readonly === true) return false; + + event = $.Event("select2-opening"); + this.opts.element.trigger(event); + return !event.isDefaultPrevented(); + }, + + // abstract + clearDropdownAlignmentPreference: function() { + // clear the classes used to figure out the preference of where the dropdown should be opened + this.container.removeClass("select2-drop-above"); + this.dropdown.removeClass("select2-drop-above"); + }, + + /** + * Opens the dropdown + * + * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example, + * the dropdown is already open, or if the 'open' event listener on the element called preventDefault(). + */ + // abstract + open: function () { + + if (!this.shouldOpen()) return false; + + this.opening(); + + // Only bind the document mousemove when the dropdown is visible + $document.on("mousemove.select2Event", function (e) { + lastMousePosition.x = e.pageX; + lastMousePosition.y = e.pageY; + }); + + return true; + }, + + /** + * Performs the opening of the dropdown + */ + // abstract + opening: function() { + var cid = this.containerEventName, + scroll = "scroll." + cid, + resize = "resize."+cid, + orient = "orientationchange."+cid, + mask; + + this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); + + this.clearDropdownAlignmentPreference(); + + if(this.dropdown[0] !== this.body.children().last()[0]) { + this.dropdown.detach().appendTo(this.body); + } + + // create the dropdown mask if doesn't already exist + mask = $("#select2-drop-mask"); + if (mask.length === 0) { + mask = $(document.createElement("div")); + mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); + mask.hide(); + mask.appendTo(this.body); + mask.on("mousedown touchstart click", function (e) { + // Prevent IE from generating a click event on the body + reinsertElement(mask); + + var dropdown = $("#select2-drop"), self; + if (dropdown.length > 0) { + self=dropdown.data("select2"); + if (self.opts.selectOnBlur) { + self.selectHighlighted({noFocus: true}); + } + self.close(); + e.preventDefault(); + e.stopPropagation(); + } + }); + } + + // ensure the mask is always right before the dropdown + if (this.dropdown.prev()[0] !== mask[0]) { + this.dropdown.before(mask); + } + + // move the global id to the correct dropdown + $("#select2-drop").removeAttr("id"); + this.dropdown.attr("id", "select2-drop"); + + // show the elements + mask.show(); + + this.positionDropdown(); + this.dropdown.show(); + this.positionDropdown(); + + this.dropdown.addClass("select2-drop-active"); + + // attach listeners to events that can change the position of the container and thus require + // the position of the dropdown to be updated as well so it does not come unglued from the container + var that = this; + this.container.parents().add(window).each(function () { + $(this).on(resize+" "+scroll+" "+orient, function (e) { + if (that.opened()) that.positionDropdown(); + }); + }); + + + }, + + // abstract + close: function () { + if (!this.opened()) return; + + var cid = this.containerEventName, + scroll = "scroll." + cid, + resize = "resize."+cid, + orient = "orientationchange."+cid; + + // unbind event listeners + this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); }); + + this.clearDropdownAlignmentPreference(); + + $("#select2-drop-mask").hide(); + this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id + this.dropdown.hide(); + this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); + this.results.empty(); + + // Now that the dropdown is closed, unbind the global document mousemove event + $document.off("mousemove.select2Event"); + + this.clearSearch(); + this.search.removeClass("select2-active"); + + // Remove the aria active descendant for highlighted element + this.search.removeAttr("aria-activedescendant"); + this.opts.element.trigger($.Event("select2-close")); + }, + + /** + * Opens control, sets input value, and updates results. + */ + // abstract + externalSearch: function (term) { + this.open(); + this.search.val(term); + this.updateResults(false); + }, + + // abstract + clearSearch: function () { + + }, + + /** + * @return {Boolean} Whether or not search value was changed. + * @private + */ + prefillNextSearchTerm: function () { + // initializes search's value with nextSearchTerm (if defined by user) + // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter + if(this.search.val() !== "") { + return false; + } + + var nextSearchTerm = this.opts.nextSearchTerm(this.data(), this.lastSearchTerm); + if(nextSearchTerm !== undefined){ + this.search.val(nextSearchTerm); + this.search.select(); + return true; + } + + return false; + }, + + //abstract + getMaximumSelectionSize: function() { + return evaluate(this.opts.maximumSelectionSize, this.opts.element); + }, + + // abstract + ensureHighlightVisible: function () { + var results = this.results, children, index, child, hb, rb, y, more, topOffset; + + index = this.highlight(); + + if (index < 0) return; + + if (index == 0) { + + // if the first element is highlighted scroll all the way to the top, + // that way any unselectable headers above it will also be scrolled + // into view + + results.scrollTop(0); + return; + } + + children = this.findHighlightableChoices().find('.select2-result-label'); + + child = $(children[index]); + + topOffset = (child.offset() || {}).top || 0; + + hb = topOffset + child.outerHeight(true); + + // if this is the last child lets also make sure select2-more-results is visible + if (index === children.length - 1) { + more = results.find("li.select2-more-results"); + if (more.length > 0) { + hb = more.offset().top + more.outerHeight(true); + } + } + + rb = results.offset().top + results.outerHeight(false); + if (hb > rb) { + results.scrollTop(results.scrollTop() + (hb - rb)); + } + y = topOffset - results.offset().top; + + // make sure the top of the element is visible + if (y < 0 && child.css('display') != 'none' ) { + results.scrollTop(results.scrollTop() + y); // y is negative + } + }, + + // abstract + findHighlightableChoices: function() { + return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)"); + }, + + // abstract + moveHighlight: function (delta) { + var choices = this.findHighlightableChoices(), + index = this.highlight(); + + while (index > -1 && index < choices.length) { + index += delta; + var choice = $(choices[index]); + if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) { + this.highlight(index); + break; + } + } + }, + + // abstract + highlight: function (index) { + var choices = this.findHighlightableChoices(), + choice, + data; + + if (arguments.length === 0) { + return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); + } + + if (index >= choices.length) index = choices.length - 1; + if (index < 0) index = 0; + + this.removeHighlight(); + + choice = $(choices[index]); + choice.addClass("select2-highlighted"); + + // ensure assistive technology can determine the active choice + this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id")); + + this.ensureHighlightVisible(); + + this.liveRegion.text(choice.text()); + + data = choice.data("select2-data"); + if (data) { + this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data }); + } + }, + + removeHighlight: function() { + this.results.find(".select2-highlighted").removeClass("select2-highlighted"); + }, + + touchMoved: function() { + this._touchMoved = true; + }, + + clearTouchMoved: function() { + this._touchMoved = false; + }, + + // abstract + countSelectableResults: function() { + return this.findHighlightableChoices().length; + }, + + // abstract + highlightUnderEvent: function (event) { + var el = $(event.target).closest(".select2-result-selectable"); + if (el.length > 0 && !el.is(".select2-highlighted")) { + var choices = this.findHighlightableChoices(); + this.highlight(choices.index(el)); + } else if (el.length == 0) { + // if we are over an unselectable item remove all highlights + this.removeHighlight(); + } + }, + + // abstract + loadMoreIfNeeded: function () { + var results = this.results, + more = results.find("li.select2-more-results"), + below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible + page = this.resultsPage + 1, + self=this, + term=this.search.val(), + context=this.context; + + if (more.length === 0) return; + below = more.offset().top - results.offset().top - results.height(); + + if (below <= this.opts.loadMorePadding) { + more.addClass("select2-active"); + this.opts.query({ + element: this.opts.element, + term: term, + page: page, + context: context, + matcher: this.opts.matcher, + callback: this.bind(function (data) { + + // ignore a response if the select2 has been closed before it was received + if (!self.opened()) return; + + + self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context}); + self.postprocessResults(data, false, false); + + if (data.more===true) { + more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1))); + window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); + } else { + more.remove(); + } + self.positionDropdown(); + self.resultsPage = page; + self.context = data.context; + this.opts.element.trigger({ type: "select2-loaded", items: data }); + })}); + } + }, + + /** + * Default tokenizer function which does nothing + */ + tokenize: function() { + + }, + + /** + * @param initial whether or not this is the call to this method right after the dropdown has been opened + */ + // abstract + updateResults: function (initial) { + var search = this.search, + results = this.results, + opts = this.opts, + data, + self = this, + input, + term = search.val(), + lastTerm = $.data(this.container, "select2-last-term"), + // sequence number used to drop out-of-order responses + queryNumber; + + // prevent duplicate queries against the same term + if (initial !== true && lastTerm && equal(term, lastTerm)) return; + + $.data(this.container, "select2-last-term", term); + + // if the search is currently hidden we do not alter the results + if (initial !== true && (this.showSearchInput === false || !this.opened())) { + return; + } + + function postRender() { + search.removeClass("select2-active"); + self.positionDropdown(); + if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) { + self.liveRegion.text(results.text()); + } + else { + self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable:not(".select2-selected")').length)); + } + } + + function render(html) { + results.html(html); + postRender(); + } + + queryNumber = ++this.queryCount; + + var maxSelSize = this.getMaximumSelectionSize(); + if (maxSelSize >=1) { + data = this.data(); + if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { + render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, opts.element, maxSelSize) + "</li>"); + return; + } + } + + if (search.val().length < opts.minimumInputLength) { + if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) { + render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, opts.element, search.val(), opts.minimumInputLength) + "</li>"); + } else { + render(""); + } + if (initial && this.showSearch) this.showSearch(true); + return; + } + + if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) { + if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) { + render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, opts.element, search.val(), opts.maximumInputLength) + "</li>"); + } else { + render(""); + } + return; + } + + if (opts.formatSearching && this.findHighlightableChoices().length === 0) { + render("<li class='select2-searching'>" + evaluate(opts.formatSearching, opts.element) + "</li>"); + } + + search.addClass("select2-active"); + + this.removeHighlight(); + + // give the tokenizer a chance to pre-process the input + input = this.tokenize(); + if (input != undefined && input != null) { + search.val(input); + } + + this.resultsPage = 1; + + opts.query({ + element: opts.element, + term: search.val(), + page: this.resultsPage, + context: null, + matcher: opts.matcher, + callback: this.bind(function (data) { + var def; // default choice + + // ignore old responses + if (queryNumber != this.queryCount) { + return; + } + + // ignore a response if the select2 has been closed before it was received + if (!this.opened()) { + this.search.removeClass("select2-active"); + return; + } + + // handle ajax error + if(data.hasError !== undefined && checkFormatter(opts.formatAjaxError, "formatAjaxError")) { + render("<li class='select2-ajax-error'>" + evaluate(opts.formatAjaxError, opts.element, data.jqXHR, data.textStatus, data.errorThrown) + "</li>"); + return; + } + + // save context, if any + this.context = (data.context===undefined) ? null : data.context; + // create a default choice and prepend it to the list + if (this.opts.createSearchChoice && search.val() !== "") { + def = this.opts.createSearchChoice.call(self, search.val(), data.results); + if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) { + if ($(data.results).filter( + function () { + return equal(self.id(this), self.id(def)); + }).length === 0) { + this.opts.createSearchChoicePosition(data.results, def); + } + } + } + + if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) { + render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, opts.element, search.val()) + "</li>"); + if(this.showSearch){ + this.showSearch(search.val()); + } + return; + } + + results.empty(); + self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null}); + + if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) { + results.append("<li class='select2-more-results'>" + opts.escapeMarkup(evaluate(opts.formatLoadMore, opts.element, this.resultsPage)) + "</li>"); + window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); + } + + this.postprocessResults(data, initial); + + postRender(); + + this.opts.element.trigger({ type: "select2-loaded", items: data }); + })}); + }, + + // abstract + cancel: function () { + this.close(); + }, + + // abstract + blur: function () { + // if selectOnBlur == true, select the currently highlighted option + if (this.opts.selectOnBlur) + this.selectHighlighted({noFocus: true}); + + this.close(); + this.container.removeClass("select2-container-active"); + // synonymous to .is(':focus'), which is available in jquery >= 1.6 + if (this.search[0] === document.activeElement) { this.search.blur(); } + this.clearSearch(); + this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); + }, + + // abstract + focusSearch: function () { + focus(this.search); + }, + + // abstract + selectHighlighted: function (options) { + if (this._touchMoved) { + this.clearTouchMoved(); + return; + } + var index=this.highlight(), + highlighted=this.results.find(".select2-highlighted"), + data = highlighted.closest('.select2-result').data("select2-data"); + + if (data) { + this.highlight(index); + this.onSelect(data, options); + } else if (options && options.noFocus) { + this.close(); + } + }, + + // abstract + getPlaceholder: function () { + var placeholderOption; + return this.opts.element.attr("placeholder") || + this.opts.element.attr("data-placeholder") || // jquery 1.4 compat + this.opts.element.data("placeholder") || + this.opts.placeholder || + ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined); + }, + + // abstract + getPlaceholderOption: function() { + if (this.select) { + var firstOption = this.select.children('option').first(); + if (this.opts.placeholderOption !== undefined ) { + //Determine the placeholder option based on the specified placeholderOption setting + return (this.opts.placeholderOption === "first" && firstOption) || + (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select)); + } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") { + //No explicit placeholder option specified, use the first if it's blank + return firstOption; + } + } + }, + + /** + * Get the desired width for the container element. This is + * derived first from option `width` passed to select2, then + * the inline 'style' on the original element, and finally + * falls back to the jQuery calculated element width. + */ + // abstract + initContainerWidth: function () { + function resolveContainerWidth() { + var style, attrs, matches, i, l, attr; + + if (this.opts.width === "off") { + return null; + } else if (this.opts.width === "element"){ + return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'; + } else if (this.opts.width === "copy" || this.opts.width === "resolve") { + // check if there is inline style on the element that contains width + style = this.opts.element.attr('style'); + if (typeof(style) === "string") { + attrs = style.split(';'); + for (i = 0, l = attrs.length; i < l; i = i + 1) { + attr = attrs[i].replace(/\s/g, ''); + matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i); + if (matches !== null && matches.length >= 1) + return matches[1]; + } + } + + if (this.opts.width === "resolve") { + // next check if css('width') can resolve a width that is percent based, this is sometimes possible + // when attached to input type=hidden or elements hidden via css + style = this.opts.element.css('width'); + if (style.indexOf("%") > 0) return style; + + // finally, fallback on the calculated width of the element + return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'); + } + + return null; + } else if ($.isFunction(this.opts.width)) { + return this.opts.width(); + } else { + return this.opts.width; + } + }; + + var width = resolveContainerWidth.call(this); + if (width !== null) { + this.container.css("width", width); + } + } + }); + + SingleSelect2 = clazz(AbstractSelect2, { + + // single + + createContainer: function () { + var container = $(document.createElement("div")).attr({ + "class": "select2-container" + }).html([ + "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>", + " <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>", + " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>", + "</a>", + "<label for='' class='select2-offscreen'></label>", + "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />", + "<div class='select2-drop select2-display-none'>", + " <div class='select2-search'>", + " <label for='' class='select2-offscreen'></label>", + " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'", + " aria-autocomplete='list' />", + " </div>", + " <ul class='select2-results' role='listbox'>", + " </ul>", + "</div>"].join("")); + return container; + }, + + // single + enableInterface: function() { + if (this.parent.enableInterface.apply(this, arguments)) { + this.focusser.prop("disabled", !this.isInterfaceEnabled()); + } + }, + + // single + opening: function () { + var el, range, len; + + if (this.opts.minimumResultsForSearch >= 0) { + this.showSearch(true); + } + + this.parent.opening.apply(this, arguments); + + if (this.showSearchInput !== false) { + // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range + // all other browsers handle this just fine + + this.search.val(this.focusser.val()); + } + if (this.opts.shouldFocusInput(this)) { + this.search.focus(); + // move the cursor to the end after focussing, otherwise it will be at the beginning and + // new text will appear *before* focusser.val() + el = this.search.get(0); + if (el.createTextRange) { + range = el.createTextRange(); + range.collapse(false); + range.select(); + } else if (el.setSelectionRange) { + len = this.search.val().length; + el.setSelectionRange(len, len); + } + } + + this.prefillNextSearchTerm(); + + this.focusser.prop("disabled", true).val(""); + this.updateResults(true); + this.opts.element.trigger($.Event("select2-open")); + }, + + // single + close: function () { + if (!this.opened()) return; + this.parent.close.apply(this, arguments); + + this.focusser.prop("disabled", false); + + if (this.opts.shouldFocusInput(this)) { + this.focusser.focus(); + } + }, + + // single + focus: function () { + if (this.opened()) { + this.close(); + } else { + this.focusser.prop("disabled", false); + if (this.opts.shouldFocusInput(this)) { + this.focusser.focus(); + } + } + }, + + // single + isFocused: function () { + return this.container.hasClass("select2-container-active"); + }, + + // single + cancel: function () { + this.parent.cancel.apply(this, arguments); + this.focusser.prop("disabled", false); + + if (this.opts.shouldFocusInput(this)) { + this.focusser.focus(); + } + }, + + // single + destroy: function() { + $("label[for='" + this.focusser.attr('id') + "']") + .attr('for', this.opts.element.attr("id")); + this.parent.destroy.apply(this, arguments); + + cleanupJQueryElements.call(this, + "selection", + "focusser" + ); + }, + + // single + initContainer: function () { + + var selection, + container = this.container, + dropdown = this.dropdown, + idSuffix = nextUid(), + elementLabel; + + if (this.opts.minimumResultsForSearch < 0) { + this.showSearch(false); + } else { + this.showSearch(true); + } + + this.selection = selection = container.find(".select2-choice"); + + this.focusser = container.find(".select2-focusser"); + + // add aria associations + selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix); + this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix); + this.results.attr("id", "select2-results-"+idSuffix); + this.search.attr("aria-owns", "select2-results-"+idSuffix); + + // rewrite labels from original element to focusser + this.focusser.attr("id", "s2id_autogen"+idSuffix); + + elementLabel = $("label[for='" + this.opts.element.attr("id") + "']"); + this.opts.element.on('focus.select2', this.bind(function () { this.focus(); })); + + this.focusser.prev() + .text(elementLabel.text()) + .attr('for', this.focusser.attr('id')); + + // Ensure the original element retains an accessible name + var originalTitle = this.opts.element.attr("title"); + this.opts.element.attr("title", (originalTitle || elementLabel.text())); + + this.focusser.attr("tabindex", this.elementTabIndex); + + // write label for search field using the label from the focusser element + this.search.attr("id", this.focusser.attr('id') + '_search'); + + this.search.prev() + .text($("label[for='" + this.focusser.attr('id') + "']").text()) + .attr('for', this.search.attr('id')); + + this.search.on("keydown", this.bind(function (e) { + if (!this.isInterfaceEnabled()) return; + + // filter 229 keyCodes (input method editor is processing key input) + if (229 == e.keyCode) return; + + if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { + // prevent the page from scrolling + killEvent(e); + return; + } + + switch (e.which) { + case KEY.UP: + case KEY.DOWN: + this.moveHighlight((e.which === KEY.UP) ? -1 : 1); + killEvent(e); + return; + case KEY.ENTER: + this.selectHighlighted(); + killEvent(e); + return; + case KEY.TAB: + this.selectHighlighted({noFocus: true}); + return; + case KEY.ESC: + this.cancel(e); + killEvent(e); + return; + } + })); + + this.search.on("blur", this.bind(function(e) { + // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown. + // without this the search field loses focus which is annoying + if (document.activeElement === this.body.get(0)) { + window.setTimeout(this.bind(function() { + if (this.opened() && this.results && this.results.length > 1) { + this.search.focus(); + } + }), 0); + } + })); + + this.focusser.on("keydown", this.bind(function (e) { + if (!this.isInterfaceEnabled()) return; + + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { + return; + } + + if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { + killEvent(e); + return; + } + + if (e.which == KEY.DOWN || e.which == KEY.UP + || (e.which == KEY.ENTER && this.opts.openOnEnter)) { + + if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return; + + this.open(); + killEvent(e); + return; + } + + if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { + if (this.opts.allowClear) { + this.clear(); + } + killEvent(e); + return; + } + })); + + + installKeyUpChangeEvent(this.focusser); + this.focusser.on("keyup-change input", this.bind(function(e) { + if (this.opts.minimumResultsForSearch >= 0) { + e.stopPropagation(); + if (this.opened()) return; + this.open(); + } + })); + + selection.on("mousedown touchstart", "abbr", this.bind(function (e) { + if (!this.isInterfaceEnabled()) { + return; + } + + this.clear(); + killEventImmediately(e); + this.close(); + + if (this.selection) { + this.selection.focus(); + } + })); + + selection.on("mousedown touchstart", this.bind(function (e) { + // Prevent IE from generating a click event on the body + reinsertElement(selection); + + if (!this.container.hasClass("select2-container-active")) { + this.opts.element.trigger($.Event("select2-focus")); + } + + if (this.opened()) { + this.close(); + } else if (this.isInterfaceEnabled()) { + this.open(); + } + + killEvent(e); + })); + + dropdown.on("mousedown touchstart", this.bind(function() { + if (this.opts.shouldFocusInput(this)) { + this.search.focus(); + } + })); + + selection.on("focus", this.bind(function(e) { + killEvent(e); + })); + + this.focusser.on("focus", this.bind(function(){ + if (!this.container.hasClass("select2-container-active")) { + this.opts.element.trigger($.Event("select2-focus")); + } + this.container.addClass("select2-container-active"); + })).on("blur", this.bind(function() { + if (!this.opened()) { + this.container.removeClass("select2-container-active"); + this.opts.element.trigger($.Event("select2-blur")); + } + })); + this.search.on("focus", this.bind(function(){ + if (!this.container.hasClass("select2-container-active")) { + this.opts.element.trigger($.Event("select2-focus")); + } + this.container.addClass("select2-container-active"); + })); + + this.initContainerWidth(); + this.opts.element.hide(); + this.setPlaceholder(); + + }, + + // single + clear: function(triggerChange) { + var data=this.selection.data("select2-data"); + if (data) { // guard against queued quick consecutive clicks + var evt = $.Event("select2-clearing"); + this.opts.element.trigger(evt); + if (evt.isDefaultPrevented()) { + return; + } + var placeholderOption = this.getPlaceholderOption(); + this.opts.element.val(placeholderOption ? placeholderOption.val() : ""); + this.selection.find(".select2-chosen").empty(); + this.selection.removeData("select2-data"); + this.setPlaceholder(); + + if (triggerChange !== false){ + this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); + this.triggerChange({removed:data}); + } + } + }, + + /** + * Sets selection based on source element's value + */ + // single + initSelection: function () { + var selected; + if (this.isPlaceholderOptionSelected()) { + this.updateSelection(null); + this.close(); + this.setPlaceholder(); + } else { + var self = this; + this.opts.initSelection.call(null, this.opts.element, function(selected){ + if (selected !== undefined && selected !== null) { + self.updateSelection(selected); + self.close(); + self.setPlaceholder(); + self.lastSearchTerm = self.search.val(); + } + }); + } + }, + + isPlaceholderOptionSelected: function() { + var placeholderOption; + if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered + return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected")) + || (this.opts.element.val() === "") + || (this.opts.element.val() === undefined) + || (this.opts.element.val() === null); + }, + + // single + prepareOpts: function () { + var opts = this.parent.prepareOpts.apply(this, arguments), + self=this; + + if (opts.element.get(0).tagName.toLowerCase() === "select") { + // install the selection initializer + opts.initSelection = function (element, callback) { + var selected = element.find("option").filter(function() { return this.selected && !this.disabled }); + // a single select box always has a value, no need to null check 'selected' + callback(self.optionToData(selected)); + }; + } else if ("data" in opts) { + // install default initSelection when applied to hidden input and data is local + opts.initSelection = opts.initSelection || function (element, callback) { + var id = element.val(); + //search in data by id, storing the actual matching item + var match = null; + opts.query({ + matcher: function(term, text, el){ + var is_match = equal(id, opts.id(el)); + if (is_match) { + match = el; + } + return is_match; + }, + callback: !$.isFunction(callback) ? $.noop : function() { + callback(match); + } + }); + }; + } + + return opts; + }, + + // single + getPlaceholder: function() { + // if a placeholder is specified on a single select without a valid placeholder option ignore it + if (this.select) { + if (this.getPlaceholderOption() === undefined) { + return undefined; + } + } + + return this.parent.getPlaceholder.apply(this, arguments); + }, + + // single + setPlaceholder: function () { + var placeholder = this.getPlaceholder(); + + if (this.isPlaceholderOptionSelected() && placeholder !== undefined) { + + // check for a placeholder option if attached to a select + if (this.select && this.getPlaceholderOption() === undefined) return; + + this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder)); + + this.selection.addClass("select2-default"); + + this.container.removeClass("select2-allowclear"); + } + }, + + // single + postprocessResults: function (data, initial, noHighlightUpdate) { + var selected = 0, self = this, showSearchInput = true; + + // find the selected element in the result list + + this.findHighlightableChoices().each2(function (i, elm) { + if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { + selected = i; + return false; + } + }); + + // and highlight it + if (noHighlightUpdate !== false) { + if (initial === true && selected >= 0) { + this.highlight(selected); + } else { + this.highlight(0); + } + } + + // hide the search box if this is the first we got the results and there are enough of them for search + + if (initial === true) { + var min = this.opts.minimumResultsForSearch; + if (min >= 0) { + this.showSearch(countResults(data.results) >= min); + } + } + }, + + // single + showSearch: function(showSearchInput) { + if (this.showSearchInput === showSearchInput) return; + + this.showSearchInput = showSearchInput; + + this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput); + this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput); + //add "select2-with-searchbox" to the container if search box is shown + $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput); + }, + + // single + onSelect: function (data, options) { + + if (!this.triggerSelect(data)) { return; } + + var old = this.opts.element.val(), + oldData = this.data(); + + this.opts.element.val(this.id(data)); + this.updateSelection(data); + + this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data }); + + this.lastSearchTerm = this.search.val(); + this.close(); + + if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) { + this.focusser.focus(); + } + + if (!equal(old, this.id(data))) { + this.triggerChange({ added: data, removed: oldData }); + } + }, + + // single + updateSelection: function (data) { + + var container=this.selection.find(".select2-chosen"), formatted, cssClass; + + this.selection.data("select2-data", data); + + container.empty(); + if (data !== null) { + formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup); + } + if (formatted !== undefined) { + container.append(formatted); + } + cssClass=this.opts.formatSelectionCssClass(data, container); + if (cssClass !== undefined) { + container.addClass(cssClass); + } + + this.selection.removeClass("select2-default"); + + if (this.opts.allowClear && this.getPlaceholder() !== undefined) { + this.container.addClass("select2-allowclear"); + } + }, + + // single + val: function () { + var val, + triggerChange = false, + data = null, + self = this, + oldData = this.data(); + + if (arguments.length === 0) { + return this.opts.element.val(); + } + + val = arguments[0]; + + if (arguments.length > 1) { + triggerChange = arguments[1]; + + if (this.opts.debug && console && console.warn) { + console.warn( + 'Select2: The second option to `select2("val")` is not supported in Select2 4.0.0. ' + + 'The `change` event will always be triggered in 4.0.0.' + ); + } + } + + if (this.select) { + if (this.opts.debug && console && console.warn) { + console.warn( + 'Select2: Setting the value on a <select> using `select2("val")` is no longer supported in 4.0.0. ' + + 'You can use the `.val(newValue).trigger("change")` method provided by jQuery instead.' + ); + } + + this.select + .val(val) + .find("option").filter(function() { return this.selected }).each2(function (i, elm) { + data = self.optionToData(elm); + return false; + }); + this.updateSelection(data); + this.setPlaceholder(); + if (triggerChange) { + this.triggerChange({added: data, removed:oldData}); + } + } else { + // val is an id. !val is true for [undefined,null,'',0] - 0 is legal + if (!val && val !== 0) { + this.clear(triggerChange); + return; + } + if (this.opts.initSelection === undefined) { + throw new Error("cannot call val() if initSelection() is not defined"); + } + this.opts.element.val(val); + this.opts.initSelection(this.opts.element, function(data){ + self.opts.element.val(!data ? "" : self.id(data)); + self.updateSelection(data); + self.setPlaceholder(); + if (triggerChange) { + self.triggerChange({added: data, removed:oldData}); + } + }); + } + }, + + // single + clearSearch: function () { + this.search.val(""); + this.focusser.val(""); + }, + + // single + data: function(value) { + var data, + triggerChange = false; + + if (arguments.length === 0) { + data = this.selection.data("select2-data"); + if (data == undefined) data = null; + return data; + } else { + if (this.opts.debug && console && console.warn) { + console.warn( + 'Select2: The `select2("data")` method can no longer set selected values in 4.0.0, ' + + 'consider using the `.val()` method instead.' + ); + } + + if (arguments.length > 1) { + triggerChange = arguments[1]; + } + if (!value) { + this.clear(triggerChange); + } else { + data = this.data(); + this.opts.element.val(!value ? "" : this.id(value)); + this.updateSelection(value); + if (triggerChange) { + this.triggerChange({added: value, removed:data}); + } + } + } + } + }); + + MultiSelect2 = clazz(AbstractSelect2, { + + // multi + createContainer: function () { + var container = $(document.createElement("div")).attr({ + "class": "select2-container select2-container-multi" + }).html([ + "<ul class='select2-choices'>", + " <li class='select2-search-field'>", + " <label for='' class='select2-offscreen'></label>", + " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>", + " </li>", + "</ul>", + "<div class='select2-drop select2-drop-multi select2-display-none'>", + " <ul class='select2-results'>", + " </ul>", + "</div>"].join("")); + return container; + }, + + // multi + prepareOpts: function () { + var opts = this.parent.prepareOpts.apply(this, arguments), + self=this; + + // TODO validate placeholder is a string if specified + if (opts.element.get(0).tagName.toLowerCase() === "select") { + // install the selection initializer + opts.initSelection = function (element, callback) { + + var data = []; + + element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) { + data.push(self.optionToData(elm)); + }); + callback(data); + }; + } else if ("data" in opts) { + // install default initSelection when applied to hidden input and data is local + opts.initSelection = opts.initSelection || function (element, callback) { + var ids = splitVal(element.val(), opts.separator, opts.transformVal); + //search in data by array of ids, storing matching items in a list + var matches = []; + opts.query({ + matcher: function(term, text, el){ + var is_match = $.grep(ids, function(id) { + return equal(id, opts.id(el)); + }).length; + if (is_match) { + matches.push(el); + } + return is_match; + }, + callback: !$.isFunction(callback) ? $.noop : function() { + // reorder matches based on the order they appear in the ids array because right now + // they are in the order in which they appear in data array + var ordered = []; + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + for (var j = 0; j < matches.length; j++) { + var match = matches[j]; + if (equal(id, opts.id(match))) { + ordered.push(match); + matches.splice(j, 1); + break; + } + } + } + callback(ordered); + } + }); + }; + } + + return opts; + }, + + // multi + selectChoice: function (choice) { + + var selected = this.container.find(".select2-search-choice-focus"); + if (selected.length && choice && choice[0] == selected[0]) { + + } else { + if (selected.length) { + this.opts.element.trigger("choice-deselected", selected); + } + selected.removeClass("select2-search-choice-focus"); + if (choice && choice.length) { + this.close(); + choice.addClass("select2-search-choice-focus"); + this.opts.element.trigger("choice-selected", choice); + } + } + }, + + // multi + destroy: function() { + $("label[for='" + this.search.attr('id') + "']") + .attr('for', this.opts.element.attr("id")); + this.parent.destroy.apply(this, arguments); + + cleanupJQueryElements.call(this, + "searchContainer", + "selection" + ); + }, + + // multi + initContainer: function () { + + var selector = ".select2-choices", selection; + + this.searchContainer = this.container.find(".select2-search-field"); + this.selection = selection = this.container.find(selector); + + var _this = this; + this.selection.on("click", ".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)", function (e) { + _this.search[0].focus(); + _this.selectChoice($(this)); + }); + + // rewrite labels from original element to focusser + this.search.attr("id", "s2id_autogen"+nextUid()); + + this.search.prev() + .text($("label[for='" + this.opts.element.attr("id") + "']").text()) + .attr('for', this.search.attr('id')); + this.opts.element.on('focus.select2', this.bind(function () { this.focus(); })); + + this.search.on("input paste", this.bind(function() { + if (this.search.attr('placeholder') && this.search.val().length == 0) return; + if (!this.isInterfaceEnabled()) return; + if (!this.opened()) { + this.open(); + } + })); + + this.search.attr("tabindex", this.elementTabIndex); + + this.keydowns = 0; + this.search.on("keydown", this.bind(function (e) { + if (!this.isInterfaceEnabled()) return; + + ++this.keydowns; + var selected = selection.find(".select2-search-choice-focus"); + var prev = selected.prev(".select2-search-choice:not(.select2-locked)"); + var next = selected.next(".select2-search-choice:not(.select2-locked)"); + var pos = getCursorInfo(this.search); + + if (selected.length && + (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) { + var selectedChoice = selected; + if (e.which == KEY.LEFT && prev.length) { + selectedChoice = prev; + } + else if (e.which == KEY.RIGHT) { + selectedChoice = next.length ? next : null; + } + else if (e.which === KEY.BACKSPACE) { + if (this.unselect(selected.first())) { + this.search.width(10); + selectedChoice = prev.length ? prev : next; + } + } else if (e.which == KEY.DELETE) { + if (this.unselect(selected.first())) { + this.search.width(10); + selectedChoice = next.length ? next : null; + } + } else if (e.which == KEY.ENTER) { + selectedChoice = null; + } + + this.selectChoice(selectedChoice); + killEvent(e); + if (!selectedChoice || !selectedChoice.length) { + this.open(); + } + return; + } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1) + || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) { + + this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last()); + killEvent(e); + return; + } else { + this.selectChoice(null); + } + + if (this.opened()) { + switch (e.which) { + case KEY.UP: + case KEY.DOWN: + this.moveHighlight((e.which === KEY.UP) ? -1 : 1); + killEvent(e); + return; + case KEY.ENTER: + this.selectHighlighted(); + killEvent(e); + return; + case KEY.TAB: + this.selectHighlighted({noFocus:true}); + this.close(); + return; + case KEY.ESC: + this.cancel(e); + killEvent(e); + return; + } + } + + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) + || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { + return; + } + + if (e.which === KEY.ENTER) { + if (this.opts.openOnEnter === false) { + return; + } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { + return; + } + } + + this.open(); + + if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { + // prevent the page from scrolling + killEvent(e); + } + + if (e.which === KEY.ENTER) { + // prevent form from being submitted + killEvent(e); + } + + })); + + this.search.on("keyup", this.bind(function (e) { + this.keydowns = 0; + this.resizeSearch(); + }) + ); + + this.search.on("blur", this.bind(function(e) { + this.container.removeClass("select2-container-active"); + this.search.removeClass("select2-focused"); + this.selectChoice(null); + if (!this.opened()) this.clearSearch(); + e.stopImmediatePropagation(); + this.opts.element.trigger($.Event("select2-blur")); + })); + + this.container.on("click", selector, this.bind(function (e) { + if (!this.isInterfaceEnabled()) return; + if ($(e.target).closest(".select2-search-choice").length > 0) { + // clicked inside a select2 search choice, do not open + return; + } + this.selectChoice(null); + this.clearPlaceholder(); + if (!this.container.hasClass("select2-container-active")) { + this.opts.element.trigger($.Event("select2-focus")); + } + this.open(); + this.focusSearch(); + e.preventDefault(); + })); + + this.container.on("focus", selector, this.bind(function () { + if (!this.isInterfaceEnabled()) return; + if (!this.container.hasClass("select2-container-active")) { + this.opts.element.trigger($.Event("select2-focus")); + } + this.container.addClass("select2-container-active"); + this.dropdown.addClass("select2-drop-active"); + this.clearPlaceholder(); + })); + + this.initContainerWidth(); + this.opts.element.hide(); + + // set the placeholder if necessary + this.clearSearch(); + }, + + // multi + enableInterface: function() { + if (this.parent.enableInterface.apply(this, arguments)) { + this.search.prop("disabled", !this.isInterfaceEnabled()); + } + }, + + // multi + initSelection: function () { + var data; + if (this.opts.element.val() === "" && this.opts.element.text() === "") { + this.updateSelection([]); + this.close(); + // set the placeholder if necessary + this.clearSearch(); + } + if (this.select || this.opts.element.val() !== "") { + var self = this; + this.opts.initSelection.call(null, this.opts.element, function(data){ + if (data !== undefined && data !== null) { + self.updateSelection(data); + self.close(); + // set the placeholder if necessary + self.clearSearch(); + } + }); + } + }, + + // multi + clearSearch: function () { + var placeholder = this.getPlaceholder(), + maxWidth = this.getMaxSearchWidth(); + + if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { + this.search.val(placeholder).addClass("select2-default"); + // stretch the search box to full width of the container so as much of the placeholder is visible as possible + // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944 + this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width")); + } else { + this.search.val("").width(10); + } + }, + + // multi + clearPlaceholder: function () { + if (this.search.hasClass("select2-default")) { + this.search.val("").removeClass("select2-default"); + } + }, + + // multi + opening: function () { + this.clearPlaceholder(); // should be done before super so placeholder is not used to search + this.resizeSearch(); + + this.parent.opening.apply(this, arguments); + + this.focusSearch(); + + this.prefillNextSearchTerm(); + this.updateResults(true); + + if (this.opts.shouldFocusInput(this)) { + this.search.focus(); + } + this.opts.element.trigger($.Event("select2-open")); + }, + + // multi + close: function () { + if (!this.opened()) return; + this.parent.close.apply(this, arguments); + }, + + // multi + focus: function () { + this.close(); + this.search.focus(); + }, + + // multi + isFocused: function () { + return this.search.hasClass("select2-focused"); + }, + + // multi + updateSelection: function (data) { + var ids = {}, filtered = [], self = this; + + // filter out duplicates + $(data).each(function () { + if (!(self.id(this) in ids)) { + ids[self.id(this)] = 0; + filtered.push(this); + } + }); + + this.selection.find(".select2-search-choice").remove(); + this.addSelectedChoice(filtered); + self.postprocessResults(); + }, + + // multi + tokenize: function() { + var input = this.search.val(); + input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts); + if (input != null && input != undefined) { + this.search.val(input); + if (input.length > 0) { + this.open(); + } + } + + }, + + // multi + onSelect: function (data, options) { + + if (!this.triggerSelect(data) || data.text === "") { return; } + + this.addSelectedChoice(data); + + this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); + + // keep track of the search's value before it gets cleared + this.lastSearchTerm = this.search.val(); + + this.clearSearch(); + this.updateResults(); + + if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true); + + if (this.opts.closeOnSelect) { + this.close(); + this.search.width(10); + } else { + if (this.countSelectableResults()>0) { + this.search.width(10); + this.resizeSearch(); + if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) { + // if we reached max selection size repaint the results so choices + // are replaced with the max selection reached message + this.updateResults(true); + } else { + // initializes search's value with nextSearchTerm and update search result + if (this.prefillNextSearchTerm()) { + this.updateResults(); + } + } + this.positionDropdown(); + } else { + // if nothing left to select close + this.close(); + this.search.width(10); + } + } + + // since its not possible to select an element that has already been + // added we do not need to check if this is a new element before firing change + this.triggerChange({ added: data }); + + if (!options || !options.noFocus) + this.focusSearch(); + }, + + // multi + cancel: function () { + this.close(); + this.focusSearch(); + }, + + addSelectedChoice: function (data) { + var val = this.getVal(), self = this; + $(data).each(function () { + val.push(self.createChoice(this)); + }); + this.setVal(val); + }, + + createChoice: function (data) { + var enableChoice = !data.locked, + enabledItem = $( + "<li class='select2-search-choice'>" + + " <div></div>" + + " <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" + + "</li>"), + disabledItem = $( + "<li class='select2-search-choice select2-locked'>" + + "<div></div>" + + "</li>"); + var choice = enableChoice ? enabledItem : disabledItem, + id = this.id(data), + formatted, + cssClass; + + formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup); + if (formatted != undefined) { + choice.find("div").replaceWith($("<div></div>").html(formatted)); + } + cssClass=this.opts.formatSelectionCssClass(data, choice.find("div")); + if (cssClass != undefined) { + choice.addClass(cssClass); + } + + if(enableChoice){ + choice.find(".select2-search-choice-close") + .on("mousedown", killEvent) + .on("click dblclick", this.bind(function (e) { + if (!this.isInterfaceEnabled()) return; + + this.unselect($(e.target)); + this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); + killEvent(e); + this.close(); + this.focusSearch(); + })).on("focus", this.bind(function () { + if (!this.isInterfaceEnabled()) return; + this.container.addClass("select2-container-active"); + this.dropdown.addClass("select2-drop-active"); + })); + } + + choice.data("select2-data", data); + choice.insertBefore(this.searchContainer); + + return id; + }, + + // multi + unselect: function (selected) { + var val = this.getVal(), + data, + index; + selected = selected.closest(".select2-search-choice"); + + if (selected.length === 0) { + throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; + } + + data = selected.data("select2-data"); + + if (!data) { + // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued + // and invoked on an element already removed + return; + } + + var evt = $.Event("select2-removing"); + evt.val = this.id(data); + evt.choice = data; + this.opts.element.trigger(evt); + + if (evt.isDefaultPrevented()) { + return false; + } + + while((index = indexOf(this.id(data), val)) >= 0) { + val.splice(index, 1); + this.setVal(val); + if (this.select) this.postprocessResults(); + } + + selected.remove(); + + this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); + this.triggerChange({ removed: data }); + + return true; + }, + + // multi + postprocessResults: function (data, initial, noHighlightUpdate) { + var val = this.getVal(), + choices = this.results.find(".select2-result"), + compound = this.results.find(".select2-result-with-children"), + self = this; + + choices.each2(function (i, choice) { + var id = self.id(choice.data("select2-data")); + if (indexOf(id, val) >= 0) { + choice.addClass("select2-selected"); + // mark all children of the selected parent as selected + choice.find(".select2-result-selectable").addClass("select2-selected"); + } + }); + + compound.each2(function(i, choice) { + // hide an optgroup if it doesn't have any selectable children + if (!choice.is('.select2-result-selectable') + && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) { + choice.addClass("select2-selected"); + } + }); + + if (this.highlight() == -1 && noHighlightUpdate !== false && this.opts.closeOnSelect === true){ + self.highlight(0); + } + + //If all results are chosen render formatNoMatches + if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){ + if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) { + if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) { + this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.opts.element, self.search.val()) + "</li>"); + } + } + } + + }, + + // multi + getMaxSearchWidth: function() { + return this.selection.width() - getSideBorderPadding(this.search); + }, + + // multi + resizeSearch: function () { + var minimumWidth, left, maxWidth, containerLeft, searchWidth, + sideBorderPadding = getSideBorderPadding(this.search); + + minimumWidth = measureTextWidth(this.search) + 10; + + left = this.search.offset().left; + + maxWidth = this.selection.width(); + containerLeft = this.selection.offset().left; + + searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; + + if (searchWidth < minimumWidth) { + searchWidth = maxWidth - sideBorderPadding; + } + + if (searchWidth < 40) { + searchWidth = maxWidth - sideBorderPadding; + } + + if (searchWidth <= 0) { + searchWidth = minimumWidth; + } + + this.search.width(Math.floor(searchWidth)); + }, + + // multi + getVal: function () { + var val; + if (this.select) { + val = this.select.val(); + return val === null ? [] : val; + } else { + val = this.opts.element.val(); + return splitVal(val, this.opts.separator, this.opts.transformVal); + } + }, + + // multi + setVal: function (val) { + if (this.select) { + this.select.val(val); + } else { + var unique = [], valMap = {}; + // filter out duplicates + $(val).each(function () { + if (!(this in valMap)) { + unique.push(this); + valMap[this] = 0; + } + }); + this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); + } + }, + + // multi + buildChangeDetails: function (old, current) { + var current = current.slice(0), + old = old.slice(0); + + // remove intersection from each array + for (var i = 0; i < current.length; i++) { + for (var j = 0; j < old.length; j++) { + if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) { + current.splice(i, 1); + i--; + old.splice(j, 1); + break; + } + } + } + + return {added: current, removed: old}; + }, + + + // multi + val: function (val, triggerChange) { + var oldData, self=this; + + if (arguments.length === 0) { + return this.getVal(); + } + + oldData=this.data(); + if (!oldData.length) oldData=[]; + + // val is an id. !val is true for [undefined,null,'',0] - 0 is legal + if (!val && val !== 0) { + this.opts.element.val(""); + this.updateSelection([]); + this.clearSearch(); + if (triggerChange) { + this.triggerChange({added: this.data(), removed: oldData}); + } + return; + } + + // val is a list of ids + this.setVal(val); + + if (this.select) { + this.opts.initSelection(this.select, this.bind(this.updateSelection)); + if (triggerChange) { + this.triggerChange(this.buildChangeDetails(oldData, this.data())); + } + } else { + if (this.opts.initSelection === undefined) { + throw new Error("val() cannot be called if initSelection() is not defined"); + } + + this.opts.initSelection(this.opts.element, function(data){ + var ids=$.map(data, self.id); + self.setVal(ids); + self.updateSelection(data); + self.clearSearch(); + if (triggerChange) { + self.triggerChange(self.buildChangeDetails(oldData, self.data())); + } + }); + } + this.clearSearch(); + }, + + // multi + onSortStart: function() { + if (this.select) { + throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead."); + } + + // collapse search field into 0 width so its container can be collapsed as well + this.search.width(0); + // hide the container + this.searchContainer.hide(); + }, + + // multi + onSortEnd:function() { + + var val=[], self=this; + + // show search and move it to the end of the list + this.searchContainer.show(); + // make sure the search container is the last item in the list + this.searchContainer.appendTo(this.searchContainer.parent()); + // since we collapsed the width in dragStarted, we resize it here + this.resizeSearch(); + + // update selection + this.selection.find(".select2-search-choice").each(function() { + val.push(self.opts.id($(this).data("select2-data"))); + }); + this.setVal(val); + this.triggerChange(); + }, + + // multi + data: function(values, triggerChange) { + var self=this, ids, old; + if (arguments.length === 0) { + return this.selection + .children(".select2-search-choice") + .map(function() { return $(this).data("select2-data"); }) + .get(); + } else { + old = this.data(); + if (!values) { values = []; } + ids = $.map(values, function(e) { return self.opts.id(e); }); + this.setVal(ids); + this.updateSelection(values); + this.clearSearch(); + if (triggerChange) { + this.triggerChange(this.buildChangeDetails(old, this.data())); + } + } + } + }); + + $.fn.select2 = function () { + + var args = Array.prototype.slice.call(arguments, 0), + opts, + select2, + method, value, multiple, + allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"], + valueMethods = ["opened", "isFocused", "container", "dropdown"], + propertyMethods = ["val", "data"], + methodsMap = { search: "externalSearch" }; + + this.each(function () { + if (args.length === 0 || typeof(args[0]) === "object") { + opts = args.length === 0 ? {} : $.extend({}, args[0]); + opts.element = $(this); + + if (opts.element.get(0).tagName.toLowerCase() === "select") { + multiple = opts.element.prop("multiple"); + } else { + multiple = opts.multiple || false; + if ("tags" in opts) {opts.multiple = multiple = true;} + } + + select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single(); + select2.init(opts); + } else if (typeof(args[0]) === "string") { + + if (indexOf(args[0], allowedMethods) < 0) { + throw "Unknown method: " + args[0]; + } + + value = undefined; + select2 = $(this).data("select2"); + if (select2 === undefined) return; + + method=args[0]; + + if (method === "container") { + value = select2.container; + } else if (method === "dropdown") { + value = select2.dropdown; + } else { + if (methodsMap[method]) method = methodsMap[method]; + + value = select2[method].apply(select2, args.slice(1)); + } + if (indexOf(args[0], valueMethods) >= 0 + || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) { + return false; // abort the iteration, ready to return first matched value + } + } else { + throw "Invalid arguments to select2 plugin: " + args; + } + }); + return (value === undefined) ? this : value; + }; + + // plugin defaults, accessible to users + $.fn.select2.defaults = { + debug: false, + width: "copy", + loadMorePadding: 0, + closeOnSelect: true, + openOnEnter: true, + containerCss: {}, + dropdownCss: {}, + containerCssClass: "", + dropdownCssClass: "", + formatResult: function(result, container, query, escapeMarkup) { + var markup=[]; + markMatch(this.text(result), query.term, markup, escapeMarkup); + return markup.join(""); + }, + transformVal: function(val) { + return $.trim(val); + }, + formatSelection: function (data, container, escapeMarkup) { + return data ? escapeMarkup(this.text(data)) : undefined; + }, + sortResults: function (results, container, query) { + return results; + }, + formatResultCssClass: function(data) {return data.css;}, + formatSelectionCssClass: function(data, container) {return undefined;}, + minimumResultsForSearch: 0, + minimumInputLength: 0, + maximumInputLength: null, + maximumSelectionSize: 0, + id: function (e) { return e == undefined ? null : e.id; }, + text: function (e) { + if (e && this.data && this.data.text) { + if ($.isFunction(this.data.text)) { + return this.data.text(e); + } else { + return e[this.data.text]; + } + } else { + return e.text; + } + }, + matcher: function(term, text) { + return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0; + }, + separator: ",", + tokenSeparators: [], + tokenizer: defaultTokenizer, + escapeMarkup: defaultEscapeMarkup, + blurOnChange: false, + selectOnBlur: false, + adaptContainerCssClass: function(c) { return c; }, + adaptDropdownCssClass: function(c) { return null; }, + nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; }, + searchInputPlaceholder: '', + createSearchChoicePosition: 'top', + shouldFocusInput: function (instance) { + // Attempt to detect touch devices + var supportsTouchEvents = (('ontouchstart' in window) || + (navigator.msMaxTouchPoints > 0)); + + // Only devices which support touch events should be special cased + if (!supportsTouchEvents) { + return true; + } + + // Never focus the input if search is disabled + if (instance.opts.minimumResultsForSearch < 0) { + return false; + } + + return true; + } + }; + + $.fn.select2.locales = []; + + $.fn.select2.locales['en'] = { + formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; }, + formatNoMatches: function () { return "No matches found"; }, + formatAjaxError: function (jqXHR, textStatus, errorThrown) { return "Loading failed"; }, + formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); }, + formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); }, + formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, + formatLoadMore: function (pageNumber) { return "Loading more results…"; }, + formatSearching: function () { return "Searching…"; } + }; + + $.extend($.fn.select2.defaults, $.fn.select2.locales['en']); + + $.fn.select2.ajaxDefaults = { + transport: $.ajax, + params: { + type: "GET", + cache: false, + dataType: "json" + } + }; + + // exports + window.Select2 = { + query: { + ajax: ajax, + local: local, + tags: tags + }, util: { + debounce: debounce, + markMatch: markMatch, + escapeMarkup: defaultEscapeMarkup, + stripDiacritics: stripDiacritics + }, "class": { + "abstract": AbstractSelect2, + "single": SingleSelect2, + "multi": MultiSelect2 + } + }; + +}(jQuery)); \ No newline at end of file diff --git a/rhodecode/public/sounds/chat_pop.mp3 b/rhodecode/public/sounds/chat_pop.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..4ac7b051488e5ea99500c55414d1d02fc6b869fe GIT binary patch literal 2807 zc%1WeF=k-^0uF{zFbYP&$OZp@8yvw9jL6JO2U6@n%*4RJ_LiZa5O_&3!0NUOK)115 zFb8iDU|`X*dR1=P;Mp0Q+M_h3V+w2Yv*#=iexE+bJi+la`@IddKRs%8|45#~VrZdI z{6m4GkRkbh6W>3H|2#zvjVEfJ|48U?$d(jdx!5SsjZ0y|q&rM3I#+TVIt)A=9=w~? z)T<-m$Ir0JBV%^M1T_VVB(*sUgdRN7`dW2dp|yxJ=$Gk4m-(q0-Fgw6$C<ev9TKUl zJt`3td1Su$rBJ`e##1y`%vyEhhq#<c*Ch^d`%}@Ox9&z|ttqxqyYFT=cUO$zA?eJI zr}eI?3j4Ib_0WB&Rj{PAGN?`F?z>|tmY2O3{_MCa(>8m`mSCf->XNC8b~tZ;{k$wV z&a}mJ<%_g;LN7!9)@a>3U9xN5)_D?tYs$l}2z!<l-M7B;yT88T%(0?gx9#h$J-Ir! zKH2P5(A~q~JJa|7IX?G444mHDX0maT-ShwdKa|Z=bJw~bx=LATl}KT`u*=?D^VynA z3@11Rx+ivrv%9NE2!y45w+JcAd!(^2WKl}Wl!JHYq`A3CwAiI?m^jsmVcCui44a!y zHZNv5vGzeo<Az;+m9E@tyc`4zm{uB03}mq7=9{50LwnM12MwiyrS2NME3+n6UT13b znci6Jb1`=74JM8#?Ho~sIW2!njx#wLZJp4manx2c(A)dCLdv;K6-LjJX0Cbqx$3Bc zlxsrwR*l4!A?KMJL*IABh}*`m;VitmPNIKFMMENo=Bj7Ql>Ub6{VG|(wA@wP^So}f zdO^$srYyb{++S1oR?OXz*ygn?d8&rI#F}$vkNW@Qg{*ur&tvV5%I9fkR`E2c8rhwE zeS2lQ_OUhBrUswZ{jU4;{N8)TQ;XgOPud;+bW_EddC`h<_A_`E?Jd{-@i*t+GTHOC z*|FdNy=MDv_w?`FKVR<*e`gC4_;*-j`+JW}wbYUcSJDGk9KGptV`9Th&lW4KNk?wJ z(B<tos95mfK!h7Fht{?S4>;Q!)5M#CX5`qMYFzNxv1?L=o3fN_8~eN~z1{~z9Tu~) zXcS#C{j@kRHFs;vibhEj*Fz!#rHgWRwDg}5+A?)+jK;x4Z^6Ie9uXTS@60xzI8(W} zd_&-r+`<Q$O!t%5Uei?DE4l1#w6I@D*Z<!ej(lm*3DdRxd8WZ-jotJ8mQ4(~zovU7 zK5eUg_~Z0z_WRR}*ZN#}tFx~0*`fv6g6z#)7mvTYGx0;V*!>lIOh2yP;9M)VWa6$e zX%lAMZC_kc10zr7th_bx#C%WVyZSwz>T8Y^AGTSYy1MYphpU+}+7rAND<1sSu<^9^ zjk0^Or)|pnvqLsd+y6TGXZHWs4nKneFGU{<uIf5^s(PpIX+2MHaDIMPbMNQ6&-JZ; z?5FS9xom})oY8|<x8MJra<?Frp;PQ)q1)^unwdh1N;!J2Cr^5{9kA@Yq;NoC?F_ax zt5#K>f3^SLYWr2!mE3)mIujr6|9_>ztGu&fiW%3=2P-~YO?O%M|468hqpz#6o~5Op hY3L}RDF9U{cbHGEDOKI`8B~ayG%zr*478)5003dyD<A*> diff --git a/rhodecode/public/sounds/chat_pop.wav b/rhodecode/public/sounds/chat_pop.wav new file mode 100644 index 0000000000000000000000000000000000000000..1fe35080cb9e9c46ce492406f841615a18053181 GIT binary patch literal 3318 zc$__!Ns{Bp5k+GJGu73yK7y{Ih1yJ8E!68alWC`2RVR~}CuZM8m(W_L&<V8ZOeO)u zpy!cQGMED(h=}k0|92<<^5-9a{O>2Fe){8I|Md5NeE!1^N-53ppMNU#ub;Fs>Ie0= zpFjWnZ{Eo{=A2VGf82e$S1OisD0lKa=a98J^2oD3xB1wPL%CkX7}c0}wdjrSJJqTo z*J_Bj_bwbM?w2DRA@p|fdp0^dWq2p^B=5)Nb_rc>6T9otL}Og9FGsySv-hakCDqE> z*5tH>yx+rY8Z)X!TN|x)tx>90GwUX&TsGNG`W~&?wb2L9gVv_A?5jt0i9HBUTf5b2 z)Jb<LrB)B>ApIDgk9b^;V?Xw7tM5-++Mf=c4((j)Pmku)uiv}xtM8UiFTZ!+*$4YD zo=i2m-g|$sSJ(K}b(K4*YCcU5{!u-yRr1y2@ZeACVSUKeT18*^#%a^4Y(^VlzJ~6Q zQ#y`INMQ?oJO{ze$9+Gx^L>ARdcVKjUq8P-|MvN}_t*37e7oPy@7w$N{eIiuZ||4e z``a(K%k7uj^V^r#r`M;q^X=(&fBo{hz1>)OD^KpX=lf;bw#!~0P1wQOBeIafMa_C6 zYBRx6rw1L1BO->WmDT~q;MgQRh&Hx17XFnTZRbXBs_YjZ-Ryfm`N5B#`m3Rus<ARB zeVXB5@vU22Q^LBAceA%u3va<W*Pu<ueyu6m+kiPEnjLCXJM7eX$d|10hW*;yz*R_1 z>e3~3aSu&wVw;ZC^Uj!`i9L5Y@=ho3<sP4kXT{N7u2YN$bw9^G+=7lzao|3}dlxp; zzZ2Wha_zzs-`~Q(wF}S0S+225Eyx2XgGzW%<FNtOI^3jevJ-wV)Nd+P!G#~CUe`JU zGr~l6J)di9ZDXXyvL64A>Y1LrNEgI2*_BN8eLv`$J+!f=&Lh-O?j+w7YcgrbqSnS7 zdejZPwYn#dtUEK<!HF6Ya@OcG`$Qg@NaPUcon!~w8P=$V`LM%T18c%hrtbduviIBP zt=r!2&3508?Rm#P`+0AOu)S{$(F$Wx*7f-)Q$wajjeB4RMMpA8Mf=%ho2_z#&89b! zrF21OmCc&WnFlr4bqt{n4N-?!nBR`(fC}cph1j=x-}V+RM9YZ!4XVl~<_UbX@Q_Vn zXC?vcJKQ%psekp2_xN?LbOkRZ54@&8COQ?1bB@@@dyv5<r~=$D724x`bVSR1*!I9v z>7yXZB<Wz8njL%KH#N~SGMi?!HZTviGt@rWUJ$Le37;o36y^uj$P9=f_F(5ylQ_Gl z?oe`w1+hLrJdPuR*+fBZ1sT>srRL5sBQ3Mat%OHkSG<;CAQ8%ID%Nn_)8kBQmC9_# zL()@p1)UUv%xO>(W01+sJUSxtHw{Vh3pl@_gqk^jF%S0H{%Uvo0`5$0#%YepjU1wN zc?KSn7B_St3SLVuN1*FC1ZG~r>p;s)KzX95UE%ePCT__}s#Nsaghv))l>M}0COP(> zEw_S-izd`mX4Dx@bC&2~Hhtty*RUUMszIqk4#Hy(-y!N$M}_x$kXXUWK~Hq_f{qox z9}cAq^KQnwp1Qp2t+NAIbE&EaZ&a$_4ImEqaez%71uKLh3X)_nplyl<#~QrWGp*!j zc|tt{hQ}QX*U`+(26^ImvU1hNqS(qToAH@NvxO<NP}e}awYar`zr=ZjNfSiBfeJPK zG@zMMlgi3blhpG7cOExRb|EaiIZ>B#FX-lA(xTc7{>XHjsm>~RNn_&2GAJCPLVNUd zf(j9omKt+8ddUVRL1YN^<T-$=sc&WyNU$-idFqj8J*^?U&G^CPF4@$?8LlRjA5dzb z2N)?w&sD+S2zL%IR&Y0#-Hl$Ec2}dR#Pi$Y@c!)hVe#eUtv}J{5BOuHsu^}QW+5YL z>axciHd7gSvp4e|gN88*YbzQFjw8PXq!pcJoWP$GYM4w#DJ#2G)N^8%!Kr@0c~X&8 zeZEptmDvN0d}^tyFLha5Fc;O9DBpBcu5nGp40<Gi6TMj#lo{nGbHxoWgy)GiSG@1E zCI1<#yMiNi^mrjhi$XdX&L&OhHKE!yNggUs@MTzKVN9|%?7n<Gob~wm18t(3LBEiN zNBap3!~eR49I+y2lV|p~DC`PLf;^-dKTo_R`3!I-D;Ka9I9t(w)xtWp!J}~R%AShM zWi9Q@Ze3iNd;BSi=KnFm*#LKfs7qBg%Sx$cDJZLqQ*t#R_=2Hyr3*TlFT5@MI<P)+ z6<#Fch3i~m;xN21(p%)EuEH%DFB~2fuEa}G!&~7@lyEROeSK&BiY>XAQrQ(AUWk=E zXO54v@F!QJd|^j)bVW^HSTf{3>Z`b{97bQ2=)97XXJ5_P6g?^?_apv&DSQjo0G4#b z%H5T2_i8R2$=jZP;xGJD{~hLjDOG+P1|H>`lupFQUc#-gHo=4~hwQMHe3!zu+^zJ( z13X{Lr*9d`dmlM|tXhgAWJi7iP&yZ!s$}4mDm8uVJE|9U6y;7-ZE>I6X>>Gj^Nl5^ S1xvE1Sp5;-ykLvcUi}YdN<7v8 diff --git a/rhodecode/rcserver.py b/rhodecode/rcserver.py new file mode 100644 --- /dev/null +++ b/rhodecode/rcserver.py @@ -0,0 +1,1025 @@ +# (c) 2005 Ian Bicking and contributors; written for Paste +# (http://pythonpaste.org) Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license.php +# +# For discussion of daemonizing: +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731 +# +# Code taken also from QP: http://www.mems-exchange.org/software/qp/ From +# lib/site.py + +import atexit +import errno +import fnmatch +import logging +import optparse +import os +import re +import subprocess +import sys +import textwrap +import threading +import time +import traceback + +from logging.config import fileConfig +import ConfigParser as configparser +from paste.deploy import loadserver +from paste.deploy import loadapp + +import rhodecode +from rhodecode.lib.compat import kill + + +def make_web_build_callback(filename): + p = subprocess.Popen('make web-build', shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=os.path.dirname(os.path.dirname(__file__))) + stdout, stderr = p.communicate() + stdout = ''.join(stdout) + stderr = ''.join(stderr) + if stdout: + print stdout + if stderr: + print ('%s %s %s' % ('-' * 20, 'ERRORS', '-' * 20)) + print stderr + + +MAXFD = 1024 +HERE = os.path.dirname(os.path.abspath(__file__)) +SERVER_RUNNING_FILE = None + + +# watch those extra files for changes, server gets restarted if file changes +GLOBAL_EXTRA_FILES = { + 'rhodecode/public/css/*.less': make_web_build_callback, + 'rhodecode/public/js/src/**/*.js': make_web_build_callback, +} + + + +## HOOKS - inspired by gunicorn # + +def when_ready(server): + """ + Called just after the server is started. + """ + + def _remove_server_running_file(): + if os.path.isfile(SERVER_RUNNING_FILE): + os.remove(SERVER_RUNNING_FILE) + + if SERVER_RUNNING_FILE: + with open(SERVER_RUNNING_FILE, 'wb') as f: + f.write(str(os.getpid())) + # register cleanup of that file when server exits + atexit.register(_remove_server_running_file) + + +def setup_logging(config_uri, fileConfig=fileConfig, + configparser=configparser): + """ + Set up logging via the logging module's fileConfig function with the + filename specified via ``config_uri`` (a string in the form + ``filename#sectionname``). + + ConfigParser defaults are specified for the special ``__file__`` + and ``here`` variables, similar to PasteDeploy config loading. + """ + path, _ = _getpathsec(config_uri, None) + parser = configparser.ConfigParser() + parser.read([path]) + if parser.has_section('loggers'): + config_file = os.path.abspath(path) + return fileConfig( + config_file, + {'__file__': config_file, 'here': os.path.dirname(config_file)} + ) + + +def set_rhodecode_is_test(config_uri): + """If is_test is defined in the config file sets rhodecode.is_test.""" + path, _ = _getpathsec(config_uri, None) + parser = configparser.ConfigParser() + parser.read(path) + rhodecode.is_test = ( + parser.has_option('app:main', 'is_test') and + parser.getboolean('app:main', 'is_test')) + + +def _getpathsec(config_uri, name): + if '#' in config_uri: + path, section = config_uri.split('#', 1) + else: + path, section = config_uri, 'main' + if name: + section = name + return path, section + + +def parse_vars(args): + """ + Given variables like ``['a=b', 'c=d']`` turns it into ``{'a': + 'b', 'c': 'd'}`` + """ + result = {} + for arg in args: + if '=' not in arg: + raise ValueError( + 'Variable assignment %r invalid (no "=")' + % arg) + name, value = arg.split('=', 1) + result[name] = value + return result + + +def _match_pattern(filename): + for pattern in GLOBAL_EXTRA_FILES: + if fnmatch.fnmatch(filename, pattern): + return pattern + return False + + +def generate_extra_file_list(): + + extra_list = [] + for root, dirs, files in os.walk(HERE, topdown=True): + for fname in files: + stripped_src = os.path.join( + 'rhodecode', os.path.relpath(os.path.join(root, fname), HERE)) + + if _match_pattern(stripped_src): + extra_list.append(stripped_src) + + return extra_list + + +def run_callback_for_pattern(filename): + pattern = _match_pattern(filename) + if pattern: + _file_callback = GLOBAL_EXTRA_FILES.get(pattern) + if callable(_file_callback): + _file_callback(filename) + + +class DaemonizeException(Exception): + pass + + +class RcServerCommand(object): + + usage = '%prog config_uri [start|stop|restart|status] [var=value]' + description = """\ + This command serves a web application that uses a PasteDeploy + configuration file for the server and application. + + If start/stop/restart is given, then --daemon is implied, and it will + start (normal operation), stop (--stop-daemon), or do both. + + You can also include variable assignments like 'http_port=8080' + and then use %(http_port)s in your config files. + """ + default_verbosity = 1 + + parser = optparse.OptionParser( + usage, + description=textwrap.dedent(description) + ) + parser.add_option( + '-n', '--app-name', + dest='app_name', + metavar='NAME', + help="Load the named application (default main)") + parser.add_option( + '-s', '--server', + dest='server', + metavar='SERVER_TYPE', + help="Use the named server.") + parser.add_option( + '--server-name', + dest='server_name', + metavar='SECTION_NAME', + help=("Use the named server as defined in the configuration file " + "(default: main)")) + parser.add_option( + '--with-vcsserver', + dest='vcs_server', + action='store_true', + help=("Start the vcsserver instance together with the RhodeCode server")) + if hasattr(os, 'fork'): + parser.add_option( + '--daemon', + dest="daemon", + action="store_true", + help="Run in daemon (background) mode") + parser.add_option( + '--pid-file', + dest='pid_file', + metavar='FILENAME', + help=("Save PID to file (default to pyramid.pid if running in " + "daemon mode)")) + parser.add_option( + '--running-file', + dest='running_file', + metavar='RUNNING_FILE', + help="Create a running file after the server is initalized with " + "stored PID of process") + parser.add_option( + '--log-file', + dest='log_file', + metavar='LOG_FILE', + help="Save output to the given log file (redirects stdout)") + parser.add_option( + '--reload', + dest='reload', + action='store_true', + help="Use auto-restart file monitor") + parser.add_option( + '--reload-interval', + dest='reload_interval', + default=1, + help=("Seconds between checking files (low number can cause " + "significant CPU usage)")) + parser.add_option( + '--monitor-restart', + dest='monitor_restart', + action='store_true', + help="Auto-restart server if it dies") + parser.add_option( + '--status', + action='store_true', + dest='show_status', + help="Show the status of the (presumably daemonized) server") + parser.add_option( + '-v', '--verbose', + default=default_verbosity, + dest='verbose', + action='count', + help="Set verbose level (default "+str(default_verbosity)+")") + parser.add_option( + '-q', '--quiet', + action='store_const', + const=0, + dest='verbose', + help="Suppress verbose output") + + if hasattr(os, 'setuid'): + # I don't think these are available on Windows + parser.add_option( + '--user', + dest='set_user', + metavar="USERNAME", + help="Set the user (usually only possible when run as root)") + parser.add_option( + '--group', + dest='set_group', + metavar="GROUP", + help="Set the group (usually only possible when run as root)") + + parser.add_option( + '--stop-daemon', + dest='stop_daemon', + action='store_true', + help=('Stop a daemonized server (given a PID file, or default ' + 'pyramid.pid file)')) + + _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I) + + _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN' + _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN' + + possible_subcommands = ('start', 'stop', 'restart', 'status') + + def __init__(self, argv, quiet=False): + self.options, self.args = self.parser.parse_args(argv[1:]) + if quiet: + self.options.verbose = 0 + + def out(self, msg): # pragma: no cover + if self.options.verbose > 0: + print(msg) + + def get_options(self): + if (len(self.args) > 1 + and self.args[1] in self.possible_subcommands): + restvars = self.args[2:] + else: + restvars = self.args[1:] + + return parse_vars(restvars) + + def run(self): # pragma: no cover + if self.options.stop_daemon: + return self.stop_daemon() + + if not hasattr(self.options, 'set_user'): + # Windows case: + self.options.set_user = self.options.set_group = None + + # @@: Is this the right stage to set the user at? + self.change_user_group( + self.options.set_user, self.options.set_group) + + if not self.args: + self.out('Please provide configuration file as first argument, ' + 'most likely it should be production.ini') + return 2 + app_spec = self.args[0] + + if (len(self.args) > 1 + and self.args[1] in self.possible_subcommands): + cmd = self.args[1] + else: + cmd = None + + if self.options.reload: + if os.environ.get(self._reloader_environ_key): + if self.options.verbose > 1: + self.out('Running reloading file monitor') + + install_reloader(int(self.options.reload_interval), + [app_spec] + generate_extra_file_list()) + # if self.requires_config_file: + # watch_file(self.args[0]) + else: + return self.restart_with_reloader() + + if cmd not in (None, 'start', 'stop', 'restart', 'status'): + self.out( + 'Error: must give start|stop|restart (not %s)' % cmd) + return 2 + + if cmd == 'status' or self.options.show_status: + return self.show_status() + + if cmd == 'restart' or cmd == 'stop': + result = self.stop_daemon() + if result: + if cmd == 'restart': + self.out("Could not stop daemon; aborting") + else: + self.out("Could not stop daemon") + return result + if cmd == 'stop': + return result + self.options.daemon = True + + if cmd == 'start': + self.options.daemon = True + + app_name = self.options.app_name + + vars = self.get_options() + + if self.options.vcs_server: + vars['vcs.start_server'] = 'true' + + if self.options.running_file: + global SERVER_RUNNING_FILE + SERVER_RUNNING_FILE = self.options.running_file + + if not self._scheme_re.search(app_spec): + app_spec = 'config:' + app_spec + server_name = self.options.server_name + if self.options.server: + server_spec = 'egg:pyramid' + assert server_name is None + server_name = self.options.server + else: + server_spec = app_spec + base = os.getcwd() + + if getattr(self.options, 'daemon', False): + if not self.options.pid_file: + self.options.pid_file = 'pyramid.pid' + if not self.options.log_file: + self.options.log_file = 'pyramid.log' + + # Ensure the log file is writeable + if self.options.log_file: + try: + writeable_log_file = open(self.options.log_file, 'a') + except IOError as ioe: + msg = 'Error: Unable to write to log file: %s' % ioe + raise ValueError(msg) + writeable_log_file.close() + + # Ensure the pid file is writeable + if self.options.pid_file: + try: + writeable_pid_file = open(self.options.pid_file, 'a') + except IOError as ioe: + msg = 'Error: Unable to write to pid file: %s' % ioe + raise ValueError(msg) + writeable_pid_file.close() + + + if getattr(self.options, 'daemon', False): + try: + self.daemonize() + except DaemonizeException as ex: + if self.options.verbose > 0: + self.out(str(ex)) + return 2 + + if (self.options.monitor_restart + and not os.environ.get(self._monitor_environ_key)): + return self.restart_with_monitor() + + if self.options.pid_file: + self.record_pid(self.options.pid_file) + + if self.options.log_file: + stdout_log = LazyWriter(self.options.log_file, 'a') + sys.stdout = stdout_log + sys.stderr = stdout_log + logging.basicConfig(stream=stdout_log) + + log_fn = app_spec + if log_fn.startswith('config:'): + log_fn = app_spec[len('config:'):] + elif log_fn.startswith('egg:'): + log_fn = None + if log_fn: + log_fn = os.path.join(base, log_fn) + setup_logging(log_fn) + set_rhodecode_is_test(log_fn) + + server = self.loadserver(server_spec, name=server_name, + relative_to=base, global_conf=vars) + # starting hooks + app = self.loadapp(app_spec, name=app_name, relative_to=base, + global_conf=vars) + + if self.options.verbose > 0: + if hasattr(os, 'getpid'): + msg = 'Starting %s in PID %i.' % (__name__, os.getpid()) + else: + msg = 'Starting %s.' % (__name__,) + self.out(msg) + if SERVER_RUNNING_FILE: + self.out('PID file written as %s' % (SERVER_RUNNING_FILE, )) + elif not self.options.pid_file: + self.out('No PID file written by default.') + + try: + when_ready(server) + server(app) + except (SystemExit, KeyboardInterrupt) as e: + if self.options.verbose > 1: + raise + if str(e): + msg = ' ' + str(e) + else: + msg = '' + self.out('Exiting%s (-v to see traceback)' % msg) + + + def loadapp(self, app_spec, name, relative_to, **kw): # pragma: no cover + return loadapp(app_spec, name=name, relative_to=relative_to, **kw) + + def loadserver(self, server_spec, name, relative_to, **kw): # pragma:no cover + return loadserver( + server_spec, name=name, relative_to=relative_to, **kw) + + def quote_first_command_arg(self, arg): # pragma: no cover + """ + There's a bug in Windows when running an executable that's + located inside a path with a space in it. This method handles + that case, or on non-Windows systems or an executable with no + spaces, it just leaves well enough alone. + """ + if sys.platform != 'win32' or ' ' not in arg: + # Problem does not apply: + return arg + try: + import win32api + except ImportError: + raise ValueError( + "The executable %r contains a space, and in order to " + "handle this issue you must have the win32api module " + "installed" % arg) + arg = win32api.GetShortPathName(arg) + return arg + + def daemonize(self): # pragma: no cover + pid = live_pidfile(self.options.pid_file) + if pid: + raise DaemonizeException( + "Daemon is already running (PID: %s from PID file %s)" + % (pid, self.options.pid_file)) + + if self.options.verbose > 0: + self.out('Entering daemon mode') + pid = os.fork() + if pid: + # The forked process also has a handle on resources, so we + # *don't* want proper termination of the process, we just + # want to exit quick (which os._exit() does) + os._exit(0) + # Make this the session leader + os.setsid() + # Fork again for good measure! + pid = os.fork() + if pid: + os._exit(0) + + # @@: Should we set the umask and cwd now? + + import resource # Resource usage information. + maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] + if maxfd == resource.RLIM_INFINITY: + maxfd = MAXFD + # Iterate through and close all file descriptors. + for fd in range(0, maxfd): + try: + os.close(fd) + except OSError: # ERROR, fd wasn't open to begin with (ignored) + pass + + if hasattr(os, "devnull"): + REDIRECT_TO = os.devnull + else: + REDIRECT_TO = "/dev/null" + os.open(REDIRECT_TO, os.O_RDWR) # standard input (0) + # Duplicate standard input to standard output and standard error. + os.dup2(0, 1) # standard output (1) + os.dup2(0, 2) # standard error (2) + + def _remove_pid_file(self, written_pid, filename, verbosity): + current_pid = os.getpid() + if written_pid != current_pid: + # A forked process must be exiting, not the process that + # wrote the PID file + return + if not os.path.exists(filename): + return + with open(filename) as f: + content = f.read().strip() + try: + pid_in_file = int(content) + except ValueError: + pass + else: + if pid_in_file != current_pid: + msg = "PID file %s contains %s, not expected PID %s" + self.out(msg % (filename, pid_in_file, current_pid)) + return + if verbosity > 0: + self.out("Removing PID file %s" % filename) + try: + os.unlink(filename) + return + except OSError as e: + # Record, but don't give traceback + self.out("Cannot remove PID file: (%s)" % e) + # well, at least lets not leave the invalid PID around... + try: + with open(filename, 'w') as f: + f.write('') + except OSError as e: + self.out('Stale PID left in file: %s (%s)' % (filename, e)) + else: + self.out('Stale PID removed') + + def record_pid(self, pid_file): + pid = os.getpid() + if self.options.verbose > 1: + self.out('Writing PID %s to %s' % (pid, pid_file)) + with open(pid_file, 'w') as f: + f.write(str(pid)) + atexit.register(self._remove_pid_file, pid, pid_file, self.options.verbose) + + def stop_daemon(self): # pragma: no cover + pid_file = self.options.pid_file or 'pyramid.pid' + if not os.path.exists(pid_file): + self.out('No PID file exists in %s' % pid_file) + return 1 + pid = read_pidfile(pid_file) + if not pid: + self.out("Not a valid PID file in %s" % pid_file) + return 1 + pid = live_pidfile(pid_file) + if not pid: + self.out("PID in %s is not valid (deleting)" % pid_file) + try: + os.unlink(pid_file) + except (OSError, IOError) as e: + self.out("Could not delete: %s" % e) + return 2 + return 1 + for j in range(10): + if not live_pidfile(pid_file): + break + import signal + kill(pid, signal.SIGTERM) + time.sleep(1) + else: + self.out("failed to kill web process %s" % pid) + return 3 + if os.path.exists(pid_file): + os.unlink(pid_file) + return 0 + + def show_status(self): # pragma: no cover + pid_file = self.options.pid_file or 'pyramid.pid' + if not os.path.exists(pid_file): + self.out('No PID file %s' % pid_file) + return 1 + pid = read_pidfile(pid_file) + if not pid: + self.out('No PID in file %s' % pid_file) + return 1 + pid = live_pidfile(pid_file) + if not pid: + self.out('PID %s in %s is not running' % (pid, pid_file)) + return 1 + self.out('Server running in PID %s' % pid) + return 0 + + def restart_with_reloader(self): # pragma: no cover + self.restart_with_monitor(reloader=True) + + def restart_with_monitor(self, reloader=False): # pragma: no cover + if self.options.verbose > 0: + if reloader: + self.out('Starting subprocess with file monitor') + else: + self.out('Starting subprocess with monitor parent') + while 1: + args = [self.quote_first_command_arg(sys.executable)] + sys.argv + new_environ = os.environ.copy() + if reloader: + new_environ[self._reloader_environ_key] = 'true' + else: + new_environ[self._monitor_environ_key] = 'true' + proc = None + try: + try: + _turn_sigterm_into_systemexit() + proc = subprocess.Popen(args, env=new_environ) + exit_code = proc.wait() + proc = None + except KeyboardInterrupt: + self.out('^C caught in monitor process') + if self.options.verbose > 1: + raise + return 1 + finally: + if proc is not None: + import signal + try: + kill(proc.pid, signal.SIGTERM) + except (OSError, IOError): + pass + + if reloader: + # Reloader always exits with code 3; but if we are + # a monitor, any exit code will restart + if exit_code != 3: + return exit_code + if self.options.verbose > 0: + self.out('%s %s %s' % ('-' * 20, 'Restarting', '-' * 20)) + + def change_user_group(self, user, group): # pragma: no cover + if not user and not group: + return + import pwd + import grp + uid = gid = None + if group: + try: + gid = int(group) + group = grp.getgrgid(gid).gr_name + except ValueError: + try: + entry = grp.getgrnam(group) + except KeyError: + raise ValueError( + "Bad group: %r; no such group exists" % group) + gid = entry.gr_gid + try: + uid = int(user) + user = pwd.getpwuid(uid).pw_name + except ValueError: + try: + entry = pwd.getpwnam(user) + except KeyError: + raise ValueError( + "Bad username: %r; no such user exists" % user) + if not gid: + gid = entry.pw_gid + uid = entry.pw_uid + if self.options.verbose > 0: + self.out('Changing user to %s:%s (%s:%s)' % ( + user, group or '(unknown)', uid, gid)) + if gid: + os.setgid(gid) + if uid: + os.setuid(uid) + + +class LazyWriter(object): + + """ + File-like object that opens a file lazily when it is first written + to. + """ + + def __init__(self, filename, mode='w'): + self.filename = filename + self.fileobj = None + self.lock = threading.Lock() + self.mode = mode + + def open(self): + if self.fileobj is None: + with self.lock: + self.fileobj = open(self.filename, self.mode) + return self.fileobj + + def close(self): + fileobj = self.fileobj + if fileobj is not None: + fileobj.close() + + def __del__(self): + self.close() + + def write(self, text): + fileobj = self.open() + fileobj.write(text) + fileobj.flush() + + def writelines(self, text): + fileobj = self.open() + fileobj.writelines(text) + fileobj.flush() + + def flush(self): + self.open().flush() + + +def live_pidfile(pidfile): # pragma: no cover + """ + (pidfile:str) -> int | None + Returns an int found in the named file, if there is one, + and if there is a running process with that process id. + Return None if no such process exists. + """ + pid = read_pidfile(pidfile) + if pid: + try: + kill(int(pid), 0) + return pid + except OSError as e: + if e.errno == errno.EPERM: + return pid + return None + + +def read_pidfile(filename): + if os.path.exists(filename): + try: + with open(filename) as f: + content = f.read() + return int(content.strip()) + except (ValueError, IOError): + return None + else: + return None + + +def ensure_port_cleanup( + bound_addresses, maxtries=30, sleeptime=2): # pragma: no cover + """ + This makes sure any open ports are closed. + + Does this by connecting to them until they give connection + refused. Servers should call like:: + + ensure_port_cleanup([80, 443]) + """ + atexit.register(_cleanup_ports, bound_addresses, maxtries=maxtries, + sleeptime=sleeptime) + + +def _cleanup_ports( + bound_addresses, maxtries=30, sleeptime=2): # pragma: no cover + # Wait for the server to bind to the port. + import socket + import errno + for bound_address in bound_addresses: + for attempt in range(maxtries): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect(bound_address) + except socket.error as e: + if e.args[0] != errno.ECONNREFUSED: + raise + break + else: + time.sleep(sleeptime) + else: + raise SystemExit('Timeout waiting for port.') + sock.close() + + +def _turn_sigterm_into_systemexit(): # pragma: no cover + """ + Attempts to turn a SIGTERM exception into a SystemExit exception. + """ + try: + import signal + except ImportError: + return + def handle_term(signo, frame): + raise SystemExit + signal.signal(signal.SIGTERM, handle_term) + + +def install_reloader(poll_interval=1, extra_files=None): # pragma: no cover + """ + Install the reloading monitor. + + On some platforms server threads may not terminate when the main + thread does, causing ports to remain open/locked. The + ``raise_keyboard_interrupt`` option creates a unignorable signal + which causes the whole application to shut-down (rudely). + """ + mon = Monitor(poll_interval=poll_interval) + if extra_files is None: + extra_files = [] + mon.extra_files.extend(extra_files) + t = threading.Thread(target=mon.periodic_reload) + t.setDaemon(True) + t.start() + + +class classinstancemethod(object): + """ + Acts like a class method when called from a class, like an + instance method when called by an instance. The method should + take two arguments, 'self' and 'cls'; one of these will be None + depending on how the method was called. + """ + + def __init__(self, func): + self.func = func + self.__doc__ = func.__doc__ + + def __get__(self, obj, type=None): + return _methodwrapper(self.func, obj=obj, type=type) + + +class _methodwrapper(object): + + def __init__(self, func, obj, type): + self.func = func + self.obj = obj + self.type = type + + def __call__(self, *args, **kw): + assert not 'self' in kw and not 'cls' in kw, ( + "You cannot use 'self' or 'cls' arguments to a " + "classinstancemethod") + return self.func(*((self.obj, self.type) + args), **kw) + + +class Monitor(object): # pragma: no cover + """ + A file monitor and server restarter. + + Use this like: + + ..code-block:: Python + + install_reloader() + + Then make sure your server is installed with a shell script like:: + + err=3 + while test "$err" -eq 3 ; do + python server.py + err="$?" + done + + or is run from this .bat file (if you use Windows):: + + @echo off + :repeat + python server.py + if %errorlevel% == 3 goto repeat + + or run a monitoring process in Python (``pserve --reload`` does + this). + + Use the ``watch_file(filename)`` function to cause a reload/restart for + other non-Python files (e.g., configuration files). If you have + a dynamic set of files that grows over time you can use something like:: + + def watch_config_files(): + return CONFIG_FILE_CACHE.keys() + add_file_callback(watch_config_files) + + Then every time the reloader polls files it will call + ``watch_config_files`` and check all the filenames it returns. + """ + instances = [] + global_extra_files = [] + global_file_callbacks = [] + + def __init__(self, poll_interval): + self.module_mtimes = {} + self.keep_running = True + self.poll_interval = poll_interval + self.extra_files = list(self.global_extra_files) + self.instances.append(self) + self.file_callbacks = list(self.global_file_callbacks) + + def _exit(self): + # use os._exit() here and not sys.exit() since within a + # thread sys.exit() just closes the given thread and + # won't kill the process; note os._exit does not call + # any atexit callbacks, nor does it do finally blocks, + # flush open files, etc. In otherwords, it is rude. + os._exit(3) + + def periodic_reload(self): + while True: + if not self.check_reload(): + self._exit() + break + time.sleep(self.poll_interval) + + def check_reload(self): + filenames = list(self.extra_files) + for file_callback in self.file_callbacks: + try: + filenames.extend(file_callback()) + except: + print( + "Error calling reloader callback %r:" % file_callback) + traceback.print_exc() + for module in list(sys.modules.values()): + try: + filename = module.__file__ + except (AttributeError, ImportError): + continue + if filename is not None: + filenames.append(filename) + + for filename in filenames: + try: + stat = os.stat(filename) + if stat: + mtime = stat.st_mtime + else: + mtime = 0 + except (OSError, IOError): + continue + if filename.endswith('.pyc') and os.path.exists(filename[:-1]): + mtime = max(os.stat(filename[:-1]).st_mtime, mtime) + if not filename in self.module_mtimes: + self.module_mtimes[filename] = mtime + elif self.module_mtimes[filename] < mtime: + print("%s changed; reloading..." % filename) + run_callback_for_pattern(filename) + return False + return True + + def watch_file(self, cls, filename): + """Watch the named file for changes""" + filename = os.path.abspath(filename) + if self is None: + for instance in cls.instances: + instance.watch_file(filename) + cls.global_extra_files.append(filename) + else: + self.extra_files.append(filename) + + watch_file = classinstancemethod(watch_file) + + def add_file_callback(self, cls, callback): + """Add a callback -- a function that takes no parameters -- that will + return a list of filenames to watch for changes.""" + if self is None: + for instance in cls.instances: + instance.add_file_callback(callback) + cls.global_file_callbacks.append(callback) + else: + self.file_callbacks.append(callback) + + add_file_callback = classinstancemethod(add_file_callback) + +watch_file = Monitor.watch_file +add_file_callback = Monitor.add_file_callback + + +def main(argv=sys.argv, quiet=False): + command = RcServerCommand(argv, quiet=quiet) + return command.run() + +if __name__ == '__main__': # pragma: no cover + sys.exit(main() or 0) diff --git a/rhodecode/subscribers.py b/rhodecode/subscribers.py new file mode 100644 --- /dev/null +++ b/rhodecode/subscribers.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import pylons +from pyramid.i18n import get_localizer, TranslationStringFactory + +tsf = TranslationStringFactory('rc_root') + + +def add_renderer_globals(event): + # Put pylons stuff into the context. This will be removed as soon as + # migration to pyramid is finished. + conf = pylons.config._current_obj() + event['h'] = conf.get('pylons.h') + event['c'] = pylons.tmpl_context + event['url'] = pylons.url + + # Add Pyramid translation as '_' to context + request = event['request'] + event['_'] = request.translate + event['localizer'] = request.localizer + + +def add_localizer(event): + request = event.request + localizer = get_localizer(request) + + def auto_translate(*args, **kwargs): + return localizer.translate(tsf(*args, **kwargs)) + + request.localizer = localizer + request.translate = auto_translate diff --git a/rhodecode/templates/admin/admin.html b/rhodecode/templates/admin/admin.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/admin.html @@ -0,0 +1,40 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Admin journal')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.form(None, id_="filter_form", method="get")} + <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term or ''}" placeholder="${_('journal filter...')}"/> + <input type='submit' value="${_('filter')}" class="btn" /> + ${_('Admin journal')} - ${ungettext('%s entry', '%s entries', c.users_log.item_count) % (c.users_log.item_count)} + ${h.end_form()} + <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help())}">${_('Example Queries')}</p> +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + <!-- end box / title --> + <div class="table"> + <div id="user_log"> + ${c.log_data} + </div> + </div> +</div> + +<script> +$('#j_filter').autoGrowInput(); +</script> +</%def> diff --git a/rhodecode/templates/admin/admin_log.html b/rhodecode/templates/admin/admin_log.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/admin_log.html @@ -0,0 +1,60 @@ +## -*- coding: utf-8 -*- +%if c.users_log: +<table class="rctable admin_log"> + <tr> + <th>${_('Username')}</th> + <th>${_('Action')}</th> + <th>${_('Repository')}</th> + <th>${_('Date')}</th> + <th>${_('From IP')}</th> + </tr> + + %for cnt,l in enumerate(c.users_log): + <tr class="parity${cnt%2}"> + <td class="td-user"> + %if l.user is not None: + ${h.link_to(l.user.username,h.url('edit_user', user_id=l.user.user_id))} + %else: + ${l.username} + %endif + </td> + <td class="td-journalaction">${h.action_parser(l)[0]()} + <div class="journal_action_params"> + ${h.literal(h.action_parser(l)[1]())} + </div> + </td> + <td class="td-componentname"> + %if l.repository is not None: + ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))} + %else: + ${l.repository_name} + %endif + </td> + + <td class="td-time">${h.format_date(l.action_date)}</td> + <td class="td-ip">${l.user_ip}</td> + </tr> + %endfor +</table> + +<div class="pagination-wh pagination-left"> +${c.users_log.pager('$link_previous ~2~ $link_next')} +</div> +%else: + ${_('No actions yet')} +%endif + +<script type="text/javascript"> + $(function(){ + //because this is loaded on every pjax request, it must run only once + //therefore the .one method + $(document).on('pjax:complete',function(){ + show_more_event(); + tooltip_activate(); + show_changeset_tooltip(); + }); + + $(document).pjax('#user_log .pager_link', '#user_log'); + }); +</script> + diff --git a/rhodecode/templates/admin/auth/auth_settings.html b/rhodecode/templates/admin/auth/auth_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/auth/auth_settings.html @@ -0,0 +1,116 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Authentication Settings')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)}} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${_('Authentication Plugins')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> + +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div class='sidebar-col-wrapper'> + + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + % for item in resource.get_root().get_nav_list(): + <li ${'class=active' if item == resource else ''}> + <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a> + </li> + % endfor + </ul> + </div> + + <div class="main-content-full-width"> + ${h.secure_form(request.resource_path(resource, route_name='auth_home'))} + <div class="form"> + + <div class="panel panel-default"> + + <div class="panel-heading"> + <h3 class="panel-title">${_("Enabled and Available Plugins")}</h3> + </div> + + <div class="fields panel-body"> + + <div class="field"> + <div class="label">${_("Enabled Plugins")}</div> + <div class="textarea text-area editor"> + ${h.textarea('auth_plugins',cols=23,rows=5,class_="medium")} + </div> + <p class="help-block"> + ${_('Add a list of plugins, separated by commas. ' + 'The order of the plugins is also the order in which ' + 'RhodeCode Enterprise will try to authenticate a user.')} + </p> + </div> + + <div class="field"> + <div class="label">${_('Available Built-in Plugins')}</div> + <ul class="auth_plugins"> + %for plugin in available_plugins: + <li> + <div class="auth_buttons"> + <span plugin_id="${plugin.get_id()}" class="toggle-plugin btn ${'btn-success' if plugin.get_id() in enabled_plugins else ''}"> + ${_('enabled') if plugin.get_id() in enabled_plugins else _('disabled')} + </span> + ${plugin.get_display_name()} (${plugin.get_id()}) + </div> + </li> + %endfor + </ul> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + </div> + ${h.end_form()} + </div> + </div> +</div> + +<script> + $('.toggle-plugin').click(function(e){ + var auth_plugins_input = $('#auth_plugins'); + var notEmpty = function(element, index, array) { + return (element != ""); + } + var elems = auth_plugins_input.val().split(',').filter(notEmpty); + var cur_button = e.currentTarget; + var plugin_id = $(cur_button).attr('plugin_id'); + if($(cur_button).hasClass('btn-success')){ + elems.splice(elems.indexOf(plugin_id), 1); + auth_plugins_input.val(elems.join(',')); + $(cur_button).removeClass('btn-success'); + cur_button.innerHTML = _TM['disabled']; + } + else{ + if(elems.indexOf(plugin_id) == -1){ + elems.push(plugin_id); + } + auth_plugins_input.val(elems.join(',')); + $(cur_button).addClass('btn-success'); + cur_button.innerHTML = _TM['enabled']; + } + }); +</script> +</%def> diff --git a/rhodecode/templates/admin/auth/plugin_settings.html b/rhodecode/templates/admin/auth/plugin_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/auth/plugin_settings.html @@ -0,0 +1,118 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Authentication Settings')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)}} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Authentication Plugins'),request.resource_path(resource.__parent__, route_name='auth_home'))} + » + ${resource.display_name} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> + <div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + <div class='sidebar-col-wrapper'> + + ## TODO: This is repeated in the auth root template and should be merged + ## into a single solution. + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + % for item in resource.get_root().get_nav_list(): + <li ${'class=active' if item == resource else ''}> + <a href="${request.resource_path(item, route_name='auth_home')}">${item.display_name}</a> + </li> + % endfor + </ul> + </div> + + <div class="main-content-full-width"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Plugin')}: ${resource.display_name}</h3> + </div> + <div class="panel-body"> + <div class="plugin_form"> + <div class="fields"> + ${h.secure_form(request.resource_path(resource, route_name='auth_home'))} + <div class="form"> + %for node in plugin.get_settings_schema(): + <% label_cls = ("label-checkbox" if (node.widget == "bool") else "") %> + <div class="field"> + <div class="label ${label_cls}"><label for="${node.name}">${node.title}</label></div> + %if node.widget in ["string", "int", "unicode"]: + <div class="input"> + ${h.text(node.name, class_="medium")} + <p class="help-block">${node.description}</p> + </div> + %elif node.widget == "password": + <div class="input"> + ${h.password(node.name, class_="medium")} + <p class="help-block">${node.description}</p> + </div> + %elif node.widget == "bool": + <div class="input"> + <div class="checkbox">${h.checkbox(node.name, True)}</div> + <span class="help-block">${node.description}</span> + </div> + %elif node.widget == "select": + <div class="select"> + ${h.select(node.name, node.default, node.validator.choices)} + <p class="help-block">${node.description}</p> + </div> + %elif node.widget == "readonly": + <div class="input"> + ${node.default} + <p class="help-block">${node.description}</p> + </div> + %else: + <div class="input"> + This field is of type ${node.typ}, which cannot be displayed. Must be one of [string|int|bool|select]. + <p class="help-block">${node.description}</p> + </div> + %endif + </div> + %endfor + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + ${h.end_form()} + </div> + </div> + </div> + </div> + </div> + + </div> + </div> +</%def> + +## TODO: Ugly hack to get ldap select elements to work. +## Find a solution to integrate this nicely. +<script> +$(document).ready(function() { + var select2Options = { + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }; + $("#tls_kind").select2(select2Options); + $("#tls_reqcert").select2(select2Options); + $("#search_scope").select2(select2Options); +}); +</script> diff --git a/rhodecode/templates/admin/defaults/defaults.html b/rhodecode/templates/admin/defaults/defaults.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/defaults/defaults.html @@ -0,0 +1,42 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Repositories defaults')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${_('Repositories defaults')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + ##main + <div class="sidebar-col-wrapper"> + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='repositories' else ''}"><a href="${h.url('admin_defaults_repositories')}">${_('Repository')}</a></li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/defaults/defaults_${c.active}.html"/> + </div> + + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/defaults/defaults_repositories.html b/rhodecode/templates/admin/defaults/defaults_repositories.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/defaults/defaults_repositories.html @@ -0,0 +1,81 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Default Settings For New Repositories')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('admin_defaults_repositories'), method='post')} + <div class="form"> + <!-- fields --> + + <div class="fields"> + + <div class="field"> + <div class="label"> + <label for="default_repo_type">${_('Type')}:</label> + </div> + <div class="select"> + ${h.select('default_repo_type','hg',c.backends,class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="default_repo_private">${_('Private Repository')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('default_repo_private',value="True")} + <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span> + </div> + </div> + + + <div class="field"> + <div class="label label-checkbox"> + <label for="default_repo_enable_statistics">${_('Enable Statistics')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('default_repo_enable_statistics',value="True")} + <span class="help-block">${_('Enable a statistics window on the repository summary page.')}</span> + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="default_repo_enable_downloads">${_('Enable Downloads')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('default_repo_enable_downloads',value="True")} + <span class="help-block">${_('Enable the download option on the repository summary page.')}</span> + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="default_repo_enable_locking">${_('Enable Locking')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('default_repo_enable_locking',value="True")} + <span class="help-block">${_('Enable automatic repository locking. Pulling from a repository will lock it, and it is unlocked by pushing back by the same user.')}</span> + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> + +</div> + +<script> + $(document).ready(function(){ + $("#default_repo_type").select2({ + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }); + }) +</script> diff --git a/rhodecode/templates/admin/gists/edit.html b/rhodecode/templates/admin/gists/edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/gists/edit.html @@ -0,0 +1,136 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Edit Gist')} · ${c.gist.gist_access_id} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('Edit Gist')} · ${c.gist.gist_access_id} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='gists')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div class="table"> + <div id="edit_error" class="flash_msg" style="display:none;"> + <div class="alert alert-warning"> + ${h.literal(_('Gist was updated since you started editing. Copy your changes and click %(here)s to reload the new version.') + % {'here': h.link_to('here',h.url('edit_gist', gist_id=c.gist.gist_access_id))})} + </div> + </div> + + <div id="files_data"> + ${h.secure_form(h.url('edit_gist', gist_id=c.gist.gist_access_id), method='post', id='eform')} + <div> + <input type="hidden" value="${c.file_last_commit.raw_id}" name="parent_hash"> + <textarea id="description" name="description" + placeholder="${_('Gist description ...')}">${c.gist.gist_description}</textarea> + <div> + <span class="gist-gravatar"> + ${self.gravatar(h.email_or_none(c.rhodecode_user.full_contact), 30)} + </span> + <label for='lifetime'>${_('Gist lifetime')}</label> + ${h.dropdownmenu('lifetime', '0', c.lifetime_options)} + + <label for='acl_level'>${_('Gist access level')}</label> + ${h.dropdownmenu('acl_level', c.gist.acl_level, c.acl_options)} + </div> + </div> + + % for cnt, file in enumerate(c.files): + <div id="codeblock" class="codeblock" > + <div class="code-header"> + <div class="form"> + <div class="fields"> + <input type="hidden" value="${file.path}" name="org_files"> + <input id="filename_${h.FID('f',file.path)}" name="files" size="30" type="text" value="${file.path}"> + ${h.dropdownmenu('mimetypes' ,'plain',[('plain',_('plain'))],enable_filter=True, id='mimetype_'+h.FID('f',file.path))} + </div> + </div> + </div> + <div class="editor_container"> + <pre id="editor_pre"></pre> + <textarea id="editor_${h.FID('f',file.path)}" name="contents" >${file.content}</textarea> + </div> + </div> + + ## dynamic edit box. + <script type="text/javascript"> + $(document).ready(function(){ + var myCodeMirror = initCodeMirror( + "editor_${h.FID('f',file.path)}", ''); + + var modes_select = $('#mimetype_${h.FID('f',file.path)}'); + fillCodeMirrorOptions(modes_select); + + // try to detect the mode based on the file we edit + var mimetype = "${file.mimetype}"; + var detected_mode = detectCodeMirrorMode( + "${file.path}", mimetype); + + if(detected_mode){ + $(modes_select).select2("val", mimetype); + $(modes_select).change(); + setCodeMirrorMode(myCodeMirror, detected_mode); + } + + var filename_selector = '#filename_${h.FID('f',file.path)}'; + // on change of select field set mode + setCodeMirrorModeFromSelect( + modes_select, filename_selector, myCodeMirror, null); + + // on entering the new filename set mode, from given extension + setCodeMirrorModeFromInput( + modes_select, filename_selector, myCodeMirror, null); + }); + </script> + + %endfor + + <div class="pull-right"> + ${h.submit('update',_('Update Gist'),class_="btn btn-success")} + <a class="btn" href="${h.url('gist', gist_id=c.gist.gist_access_id)}">${_('Cancel')}</a> + </div> + ${h.end_form()} + </div> + </div> + +</div> +<script> + $('#update').on('click', function(e){ + e.preventDefault(); + + // check for newer version. + $.ajax({ + url: "${h.url('edit_gist_check_revision', gist_id=c.gist.gist_access_id)}", + data: { + 'revision': '${c.file_last_commit.raw_id}' + }, + dataType: 'json', + type: 'GET', + success: function(data) { + if(data.success === false){ + $('#edit_error').show(); + window.scrollTo(0,0); + } + else{ + $('#eform').submit(); + } + } + }); + }) + +</script> +</%def> diff --git a/rhodecode/templates/admin/gists/index.html b/rhodecode/templates/admin/gists/index.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/gists/index.html @@ -0,0 +1,151 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + %if c.show_private: + ${_('Private Gists for user %s') % c.rhodecode_user.username} + %elif c.show_public: + ${_('Public Gists for user %s') % c.rhodecode_user.username} + %else: + ${_('Public Gists')} + %endif + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + %if c.show_private and not c.show_public: + ${_('Private Gists for user %s') % c.rhodecode_user.username} + %elif c.show_public and not c.show_private: + ${_('Public Gists for user %s') % c.rhodecode_user.username} + %elif c.show_public and c.show_private: + ${_('All Gists for user %s') % c.rhodecode_user.username} + %else: + ${_('All Public Gists')} + %endif + - <span id="gists_count">0</span> +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='gists')} +</%def> + + + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs(class_="breadcrumbs block-left")} + %if c.rhodecode_user.username != h.DEFAULT_USER: + <ul class="links block-right"> + <li> + <a href="${h.url('new_gist')}" class="btn btn-primary">${_(u'Create New Gist')}</a> + </li> + </ul> + %endif + </div> + + + <div class="sidebar-col-wrapper scw-small"> + ##main + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + % if h.HasPermissionAll('hg.admin')('access admin gists page'): + <li class="${'active' if c.active=='all' else ''}"><a href="${h.url('gists', all=1)}">${_('All gists')}</a></li> + %endif + <li class="${'active' if c.active=='public' else ''}"><a href="${h.url('gists')}">${_('All public')}</a></li> + %if c.rhodecode_user.username != h.DEFAULT_USER: + <li class="${'active' if c.active=='my_all' else ''}"><a href="${h.url('gists', public=1, private=1)}">${_('My gists')}</a></li> + <li class="${'active' if c.active=='my_private' else ''}"><a href="${h.url('gists', private=1)}">${_('My private')}</a></li> + <li class="${'active' if c.active=='my_public' else ''}"><a href="${h.url('gists', public=1)}">${_('My public')}</a></li> + %endif + </ul> + </div> + + <div class="main-content"> + <div id="repos_list_wrap"> + <table id="gist_list_table" class="display"></table> + </div> + </div> + </div> +</div> +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#gist_list_table').dataTable().api(); + $('#gists_count').text(api.page.info().recordsDisplay); + }; + + + // custom filter that filters by access_id, description or author + $.fn.dataTable.ext.search.push( + function( settings, data, dataIndex ) { + var query = $('#q_filter').val(); + var author = data[0].strip(); + var access_id = data[2].strip(); + var description = data[3].strip(); + + var query_str = (access_id + " " + author + " " + description).toLowerCase(); + + if(query_str.indexOf(query.toLowerCase()) !== -1){ + return true; + } + return false; + } + ); + + // gists list + $('#gist_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.dashboard_items}, + order: [[ 4, "desc" ]], + columns: [ + { data: {"_": "author", + "sort": "author_raw"}, title: "${_("Author")}", width: "250px", className: "td-user" }, + { data: {"_": "type", + "sort": "type"}, title: "${_("Type")}", width: "70px", className: "td-tags" }, + { data: {"_": "access_id", + "sort": "access_id"}, title: "${_("Name")}", width:"150px", className: "td-componentname" }, + { data: {"_": "description", + "sort": "description"}, title: "${_("Description")}", width: "250px", className: "td-description" }, + { data: {"_": "created_on", + "sort": "created_on_raw"}, title: "${_("Created on")}", className: "td-time" }, + { data: {"_": "expires", + "sort": "expires"}, title: "${_("Expires")}", className: "td-exp" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + timeagoActivate(); + tooltip_activate(); + get_datatable_count(); + } + }); + + // update the counter when things change + $('#gist_list_table').on('draw.dt', function() { + timeagoActivate(); + tooltip_activate(); + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var repo_api = $('#gist_list_table').dataTable().api(); + repo_api + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + + }); + +</script> +</%def> + diff --git a/rhodecode/templates/admin/gists/new.html b/rhodecode/templates/admin/gists/new.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/gists/new.html @@ -0,0 +1,86 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('New Gist')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('New Gist')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='gists')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div class="table"> + <div id="files_data"> + ${h.secure_form(h.url('gists'), method='post',id='eform')} + <div> + <textarea id="description" name="description" placeholder="${_('Gist description ...')}"></textarea> + + <span class="gist-gravatar"> + ${self.gravatar(c.rhodecode_user.email, 30)} + </span> + <label for='gistid'>${_('Gist id')}</label> + ${h.text('gistid', placeholder=_('Auto generated'))} + + <label for='lifetime'>${_('Gist lifetime')}</label> + ${h.dropdownmenu('lifetime', '', c.lifetime_options)} + + <label for='acl_level'>${_('Gist access level')}</label> + ${h.dropdownmenu('acl_level', '', c.acl_options)} + + </div> + <div id="codeblock" class="codeblock"> + <div class="code-header"> + <div class="form"> + <div class="fields"> + ${h.text('filename', size=30, placeholder=_('name this file...'))} + ${h.dropdownmenu('mimetype','plain',[('plain',_('plain'))],enable_filter=True)} + </div> + </div> + </div> + <div id="editor_container"> + <div id="editor_pre"></div> + <textarea id="editor" name="content" ></textarea> + </div> + </div> + <div class="pull-right"> + ${h.submit('private',_('Create Private Gist'),class_="btn")} + ${h.submit('public',_('Create Public Gist'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + ${h.end_form()} + </div> + </div> + +</div> + +<script type="text/javascript"> + var myCodeMirror = initCodeMirror('editor', ''); + + var modes_select = $('#mimetype'); + fillCodeMirrorOptions(modes_select); + + var filename_selector = '#filename'; + // on change of select field set mode + setCodeMirrorModeFromSelect( + modes_select, filename_selector, myCodeMirror, null); + + // on entering the new filename set mode, from given extension + setCodeMirrorModeFromInput( + modes_select, filename_selector, myCodeMirror, null); + +</script> +</%def> diff --git a/rhodecode/templates/admin/gists/show.html b/rhodecode/templates/admin/gists/show.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/gists/show.html @@ -0,0 +1,108 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="robots()"> + %if c.gist.gist_type != 'public': + <meta name="robots" content="noindex, nofollow"> + %else: + ${parent.robots()} + %endif +</%def> + +<%def name="title()"> + ${_('Gist')} · ${c.gist.gist_access_id} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('Gist')} · ${c.gist.gist_access_id} + / ${_('URL')}: ${c.gist.gist_url()} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='gists')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + %if c.rhodecode_user.username != h.DEFAULT_USER: + <ul class="links"> + <li> + <a href="${h.url('new_gist')}" class="btn btn-primary">${_(u'Create New Gist')}</a> + </li> + </ul> + %endif + </div> + <div class="table"> + <div id="files_data"> + <div id="codeblock" class="codeblock"> + <div class="code-header"> + <div class="stats"> + %if h.HasPermissionAny('hg.admin')() or c.gist.gist_owner == c.rhodecode_user.user_id: + <div class="remove_gist"> + ${h.secure_form(url('gist', gist_id=c.gist.gist_access_id),method='delete')} + ${h.submit('remove_gist', _('Delete'),class_="btn btn-mini btn-danger",onclick="return confirm('"+_('Confirm to delete this Gist')+"');")} + ${h.end_form()} + </div> + %endif + <div class="buttons"> + ## only owner should see that + %if h.HasPermissionAny('hg.admin')() or c.gist.gist_owner == c.rhodecode_user.user_id: + ${h.link_to(_('Edit'),h.url('edit_gist', gist_id=c.gist.gist_access_id),class_="btn btn-mini")} + %endif + ${h.link_to(_('Show as Raw'),h.url('formatted_gist', gist_id=c.gist.gist_access_id, format='raw'),class_="btn btn-mini")} + </div> + <div class="left" > + %if c.gist.gist_type != 'public': + <span class="tag tag-ok disabled">${_('Private Gist')}</span> + %endif + <span> ${c.gist.gist_description}</span> + <span>${_('Expires')}: + %if c.gist.gist_expires == -1: + ${_('never')} + %else: + ${h.age_component(h.time_to_datetime(c.gist.gist_expires))} + %endif + </span> + </div> + </div> + + <div class="author"> + <div title="${c.file_last_commit.author}"> + ${self.gravatar_with_user(c.file_last_commit.author, 16)} - ${_('created')} ${h.age_component(c.file_last_commit.date)} + </div> + + </div> + <div class="commit">${h.urlify_commit_message(c.file_last_commit.message,c.repo_name)}</div> + </div> + + ## iterate over the files + % for file in c.files: + <% renderer = c.render and h.renderer_from_filename(file.path, exclude=['.txt', '.TXT'])%> +<!-- <div id="${h.FID('G', file.path)}" class="stats" > + <a href="${c.gist.gist_url()}">¶</a> + <b >${file.path}</b> + <div> + ${h.link_to(_('Show as raw'),h.url('formatted_gist_file', gist_id=c.gist.gist_access_id, format='raw', revision=file.commit.raw_id, f_path=file.path),class_="btn btn-mini")} + </div> + </div> --> + <div class="code-body textarea text-area editor"> + %if renderer: + ${h.render(file.content, renderer=renderer)} + %else: + ${h.pygmentize(file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")} + %endif + </div> + %endfor + </div> + </div> + </div> + + +</div> +</%def> diff --git a/rhodecode/templates/admin/my_account/my_account.html b/rhodecode/templates/admin/my_account/my_account.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account.html @@ -0,0 +1,47 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('My account')} ${c.rhodecode_user.username} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('My Account')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div class="sidebar-col-wrapper scw-small"> + ##main + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='profile' or c.active=='profile_edit' else ''}"><a href="${h.url('my_account')}">${_('My Profile')}</a></li> + <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li> + <li class="${'active' if c.active=='auth_tokens' else ''}"><a href="${h.url('my_account_auth_tokens')}">${_('Auth Tokens')}</a></li> + <li class="${'active' if c.active=='oauth' else ''}"><a href="${h.url('my_account_oauth')}">${_('OAuth Identities')}</a></li> + <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('my_account_emails')}">${_('My Emails')}</a></li> + <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('My Repositories')}</a></li> + <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li> + <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li> + <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('My Permissions')}</a></li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/my_account/my_account_${c.active}.html"/> + </div> + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/my_account/my_account_auth_tokens.html b/rhodecode/templates/admin/my_account/my_account_auth_tokens.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_auth_tokens.html @@ -0,0 +1,102 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Authentication Tokens')}</h3> + </div> + <div class="panel-body"> + <p> + ${_('Built-in tokens can be used to authenticate with all possible options.')}<br/> + ${_('Each token can have a role. VCS tokens can be used together with the authtoken auth plugin for git/hg operations.')} + </p> + <table class="rctable auth_tokens"> + <tr> + <td class="truncate-wrap td-authtoken"><div class="user_auth_tokens truncate autoexpand"><code>${c.user.api_key}</code></div></td> + <td class="td-buttons"> + <span class="btn btn-mini btn-info disabled">${_('Built-in')}</span> + </td> + <td class="td-buttons"> + <span class="btn btn-mini btn-info disabled">all</span> + </td> + <td class="td-exp">${_('expires')}: ${_('never')}</td> + <td class="td-action"> + ${h.secure_form(url('my_account_auth_tokens'),method='delete')} + ${h.hidden('del_auth_token',c.user.api_key)} + ${h.hidden('del_auth_token_builtin',1)} + <button class="btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to reset this auth token: %s') % c.user.api_key}');"> + <i class="icon-refresh"></i> + ${_('Reset')} + </button> + ${h.end_form()} + </td> + </tr> + %if c.user_auth_tokens: + %for auth_token in c.user_auth_tokens: + <tr class="${'expired' if auth_token.expired else ''}"> + <td class="truncate-wrap td-authtoken"><div class="user_auth_tokens truncate autoexpand"><code>${auth_token.api_key}</code></div></td> + <td class="td-wrap">${auth_token.description}</td> + <td class="td-buttons"> + <span class="btn btn-mini btn-info disabled">${auth_token.role_humanized}</span> + </td> + <td class="td-exp"> + %if auth_token.expires == -1: + ${_('expires')}: ${_('never')} + %else: + %if auth_token.expired: + ${_('expired')}: ${h.age_component(h.time_to_datetime(auth_token.expires))} + %else: + ${_('expires')}: ${h.age_component(h.time_to_datetime(auth_token.expires))} + %endif + %endif + </td> + <td class="td-action"> + ${h.secure_form(url('my_account_auth_tokens'),method='delete')} + ${h.hidden('del_auth_token',auth_token.api_key)} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr><td><div class="ip">${_('No additional auth token specified')}</div></td></tr> + %endif + </table> + + <div class="user_auth_tokens"> + ${h.secure_form(url('my_account_auth_tokens'), method='post')} + <div class="form form-vertical"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_email">${_('New authentication token')}:</label> + </div> + <div class="input"> + ${h.text('description', placeholder=_('Description'))} + ${h.select('lifetime', '', c.lifetime_options)} + ${h.select('role', '', c.role_options)} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> + </div> +</div> + <script> + $(document).ready(function(){ + var select2Options = { + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }; + $("#lifetime").select2(select2Options); + $("#role").select2(select2Options); + }); + </script> diff --git a/rhodecode/templates/admin/my_account/my_account_emails.html b/rhodecode/templates/admin/my_account/my_account_emails.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_emails.html @@ -0,0 +1,72 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Account Emails')}</h3> + </div> + + <div class="panel-body"> + <div class="emails_wrap"> + <table class="rctable account_emails"> + <tr> + <td class="td-user"> + ${base.gravatar(c.user.email, 16)} + <span class="user email">${c.user.email}</span> + </td> + <td class="td-tags"> + <span class="tag tag1">${_('Primary')}</span> + </td> + </tr> + %if c.user_email_map: + %for em in c.user_email_map: + <tr> + <td class="td-user"> + ${base.gravatar(em.email, 16)} + <span class="user email">${em.email}</span> + </td> + <td class="td-action"> + ${h.secure_form(url('my_account_emails'),method='delete')} + ${h.hidden('del_email_id',em.email_id)} + <button class="btn btn-link btn-danger" type="submit" id="remove_email_%s" % em.email_id + onclick="return confirm('${_('Confirm to delete this email: %s') % em.email}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr class="noborder"> + <td colspan="3"> + <div class="td-email"> + ${_('No additional emails specified')} + </div> + </td> + </tr> + %endif + </table> + </div> + + <div> + ${h.secure_form(url('my_account_emails'), method='post')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_email">${_('New email address')}:</label> + </div> + <div class="input"> + ${h.text('new_email', class_='medium')} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> + </div> +</div> diff --git a/rhodecode/templates/admin/my_account/my_account_oauth.html b/rhodecode/templates/admin/my_account/my_account_oauth.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_oauth.html @@ -0,0 +1,62 @@ +<%namespace file="/base/social_buttons.html" import="render_social_buttons"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Oauth Identities')}</h3> + </div> + <div class="panel-body"> + <p> + ${_('External services currently connected with your Rhodecode user')}. + </p> + + <p> + + % if not c.social_plugins: + ${_('No social authentication plugins are enabled by administrator')}. + %endif + + ${render_social_buttons(c.social_plugins)} + </p> + + % if c.user_oauth_tokens: + + <table class="rctable oauth-accounts"> + <thead> + <tr> + <th class="td-provider"> + Provider + </th> + <th class="td-account"> + Account + </th> + <th class="td-action"> + + </th> + </tr> + </thead> + <tbody> + % for token in c.user_oauth_tokens: + <tr> + <td class="td-provider"> + ${token.provider_name} + </td> + <td class="td-account"> + ${token.external_username} + </td> + <td class="td-action"> + ${h.secure_form(url('my_account_oauth', provider_name=token.provider_name, external_id=token.external_id), method='delete')} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to remove this provider from your account')}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + % endfor + </tbody> + </table> + % else: + <p>${_('You have no accounts linked yet')}.</p> + % endif + </div> +</div> diff --git a/rhodecode/templates/admin/my_account/my_account_password.html b/rhodecode/templates/admin/my_account/my_account_password.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_password.html @@ -0,0 +1,42 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Change Your Account Password')}</h3> + </div> + ${h.secure_form(url('my_account_password'), method='post')} + <div class="panel-body"> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="current_password">${_('Current Password')}:</label> + </div> + <div class="input"> + ${h.password('current_password',class_='medium',autocomplete="off")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="new_password">${_('New Password')}:</label> + </div> + <div class="input"> + ${h.password('new_password',class_='medium', autocomplete="off")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="password_confirmation">${_('Confirm New Password')}:</label> + </div> + <div class="input"> + ${h.password('new_password_confirmation',class_='medium', autocomplete="off")} + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} +</div> \ No newline at end of file diff --git a/rhodecode/templates/admin/my_account/my_account_perms.html b/rhodecode/templates/admin/my_account/my_account_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_perms.html @@ -0,0 +1,5 @@ +## permissions overview +<div id="perms_container"> +<%namespace name="p" file="/base/perms_summary.html"/> +${p.perms_summary(c.perm_user.permissions, actions=False)} +</div> diff --git a/rhodecode/templates/admin/my_account/my_account_profile.html b/rhodecode/templates/admin/my_account/my_account_profile.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_profile.html @@ -0,0 +1,55 @@ +<%namespace name="base" file="/base/base.html"/> +<div class="panel panel-default user-profile"> + <div class="panel-heading"> + <h3 class="panel-title">${_('My Profile')}</h3> + <a href="${url('my_account_edit')}" class="panel-edit">${_('Edit')}</a> + </div> + + <div class="panel-body"> + <div class="fieldset"> + <div class="left-label"> + ${_('Photo')}: + </div> + <div class="right-content"> + %if c.visual.use_gravatar: + ${base.gravatar(c.user.email, 100)} + %else: + ${base.gravatar(c.user.email, 20)} + ${_('Avatars are disabled')} + %endif + </div> + </div> + <div class="fieldset"> + <div class="left-label"> + ${_('Username')}: + </div> + <div class="right-content"> + ${c.user.username} + </div> + </div> + <div class="fieldset"> + <div class="left-label"> + ${_('First Name')}: + </div> + <div class="right-content"> + ${c.user.firstname} + </div> + </div> + <div class="fieldset"> + <div class="left-label"> + ${_('Last Name')}: + </div> + <div class="right-content"> + ${c.user.lastname} + </div> + </div> + <div class="fieldset"> + <div class="left-label"> + ${_('Email')}: + </div> + <div class="right-content"> + ${c.user.email or _('Missing email, please update your user email address.')} + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/rhodecode/templates/admin/my_account/my_account_profile_edit.html b/rhodecode/templates/admin/my_account/my_account_profile_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_profile_edit.html @@ -0,0 +1,110 @@ +<%namespace name="base" file="/base/base.html"/> +<div class="panel panel-default user-profile"> + <div class="panel-heading"> + <h3 class="panel-title">${_('My Profile')}</h3> + <a href="${url('my_account')}" class="panel-edit">Close</a> + </div> + + <div class="panel-body"> + ${h.secure_form(url('my_account'), method='post', class_='form')} + <% readonly = None %> + <% disabled = "" %> + + % if c.extern_type != 'rhodecode': + <% readonly = "readonly" %> + <% disabled = "disabled" %> + <div class="infoform"> + <div class="fields"> + <p>${_('Your user account details are managed by an external source, i.e. LDAP. Details cannot be managed here.')}.</p> + <div class="field"> + <div class="label"> + <label for="username">${_('Username')}:</label> + </div> + <div class="input"> + ${h.text('username', class_='input-valuedisplay', readonly=readonly)} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="name">${_('First Name')}:</label> + </div> + <div class="input"> + ${h.text('firstname', class_='input-valuedisplay', readonly=readonly)} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="lastname">${_('Last Name')}:</label> + </div> + <div class="input-valuedisplay"> + ${h.text('lastname', class_='input-valuedisplay', readonly=readonly)} + </div> + </div> + </div> + </div> + % else: + <div class="form"> + <div class="fields"> + <div class="field"> + <div class="label photo"> + ${_('Photo')}: + </div> + <div class="input profile"> + %if c.visual.use_gravatar: + ${base.gravatar(c.user.email, 100)} + <p class="help-block">${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a>.</p> + %else: + ${base.gravatar(c.user.email, 20)} + ${_('Avatars are disabled')} + %endif + </div> + </div> + <div class="field"> + <div class="label"> + <label for="username">${_('Username')}:</label> + </div> + <div class="input"> + ${h.text('username', class_='medium%s' % disabled, readonly=readonly)} + ${h.hidden('extern_name', c.extern_name)} + ${h.hidden('extern_type', c.extern_type)} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="name">${_('First Name')}:</label> + </div> + <div class="input"> + ${h.text('firstname', class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="lastname">${_('Last Name')}:</label> + </div> + <div class="input"> + ${h.text('lastname', class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="email">${_('Email')}:</label> + </div> + <div class="input"> + ## we should be able to edit email ! + ${h.text('email', class_="medium")} + </div> + </div> + + <div class="buttons"> + ${h.submit('save', _('Save'), class_="btn")} + ${h.reset('reset', _('Reset'), class_="btn")} + </div> + </div> + </div> + % endif + </div> +</div> \ No newline at end of file diff --git a/rhodecode/templates/admin/my_account/my_account_pullrequests.html b/rhodecode/templates/admin/my_account/my_account_pullrequests.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_pullrequests.html @@ -0,0 +1,85 @@ + +<div class="panel panel-default"> + <div class="panel-body"> + <div class="field"> + %if c.show_closed: + ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))} + %else: + ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))} + %endif + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Pull Requests You Opened')}</h3> + </div> + + <div class="panel-body"> + <div class="pullrequestlist"> + %if c.my_pull_requests: + %for pull_request in c.my_pull_requests: + <div class="${'closed' if pull_request.is_closed() else ''} prwrapper"> + <div class="pr"> + <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> + <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}"> + ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.format_date(pull_request.created_on))} + %if pull_request.is_closed(): + (${_('Closed')}) + %endif + </a> + <div class="repolist_actions"> + ${h.secure_form(url('pullrequest_delete', repo_name=pull_request.target_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')} + ${h.submit('remove_%s' % pull_request.pull_request_id, _('Delete'), + class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")} + ${h.end_form()} + </div> + </div> + </div> + %endfor + %else: + <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2> + %endif + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Pull Requests You Participate In')}</h3> + </div> + + <div class="panel-body"> + <div class="pullrequestlist"> + %if c.participate_in_pull_requests: + %for pull_request in c.participate_in_pull_requests: + <div class="${'closed' if pull_request.is_closed() else ''} prwrapper"> + <div class="pr"> + <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> + <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}"> + ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.format_date(pull_request.created_on))} + </a> + %if pull_request.is_closed(): + (${_('Closed')}) + %endif + </div> + </div> + %endfor + %else: + <li><span class="empty_data">${_('There are currently no open pull requests requiring your participation.')}</span></li> + %endif + </div> + </div> +</div> + +<script> + $('#show_closed').on('click', function(e){ + if($(this).is(":checked")){ + window.location = "${h.url('my_account_pullrequests', pr_show_closed=1)}"; + } + else{ + window.location = "${h.url('my_account_pullrequests')}"; + } + }) +</script> diff --git a/rhodecode/templates/admin/my_account/my_account_repos.html b/rhodecode/templates/admin/my_account/my_account_repos.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_repos.html @@ -0,0 +1,68 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repositories You Own')}</h3> + </div> + + <div class="panel-body"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + + <div id="repos_list_wrap"> + <table id="repo_list_table" class="display"></table> + </div> + </div> +</div> + +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#repo_list_table').dataTable().api(); + $('#repo_count').text(api.page.info().recordsDisplay); + }; + + // repo list + $('#repo_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 0, "asc" ]], + columns: [ + { data: {"_": "name", + "sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" }, + { data: 'menu', className: "quick_repo_menu" }, + { data: {"_": "last_changeset", + "sort": "last_changeset_raw", + "type": Number}, title: "${_('Commit')}", className: "td-hash" }, + { data: {"_": "action", + "sort": "action"}, title: "${_('Action')}", className: "td-action" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + quick_repo_menu(); + } + }); + + // update the counter when doing search + $('#repo_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var repo_api = $('#repo_list_table').dataTable().api(); + repo_api + .columns(0) + .search(this.value) + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + + }); + +</script> diff --git a/rhodecode/templates/admin/my_account/my_account_watched.html b/rhodecode/templates/admin/my_account/my_account_watched.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/my_account/my_account_watched.html @@ -0,0 +1,66 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Your Watched Repositories')}</h3> + </div> + + <div class="panel-body"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + + <div id="repos_list_wrap"> + <table id="repo_list_table" class="display"></table> + </div> + </div> +</div> + +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#repo_list_table').dataTable().api(); + $('#repo_count').text(api.page.info().recordsDisplay); + }; + + // repo list + $('#repo_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 0, "asc" ]], + columns: [ + { data: {"_": "name", + "sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" }, + { data: 'menu', className: "quick_repo_menu" }, + { data: {"_": "last_changeset", + "sort": "last_changeset_raw", + "type": Number}, title: "${_('Commit')}", className: "td-hash" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + quick_repo_menu(); + } + }); + + // update the counter when doing search + $('#repo_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var repo_api = $('#repo_list_table').dataTable().api(); + repo_api + .columns(0) + .search(this.value) + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + + }); + +</script> diff --git a/rhodecode/templates/admin/notifications/notifications.html b/rhodecode/templates/admin/notifications/notifications.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/notifications/notifications.html @@ -0,0 +1,78 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('My Notifications')} ${c.rhodecode_user.username} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('My Notifications')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + ##<ul class="links"> + ## <li> + ## <span ><a href="#">${_('Compose message')}</a></span> + ## </li> + ##</ul> + + <div class="notifications_buttons"> + <span id='all' class="action-link first ${'active' if c.current_filter=='all' else ''}"><a href="${h.url.current()}">${_('All')}</a></span> + <span id='comment' class="action-link ${'active' if c.current_filter=='comment' else ''}"><a href="${h.url.current(type=c.comment_type)}">${_('Comments')}</a></span> + <span id='pull_request' class="action-link last ${'active' if c.current_filter=='pull_request' else ''}"><a href="${h.url.current(type=c.pull_request_type)}">${_('Pull Requests')}</a></span> + + %if c.notifications: + + <span id='mark_all_read' class="btn btn-default">${_('Mark all as read')}</span> + + %endif + </div> + </div> + <div id='notification_data' class='main-content-full'> + <%include file='notifications_data.html'/> + </div> +</div> +<script type="text/javascript"> +var url_action = "${url('notification', notification_id='__NOTIFICATION_ID__')}"; +var run = function(){ + $('#notification_data').on('click','.delete-notification',function(e){ + var notification_id = e.currentTarget.id; + deleteNotification(url_action,notification_id) + }) + $('#notification_data').on('click','.read-notification',function(e){ + var notification_id = e.currentTarget.id; + readNotification(url_action,notification_id) + }) +} +run(); +$('#mark_all_read').on('click',function(e){ + //set notifications as read + var url = "${h.url('notifications_mark_all_read', **request.GET.mixed())}"; + $.post(url, {'csrf_token': CSRF_TOKEN}). + done(function(data){ + // hide notifications counter + $('#quick_login_link > .menu_link_notifications').hide(); + $('#notification_data').html(data); + }) + .fail(function(data, textStatus, errorThrown){ + alert("Error while saving notifications.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); +}) + +var current_filter = $("${c.current_filter}"); +if (current_filter.length){ + current_filter.addClass('active'); +} +</script> +</%def> diff --git a/rhodecode/templates/admin/notifications/notifications_data.html b/rhodecode/templates/admin/notifications/notifications_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/notifications/notifications_data.html @@ -0,0 +1,40 @@ +<%namespace name="base" file="/base/base.html"/> +%if c.notifications: +<% +unread = lambda n:{False:'unread'}.get(n) +%> + + +<div class="notification-list notification-table"> +%for notification in c.notifications: + <div id="notification_${notification.notification.notification_id}" class="container ${unread(notification.read)}"> + <div class="notification-header"> + <div class="desc ${unread(notification.read)}"> + <a href="${url('notification', notification_id=notification.notification.notification_id)}"> + ${base.gravatar(notification.notification.created_by_user.email, 16)} + ${notification.notification.description} + </a> + </div> + <div class="delete-notifications"> + <span id="${notification.notification.notification_id}" class="delete-notification"><i class="icon-delete" ></i></span> + </div> + <div class="read-notifications"> + %if not notification.read: + <span id="${notification.notification.notification_id}" class="read-notification"><i class="icon-ok" ></i></span> + %endif + </div> + </div> + <div class="notification-subject"></div> + </div> +%endfor +</div> + +<div class="notification-paginator"> + <div class="pagination-wh pagination-left"> + ${c.notifications.pager('$link_previous ~2~ $link_next')} + </div> +</div> + +%else: + <div class="table">${_('No notifications here yet')}</div> +%endif diff --git a/rhodecode/templates/admin/notifications/show_notification.html b/rhodecode/templates/admin/notifications/show_notification.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/notifications/show_notification.html @@ -0,0 +1,60 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Show notification')} ${c.rhodecode_user.username} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Notifications'),h.url('notifications'))} + » + ${_('Show notification')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + ##<ul class="links"> + ## <li> + ## <span ><a href="#">${_('Compose message')}</a></span> + ## </li> + ##</ul> + </div> + <div class="table"> + <div id="notification_${c.notification.notification_id}" class="main-content-full"> + <div class="notification-header"> + ${self.gravatar(c.notification.created_by_user.email, 30)} + <div class="desc"> + ${c.notification.description} + </div> + <div class="delete-notifications"> + <span id="${c.notification.notification_id}" class="delete-notification action"><i class="icon-delete" ></i></span> + </div> + </div> + <div class="notification-body"> + <div class="notification-subject">${h.literal(c.notification.subject)}</div> + %if c.notification.body: + ${h.render(c.notification.body, renderer=c.visual.default_renderer, mentions=True)} + %endif + </div> + </div> + </div> +</div> +<script type="text/javascript"> +var url = "${url('notification', notification_id='__NOTIFICATION_ID__')}"; +var main = "${url('notifications')}"; + $('.delete-notification').on('click',function(e){ + var notification_id = e.currentTarget.id; + deleteNotification(url,notification_id,[function(){window.location=main}]) + }) +</script> +</%def> diff --git a/rhodecode/templates/admin/permissions/permissions.html b/rhodecode/templates/admin/permissions/permissions.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions.html @@ -0,0 +1,56 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Permissions Administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${_('Permissions')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div class="sidebar-col-wrapper scw-small"> + ##main + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='application' else ''}"> + <a href="${h.url('admin_permissions_application')}">${_('Application')}</a> + </li> + <li class="${'active' if c.active=='global' else ''}"> + <a href="${h.url('admin_permissions_global')}">${_('Global')}</a> + </li> + <li class="${'active' if c.active=='objects' else ''}"> + <a href="${h.url('admin_permissions_object')}">${_('Object')}</a> + </li> + <li class="${'active' if c.active=='ips' else ''}"> + <a href="${h.url('admin_permissions_ips')}">${_('IP Whitelist')}</a> + </li> + <li class="${'active' if c.active=='perms' else ''}"> + <a href="${h.url('admin_permissions_overview')}">${_('Overview')}</a> + </li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/permissions/permissions_${c.active}.html"/> + </div> + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/permissions/permissions_application.html b/rhodecode/templates/admin/permissions/permissions_application.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions_application.html @@ -0,0 +1,71 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('System Wide Application Permissions')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('admin_permissions_application'), method='post')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label label-checkbox"> + <label for="anonymous">${_('Anonymous Access')}:</label> + </div> + <div class="checkboxes"> + <div class="checkbox"> + ${h.checkbox('anonymous',True)} Allow Anonymous Access + </div> + <span class="help-block">${h.literal(_('Allow access to RhodeCode Enterprise without requiring users to login. Anonymous users get the %s permission settings.' % (h.link_to('"default user"',h.url('admin_permissions_object')))))}</span> + </div> + </div> + + <div class="field"> + <div class="label label-select"> + <label for="default_register">${_('Registration')}:</label> + </div> + <div class="select"> + ${h.select('default_register','',c.register_choices)} + </div> + </div> + + <div class="field"> + <div class="label label-textarea"> + <label for="default_register_message">${_('Registration Page Message')}:</label> + </div> + <div class="textarea text-area editor" > + ${h.textarea('default_register_message', class_="medium", )} + <span class="help-block">${_('Custom message to be displayed on the registration page. HTML syntax is supported.')}</span> + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="default_extern_activate">${_('External Authentication Account Activation')}:</label> + </div> + <div class="select"> + ${h.select('default_extern_activate','',c.extern_activate_choices)} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> + +<script> + $(document).ready(function(){ + var select2Options = { + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }; + + $("#default_register").select2(select2Options); + $("#default_extern_activate").select2(select2Options); + }); +</script> diff --git a/rhodecode/templates/admin/permissions/permissions_global.html b/rhodecode/templates/admin/permissions/permissions_global.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions_global.html @@ -0,0 +1,10 @@ + +${h.secure_form(url('admin_permissions_global'), method='post')} + <div class="form permissions-global"> + <!-- fields --> + <div class="fields"> + <%namespace name="dpb" file="/base/default_perms_box.html"/> + ${dpb.default_perms_radios(global_permissions_template = True)} + </div> + </div> +${h.end_form()} diff --git a/rhodecode/templates/admin/permissions/permissions_ips.html b/rhodecode/templates/admin/permissions/permissions_ips.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions_ips.html @@ -0,0 +1,67 @@ + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Default IP Whitelist For All Users')}</h3> + </div> + <div class="panel-body"> + <div class="ips_wrap"> + <table class="rctable ip-whitelist"> + <tr> + <th>IP Address</th> + <th>IP Range</th> + <th>Description</th> + <th></th> + </tr> + %if c.user_ip_map: + %for ip in c.user_ip_map: + <tr> + <td class="td-ip"><div class="ip">${ip.ip_addr}</div></td> + <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td> + <td class="td-description"><div class="ip">${ip.description}</div></td> + <td class="td-action"> + ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='delete')} + ${h.hidden('del_ip_id',ip.ip_id)} + ${h.hidden('default_user', 'True')} + ${h.submit('remove_',_('Delete'),id="remove_ip_%s" % ip.ip_id, + class_="btn btn-link btn-danger", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")} + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr> + <td class="ip">${_('All IP addresses are allowed')}</td> + <td></td> + <td></td> + <td></td> + </tr> + %endif + </table> + </div> + + ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_ip">${_('New IP Address')}:</label> + </div> + <div class="input"> + ${h.hidden('default_user', 'True')} + ${h.text('new_ip')} ${h.text('description', placeholder=_('Description...'))} + <span class="help-block">${_('Enter a comma separated list of IP Addresses like 127.0.0.1,\n' + 'or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n' + 'To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax')}</span> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> diff --git a/rhodecode/templates/admin/permissions/permissions_objects.html b/rhodecode/templates/admin/permissions/permissions_objects.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions_objects.html @@ -0,0 +1,77 @@ + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Default Permissions for Repositories, User Groups and Repository Groups.')}</h3> + </div> + <div class="panel-body"> + <p>${_('Default system permissions. Each permissions management entity will be created with the following default settings. Check the overwrite checkbox to force any permission changes on already existing settings.')} + </p> + ${h.secure_form(url('admin_permissions_object'), method='post')} + <div class="form"> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="default_repo_perm">${_('Repository')}:</label> + </div> + <div class="select"> + ${h.select('default_repo_perm','',c.repo_perms_choices)} + + ${h.checkbox('overwrite_default_repo','true')} + <label for="overwrite_default_repo"> + <span class="tooltip" title="${h.tooltip(_('All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost'))}"> + ${_('Overwrite Existing Settings')} + </span> + </label> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_group_perm">${_('Repository Groups')}:</label> + </div> + <div class="select"> + ${h.select('default_group_perm','',c.group_perms_choices)} + ${h.checkbox('overwrite_default_group','true')} + <label for="overwrite_default_group"> + <span class="tooltip" title="${h.tooltip(_('All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}"> + ${_('Overwrite Existing Settings')} + </span> + </label> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_group_perm">${_('User Groups')}:</label> + </div> + <div class="select"> + ${h.select('default_user_group_perm','',c.user_group_perms_choices)} + ${h.checkbox('overwrite_default_user_group','true')} + <label for="overwrite_default_user_group"> + <span class="tooltip" title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}"> + ${_('Overwrite Existing Settings')} + </span> + </label> + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> + +<script> + $(document).ready(function(){ + var select2Options = { + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }; + $("#default_repo_perm").select2(select2Options); + $("#default_group_perm").select2(select2Options); + $("#default_user_group_perm").select2(select2Options); + }); +</script> diff --git a/rhodecode/templates/admin/permissions/permissions_perms.html b/rhodecode/templates/admin/permissions/permissions_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/permissions/permissions_perms.html @@ -0,0 +1,5 @@ +<h2>${_('Default User Permissions Overview')}</h2> + +## permissions overview +<%namespace name="p" file="/base/perms_summary.html"/> +${p.perms_summary(c.perm_user.permissions, show_all=True)} diff --git a/rhodecode/templates/admin/repo_groups/repo_group_add.html b/rhodecode/templates/admin/repo_groups/repo_group_add.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_group_add.html @@ -0,0 +1,100 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Add repository group')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Repository groups'),h.url('repo_groups'))} + » + ${_('Add Repository Group')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + <!-- end box / title --> + ${h.secure_form(url('repo_groups'), method='post')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="group_name">${_('Group Name')}:</label> + </div> + <div class="input"> + ${h.text('group_name', class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="group_description">${_('Description')}:</label> + </div> + <div class="textarea editor"> + ${h.textarea('group_description',cols=23,rows=5,class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="group_parent_id">${_('Group Parent')}:</label> + </div> + <div class="select"> + ${h.select('group_parent_id',request.GET.get('parent_group'),c.repo_groups,class_="medium")} + </div> + </div> + + <div id="copy_perms" class="field"> + <div class="label label-checkbox"> + <label for="group_copy_permissions">${_('Copy Parent Group Permissions')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('group_copy_permissions', value="True", checked="checked")} + <span class="help-block">${_('Copy permission settings from parent repository group.')}</span> + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} +</div> +<script> + $(document).ready(function(){ + var setCopyPermsOption = function(group_val){ + if(group_val != "-1"){ + $('#copy_perms').show() + } + else{ + $('#copy_perms').hide(); + } + } + $("#group_parent_id").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); + setCopyPermsOption($('#group_parent_id').val()) + $("#group_parent_id").on("change", function(e) { + setCopyPermsOption(e.val) + }) + $('#group_name').focus(); + }) +</script> +</%def> diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit.html b/rhodecode/templates/admin/repo_groups/repo_group_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit.html @@ -0,0 +1,56 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s repository group settings') % c.repo_group.name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Repository Groups'),h.url('repo_groups'))} + %if c.repo_group.parent_group: + » ${h.link_to(c.repo_group.parent_group.name,h.url('repo_group_home',group_name=c.repo_group.parent_group.group_name))} + %endif + » ${c.repo_group.name} +</%def> + +<%def name="breadcrumbs_side_links()"> + <ul class="links"> + <li> + <a href="${h.url('new_repo_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-success">${_(u'Add Child Group')}</a> + </li> + </ul> +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + ${self.breadcrumbs_side_links()} + </div> + + <div class="sidebar-col-wrapper"> + ##main + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li> + <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li> + <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/> + </div> + + </div> +</div> +</%def> diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html b/rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html @@ -0,0 +1,63 @@ +<%namespace name="base" file="/base/base.html"/> + +<% + elems = [ + (_('Owner'), lambda:base.gravatar_with_user(c.repo_group.user.email), '', ''), + (_('Created on'), h.format_date(c.repo_group.created_on), '', ''), + + (_('Total repositories'), c.repo_group.repositories_recursive_count, '', ''), + (_('Top level repositories'), c.repo_group.repositories.count(), '', c.repo_group.repositories.all()), + + (_('Children groups'), c.repo_group.children.count(), '', c.repo_group.children.all()), + ] +%> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repository Group: %s') % c.repo_group.group_name}</h3> + </div> + <div class="panel-body"> + ${base.dt_info_panel(elems)} + </div> + +</div> + +<div class="panel panel-danger"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Delete repository group')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(h.url('delete_repo_group', group_name=c.repo_group.group_name),method='delete')} + <table class="display"> + + <tr> + <td> + ${ungettext('This repository group includes %s children repository group.', 'This repository group includes %s children repository groups.', c.repo_group.children.count()) % c.repo_group.children.count()} + </td> + <td> + </td> + <td> + </td> + </tr> + <tr> + <td> + ${ungettext('This repository group includes %s repository.', 'This repository group includes %s repositories.', c.repo_group.repositories_recursive_count) % c.repo_group.repositories_recursive_count} + </td> + <td> + </td> + <td> + </td> + </tr> + + </table> + <div style="margin: 0 0 20px 0" class="fake-space"></div> + + <button class="btn btn-small btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete this group: %s') % (c.repo_group.group_name)}');"> + ${_('Delete this repository group')} + </button> + ${h.end_form()} + </div> +</div> + + diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html b/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html @@ -0,0 +1,148 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repository Group Permissions')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_group_perms', group_name=c.repo_group.group_name),method='put')} + <table id="permissions_manage" class="rctable permissions"> + <tr> + <th class="td-radio">${_('None')}</th> + <th class="td-radio">${_('Read')}</th> + <th class="td-radio">${_('Write')}</th> + <th class="td-radio">${_('Admin')}</th> + <th class="td-user">${_('User/User Group')}</th> + <th></th> + </tr> + ## USERS + %for _user in c.repo_group.permissions(): + %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None): + <tr class="perm_admin_row"> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + ${h.link_to_user(_user.username)} + %if getattr(_user, 'admin_row', None): + (${_('super admin')}) + %endif + %if getattr(_user, 'owner_row', None): + (${_('owner')}) + %endif + </span> + </td> + <td></td> + </tr> + %else: + ##forbid revoking permission from yourself, except if you're an super admin + <tr> + %if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin: + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin')}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + % if _user.username == h.DEFAULT_USER: + ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> + % else: + ${h.link_to_user(_user.username)} + % endif + </span> + </td> + <td class="td-action"> + %if _user.username != h.DEFAULT_USER: + <span class="btn btn-link btn-danger revoke_perm" + member="${_user.user_id}" member_type="user"> + <i class="icon-remove"></i> ${_('Revoke')} + </span> + %endif + </td> + %else: + ## special case for current user permissions, we make sure he cannot take his own permissions + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin', disabled="disabled")}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + % if _user.username == h.DEFAULT_USER: + ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> + % else: + ${h.link_to_user(_user.username)} + % endif + <span class="user-perm-help-text">(${_('delegated admin')})</span> + </span> + </td> + <td></td> + %endif + </tr> + %endif + %endfor + + ## USER GROUPS + %for _user_group in c.repo_group.permission_user_groups(): + <tr id="id${id(_user_group.users_group_name)}"> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.none')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.read')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin')}</td> + <td class="td-componentname"> + <i class="icon-group" ></i> + %if h.HasPermissionAny('hg.admin')(): + <a href="${h.url('edit_users_group',user_group_id=_user_group.users_group_id)}"> + ${_user_group.users_group_name} + </a> + %else: + ${_user_group.users_group_name} + %endif + </td> + <td class="td-action"> + <span class="btn btn-link btn-danger revoke_perm" + member="${_user_group.users_group_id}" member_type="user_group"> + <i class="icon-remove"></i> ${_('Revoke')} + </span> + </td> + </tr> + %endfor + + <tr class="new_members" id="add_perm_input"></tr> + </table> + <div id="add_perm" class="link"> + ${_('Add new')} + </div> + <div class="fields"> + <div class="field"> + <div class="label label-radio"> + ${_('Apply to children')}: + </div> + <div class="radios"> + ${h.radio('recursive', 'none', label=_('None'), checked="checked")} + ${h.radio('recursive', 'groups', label=_('Repository Groups'))} + ${h.radio('recursive', 'repos', label=_('Repositories'))} + ${h.radio('recursive', 'all', label=_('Both'))} + <span class="help-block">${_('Set or revoke permissions to selected types of children of this group, including non-private repositories and other groups if chosen.')}</span> + </div> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn btn-primary")} + ${h.reset('reset',_('Reset'),class_="btn btn-danger")} + </div> + ${h.end_form()} + </div> +</div> +<script type="text/javascript"> + $('#add_perm').on('click', function(e){ + addNewPermInput($(this), 'group'); + }); + $('.revoke_perm').on('click', function(e){ + markRevokePermInput($(this), 'group'); + }) +</script> diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html b/rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html @@ -0,0 +1,72 @@ +## -*- coding: utf-8 -*- +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('update_repo_group',group_name=c.repo_group.group_name),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="group_name">${_('Group Name')}:</label> + </div> + <div class="input"> + ${h.text('group_name',class_='medium')} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="user">${_('Owner')}:</label> + </div> + <div class="input"> + ${h.text('user', class_="medium", autocomplete="off")} + <span class="help-block">${_('Change Repository Group Owner.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-textarea"> + <label for="group_description">${_('Description')}:</label> + </div> + <div class="textarea text-area editor"> + ${h.textarea('group_description',cols=23,rows=5,class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="group_parent_id">${_('Group parent')}:</label> + </div> + <div class="select"> + ${h.select('group_parent_id','',c.repo_groups,class_="medium")} + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="enable_locking">${_('Enable Repository Locking')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('enable_locking',value="True")} + <span class="help-block">${_('Repository locking will be enabled on all subgroups and repositories inside this repository group. Pulling from a repository locks it, and it is unlocked by pushing back by the same user.')}</span> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> +<script> + $(document).ready(function(){ + $("#group_parent_id").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); + UsersAutoComplete('user', '${c.rhodecode_user.user_id}'); + }) +</script> diff --git a/rhodecode/templates/admin/repo_groups/repo_groups.html b/rhodecode/templates/admin/repo_groups/repo_groups.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repo_groups/repo_groups.html @@ -0,0 +1,94 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Repository groups administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + ${h.link_to(_('Admin'),h.url('admin_home'))} » <span id="repo_group_count">0</span> ${_('repository groups')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + <ul class="links"> + %if h.HasPermissionAny('hg.admin','hg.repogroup.create.true')(): + <li> + <a href="${h.url('new_repo_group')}" class="btn btn-small btn-success">${_(u'Add Repository Group')}</a> + </li> + %endif + </ul> + </div> + <div id="repos_list_wrap"> + <table id="group_list_table" class="display"></table> + </div> +</div> + +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#group_list_table').dataTable().api(); + $('#repo_group_count').text(api.page.info().recordsDisplay); + }; + + // repo group list + $('#group_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 0, "asc" ]], + columns: [ + { data: {"_": "name", + "sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" }, + { data: 'menu', "bSortable": false, className: "quick_repo_menu" }, + { data: {"_": "desc", + "sort": "desc"}, title: "${_('Description')}", className: "td-description" }, + { data: {"_": "top_level_repos", + "sort": "top_level_repos"}, title: "${_('Number of top level repositories')}" }, + { data: {"_": "owner", + "sort": "owner"}, title: "${_('Owner')}", className: "td-user" }, + { data: {"_": "action", + "sort": "action"}, title: "${_('Action')}", className: "td-action" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + quick_repo_menu(); + } + }); + + // update the counter when doing search + $('#group_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + + var repo_group_api = $('#group_list_table').dataTable().api(); + repo_group_api + .columns(0) + .search(this.value) + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); +}); +</script> +</%def> + diff --git a/rhodecode/templates/admin/repos/repo_add.html b/rhodecode/templates/admin/repos/repo_add.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_add.html @@ -0,0 +1,37 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Add repository')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + %if c.rhodecode_user.is_admin: + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Repositories'),h.url('repos'))} + %else: + ${_('Admin')} + » + ${_('Repositories')} + %endif + » + ${_('Add Repository')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> + <div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + <%include file="repo_add_base.html"/> + </div> +</%def> diff --git a/rhodecode/templates/admin/repos/repo_add_base.html b/rhodecode/templates/admin/repos/repo_add_base.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_add_base.html @@ -0,0 +1,146 @@ +## -*- coding: utf-8 -*- + +${h.secure_form(url('repos'))} +<div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="repo_name">${_('Name')}:</label> + </div> + <div class="input"> + ${h.text('repo_name', class_="medium")} + <div class="info-block"> + <a id="remote_clone_toggle" href="#"><i class="icon-download-alt"></i> ${_('Import Existing Repository ?')}</a> + </div> + %if not c.rhodecode_user.is_admin: + ${h.hidden('user_created',True)} + %endif + </div> + </div> + <div id="remote_clone" class="field" style="display: none;"> + <div class="label"> + <label for="clone_uri">${_('Clone from')}:</label> + </div> + <div class="input"> + ${h.text('clone_uri', class_="medium")} + <span class="help-block">${_('Optional http[s] URL from which to clone a repository.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="repo_description">${_('Description')}:</label> + </div> + <div class="textarea editor"> + ${h.textarea('repo_description')} + <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="repo_group">${_('Repository Group')}:</label> + </div> + <div class="select"> + ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")} + %if c.personal_repo_group: + <a style="padding: 4px" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}}</a> + %endif + <span class="help-block">${_('Optionally select a group to put this repository into.')}</span> + </div> + </div> + <div id="copy_perms" class="field"> + <div class="label label-checkbox"> + <label for="repo_copy_permissions">${_('Copy Parent Group Permissions')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_copy_permissions', value="True", checked="checked")} + <span class="help-block">${_('Copy permission set from the parent repository group.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="repo_type">${_('Type')}:</label> + </div> + <div class="select"> + ${h.select('repo_type','hg',c.backends)} + <span class="help-block">${_('Set the type of repository to create.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="repo_landing_rev">${_('Landing commit')}:</label> + </div> + <div class="select"> + ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")} + <span class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="repo_private">${_('Private Repository')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_private',value="True")} + <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> +</div> +<script> + $(document).ready(function(){ + var setCopyPermsOption = function(group_val){ + if(group_val != "-1"){ + $('#copy_perms').show() + } + else{ + $('#copy_perms').hide(); + } + }; + + $('#remote_clone_toggle').on('click', function(e){ + $('#remote_clone').show(); + e.preventDefault(); + }); + + if($('#remote_clone input').hasClass('error')){ + $('#remote_clone').show(); + } + if($('#remote_clone input').val()){ + $('#remote_clone').show(); + } + + $("#repo_group").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true, + 'width': "resolve" + }); + + setCopyPermsOption($('#repo_group').val()); + $("#repo_group").on("change", function(e) { + setCopyPermsOption(e.val) + }); + + $("#repo_type").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'minimumResultsForSearch': -1, + }); + $("#repo_landing_rev").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'minimumResultsForSearch': -1, + }); + $('#repo_name').focus(); + + $('#select_my_group').on('click', function(e){ + e.preventDefault(); + $("#repo_group").val($(this).data('personalGroupId')).trigger("change"); + }) + + }) +</script> +${h.end_form()} diff --git a/rhodecode/templates/admin/repos/repo_creating.html b/rhodecode/templates/admin/repos/repo_creating.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_creating.html @@ -0,0 +1,74 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +## don't trigger flash messages on this page +<%def name="flash_msg()"> +</%def> + +<%def name="title()"> + ${_('%s Creating repository') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('Creating repository')} ${c.repo} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} +</%def> +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + + <div id="progress-message"> + ${_('Repository "%(repo_name)s" is being created, you will be redirected when this process is finished.' % {'repo_name':c.repo_name})} + </div> + + <div id="progress"> + <div class="progress progress-striped active"> + <div class="progress-bar progress-bar" role="progressbar" + aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"> + </div> + </div> + </div> +</div> +</%def> + +<script> +(function worker() { + var skipCheck = false; + var url = "${h.url('repo_check_home', repo_name=c.repo_name, repo=c.repo, task_id=c.task_id)}"; + $.ajax({ + url: url, + complete: function(resp) { + if (resp.status == 200) { + var jsonResponse = resp.responseJSON; + + if (jsonResponse === undefined){ + setTimeout(function(){ + // we might have a backend problem, try dashboard again + window.location = "${h.url('summary_home', repo_name = c.repo)}"; + }, 1000); + } + + if (skipCheck || jsonResponse.result === true) { + // success, means go to dashboard + window.location = "${h.url('summary_home', repo_name = c.repo)}"; + } else { + // Schedule the next request when the current one's complete + setTimeout(worker, 1000); + } + } + else { + window.location = "${h.url('home')}"; + } + } + }); +})(); +</script> diff --git a/rhodecode/templates/admin/repos/repo_edit.html b/rhodecode/templates/admin/repos/repo_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit.html @@ -0,0 +1,77 @@ +## -*- coding: utf-8 -*- +## +## See also repo_settings.html +## +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s repository settings') % c.repo_info.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${_('Settings')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} +</%def> + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='options')} +</%def> + + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.repo_page_title(c.rhodecode_db_repo)} + ${self.breadcrumbs()} + </div> + + <div class="sidebar-col-wrapper scw-small"> + ##main + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='settings' else ''}"> + <a href="${h.url('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a> + </li> + <li class="${'active' if c.active=='permissions' else ''}"> + <a href="${h.url('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a> + </li> + <li class="${'active' if c.active=='advanced' else ''}"> + <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a> + </li> + <li class="${'active' if c.active=='vcs' else ''}"> + <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">${_('VCS')}</a> + </li> + <li class="${'active' if c.active=='fields' else ''}"> + <a href="${h.url('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra Fields')}</a> + </li> + <li class="${'active' if c.active=='issuetracker' else ''}"> + <a href="${h.url('repo_settings_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a> + </li> + <li class="${'active' if c.active=='caches' else ''}"> + <a href="${h.url('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a> + </li> + %if c.repo_info.repo_type != 'svn': + <li class="${'active' if c.active=='remote' else ''}"> + <a href="${h.url('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a> + </li> + %endif + <li class="${'active' if c.active=='statistics' else ''}"> + <a href="${h.url('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a> + </li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/repos/repo_edit_${c.active}.html"/> + </div> + + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/repos/repo_edit_advanced.html b/rhodecode/templates/admin/repos/repo_edit_advanced.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_advanced.html @@ -0,0 +1,211 @@ +<%namespace name="base" file="/base/base.html"/> + +<% + elems = [ + (_('Owner'), lambda:base.gravatar_with_user(c.repo_info.user.email), '', ''), + (_('Created on'), h.format_date(c.repo_info.created_on), '', ''), + (_('Updated on'), h.format_date(c.repo_info.updated_on), '', ''), + (_('Cached Commit id'), lambda: h.link_to(c.repo_info.changeset_cache.get('short_id'), h.url('changeset_home',repo_name=c.repo_name,revision=c.repo_info.changeset_cache.get('raw_id'))), '', ''), + ] +%> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repository: %s') % c.repo_info.repo_name}</h3> + </div> + <div class="panel-body"> + ${base.dt_info_panel(elems)} + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Fork Reference')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='put')} + + % if c.repo_info.fork: + <div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h.url('summary_home', repo_name=c.repo_info.fork.repo_name))})} + | <button class="btn btn-link btn-danger" type="submit">Remove fork reference</button></div> + % endif + + <div class="field"> + ${h.hidden('id_fork_of')} + ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small",)} + </div> + <div class="field"> + <span class="help-block">${_('Manually set this repository as a fork of another from the list')}</span> + </div> + ${h.end_form()} + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Public Journal Visibility')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_advanced_journal', repo_name=c.repo_info.repo_name), method='put')} + <div class="field"> + %if c.in_public_journal: + <button class="btn btn-small" type="submit"> + <i class="icon-minus"></i> + ${_('Remove from Public Journal')} + </button> + %else: + <button class="btn btn-small" type="submit"> + ${_('Add to Public Journal')} + </button> + %endif + </div> + <div class="field" > + <span class="help-block">${_('All actions made on this repository will be visible to everyone following the public journal.')}</span> + </div> + ${h.end_form()} + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Locking state')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name), method='put')} + + %if c.repo_info.locked[0]: + <div class="panel-body-title-text">${'Locked by %s on %s. Lock reason: %s' % (h.person_by_id(c.repo_info.locked[0]), + h.format_date(h. time_to_datetime(c.repo_info.locked[1])), c.repo_info.locked[2])}</div> + %else: + <div class="panel-body-title-text">${_('This Repository is not currently locked.')}</div> + %endif + + <div class="field" > + %if c.repo_info.locked[0]: + ${h.hidden('set_unlock', '1')} + <button class="btn btn-small" type="submit" + onclick="return confirm('${_('Confirm to unlock repository.')}');"> + <i class="icon-unlock"></i> + ${_('Unlock repository')} + </button> + %else: + ${h.hidden('set_lock', '1')} + <button class="btn btn-small" type="submit" + onclick="return confirm('${_('Confirm to lock repository.')}');"> + <i class="icon-lock"></i> + ${_('Lock Repository')} + </button> + %endif + </div> + <div class="field" > + <span class="help-block"> + ${_('Force repository locking. This only works when anonymous access is disabled. Pulling from the repository locks the repository to that user until the same user pushes to that repository again.')} + </span> + </div> + ${h.end_form()} + </div> +</div> + +<div class="panel panel-danger"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Delete repository')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('repo', repo_name=c.repo_name),method='delete')} + <table class="display"> + <tr> + <td> + ${ungettext('This repository has %s fork.', 'This repository has %s forks.', c.repo_info. forks.count()) % c.repo_info.forks.count()} + </td> + <td> + %if c.repo_info.forks.count(): + <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label> + %endif + </td> + <td> + %if c.repo_info.forks.count(): + <input type="radio" name="forks" value="delete_forks"/> <label for="forks">${_('Delete forks')}</label> + %endif + </td> + </tr> + </table> + <div style="margin: 0 0 20px 0" class="fake-space"></div> + + <div class="field"> + <button class="btn btn-small btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete this repository: %s') % c.repo_name}');"> + <i class="icon-remove-sign"></i> + ${_('Delete This Repository')} + </button> + </div> + <div class="field"> + <span class="help-block"> + ${_('This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command.')} + </span> + </div> + + ${h.end_form()} + </div> +</div> + + +<script> + +var currentRepoId = ${c.repo_info.repo_id}; + +var repoTypeFilter = function(data) { + var results = []; + + if (!data.results[0]) { + return data + } + + $.each(data.results[0].children, function() { + // filter out the SAME repo, it cannot be used as fork of itself + if (this.obj.repo_id != currentRepoId) { + this.id = this.obj.repo_id; + results.push(this) + } + }); + data.results[0].children = results; + return data; +}; + +$("#id_fork_of").select2({ + cachedDataSource: {}, + minimumInputLength: 2, + placeholder: "${_('Change repository') if c.repo_info.fork else _('Pick repository')}", + dropdownAutoWidth: true, + containerCssClass: "drop-menu", + dropdownCssClass: "drop-menu-dropdown", + formatResult: formatResult, + query: $.debounce(250, function(query){ + self = this; + var cacheKey = query.term; + var cachedData = self.cachedDataSource[cacheKey]; + + if (cachedData) { + query.callback({results: cachedData.results}); + } else { + $.ajax({ + url: "${h.url('repo_list_data')}", + data: {'query': query.term, repo_type: '${c.repo_info.repo_type}'}, + dataType: 'json', + type: 'GET', + success: function(data) { + data = repoTypeFilter(data); + self.cachedDataSource[cacheKey] = data; + query.callback({results: data.results}); + }, + error: function(data, textStatus, errorThrown) { + alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText)); + } + }) + } + }) +}); +</script> + diff --git a/rhodecode/templates/admin/repos/repo_edit_caches.html b/rhodecode/templates/admin/repos/repo_edit_caches.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_caches.html @@ -0,0 +1,51 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Invalidate Cache for Repository')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_caches', repo_name=c.repo_name), method='put')} + <div> + <div class="fields"> + <p> + ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")} + </p> + <div class="field" > + <span class="help-block"> + ${_('Manually invalidate the repository cache. On the next access a repository cache will be recreated.')} + </span> + </div> + + </div> + </div> + ${h.end_form()} + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"> + ${(ungettext('List of repository caches (%(count)s entry)', 'List of repository caches (%(count)s entries)' ,len(c.repo_info.cache_keys)) % {'count': len(c.repo_info.cache_keys)})} + </h3> + </div> + <div class="panel-body"> + <div class="field" > + <table class="rctable edit_cache"> + <tr> + <th>${_('Prefix')}</th> + <th>${_('Key')}</th> + <th>${_('Active')}</th> + </tr> + %for cache in c.repo_info.cache_keys: + <tr> + <td class="td-prefix">${cache.get_prefix() or '-'}</td> + <td class="td-cachekey">${cache.cache_key}</td> + <td class="td-active">${h.bool2icon(cache.cache_active)}</td> + </tr> + %endfor + </table> + </div> + </div> +</div> + + diff --git a/rhodecode/templates/admin/repos/repo_edit_fields.html b/rhodecode/templates/admin/repos/repo_edit_fields.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_fields.html @@ -0,0 +1,79 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Custom extra fields for this repository')}</h3> + </div> + <div class="panel-body"> + %if c.visual.repository_fields: + %if c.repo_fields: + <div class="emails_wrap"> + <table class="rctable edit_fields"> + <th>${_('Label')}</th> + <th>${_('Key')}</th> + <th>${_('Type')}</th> + <th>${_('Action')}</th> + + %for field in c.repo_fields: + <tr> + <td class="td-tags">${field.field_label}</td> + <td class="td-hash">${field.field_key}</td> + <td class="td-type">${field.field_type}</td> + <td class="td-action"> + ${h.secure_form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')} + ${h.hidden('del_repo_field',field.repo_field_id)} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete this field: %s') % field.field_key}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + </table> + </div> + %endif + ${h.secure_form(url('create_repo_fields', repo_name=c.repo_name),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_field_key">${_('New Field Key')}:</label> + </div> + <div class="input"> + ${h.text('new_field_key', class_='medium')} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="new_field_label">${_('New Field Label')}:</label> + </div> + <div class="input"> + ${h.text('new_field_label', class_='medium', placeholder=_('Enter short label'))} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="new_field_desc">${_('New Field Description')}:</label> + </div> + <div class="input"> + ${h.text('new_field_desc', class_='medium', placeholder=_('Enter a full description for the field'))} + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + %else: + <h2> + ${_('Extra fields are disabled. You can enable them from the Admin/Settings/Visual page.')} + </h2> + %endif + </div> +</div> + + diff --git a/rhodecode/templates/admin/repos/repo_edit_fork.html b/rhodecode/templates/admin/repos/repo_edit_fork.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_fork.html @@ -0,0 +1,23 @@ +${h.secure_form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')} +<div class="form"> + <div class="fields"> + ${h.select('id_fork_of','',c.repo_list,class_="medium")} + ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="btn btn-small",)} + </div> + <div class="field" > + <ul> + <li>${_('''Manually set this repository as a fork of another from the list''')}</li> + </ul> + </div> +</div> +${h.end_form()} + +<script> + $(document).ready(function(){ + $("#id_fork_of").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true, + }); + }) +</script> diff --git a/rhodecode/templates/admin/repos/repo_edit_issuetracker.html b/rhodecode/templates/admin/repos/repo_edit_issuetracker.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_issuetracker.html @@ -0,0 +1,109 @@ +<%namespace name="its" file="/base/issue_tracker_settings.html"/> + +<div id="repo_issue_tracker" class="${'inherited' if c.settings_model.inherit_global_settings else ''}"> + ${h.secure_form(url('repo_issuetracker_save', repo_name=c.repo_name), method='post', id="inherit-form")} + <div class="panel panel-default panel-body"> + <div class="fields"> + <div class="field"> + <div class="label label-checkbox"> + <label for="inherit_default_permissions">${_('Inherit from global settings')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('inherit_global_issuetracker', value='inherited', checked=c.settings_model.inherit_global_settings)} + <span class="help-block"> + ${h.literal(_('Select to inherit global patterns for issue tracker.'))} + </span> + </div> + </div> + </div> + </div> + + <div id="inherit_overlay"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Inherited Issue Tracker Patterns')}</h3> + </div> + <div class="panel-body"> + <table class="rctable issuetracker readonly"> + <tr> + <th>${_('Description')}</th> + <th>${_('Pattern')}</th> + <th>${_('Url')}</th> + <th>${_('Prefix')}</th> + <th ></th> + </tr> + %for uid, entry in c.global_patterns.items(): + <tr id="${uid}"> + <td class="td-description issuetracker_desc"> + <span class="entry"> + ${entry.desc} + </span> + </td> + <td class="td-regex issuetracker_pat"> + <span class="entry"> + ${entry.pat} + </span> + </td> + <td class="td-url issuetracker_url"> + <span class="entry"> + ${entry.url} + </span> + </td> + <td class="td-prefix issuetracker_pref"> + <span class="entry"> + ${entry.pref} + </span> + </td> + <td class="td-action"> + </td> + </tr> + %endfor + + </table> + </div> + </div> + </div> + + <div id="custom_overlay"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Issue Tracker / Wiki Patterns')}</h3> + </div> + <div class="panel-body"> + ${its.issue_tracker_settings_table( + patterns=c.repo_patterns.items(), + form_url=url('repo_settings_issuetracker', repo_name=c.repo_info.repo_name), + delete_url=url('repo_issuetracker_delete', repo_name=c.repo_info.repo_name) + )} + <div class="buttons"> + <button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button> + <button type="reset" class="btn reset-inheritance">${_('Reset')}</button> + </div> + </div> + </div> + </div> + + + ${h.end_form()} + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Test Patterns')}</h3> + </div> + <div class="panel-body"> + ${its.issue_tracker_new_row()} + ${its.issue_tracker_settings_test(test_url=url('repo_issuetracker_test', repo_name=c.repo_info.repo_name))} + </div> +</div> + +</div> + +<script> + $('#inherit_global_issuetracker').on('change', function(e){ + $('#repo_issue_tracker').toggleClass('inherited',this.checked); + }); + + $('.reset-inheritance').on('click', function(e){ + $('#inherit_global_issuetracker').prop('checked', false).change(); + }); +</script> diff --git a/rhodecode/templates/admin/repos/repo_edit_permissions.html b/rhodecode/templates/admin/repos/repo_edit_permissions.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_permissions.html @@ -0,0 +1,124 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repository Permissions')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_perms_update', repo_name=c.repo_name), method='put')} + ${h.hidden('repo_private')} + <table id="permissions_manage" class="rctable permissions"> + <tr> + <th class="td-radio">${_('None')}</th> + <th class="td-radio">${_('Read')}</th> + <th class="td-radio">${_('Write')}</th> + <th class="td-radio">${_('Admin')}</th> + <th class="td-owner">${_('User/User Group')}</th> + <th></th> + </tr> + ## USERS + %for _user in c.repo_info.permissions(): + %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None): + <tr class="perm_admin_row"> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + ${h.link_to_user(_user.username)} + %if getattr(_user, 'admin_row', None): + (${_('super admin')}) + %endif + %if getattr(_user, 'owner_row', None): + (${_('owner')}) + %endif + </td> + <td></td> + </tr> + %elif _user.username == h.DEFAULT_USER and c.repo_info.private: + <tr> + <td colspan="4"> + <span class="private_repo_msg"> + <strong>${_('private repository')}</strong> + </span> + </td> + <td class="private_repo_msg"> + ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)} + ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td> + <td></td> + </tr> + %else: + <tr> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin')}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + % if _user.username == h.DEFAULT_USER: + ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> + % else: + ${h.link_to_user(_user.username)} + % endif + </span> + </td> + <td class="td-action"> + %if _user.username != h.DEFAULT_USER: + <span class="btn btn-link btn-danger revoke_perm" + member="${_user.user_id}" member_type="user"> + <i class="icon-remove"></i> ${_('Revoke')} + </span> + %endif + </td> + </tr> + %endif + %endfor + + ## USER GROUPS + %for _user_group in c.repo_info.permission_user_groups(): + <tr> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin')}</td> + <td class="td-componentname"> + <i class="icon-group" ></i> + %if h.HasPermissionAny('hg.admin')(): + <a href="${h.url('edit_users_group',user_group_id=_user_group.users_group_id)}"> + ${_user_group.users_group_name} + </a> + %else: + ${_user_group.users_group_name} + %endif + </td> + <td class="td-action"> + <span class="btn btn-link btn-danger revoke_perm" + member="${_user_group.users_group_id}" member_type="user_group"> + <i class="icon-remove"></i> ${_('Revoke')} + </span> + </td> + </tr> + %endfor + <tr class="new_members" id="add_perm_input"></tr> + </table> + <div id="add_perm" class="link"> + ${_('Add new')} + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn btn-primary")} + ${h.reset('reset',_('Reset'),class_="btn btn-danger")} + </div> + ${h.end_form()} + </div> +</div> + +<script type="text/javascript"> + $('#add_perm').on('click', function(e){ + addNewPermInput($(this), 'repository'); + }); + $('.revoke_perm').on('click', function(e){ + markRevokePermInput($(this), 'repository'); + }); +</script> diff --git a/rhodecode/templates/admin/repos/repo_edit_remote.html b/rhodecode/templates/admin/repos/repo_edit_remote.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_remote.html @@ -0,0 +1,29 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Remote url')}</h3> + </div> + <div class="panel-body"> + + %if c.repo_info.clone_uri: + + <div class="panel-body-title-text">${_('Remote mirror url')}: <a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri_hidden}</a></div> + + ${h.secure_form(url('edit_repo_remote', repo_name=c.repo_name), method='put')} + <div class="form"> + <div class="fields"> + ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")} + </div> + </div> + ${h.end_form()} + %else: + <div class="panel-body-title-text">${_('This repository does not have any remote mirror url set.')}</div> + + <button class="btn btn-default" type="submit" disabled="disabled"> + ${_('Pull changes from remote location')} + </button> + %endif + </div> +</div> + + + diff --git a/rhodecode/templates/admin/repos/repo_edit_settings.html b/rhodecode/templates/admin/repos/repo_edit_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_settings.html @@ -0,0 +1,225 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('repo', repo_name=c.repo_info.repo_name),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="repo_name">${_('Name')}:</label> + </div> + <div class="input"> + ${h.text('repo_name',class_="medium")} + <p class="help-block">${_('Non-changeable id')}: `_${c.repo_info.repo_id}` <span><a id="show_more_clone_id" href="#">${_('what is that ?')}</a></span></p> + <p id="clone_id" style="display:none;"> + ${_('URL by id')}: `${c.repo_info.clone_url(with_id=True)}` </br> + ${_('''In case this repository is renamed or moved into another group the repository url changes. + Using above url guarantees that this repository will always be accessible under such url. + Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service.''')}</p> + </div> + </div> + % if c.repo_info.repo_type != 'svn': + <div class="field"> + <div class="label"> + <label for="clone_uri">${_('Remote uri')}:</label> + </div> + <div class="input"> + %if c.repo_info.clone_uri: + <div id="clone_uri_hidden" class='text-as-placeholder'> + <span id="clone_uri_hidden_value">${c.repo_info.clone_uri_hidden}</span> + <span class="link" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span> + </div> + <div id="alter_clone_uri" style="display: none"> + ${h.text('clone_uri',class_="medium", placeholder=_('new value, leave empty to remove'))} + ${h.hidden('clone_uri_change', 'OLD')} + <span class="link" id="cancel_edit_clone_uri">${_('cancel')}</span> + </div> + %else: + ## not set yet, display form to set it + ${h.text('clone_uri',class_="medium")} + ${h.hidden('clone_uri_change', 'NEW')} + %endif + <p id="alter_clone_uri_help_block" class="help-block">${_('http[s] url where from repository was imported, also used for doing remote pulls.')}</p> + </div> + </div> + % else: + ${h.hidden('clone_uri', '')} + % endif + <div class="field"> + <div class="label"> + <label for="repo_group">${_('Repository group')}:</label> + </div> + <div class="select"> + ${h.select('repo_group','',c.repo_groups,class_="medium")} + %if c.personal_repo_group: + <a style="padding: 4px" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}}</a> + %endif + <p class="help-block">${_('Optional select a group to put this repository into.')}</p> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="repo_landing_rev">${_('Landing commit')}:</label> + </div> + <div class="select"> + ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")} + <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="user">${_('Owner')}:</label> + </div> + <div class="input"> + ${h.text('user', class_="medium", autocomplete="off")} + <p class="help-block">${_('Change owner of this repository.')}</p> + </div> + </div> + <div class="field"> + <div class="label label-textarea"> + <label for="repo_description">${_('Description')}:</label> + </div> + <div class="textarea text-area editor"> + ${h.textarea('repo_description', )} + <p class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</p> + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="repo_private">${_('Private repository')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_private',value="True")} + <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="repo_enable_statistics">${_('Enable statistics')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_enable_statistics',value="True")} + <span class="help-block">${_('Enable statistics window on summary page.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="repo_enable_downloads">${_('Enable downloads')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_enable_downloads',value="True")} + <span class="help-block">${_('Enable download menu on summary page.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="repo_enable_locking">${_('Enable automatic locking')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('repo_enable_locking',value="True")} + <span class="help-block">${_('Enable automatic locking on repository. Pulling from this repository creates a lock that can be released by pushing back by the same user')}</span> + </div> + </div> + + %if c.visual.repository_fields: + ## EXTRA FIELDS + %for field in c.repo_fields: + <div class="field"> + <div class="label"> + <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label> + </div> + <div class="input input-medium"> + ${h.text(field.field_key_prefixed, field.field_value, class_='medium')} + %if field.field_desc: + <span class="help-block">${field.field_desc}</span> + %endif + </div> + </div> + %endfor + %endif + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> + +<script> + $(document).ready(function(){ + var select2Options = { + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }; + + var cloneUrl = function() { + var alterButton = $('#alter_clone_uri'); + var editButton = $('#edit_clone_uri'); + var cancelEditButton = $('#cancel_edit_clone_uri'); + var hiddenUrl = $('#clone_uri_hidden'); + var hiddenUrlValue = $('#clone_uri_hidden_value'); + var input = $('#clone_uri'); + var helpBlock = $('#alter_clone_uri_help_block'); + var changedFlag = $('#clone_uri_change'); + var originalText = helpBlock.html(); + var obfuscatedUrl = hiddenUrlValue.html(); + + var edit = function(e) { + alterButton.show(); + editButton.hide(); + hiddenUrl.hide(); + + //add the old value next to input for verification + helpBlock.html("(" + obfuscatedUrl + ")" + "<br\>" + originalText); + changedFlag.val('MOD'); + }; + + var cancelEdit = function(e) { + alterButton.hide(); + editButton.show(); + hiddenUrl.show(); + + helpBlock.html(originalText); + changedFlag.val('OLD'); + input.val(''); + }; + + var initEvents = function() { + editButton.on('click', edit); + cancelEditButton.on('click', cancelEdit); + }; + + var setInitialState = function() { + if (input.hasClass('error')) { + alterButton.show(); + editButton.hide(); + hiddenUrl.hide(); + } + }; + + setInitialState(); + initEvents(); + }(); + + $('#show_more_clone_id').on('click', function(e){ + $('#clone_id').show(); + e.preventDefault(); + }); + + $('#repo_landing_rev').select2(select2Options); + $('#repo_group').select2(select2Options); + + UsersAutoComplete('user', '${c.rhodecode_user.user_id}'); + $('#select_my_group').on('click', function(e){ + e.preventDefault(); + $("#repo_group").val($(this).data('personalGroupId')).trigger("change"); + }); + }); +</script> diff --git a/rhodecode/templates/admin/repos/repo_edit_statistics.html b/rhodecode/templates/admin/repos/repo_edit_statistics.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_statistics.html @@ -0,0 +1,22 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Repository statistics')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_repo_statistics', repo_name=c.repo_info.repo_name), method='put')} + <div class="form"> + <div class="fields"> + <div class="field" > + <dl class="dl-horizontal settings"> + <dt>${_('Processed commits')}:</dt><dd>${c.stats_revision}/${c.repo_last_rev}</dd> + <dt>${_('Processed progress')}:</dt><dd>${c.stats_percentage}%</dd> + </dl> + </div> + ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset statistics'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")} + </div> + </div> + ${h.end_form()} + </div> +</div> + + diff --git a/rhodecode/templates/admin/repos/repo_edit_vcs.html b/rhodecode/templates/admin/repos/repo_edit_vcs.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repo_edit_vcs.html @@ -0,0 +1,76 @@ +<%namespace name="vcss" file="/base/vcs_settings.html"/> + +<div id="repo_vcs_settings" class="${'inherited' if c.inherit_global_settings else ''}"> + ${h.secure_form(url('repo_vcs_settings', repo_name=c.repo_info.repo_name), method='post')} + <div class="form panel panel-default"> + <div class="fields panel-body"> + <div class="field"> + <div class="label label-checkbox"> + <label for="inherit_global_settings">${_('Inherit from global settings')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('inherit_global_settings',value=True)} + <span class="help-block"> + ${h.literal(_('Select to inherit global vcs settings.'))} + </span> + </div> + </div> + </div> + </div> + + <div id="inherit_overlay_vcs_default"> + <div> + ${vcss.vcs_settings_fields( + suffix='_inherited', + svn_tag_patterns=c.global_svn_tag_patterns, + svn_branch_patterns=c.global_svn_branch_patterns, + repo_type=c.repo_info.repo_type, + disabled='disabled' + )} + </div> + </div> + + <div id="inherit_overlay_vcs_custom"> + <div> + ${vcss.vcs_settings_fields( + suffix='', + svn_tag_patterns=c.svn_tag_patterns, + svn_branch_patterns=c.svn_branch_patterns, + repo_type=c.repo_info.repo_type + )} + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save settings'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + + ${h.end_form()} +</div> + +<script type="text/javascript"> + + function ajaxDeletePattern(pattern_id, field_id) { + var sUrl = "${h.url('repo_vcs_settings', repo_name=c.repo_info.repo_name)}"; + var callback = function (o) { + var elem = $("#"+field_id); + elem.remove(); + }; + var postData = { + '_method': 'delete', + 'delete_svn_pattern': pattern_id, + 'csrf_token': CSRF_TOKEN + }; + var request = $.post(sUrl, postData) + .done(callback) + .fail(function (data, textStatus, errorThrown) { + alert("Error while deleting hooks.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); + } + + $('#inherit_global_settings').on('change', function(e){ + $('#repo_vcs_settings').toggleClass('inherited', this.checked); + }); + +</script> diff --git a/rhodecode/templates/admin/repos/repos.html b/rhodecode/templates/admin/repos/repos.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/repos/repos.html @@ -0,0 +1,101 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Repositories administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + ${h.link_to(_('Admin'),h.url('admin_home'))} » <span id="repo_count">0</span> ${_('repositories')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + <ul class="links"> + %if h.HasPermissionAny('hg.admin','hg.create.repository')(): + <li> + <a href="${h.url('new_repo')}" class="btn btn-small btn-success">${_(u'Add Repository')}</a> + </li> + %endif + </ul> + </div> + <div id="repos_list_wrap"> + <table id="repo_list_table" class="display"></table> + </div> +</div> + +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#repo_list_table').dataTable().api(); + $('#repo_count').text(api.page.info().recordsDisplay); + }; + + + // repo list + $('#repo_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 0, "asc" ]], + columns: [ + { data: {"_": "name", + "sort": "name_raw"}, title: "${_('Name')}", className: "td-componentname" }, + { data: 'menu', "bSortable": false, className: "quick_repo_menu" }, + { data: {"_": "desc", + "sort": "desc"}, title: "${_('Description')}", className: "td-description" }, + { data: {"_": "last_change", + "sort": "last_change_raw", + "type": Number}, title: "${_('Last Change')}", className: "td-time" }, + { data: {"_": "last_changeset", + "sort": "last_changeset_raw", + "type": Number}, title: "${_('Commit')}", className: "td-commit" }, + { data: {"_": "owner", + "sort": "owner"}, title: "${_('Owner')}", className: "td-user" }, + { data: {"_": "state", + "sort": "state"}, title: "${_('State')}", className: "td-tags td-state" }, + { data: {"_": "action", + "sort": "action"}, title: "${_('Action')}", className: "td-action" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + quick_repo_menu(); + } + }); + + // update the counter when doing search + $('#repo_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var repo_api = $('#repo_list_table').dataTable().api(); + repo_api + .columns(0) + .search(this.value) + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + }); + +</script> + +</%def> diff --git a/rhodecode/templates/admin/settings/settings.html b/rhodecode/templates/admin/settings/settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings.html @@ -0,0 +1,45 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Settings administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${_('Settings')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + ##main + <div class='sidebar-col-wrapper'> + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + % for navitem in c.navlist: + <li class="${'active' if c.active==navitem.key else ''}"> + <a href="${navitem.url}">${navitem.name}</a> + </li> + % endfor + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/settings/settings_${c.active}.html"/> + </div> + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/settings/settings_email.html b/rhodecode/templates/admin/settings/settings_email.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_email.html @@ -0,0 +1,56 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Email Configuration')}</h3> + </div> + <div class="panel-body"> + <% + elems = [ + (_('Email prefix'), c.rhodecode_ini.get('email_prefix'), ''), + (_('RhodeCode email from'), c.rhodecode_ini.get('app_email_from'), ''), + (_('Error email from'), c.rhodecode_ini.get('error_email_from'), ''), + (_('Error email recipients'), c.rhodecode_ini.get('email_to'), ''), + + (_('SMTP server'), c.rhodecode_ini.get('smtp_server'), ''), + (_('SMTP username'), c.rhodecode_ini.get('smtp_username'), ''), + (_('SMTP password'), '%s chars' % len(c.rhodecode_ini.get('smtp_password', '')), ''), + (_('SMTP port'), c.rhodecode_ini.get('smtp_port'), ''), + + (_('SMTP use TLS'), c.rhodecode_ini.get('smtp_use_tls'), ''), + (_('SMTP use SSL'), c.rhodecode_ini.get('smtp_use_ssl'), ''), + (_('SMTP auth'), c.rhodecode_ini.get('smtp_auth'), ''), + ] + %> + <dl class="dl-horizontal"> + %for dt, dd, tt in elems: + <dt >${dt}:</dt> + <dd title="${tt}">${dd}</dd> + %endfor + </dl> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Test Email')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('admin_settings_email'), method='post')} + + <div class="field input"> + ${h.text('test_email', size=60, placeholder=_('enter valid email'))} + </div> + <div class="field"> + <span class="help-block"> + ${_('Send an auto-generated email from this server to above email...')} + </span> + </div> + <div class="buttons"> + ${h.submit('send',_('Send'),class_="btn")} + </div> + ${h.end_form()} + </div> +</div> + + + + diff --git a/rhodecode/templates/admin/settings/settings_global.html b/rhodecode/templates/admin/settings/settings_global.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_global.html @@ -0,0 +1,245 @@ +${h.secure_form(url('admin_settings_global'), method='post')} + +<div class="panel panel-default"> + <div class="panel-heading" id="branding-options"> + <h3 class="panel-title">${_('Branding')} <a class="permalink" href="#branding-options"> ¶</a></h3> + </div> + <div class="panel-body"> + <div class="label"> + <label for="rhodecode_title">${_('Title')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_title',size=60)} + </div> + <div class="field"> + <span class="help-block"> + ${_('Set a custom title for your RhodeCode instance (limited to 40 characters).')} + </span> + </div> + <div class="label"> + <label for="rhodecode_realm">${_('HTTP[S] authentication realm')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_realm',size=60)} + </div> + <div class="field"> + <span class="help-block"> + ${_('Set a custom text that is shown as authentication message to clients trying to connect.')} + </span> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading" id="captcha-options"> + <h3 class="panel-title">${_('Registration Captcha')} <a class="permalink" href="#captcha-options"> ¶</a></h3> + </div> + <div class="panel-body"> + <div class="label"> + <label for="rhodecode_captcha_public_key">${_('Google ReCaptcha public key')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_captcha_public_key',size=60)} + </div> + <div class="field"> + <span class="help-block"> + ${_('Public key for reCaptcha system.')} + </span> + </div> + + <div class="label"> + <label for="rhodecode_captcha_private_key">${_('Google ReCaptcha private key')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_captcha_private_key',size=60)} + </div> + <div class="field"> + <span class="help-block"> + ${_('Private key for reCaptcha system. Setting this value will enable captcha on registration')} + </span> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading" id="header-code-options"> + <h3 class="panel-title">${_('Custom Header Code')} <a class="permalink" href="#header-code-options"> ¶</a></h3> + </div> + <div class="panel-body"> + <div class="select"> + <select id="pre_template" > + <option value="#">${_('Templates...')}</option> + <option value="ga">Google Analytics</option> + <option value="clicky">Clicky</option> + <option value="server_announce">${_('Server Announcement')}</option> + </select> + </div> + <div style="padding: 10px 0px"></div> + <div class="textarea text-area"> + ${h.textarea('rhodecode_pre_code',cols=23,rows=5,class_="medium")} + <span class="help-block">${_('Custom js/css code added at the end of the <header> tag.')} + ${_('Use <script> or <css> tags to define custom styling or scripting')}</span> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading" id="footer-code-options"> + <h3 class="panel-title">${_('Custom Footer Code')} <a class="permalink" href="#footer-code-options"> ¶</a></h3> + </div> + <div class="panel-body"> + <div class="select"> + <select id="post_template" > + <option value="#">${_('Templates...')}</option> + <option value="ga">Google Analytics</option> + <option value="clicky">Clicky</option> + <option value="server_announce">${_('Server Announcement')}</option> + </select> + </div> + <div style="padding: 10px 0px"></div> + <div class="textarea text-area"> + ${h.textarea('rhodecode_post_code',cols=23,rows=5, class_="medium")} + <span class="help-block">${_('Custom js/css code added at the end of the <body> tag.')} + ${_('Use <script> or <css> tags to define custom styling or scripting')}</span> + </div> + </div> +</div> + +<div class="buttons"> + ${h.submit('save',_('Save settings'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} +</div> +${h.end_form()} + + + +## TEMPLATES ## +############### + +<script id="ga_tmpl" type="text/x-template"> +<%text filter="h"> +<script> + // Google Analytics + // Put your Google Analytics code instead of _GACODE_ + var _gaq_code = '_GACODE_'; + var _gaq = _gaq || []; + _gaq.push(['_setAccount', _gaq_code]); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + + rhodecode_statechange_callback = function(url, data){ + // ANALYTICS callback on html5 history state changed + // triggered by file browser, url is the new url, + // data is extra info passed from the State object + if (typeof window._gaq !== 'undefined') { + _gaq.push(['_trackPageview', url]); + } + }; +</script> +</%text> +</script> + + + +<script id="clicky_tmpl" type="text/x-template"> +<%text filter="h"> +<script src="//static.getclicky.com/js" type="text/javascript"></script> +<script type="text/javascript"> + // Clicky Analytics - should be used in the footer code section. + // Put your Clicky code instead of _CLICKYCODE_ here, + // and below in the <img> tag. + var _cl_code = _CLICKYCODE_; + try{clicky.init(_cl_code);}catch(e){} + + rhodecode_statechange_callback = function(url, data){ + // ANALYTICS callback on html5 history state changed + // triggered by file browser, url is the new url, + // data is extra info passed from the State object + if (typeof window.clicky !== 'undefined') { + clicky.log(url); + } +} +</script> +<noscript> +// Put your clicky code in the src file. +<p><img alt="Clicky" width="1" height="1" + src="//in.getclicky.com/_CLICKYCODE_ns.gif" /></p> +</noscript> +</%text> +</script> + + + +<script id="server_announce_tmpl" type='text/x-template'> +<%text filter="h"> +<script> +// Server announcement displayed on the top of the page. +// This can be used to send a global maintainance messages or other +// important messages to all users of the RhodeCode Enterprise system. + +$(document).ready(function(e){ + // put your message below + var message = "TYPE YOUR MESSAGE HERE"; + + $('#body').prepend( + ('<div class="flash_msg">'+ + '<div class="alert alert-info">_MSG_'+ + '</div></div>').replace('_MSG_', message) + ) +}) +</script> +</%text> +</script> + + + +<script> +var pre_cm = initCodeMirror('rhodecode_pre_code', '', false); +var pre_old = pre_cm.getValue(); + +var post_cm = initCodeMirror('rhodecode_post_code', '', false); +var post_old = post_cm.getValue(); + +var get_data = function(type, old){ + var get_tmpl = function(tmpl_name){ + // unescape some stuff + var html = htmlEnDeCode.htmlDecode($('#'+tmpl_name+'_tmpl').html()); + return html; + }; + return { + '#': old, + 'ga': get_tmpl('ga'), + 'clicky': get_tmpl('clicky'), + 'server_announce': get_tmpl('server_announce') + }[type] +}; + +$('#pre_template').select2({ + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 +}); + +$('#post_template').select2({ + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 +}); + +$('#post_template').on('change', function(e){ + var sel = this.value; + post_cm.setValue(get_data(sel, post_old)) +}); + +$('#pre_template').on('change', function(e){ + var sel = this.value; + pre_cm.setValue(get_data(sel, pre_old)) +}) +</script> diff --git a/rhodecode/templates/admin/settings/settings_hooks.html b/rhodecode/templates/admin/settings/settings_hooks.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_hooks.html @@ -0,0 +1,93 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Built in Mercurial hooks - read only')}</h3> + </div> + <div class="panel-body"> + <div class="form"> + <div class="fields"> + % for hook in c.hooks: + <div class="field"> + <div class="label label"> + <label for="${hook.ui_key}">${hook.ui_key}</label> + </div> + <div class="input" > + ${h.text(hook.ui_key,hook.ui_value,size=59,readonly="readonly")} + </div> + </div> + % endfor + </div> + <span class="help-block">${_('Hooks can be used to trigger actions on certain events such as push / pull. They can trigger Python functions or external applications.')}</span> + </div> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Custom hooks')}</h3> + </div> + <div class="panel-body"> + % if c.visual.allow_custom_hooks_settings: + ${h.secure_form(url('admin_settings_hooks'), method='post')} + <div class="form"> + <div class="fields"> + + % for hook in c.custom_hooks: + <div class="field" id="${'id%s' % hook.ui_id }"> + <div class="label label"> + <label for="${hook.ui_key}">${hook.ui_key}</label> + </div> + <div class="input" > + ${h.hidden('hook_ui_key',hook.ui_key)} + ${h.hidden('hook_ui_value',hook.ui_value)} + ${h.text('hook_ui_value_new',hook.ui_value,size=59)} + <span class="btn btn-danger" + onclick="ajaxActionHook(${hook.ui_id},'${'id%s' % hook.ui_id }')"> + ${_('Delete')} + </span> + </div> + </div> + % endfor + + <div class="field customhooks"> + <div class="label"> + <div class="input-wrapper"> + ${h.text('new_hook_ui_key',size=30)} + </div> + </div> + <div class="input"> + ${h.text('new_hook_ui_value',size=59)} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + %else: + DISABLED + % endif + </div> +</div> + + +<script type="text/javascript"> +function ajaxActionHook(hook_id,field_id) { + var sUrl = "${h.url('admin_settings_hooks')}"; + var callback = function (o) { + var elem = $("#"+field_id); + elem.remove(); + }; + var postData = { + '_method': 'delete', + 'hook_id': hook_id, + 'csrf_token': CSRF_TOKEN + }; + var request = $.post(sUrl, postData) + .done(callback) + .fail(function (data, textStatus, errorThrown) { + alert("Error while deleting hooks.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); +}; +</script> diff --git a/rhodecode/templates/admin/settings/settings_issuetracker.html b/rhodecode/templates/admin/settings/settings_issuetracker.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_issuetracker.html @@ -0,0 +1,34 @@ +<%namespace name="its" file="/base/issue_tracker_settings.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Issue Tracker / Wiki Patterns')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('admin_settings_issuetracker_save'), method='post')} + ${its.issue_tracker_settings_table( + patterns=c.issuetracker_entries.items(), + form_url=url('admin_settings_issuetracker'), + delete_url=url('admin_issuetracker_delete') + )} + <div class="buttons"> + <button type="submit" class="btn btn-primary" id="save">${_('Save')}</button> + <button type="reset" class="btn">${_('Reset')}</button> + </div> + ${h.end_form()} + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Test Patterns')}</h3> + </div> + <div class="panel-body"> + ${its.issue_tracker_new_row()} + ${its.issue_tracker_settings_test(test_url=url('admin_issuetracker_test'))} + </div> +</div> + + + + diff --git a/rhodecode/templates/admin/settings/settings_labs.html b/rhodecode/templates/admin/settings/settings_labs.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_labs.html @@ -0,0 +1,54 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Labs Settings')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('admin_settings_labs'), method='post')} + <div class="form"> + <div class="fields"> + % for lab_setting in c.lab_settings: + <div class="field"> + <div class="label"> + <label>${lab_setting.group}:</label> + </div> + % if lab_setting.type == 'bool': + <div class="checkboxes"> + <div class="checkbox"> + ${h.checkbox(lab_setting.key, 'True')} + % if lab_setting.label: + <label for="${lab_setting.key}">${lab_setting.label}</label> + % endif + </div> + % if lab_setting.help: + <p class="help-block">${lab_setting.help}</p> + % endif + </div> + % else: + <div class="input"> + ${h.text(lab_setting.key, size=60)} + + ## TODO: johbo: This style does not yet exist for our forms, + ## the lab settings seem not to adhere to the structure which + ## we use in other places. + % if lab_setting.label: + <label for="${lab_setting.key}">${lab_setting.label}</label> + % endif + + % if lab_setting.help: + <p class="help-block">${lab_setting.help}</p> + % endif + </div> + % endif + </div> + % endfor + <div class="buttons"> + ${h.submit('save', _('Save settings'), class_='btn')} + ${h.reset('reset', _('Reset'), class_='btn')} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> + + diff --git a/rhodecode/templates/admin/settings/settings_mapping.html b/rhodecode/templates/admin/settings/settings_mapping.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_mapping.html @@ -0,0 +1,28 @@ +${h.secure_form(url('admin_settings_mapping'), method='post')} + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Import New Groups or Repositories')}</h3> + </div> + <div class="panel-body"> + <div class="checkbox"> + ${h.checkbox('destroy',True)} + <label for="destroy">${_('Destroy old data')}</label> + </div> + <span class="help-block">${_('In case a repository or a group was deleted from the filesystem and it still exists in the database, check this option to remove obsolete data from the database.')}</span> + + <div class="checkbox"> + ${h.checkbox('invalidate',True)} + <label for="invalidate"> ${_('Invalidate cache for all repositories')}</label> + </div> + <span class="help-block">${_('Each cache data for repositories will be cleaned with this option selected. Use this to reload data and clear cache keys.')}</span> + + <div class="buttons"> + ${h.submit('rescan',_('Rescan Filesystem'),class_="btn")} + </div> + + </div> +</div> + + +${h.end_form()} diff --git a/rhodecode/templates/admin/settings/settings_open_source.html b/rhodecode/templates/admin/settings/settings_open_source.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_open_source.html @@ -0,0 +1,32 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Licenses of Third Party Packages')}</h3> + </div> + <div class="panel-body"> + <p> + RhodeCode Enterprise uses various third party packages, many of them + provided by the open source community. + </p> + + % if c.opensource_licenses: + <table class="rctable dl-settings"> + <thead> + <th>Product</th> + <th>License</th> + </thead> + %for product, licenses in c.opensource_licenses.items(): + <tr> + <td>${product}</td> + <td> + ${h.literal(', '.join([ + '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name} + for name,link in licenses.items()]))} + </td> + </tr> + %endfor + </table> + % endif + </div> +</div> + + diff --git a/rhodecode/templates/admin/settings/settings_search.html b/rhodecode/templates/admin/settings/settings_search.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_search.html @@ -0,0 +1,13 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('RhodeCode Full Text Search')}</h3> + </div> + <div class="panel-body"> + <dl class="dl-horizontal"> + % for stat in c.statistics: + <dt>${stat['key']}</dt> + <dd>${stat['value']}</dd> + % endfor + </dl> + </div> +</div> diff --git a/rhodecode/templates/admin/settings/settings_supervisor.html b/rhodecode/templates/admin/settings/settings_supervisor.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_supervisor.html @@ -0,0 +1,27 @@ +%if c.connection_error: + <h4>Cannot connect to supervisor: ${c.connection_error}</h4> +%else: +<table class="rctable supervisor"> + <tr> + <th>Name</th> + <th>Description</th> + <th>State</th> + </tr> + +% for proc,vals in c.supervisor_procs.items(): + <tr> + %if vals.get('_rhodecode_error'): + <td>${proc}</td> + <td>${vals['_rhodecode_error']}</td> + <td></td> + %else: + <td class="td-componentname"><a href="${h.url('admin_settings_supervisor_log', procid=proc, offset=c.log_size)}">${vals['name']}</a></td> + <td class="td-description">${vals['description']}</td> + <td class="td-state">${vals['statename']}</td> + %endif + ##<td class="td-action"> start | stop | restart</td> + </tr> + +% endfor +</table> +%endif diff --git a/rhodecode/templates/admin/settings/settings_supervisor_tail.html b/rhodecode/templates/admin/settings/settings_supervisor_tail.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_supervisor_tail.html @@ -0,0 +1,4 @@ +<h4>${_('Last %(size)s bytes of process logs, use ?offset=[num] GET param to set custom size') % {'size': c.log_size}}</h4> +<pre> +${c.log} +</pre> diff --git a/rhodecode/templates/admin/settings/settings_system.html b/rhodecode/templates/admin/settings/settings_system.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_system.html @@ -0,0 +1,86 @@ +<% + elems = [ + ## general + (_('RhodeCode Enterprise version'), h.literal('%s <div class="link" id="check_for_update" >%s</div>' % (c.rhodecode_version, _('check for updates'))), ''), + (_('Upgrade info endpoint'), h.literal('%s <br/><span >%s.</span>' % (c.rhodecode_update_url, _('Note: please make sure this server can access this url'))), ''), + (_('Configuration INI file'), c.rhodecode_config_ini, ''), + ## systems stats + (_('RhodeCode Enterprise Server IP'), c.server_ip, ''), + (_('RhodeCode Enterprise Server ID'), c.server_id, ''), + (_('Platform'), c.platform, ''), + (_('Uptime'), c.uptime_age, ''), + (_('Storage location'), c.storage, ''), + (_('Storage disk space'), "%s/%s, %s%% used%s" % (h.format_byte_size_binary(c.disk['used']), h.format_byte_size_binary(c.disk['total']),(c.disk['percent']), ' %s' % c.disk['error'] if 'error' in c.disk else ''), ''), + + (_('Search index storage'), c.index_storage, ''), + (_('Search index size'), "%s %s" % (h.format_byte_size_binary(c.disk_index['used']), ' %s' % c.disk_index['error'] if 'error' in c.disk_index else ''), ''), + + (_('Gist storage'), c.gist_storage, ''), + (_('Gist storage size'), "%s (%s items)%s" % (h.format_byte_size_binary(c.disk_gist['used']),c.disk_gist['items'], ' %s' % c.disk_gist['error'] if 'error' in c.disk_gist else ''), ''), + + (_('Archive cache'), h.literal('%s <br/><span >%s.</span>' % (c.archive_storage, _('Enable this by setting archive_cache_dir=/path/to/cache option in the .ini file'))), ''), + (_('Archive cache size'), "%s%s" % (h.format_byte_size_binary(c.disk_archive['used']), ' %s' % c.disk_archive['error'] if 'error' in c.disk_archive else ''), ''), + + (_('System memory'), c.system_memory, ''), + (_('CPU'), '%s %%' %(c.cpu), ''), + (_('Load'), '1min: %s, 5min: %s, 15min: %s' %(c.load['1_min'],c.load['5_min'],c.load['15_min']), ''), + + ## rhodecode stuff + (_('Python version'), c.py_version, ''), + (_('Python path'), c.py_path, ''), + (_('GIT version'), c.git_version, ''), + (_('HG version'), c.hg_version, ''), + (_('SVN version'), c.svn_version, ''), + (_('Database'), "%s @ version: %s" % (c.db_type, c.db_migrate_version), ''), + (_('Database version'), c.db_version, ''), + + ] +%> + +<div id="update_notice" style="display: none; margin: -40px 0px 20px 0px"> + <div>${_('Checking for updates...')}</div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('System Info')}</h3> + </div> + <div class="panel-body"> + <dl class="dl-horizontal settings"> + %for dt, dd, tt in elems: + <dt >${dt}:</dt> + <dd title="${tt}">${dd}</dd> + %endfor + </dl> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Python Packages')}</h3> + </div> + <div class="panel-body"> + <table class="table"> + <colgroup> + <col class='label'> + <col class='content'> + </colgroup> + <tbody> + %for key, value in c.py_modules: + <tr> + <td >${key}</td> + <td>${value}</td> + </tr> + %endfor + </tbody> + </table> + </div> +</div> + +<script> + $('#check_for_update').click(function(e){ + $('#update_notice').show(); + $('#update_notice').load("${h.url('admin_settings_system_update')}"); + }) +</script> diff --git a/rhodecode/templates/admin/settings/settings_system_update.html b/rhodecode/templates/admin/settings/settings_system_update.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_system_update.html @@ -0,0 +1,27 @@ +## -*- coding: utf-8 -*- +## upgrade block rendered afte on-click check + +<div class="alert ${'alert-warning' if c.should_upgrade else 'alert-success'}"> +<p > + +%if c.should_upgrade: + A <b>new version</b> is available: + %if c.latest_data.get('title'): + <b>${h.literal(c.latest_data['title'])}</b> + %else: + <b>${c.latest_ver}</b> + %endif +%else: + You already have the <b>latest</b> stable version. +%endif +</p> + +% if c.should_upgrade and c.important_notices: +<div>Important notes for this release:</div> + <ul> + % for notice in c.important_notices: + <li>- ${notice}</li> + % endfor + </ul> +% endif +</div> diff --git a/rhodecode/templates/admin/settings/settings_vcs.html b/rhodecode/templates/admin/settings/settings_vcs.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_vcs.html @@ -0,0 +1,54 @@ +<%namespace name="vcss" file="/base/vcs_settings.html"/> + +${h.secure_form(url('admin_settings_vcs'), method='post')} + <div> + ${vcss.vcs_settings_fields( + suffix='', + svn_tag_patterns=c.svn_tag_patterns, + svn_branch_patterns=c.svn_branch_patterns, + display_globals=True, + allow_repo_location_change=c.visual.allow_repo_location_change + )} + <div class="buttons"> + ${h.submit('save',_('Save settings'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> +${h.end_form()} + +<script type="text/javascript"> + + function ajaxDeletePattern(pattern_id, field_id) { + var sUrl = "${h.url('admin_settings_vcs')}"; + var callback = function (o) { + var elem = $("#"+field_id); + elem.remove(); + }; + var postData = { + '_method': 'delete', + 'delete_svn_pattern': pattern_id, + 'csrf_token': CSRF_TOKEN + }; + var request = $.post(sUrl, postData) + .done(callback) + .fail(function (data, textStatus, errorThrown) { + alert("Error while deleting hooks.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(this)[0].url)); + }); + }; + + $(document).ready(function() { + + var unlockpath = function() { + $('#path_unlock_icon').removeClass('icon-lock').addClass('icon-unlock'); + $('#paths_root_path').removeAttr('readonly').removeClass('disabled'); + }; + + $('#path_unlock').on('click', function(e) { + unlockpath(); + }); + + if ($('.locked_input').children().hasClass('error-message')) { + unlockpath(); + } + }) +</script> diff --git a/rhodecode/templates/admin/settings/settings_visual.html b/rhodecode/templates/admin/settings/settings_visual.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/settings/settings_visual.html @@ -0,0 +1,235 @@ +${h.secure_form(url('admin_settings_visual'), method='post')} + +<div class="panel panel-default"> + <div class="panel-heading" id="general"> + <h3 class="panel-title">${_('General')}</h3> + </div> + <div class="panel-body"> + <div class="checkbox"> + ${h.checkbox('rhodecode_repository_fields','True')} + <label for="rhodecode_repository_fields">${_('Use repository extra fields')}</label> + </div> + <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span> + + <div></div> + <div class="checkbox"> + ${h.checkbox('rhodecode_show_version','True')} + <label for="rhodecode_show_version">${_('Show RhodeCode version')}</label> + </div> + <span class="help-block">${_('Shows or hides a version number of RhodeCode displayed in the footer.')}</span> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading" id="gravatars"> + <h3 class="panel-title">${_('Gravatars')}</h3> + </div> + <div class="panel-body"> + <div class="checkbox"> + ${h.checkbox('rhodecode_use_gravatar','True')} + <label for="rhodecode_use_gravatar">${_('Use Gravatars based avatars')}</label> + </div> + <span class="help-block">${_('Use gravatar.com as avatar system for RhodeCode accounts. If this is disabled avatars are generated based on initials and email.')}</span> + + <div class="label"> + <label for="rhodecode_gravatar_url">${_('Gravatar URL')}</label> + </div> + <div class="input"> + <div class="field"> + ${h.text('rhodecode_gravatar_url', size='100%')} + </div> + + <div class="field"> + <span class="help-block">${_('''Gravatar url allows you to use other avatar server application. + Following variables of the URL will be replaced accordingly. + {scheme} 'http' or 'https' sent from running RhodeCode server, + {email} user email, + {md5email} md5 hash of the user email (like at gravatar.com), + {size} size of the image that is expected from the server application, + {netloc} network location/server host of running RhodeCode server''')}</span> + </div> + </div> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading" id="meta-tagging"> + <h3 class="panel-title">${_('Meta-Tagging')}</h3> + </div> + <div class="panel-body"> + <div class="checkbox"> + ${h.checkbox('rhodecode_stylify_metatags','True')} + <label for="rhodecode_stylify_metatags">${_('Stylify recognised meta tags')}</label> + </div> + <span class="help-block">${_('Parses meta tags from repository description field and turns them into colored tags.')}</span> + <div> + <table> + <tr><td>[featured] </td><td><span class="metatag" tag="featured">featured</span></td></tr> + <tr><td>[stale] </td><td><span class="metatag" tag="stale">stale</span></td></tr> + <tr><td>[dead] </td><td><span class="metatag" tag="dead">dead</span></td></tr> + <tr><td>[lang => lang] </td><td><span class="metatag" tag="lang" >lang</span></td></tr> + + <tr><td>[license => License] </td><td><span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></td></tr> + <tr><td>[requires => Repo] </td><td><span class="metatag" tag="requires" >requires => <a href="#" >Repo</a></span></td></tr> + <tr><td>[recommends => Repo] </td><td><span class="metatag" tag="recommends" >recommends => <a href="#" >Repo</a></span></td></tr> + <tr><td>[see => URI] </td><td><span class="metatag" tag="see">see => <a href="#">URI</a> </span></td></tr> + </table> + </div> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Dashboard Items')}</h3> + </div> + <div class="panel-body"> + <div class="label"> + <label for="rhodecode_dashboard_items">${_('Main page dashboard items')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_dashboard_items',size=5)} + </div> + <div class="field"> + <span class="help-block">${_('Number of items displayed in the main page dashboard before pagination is shown.')}</span> + </div> + + <div class="label"> + <label for="rhodecode_admin_grid_items">${_('Admin pages items')}</label> + </div> + <div class="field input"> + ${h.text('rhodecode_admin_grid_items',size=5)} + </div> + <div class="field"> + <span class="help-block">${_('Number of items displayed in the admin pages grids before pagination is shown.')}</span> + </div> + </div> +</div> + + + +<div class="panel panel-default"> + <div class="panel-heading" id="commit-id"> + <h3 class="panel-title">${_('Commit ID Style')}</h3> + </div> + <div class="panel-body"> + <div class="label"> + <label for="rhodecode_show_sha_length">${_('Commit sha length')}</label> + </div> + <div class="input"> + <div class="field"> + ${h.text('rhodecode_show_sha_length',size=5)} + </div> + <div class="field"> + <span class="help-block">${_('''Number of chars to show in commit sha displayed in web interface. + By default it's shown as r123:9043a6a4c226 this value defines the + length of the sha after the `r123:` part.''')}</span> + </div> + </div> + + <div class="checkbox"> + ${h.checkbox('rhodecode_show_revision_number','True')} + <label for="rhodecode_show_revision_number">${_('Show commit ID numeric reference')} / ${_('Commit show revision number')}</label> + </div> + <span class="help-block">${_('''Show revision number in commit sha displayed in web interface. + By default it's shown as r123:9043a6a4c226 this value defines the + if the `r123:` part is shown.''')}</span> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading" id="icons"> + <h3 class="panel-title">${_('Icons')}</h3> + </div> + <div class="panel-body"> + <div class="checkbox"> + ${h.checkbox('rhodecode_show_public_icon','True')} + <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label> + </div> + <div></div> + + <div class="checkbox"> + ${h.checkbox('rhodecode_show_private_icon','True')} + <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label> + </div> + <span class="help-block">${_('Show public/private icons next to repositories names.')}</span> + </div> +</div> + + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Markup Renderer')}</h3> + </div> + <div class="panel-body"> + <div class="field select"> + ${h.select('rhodecode_markup_renderer', '', ['rst', 'markdown'])} + </div> + <div class="field"> + <span class="help-block">${_('Default renderer used to render comments, pull request descriptions and other description elements. After change old entries will still work correctly.')}</span> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Clone URL')}</h3> + </div> + <div class="panel-body"> + <div class="field"> + ${h.text('rhodecode_clone_uri_tmpl', size=60)} + </div> + + <div class="field"> + <span class="help-block"> + ${_('''Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars: + {scheme} 'http' or 'https' sent from running RhodeCode server, + {user} current user username, + {netloc} network location/server host of running RhodeCode server, + {repo} full repository name, + {repoid} ID of repository, can be used to contruct clone-by-id''')} + </span> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Custom Support Link')}</h3> + </div> + <div class="panel-body"> + <div class="field"> + ${h.text('rhodecode_support_url', size=60)} + </div> + <div class="field"> + <span class="help-block"> + ${_('''Custom url for the support link located at the bottom. + The default is set to %(default_url)s. In case there's a need + to change the support link to internal issue tracker, it should be done here. + ''') % {'default_url': h.url('rhodecode_support')}} + </span> + </div> + </div> +</div> + +<div class="buttons"> + ${h.submit('save',_('Save settings'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} +</div> + + +${h.end_form()} + +<script> +$(document).ready(function() { + $('#rhodecode_markup_renderer').select2({ + containerCssClass: 'drop-menu', + dropdownCssClass: 'drop-menu-dropdown', + dropdownAutoWidth: true, + minimumResultsForSearch: -1 + }); +}); +</script> diff --git a/rhodecode/templates/admin/user_groups/user_group_add.html b/rhodecode/templates/admin/user_groups/user_group_add.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_add.html @@ -0,0 +1,72 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Add user group')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('User groups'),h.url('users_groups'))} + » + ${_('Add User Group')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box main-content"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + <!-- end box / title --> + ${h.secure_form(url('users_groups'))} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="users_group_name">${_('Group name')}:</label> + </div> + <div class="input"> + ${h.text('users_group_name', class_='medium')} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="user_group_description">${_('Description')}:</label> + </div> + <div class="textarea editor"> + ${h.textarea('user_group_description')} + <span class="help-block">${_('Short, optional description for this user group.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="users_group_active">${_('Active')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('users_group_active',value=True, checked='checked')} + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} +</div> +</%def> + +<script> + $(document).ready(function(){ + $('#users_group_name').focus(); + }) +</script> diff --git a/rhodecode/templates/admin/user_groups/user_group_edit.html b/rhodecode/templates/admin/user_groups/user_group_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit.html @@ -0,0 +1,47 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s user group settings') % c.user_group.users_group_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('User Groups'),h.url('users_groups'))} + » + ${c.user_group.users_group_name} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + ##main + <div class="sidebar-col-wrapper"> + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_users_group', user_group_id=c.user_group.users_group_id)}">${_('Settings')}</a></li> + <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_user_group_perms', user_group_id=c.user_group.users_group_id)}">${_('Permissions')}</a></li> + <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_group_advanced', user_group_id=c.user_group.users_group_id)}">${_('Advanced')}</a></li> + <li class="${'active' if c.active=='global_perms' else ''}"><a href="${h.url('edit_user_group_global_perms', user_group_id=c.user_group.users_group_id)}">${_('Global permissions')}</a></li> + <li class="${'active' if c.active=='perms_summary' else ''}"><a href="${h.url('edit_user_group_perms_summary', user_group_id=c.user_group.users_group_id)}">${_('Permissions summary')}</a></li> + <li class="${'active' if c.active=='members' else ''}"><a href="${h.url('edit_user_group_members', user_group_id=c.user_group.users_group_id)}">${_('Members')}</a></li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/user_groups/user_group_edit_${c.active}.html"/> + </div> + </div> +</div> +</%def> diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_advanced.html b/rhodecode/templates/admin/user_groups/user_group_edit_advanced.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_advanced.html @@ -0,0 +1,38 @@ +<%namespace name="base" file="/base/base.html"/> + +<% + elems = [ + (_('Owner'), lambda:base.gravatar_with_user(c.user_group.user.email), '', ''), + (_('Created on'), h.format_date(c.user_group.created_on), '', '',), + + (_('Members'), len(c.group_members_obj),'', [x for x in c.group_members_obj]), + (_('Assigned to repositories'), len(c.group_to_repos),'', [x for x in c.group_to_repos]), + (_('Assigned to repo groups'), len(c.group_to_repo_groups), '', [x for x in c.group_to_repo_groups]), + + ] +%> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> + </div> + <div class="panel-body"> + ${base.dt_info_panel(elems)} + </div> +</div> + +<div class="panel panel-danger"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Delete User Group')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(h.url('delete_users_group', user_group_id=c.user_group.users_group_id),method='delete')} + ${h.hidden('force', 1)} + <button class="btn btn-small btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete user group `%(ugroup)s` with all permission assignments') % {'ugroup': c.user_group.users_group_name}}');"> + <i class="icon-remove-sign"></i> + ${_('Delete This User Group')} + </button> + ${h.end_form()} + </div> +</div> diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_global_perms.html b/rhodecode/templates/admin/user_groups/user_group_edit_global_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_global_perms.html @@ -0,0 +1,3 @@ +<%namespace name="dpb" file="/base/default_perms_box.html"/> +${dpb.default_perms_box(url('edit_user_group_global_perms', user_group_id=c.user_group.users_group_id))} + diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_members.html b/rhodecode/templates/admin/user_groups/user_group_edit_members.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_members.html @@ -0,0 +1,30 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Members of User Group: %s') % c.user_group.users_group_name}</h3> + </div> + <div class="panel-body"> + % if c.group_members_obj: + <table class="rctable group_members"> + <tr> + <th>Username</th> + <th>Name</th> + </tr> + %for user in c.group_members_obj: + <tr> + <td class="td-author"> + <div class="group_member"> + ${base.gravatar(user.email, 16)} + <span class="username user">${h.link_to(user.username, h.url( 'edit_user',user_id=user.user_id))}</span> + </div> + </td> + <td class="fullname">${user.full_name}</td> + </tr> + %endfor + </table> + %else: + <p class="empty_data">${_('No members yet')}</p> + %endif + </div> +</div> diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_perms.html b/rhodecode/templates/admin/user_groups/user_group_edit_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_perms.html @@ -0,0 +1,134 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('User Group Permissions')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('edit_user_group_perms', user_group_id=c.user_group.users_group_id),method='put')} + <table id="permissions_manage" class="rctable permissions"> + <tr> + <th class="td-radio">${_('None')}</th> + <th class="td-radio">${_('Read')}</th> + <th class="td-radio">${_('Write')}</th> + <th class="td-radio">${_('Admin')}</th> + <th>${_('User/User Group')}</th> + <th></th> + </tr> + ## USERS + %for _user in c.user_group.permissions(): + %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None): + <tr class="perm_admin_row"> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td> + <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + ${h.link_to_user(_user.username)} + %if getattr(_user, 'admin_row', None): + (${_('super admin')}) + %endif + %if getattr(_user, 'owner_row', None): + (${_('owner')}) + %endif + </span> + </td> + <td></td> + </tr> + %else: + ##forbid revoking permission from yourself, except if you're an super admin + <tr> + %if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin: + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write')}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin')}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + % if _user.username == h.DEFAULT_USER: + ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> + % else: + ${h.link_to_user(_user.username)} + % endif + </span> + </td> + <td class="td-action"> + %if _user.username != h.DEFAULT_USER: + <span class="btn btn-link btn-danger revoke_perm" + member="${_user.user_id}" member_type="user"> + <i class="icon-remove"></i> ${_('revoke')} + </span> + %endif + </td> + %else: + ## special case for current user permissions, we make sure he cannot take his own permissions + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write', disabled="disabled")}</td> + <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin', disabled="disabled")}</td> + <td class="td-user"> + ${base.gravatar(_user.email, 16)} + <span class="user"> + % if _user.username == h.DEFAULT_USER: + ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> + % else: + ${h.link_to_user(_user.username)} + % endif + <span class="user-perm-help-text">(${_('delegated admin')})</span> + </span> + </td> + <td></td> + %endif + </tr> + %endif + %endfor + + ## USER GROUPS + %for _user_group in c.user_group.permission_user_groups(): + <tr> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.none')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.read')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td> + <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td> + <td class="td-user"> + <i class="icon-group" ></i> + %if h.HasPermissionAny('hg.admin')(): + <a href="${h.url('edit_users_group',user_group_id=_user_group.users_group_id)}"> + ${_user_group.users_group_name} + </a> + %else: + ${_user_group.users_group_name} + %endif + </td> + <td class="td-action"> + <span class="btn btn-link btn-danger revoke_perm" + member="${_user_group.users_group_id}" member_type="user_group"> + <i class="icon-remove"></i> ${_('revoke')} + </span> + </td> + </tr> + %endfor + <tr class="new_members" id="add_perm_input"></tr> + </table> + <div id="add_perm" class="link"> + ${_('Add new')} + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn btn-primary")} + ${h.reset('reset',_('Reset'),class_="btn btn-danger")} + </div> + ${h.end_form()} + </div> +</div> + +<script type="text/javascript"> + $('#add_perm').on('click', function(e){ + addNewPermInput($(this), 'usergroup'); + }); + $('.revoke_perm').on('click', function(e){ + markRevokePermInput($(this), 'usergroup'); + }); +</script> diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_perms_summary.html b/rhodecode/templates/admin/user_groups/user_group_edit_perms_summary.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_perms_summary.html @@ -0,0 +1,3 @@ +## permissions overview +<%namespace name="p" file="/base/perms_summary.html"/> +${p.perms_summary(c.permissions)} diff --git a/rhodecode/templates/admin/user_groups/user_group_edit_settings.html b/rhodecode/templates/admin/user_groups/user_group_edit_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_group_edit_settings.html @@ -0,0 +1,91 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(url('update_users_group', user_group_id=c.user_group.users_group_id),method='put', id='edit_users_group')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="users_group_name">${_('Group name')}:</label> + </div> + <div class="input"> + ${h.text('users_group_name',class_='medium')} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="user">${_('Owner')}:</label> + </div> + <div class="input"> + ${h.text('user', class_="medium", autocomplete="off")} + <span class="help-block">${_('Change owner of this user group.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-textarea"> + <label for="user_group_description">${_('Description')}:</label> + </div> + <div class="textarea textarea-small editor"> + ${h.textarea('user_group_description',cols=23,rows=5,class_="medium")} + <span class="help-block">${_('Short, optional description for this user group.')}</span> + </div> + </div> + <div class="field"> + <div class="label label-checkbox"> + <label for="users_group_active">${_('Active')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('users_group_active',value=True)} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="users_group_active">${_('Members')}:</label> + </div> + <div class="select side-by-side-selector"> + <div class="left-group"> + <label class="text" >${_('Chosen group members')}</label> + ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,)} + <div class="btn" id="remove_all_elements" > + ${_('Remove all elements')} + <i class="icon-chevron-right"></i> + </div> + </div> + <div class="middle-group"> + <i id="add_element" class="icon-chevron-left"></i> + <br /> + <i id="remove_element" class="icon-chevron-right"></i> + </div> + <div class="right-group"> + <label class="text" >${_('Available members')}</label> + ${h.select('available_members',[],c.available_members,multiple=True,size=8,)} + <div class="btn" id="add_all_elements" > + <i class="icon-chevron-left"></i>${_('Add all elements')} + </div> + </div> + </div> + </div> + <div class="buttons"> + ${h.submit('Save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> +<script> + $(document).ready(function(){ + MultiSelectWidget('users_group_members','available_members','edit_users_group'); + + $("#group_parent_id").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); + + UsersAutoComplete('user', '${c.rhodecode_user.user_id}'); + }) +</script> diff --git a/rhodecode/templates/admin/user_groups/user_groups.html b/rhodecode/templates/admin/user_groups/user_groups.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/user_groups/user_groups.html @@ -0,0 +1,98 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('User groups administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + ${h.link_to(_('Admin'),h.url('admin_home'))} » <span id="user_group_count">0</span> ${_('user groups')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + + <div class="title"> + ${self.breadcrumbs()} + <ul class="links"> + %if h.HasPermissionAny('hg.admin', 'hg.usergroup.create.true')(): + <li> + <a href="${h.url('new_users_group')}" class="btn btn-small btn-success">${_(u'Add User Group')}</a> + </li> + %endif + </ul> + </div> + + <div id="repos_list_wrap"> + <table id="user_group_list_table" class="display"></table> + </div> + +</div> +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var api = $('#user_group_list_table').dataTable().api(); + $('#user_group_count').text(api.page.info().recordsDisplay); + }; + + // user list + $('#user_group_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 0, "asc" ]], + columns: [ + { data: {"_": "group_name", + "sort": "group_name_raw"}, title: "${_('Name')}", className: "td-componentname" }, + { data: {"_": "desc", + "sort": "desc"}, title: "${_('Description')}", className: "td-description" }, + { data: {"_": "members", + "sort": "members", + "type": Number}, title: "${_('Members')}", className: "td-number" }, + { data: {"_": "active", + "sort": "active"}, title: "${_('Active')}", className: "td-active", className: "td-number"}, + { data: {"_": "owner", + "sort": "owner"}, title: "${_('Owner')}", className: "td-user" }, + { data: {"_": "action", + "sort": "action"}, title: "${_('Action')}", className: "td-action" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + } + }); + + // update the counter when doing search + $('#user_group_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var user_api = $('#user_group_list_table').dataTable().api(); + user_api + .columns(0) + .search(this.value) + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + + }); + +</script> + +</%def> diff --git a/rhodecode/templates/admin/users/user_add.html b/rhodecode/templates/admin/users/user_add.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_add.html @@ -0,0 +1,144 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Add user')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Users'),h.url('users'))} + » + ${_('Add User')} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + <!-- box / title --> + <div class="title"> + ${self.breadcrumbs()} + </div> + <!-- end box / title --> + ${h.secure_form(url('users'))} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="username">${_('Username')}:</label> + </div> + <div class="input"> + ${h.text('username', class_='medium')} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="password">${_('Password')}:</label> + </div> + <div class="input"> + ${h.password('password', class_='medium')} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="password_confirmation">${_('Password confirmation')}:</label> + </div> + <div class="input"> + ${h.password('password_confirmation',autocomplete="off", class_='medium')} + <div class="info-block"> + <a id="generate_password" href="#"> + <i class="icon-lock"></i> ${_('Generate password')} + </a> + <span id="generate_password_preview"></span> + </div> + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="firstname">${_('First Name')}:</label> + </div> + <div class="input"> + ${h.text('firstname', class_='medium')} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="lastname">${_('Last Name')}:</label> + </div> + <div class="input"> + ${h.text('lastname', class_='medium')} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="email">${_('Email')}:</label> + </div> + <div class="input"> + ${h.text('email', class_='medium')} + ${h.hidden('extern_name', c.default_extern_type)} + ${h.hidden('extern_type', c.default_extern_type)} + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="active">${_('Active')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('active',value=True,checked='checked')} + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="password_change">${_('Password change')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('password_change',value=True)} + <span class="help-block">${_('Force user to change his password on the next login')}</span> + </div> + </div> + + <div class="field"> + <div class="label label-checkbox"> + <label for="create_repo_group">${_('Add repository group')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('create_repo_group',value=True)} + <span class="help-block">${_('Add repository group with the same name as username. \nUser will be automatically set as this group owner.')}</span> + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + </div> + </div> + </div> + ${h.end_form()} +</div> +</%def> +<script> + $(document).ready(function(){ + $('#username').focus(); + + $('#generate_password').on('click', function(e){ + var tmpl = "(${_('generated password:')} {0})" + var new_passwd = generatePassword(12) + $('#generate_password_preview').html(tmpl.format(new_passwd)) + $('#password').val(new_passwd); + $('#password_confirmation').val(new_passwd); + }) + }) +</script> diff --git a/rhodecode/templates/admin/users/user_edit.html b/rhodecode/templates/admin/users/user_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit.html @@ -0,0 +1,49 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s user settings') % c.user.username} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Admin'),h.url('admin_home'))} + » + ${h.link_to(_('Users'),h.url('users'))} + » + ${c.user.username} +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box user_settings"> + <div class="title"> + ${self.breadcrumbs()} + </div> + + ##main + <div class="sidebar-col-wrapper"> + <div class="sidebar"> + <ul class="nav nav-pills nav-stacked"> + <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('edit_user', user_id=c.user.user_id)}">${_('User Profile')}</a></li> + <li class="${'active' if c.active=='auth_tokens' else ''}"><a href="${h.url('edit_user_auth_tokens', user_id=c.user.user_id)}">${_('Auth tokens')}</a></li> + <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_advanced', user_id=c.user.user_id)}">${_('Advanced')}</a></li> + <li class="${'active' if c.active=='global_perms' else ''}"><a href="${h.url('edit_user_global_perms', user_id=c.user.user_id)}">${_('Global permissions')}</a></li> + <li class="${'active' if c.active=='perms_summary' else ''}"><a href="${h.url('edit_user_perms_summary', user_id=c.user.user_id)}">${_('Permissions summary')}</a></li> + <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('edit_user_emails', user_id=c.user.user_id)}">${_('Emails')}</a></li> + <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('edit_user_ips', user_id=c.user.user_id)}">${_('Ip Whitelist')}</a></li> + </ul> + </div> + + <div class="main-content-full-width"> + <%include file="/admin/users/user_edit_${c.active}.html"/> + </div> + </div> +</div> + +</%def> diff --git a/rhodecode/templates/admin/users/user_edit_advanced.html b/rhodecode/templates/admin/users/user_edit_advanced.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_advanced.html @@ -0,0 +1,154 @@ +<%namespace name="base" file="/base/base.html"/> + +<% + elems = [ + (_('Created on'), h.format_date(c.user.created_on), '', ''), + (_('Source of Record'), c.user.extern_type, '', ''), + + (_('Last login'), c.user.last_login or '-', '', ''), + (_('Last activity'), h.format_date(h.time_to_datetime(c.user.user_data.get('last_activity', 0))), '', ''), + + (_('Repositories'), len(c.user.repositories), '', [x.repo_name for x in c.user.repositories]), + (_('Repository groups'), len(c.user.repository_groups), '', [x.group_name for x in c.user.repository_groups]), + (_('User groups'), len(c.user.user_groups), '', [x.users_group_name for x in c.user.user_groups]), + + (_('Member of User groups'), len(c.user.group_member), '', [x.users_group.users_group_name for x in c.user.group_member]), + (_('Force password change'), c.user.user_data.get('force_password_change', 'False'), '', ''), + ] +%> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('User: %s') % c.user.username}</h3> + </div> + <div class="panel-body"> + ${base.dt_info_panel(elems)} + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Force Password Reset')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(h.url('force_password_reset_user', user_id=c.user.user_id), method='post')} + <div class="field"> + <button class="btn btn-default" type="submit"> + <i class="icon-lock"></i> + %if c.user.user_data.get('force_password_change'): + ${_('Disable forced password reset')} + %else: + ${_('Enable forced password reset')} + %endif + </button> + </div> + <div class="field"> + <span class="help-block"> + ${_("When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface")} + </span> + </div> + ${h.end_form()} + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Personal Repository Group')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(h.url('create_personal_repo_group', user_id=c.user.user_id), method='post')} + + %if c.personal_repo_group: + <div class="panel-body-title-text">${_('Users personal repository group')} : ${h.link_to(c.personal_repo_group.group_name, url('repo_group_home', group_name=c.personal_repo_group.group_name))}</div> + %else: + <div class="panel-body-title-text">${_('This user currently does not have a personal repository group')}</div> + %endif + <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}> + <i class="icon-folder-close"></i> + ${_('Create personal repository group')} + </button> + ${h.end_form()} + </div> +</div> + + +<div class="panel panel-danger"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Delete User')}</h3> + </div> + <div class="panel-body"> + ${h.secure_form(h.url('delete_user', user_id=c.user.user_id), method='delete')} + + <table class="display"> + <tr> + <td> + ${ungettext('This user owns %s repository.', 'This user owns %s repositories.', len(c.user.repositories)) % len(c.user.repositories)} + </td> + <td> + %if len(c.user.repositories) > 0: + <input type="radio" id="user_repos_1" name="user_repos" value="detach" checked="checked"/> <label for="user_repos_1">${_('Detach repositories')}</label> + %endif + </td> + <td> + %if len(c.user.repositories) > 0: + <input type="radio" id="user_repos_2" name="user_repos" value="delete" /> <label for="user_repos_2">${_('Delete repositories')}</label> + %endif + </td> + </tr> + + <tr> + <td> + ${ungettext('This user owns %s repository group.', 'This user owns %s repository groups.', len(c.user.repository_groups)) % len(c.user.repository_groups)} + </td> + <td> + %if len(c.user.repository_groups) > 0: + <input type="radio" id="user_repo_groups_1" name="user_repo_groups" value="detach" checked="checked"/> <label for="user_repo_groups_1">${_('Detach repository groups')}</label> + %endif + </td> + <td> + %if len(c.user.repository_groups) > 0: + <input type="radio" id="user_repo_groups_2" name="user_repo_groups" value="delete" /> <label for="user_repo_groups_2">${_('Delete repositories')}</label> + %endif + </td> + </tr> + + <tr> + <td> + ${ungettext('This user owns %s user group.', 'This user owns %s user groups.', len(c.user.user_groups)) % len(c.user.user_groups)} + </td> + <td> + %if len(c.user.user_groups) > 0: + <input type="radio" id="user_user_groups_1" name="user_user_groups" value="detach" checked="checked"/> <label for="user_user_groups_1">${_('Detach user groups')}</label> + %endif + </td> + <td> + %if len(c.user.user_groups) > 0: + <input type="radio" id="user_user_groups_2" name="user_user_groups" value="delete" /> <label for="user_user_groups_2">${_('Delete repositories')}</label> + %endif + </td> + </tr> + </table> + <div style="margin: 0 0 20px 0" class="fake-space"></div> + + <div class="field"> + <button class="btn btn-small btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete this user: %s') % c.user.username}');" + ${"disabled" if not c.can_delete_user else ""}> + ${_('Delete this user')} + </button> + </div> + % if c.can_delete_user_message: + <p class="help-block">${c.can_delete_user_message}</p> + % endif + + <div class="field"> + <span class="help-block"> + %if len(c.user.repositories) > 0 or len(c.user.repository_groups) > 0 or len(c.user.user_groups) > 0: + <p class="help-block">${_("When selecting the detach option, the depending objects owned by this user will be assigned to the `%s` super admin in the system. The delete option will delete the user's repositories!") % (c.first_admin.full_name)}</p> + %endif + </span> + </div> + + ${h.end_form()} + </div> +</div> diff --git a/rhodecode/templates/admin/users/user_edit_auth_tokens.html b/rhodecode/templates/admin/users/user_edit_auth_tokens.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_auth_tokens.html @@ -0,0 +1,103 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Authentication Access Tokens')}</h3> + </div> + <div class="panel-body"> + <div class="apikeys_wrap"> + <table class="rctable auth_tokens"> + <tr> + <td class="truncate-wrap td-authtoken"><div class="user_auth_tokens truncate autoexpand"><code>${c.user.api_key}</code></div></td> + <td class="td-tags"> + <span class="tag disabled">${_('Built-in')}</span> + </td> + <td class="td-tags"> + <span class="tag disabled">all</span> + </td> + <td class="td-exp">${_('expires')}: ${_('never')}</td> + <td class="td-action"> + ${h.secure_form(url('edit_user_auth_tokens', user_id=c.user.user_id),method='delete')} + ${h.hidden('del_auth_token',c.user.api_key)} + ${h.hidden('del_auth_token_builtin',1)} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to reset this auth token: %s') % c.user.api_key}');"> + ${_('Reset')} + </button> + ${h.end_form()} + </td> + </tr> + %if c.user_auth_tokens: + %for auth_token in c.user_auth_tokens: + <tr class="${'expired' if auth_token.expired else ''}"> + <td class="truncate-wrap td-authtoken"><div class="user_auth_tokens truncate autoexpand"><code>${auth_token.api_key}</code></div></td> + <td class="td-wrap">${auth_token.description}</td> + <td class="td-tags"> + <span class="tag">${auth_token.role_humanized}</span> + </td> + <td class="td-exp"> + %if auth_token.expires == -1: + ${_('expires')}: ${_('never')} + %else: + %if auth_token.expired: + ${_('expired')}: ${h.age_component(h.time_to_datetime(auth_token.expires))} + %else: + ${_('expires')}: ${h.age_component(h.time_to_datetime(auth_token.expires))} + %endif + %endif + </td> + <td> + ${h.secure_form(url('edit_user_auth_tokens', user_id=c.user.user_id),method='delete')} + ${h.hidden('del_auth_token',auth_token.api_key)} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr><td><div class="ip">${_('No additional auth tokens specified')}</div></td></tr> + %endif + </table> + </div> + + <div class="user_auth_tokens"> + ${h.secure_form(url('edit_user_auth_tokens', user_id=c.user.user_id), method='put')} + <div class="form form-vertical"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_email">${_('New auth token')}:</label> + </div> + <div class="input"> + ${h.text('description', class_='medium', placeholder=_('Description'))} + ${h.select('lifetime', '', c.lifetime_options)} + ${h.select('role', '', c.role_options)} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn btn-small")} + ${h.reset('reset',_('Reset'),class_="btn btn-small")} + </div> + </div> + </div> + ${h.end_form()} + </div> + </div> +</div> + +<script> + $(document).ready(function(){ + $("#lifetime").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); + $("#role").select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); + }) +</script> diff --git a/rhodecode/templates/admin/users/user_edit_emails.html b/rhodecode/templates/admin/users/user_edit_emails.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_emails.html @@ -0,0 +1,71 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Additional Email Addresses')}</h3> + </div> + <div class="panel-body"> + <div class="emails_wrap"> + <table class="rctable account_emails useremails"> + <tr> + <td class="td-user"> + ${base.gravatar(c.user.email, 16)} + <span class="user email">${c.user.email} + </td> + <td class="td-tags"> + <span class="tag">${_('Primary')}</span> + </td> + </tr> + %if c.user_email_map: + %for em in c.user_email_map: + <tr> + <td class="td-user"> + ${base.gravatar(em.email, 16)} + <span class="user email">${em.email}</span> + </td> + <td class="td-action"> + ${h.secure_form(url('edit_user_emails', user_id=c.user.user_id),method='delete')} + ${h.hidden('del_email_id',em.email_id)} + <button class="btn btn-link btn-danger" type="submit" + onclick="return confirm('${_('Confirm to delete this email: %s') % em.email}');"> + ${_('Delete')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr class="noborder"> + <td colspan="3"> + <div class="td-email"> + ${_('No additional emails specified')} + </div> + </td> + </tr> + %endif + </table> + </div> + + ${h.secure_form(url('edit_user_emails', user_id=c.user.user_id),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_email">${_('New email address')}:</label> + </div> + <div class="input"> + ${h.text('new_email', class_='medium')} + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn btn-small")} + ${h.reset('reset',_('Reset'),class_="btn btn-small")} + </div> + </div> + </div> + ${h.end_form()} + </div> +</div> + + diff --git a/rhodecode/templates/admin/users/user_edit_global_perms.html b/rhodecode/templates/admin/users/user_edit_global_perms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_global_perms.html @@ -0,0 +1,2 @@ +<%namespace name="dpb" file="/base/default_perms_box.html"/> +${dpb.default_perms_box(url('edit_user_global_perms', user_id=c.user.user_id))} diff --git a/rhodecode/templates/admin/users/user_edit_ips.html b/rhodecode/templates/admin/users/user_edit_ips.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_ips.html @@ -0,0 +1,77 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${_('Custom IP Whitelist')}</h3> + </div> + <div class="panel-body"> + <div class="ips_wrap"> + <table class="rctable ip-whitelist"> + <tr> + <th>IP Address</th> + <th>IP Range</th> + <th>Description</th> + <th></th> + </tr> + %if c.default_user_ip_map and c.inherit_default_ips: + %for ip in c.default_user_ip_map: + <tr> + <td class="td-ip"><div class="ip">${ip.ip_addr}</div></td> + <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td> + <td class="td-description">${h.literal(_('Inherited from %s') % h.link_to('*default*',h.url('admin_permissions_ips')))}</td> + <td></td> + </tr> + %endfor + %endif + + %if c.user_ip_map: + %for ip in c.user_ip_map: + <tr> + <td class="td-ip"><div class="ip">${ip.ip_addr}</div></td> + <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td> + <td class="td-description"><div class="ip">${ip.description}</div></td> + <td class="td-action"> + ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='delete')} + ${h.hidden('del_ip_id',ip.ip_id)} + ${h.submit('remove_',_('Delete'),id="remove_ip_%s" % ip.ip_id, + class_="btn btn-link btn-danger", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")} + ${h.end_form()} + </td> + </tr> + %endfor + %endif + %if not c.default_user_ip_map and not c.user_ip_map: + <tr> + <td><h2 class="ip">${_('All IP addresses are allowed')}</h2></td> + <td></td> + <td></td> + <td></td> + </tr> + %endif + </table> +</div> + + <div> + ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='put')} + <div class="form"> + <!-- fields --> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="new_ip">${_('New IP Address')}:</label> + </div> + <div class="input"> + ${h.text('new_ip')} ${h.text('description', placeholder=_('Description...'))} + <span class="help-block">${_('Enter comma separated list of ip addresses like 127.0.0.1,\n' + 'or use a ip address with a mask 127.0.0.1/24, to create a network range.\n' + 'To specify multiple address range use 127.0.0.1-127.0.0.10 syntax')}</span> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Add'),class_="btn btn-small")} + ${h.reset('reset',_('Reset'),class_="btn btn-small")} + </div> + </div> + </div> + ${h.end_form()} +</div> + </div> +</div> diff --git a/rhodecode/templates/admin/users/user_edit_perms_summary.html b/rhodecode/templates/admin/users/user_edit_perms_summary.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_perms_summary.html @@ -0,0 +1,3 @@ +## permissions overview +<%namespace name="p" file="/base/perms_summary.html"/> +${p.perms_summary(c.perm_user.permissions, show_all=True)} diff --git a/rhodecode/templates/admin/users/user_edit_profile.html b/rhodecode/templates/admin/users/user_edit_profile.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_profile.html @@ -0,0 +1,150 @@ +<%namespace name="base" file="/base/base.html"/> + +<div class="panel panel-default user-profile"> + <div class="panel-heading"> + <h3 class="panel-title">${_('User Profile')}</h3> + </div> + <div class="panel-body"> + <div class="user-profile-content"> + ${h.secure_form(url('update_user', user_id=c.user.user_id),method='put', class_='form')} + <% readonly = None %> + <% disabled = "" %> + %if c.extern_type != 'rhodecode': + <% readonly = "readonly" %> + <% disabled = " disabled" %> + <div class="infoform"> + <div class="fields"> + <p>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</p> + </div> + </div> + %endif + <div class="form"> + <div class="fields"> + <div class="field"> + <div class="label photo"> + ${_('Photo')}: + </div> + <div class="input profile"> + %if c.visual.use_gravatar: + ${base.gravatar(c.user.email, 100)} + <p class="help-block">${_('Change the avatar at')} <a href="http://gravatar.com">gravatar.com</a>.</p> + %else: + ${base.gravatar(c.user.email, 20)} + ${_('Avatars are disabled')} + %endif + </div> + </div> + <div class="field"> + <div class="label"> + ${_('Username')}: + </div> + <div class="input"> + ${h.text('username', class_='%s medium' % disabled, readonly=readonly)} + </div> + </div> + <div class="field"> + <div class="label"> + <label for="name">${_('First Name')}:</label> + </div> + <div class="input"> + ${h.text('firstname', class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="lastname">${_('Last Name')}:</label> + </div> + <div class="input"> + ${h.text('lastname', class_="medium")} + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="email">${_('Email')}:</label> + </div> + <div class="input"> + ## we should be able to edit email ! + ${h.text('email', class_="medium")} + </div> + </div> + <div class="field"> + <div class="label"> + ${_('New Password')}: + </div> + <div class="input"> + ${h.password('new_password',class_='%s medium' % disabled,autocomplete="off",readonly=readonly)} + </div> + </div> + <div class="field"> + <div class="label"> + ${_('New Password Confirmation')}: + </div> + <div class="input"> + ${h.password('password_confirmation',class_="%s medium" % disabled,autocomplete="off",readonly=readonly)} + </div> + </div> + <div class="field"> + <div class="label-text"> + ${_('Active')}: + </div> + <div class="input user-checkbox"> + ${h.checkbox('active',value=True)} + </div> + </div> + <div class="field"> + <div class="label-text"> + ${_('Super Admin')}: + </div> + <div class="input user-checkbox"> + ${h.checkbox('admin',value=True)} + </div> + </div> + <div class="field"> + <div class="label-text"> + ${_('Source of Record')}: + </div> + <div class="input"> + <p>${c.extern_type}</p> + ${h.hidden('extern_type', readonly="readonly")} + </div> + </div> + <div class="field"> + <div class="label-text"> + ${_('Name in Source of Record')}: + </div> + <div class="input"> + <p>${c.extern_name}</p> + ${h.hidden('extern_name', readonly="readonly")} + </div> + </div> + <div class="field"> + <div class="label"> + ${_('Language')}: + </div> + <div class="input"> + ## allowed_languages is defined in the users.py + ## c.language comes from base.py as a default language + ${h.select('language', c.language, c.allowed_languages)} + <p class="help-block">${h.literal(_('Help translate %(rc_link)s into your language.') % {'rc_link': h.link_to('RhodeCode Enterprise', h.url('rhodecode_translations'))})}</p> + </div> + </div> + <div class="buttons"> + ${h.submit('save', _('Save'), class_="btn")} + ${h.reset('reset', _('Reset'), class_="btn")} + </div> + </div> + </div> + ${h.end_form()} + </div> + </div> +</div> + +<script> + $('#language').select2({ + 'containerCssClass': "drop-menu", + 'dropdownCssClass': "drop-menu-dropdown", + 'dropdownAutoWidth': true + }); +</script> diff --git a/rhodecode/templates/admin/users/users.html b/rhodecode/templates/admin/users/users.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/users.html @@ -0,0 +1,141 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Users administration')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif +</%def> + +<%def name="breadcrumbs_links()"> + <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> + ${h.link_to(_('Admin'),h.url('admin_home'))} » <span id="user_count">0</span> +</%def> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} +</%def> + +<%def name="main()"> +<div class="box"> + + <div class="title"> + ${self.breadcrumbs()} + <ul class="links"> + <li> + <a href="${h.url('new_user')}" class="btn btn-small btn-success">${_(u'Add User')}</a> + </li> + </ul> + </div> + + <div id="repos_list_wrap"> + <table id="user_list_table" class="display"></table> + </div> +</div> + +<script> +$(document).ready(function() { + + var get_datatable_count = function(){ + var datatable = $('#user_list_table').dataTable(); + var api = datatable.api(); + var total = api.page.info().recordsDisplay; + var active = datatable.fnGetFilteredData(); + + $('#user_count').text(_TM["{0} active out of {1} users"].format(active, total)); + }; + + // custom filter that filters by username OR email + $.fn.dataTable.ext.search.push( + function( settings, data, dataIndex ) { + var query = $('#q_filter').val(); + var username = data[1]; + var email = data[2]; + var first_name = data[3]; + var last_name = data[4]; + + var query_str = username + " " + + email + " " + + first_name + " " + + last_name; + if((query_str).indexOf(query) !== -1){ + return true; + } + return false; + } + ); + // filtered data plugin + $.fn.dataTableExt.oApi.fnGetFilteredData = function ( oSettings ) { + var res = []; + for ( var i=0, iLen=oSettings.fnRecordsDisplay() ; i<iLen ; i++ ) { + var record = oSettings.aoData[i]._aData; + if(record['active_raw']){ + res.push(record); + } + } + return res.length; + }; + + // user list + $('#user_list_table').DataTable({ + data: ${c.data|n}, + dom: 'rtp', + pageLength: ${c.visual.admin_grid_items}, + order: [[ 1, "asc" ]], + columns: [ + { data: {"_": "gravatar"}, className: "td-gravatar" }, + { data: {"_": "username", + "sort": "username_raw"}, title: "${_('Username')}", className: "td-user" }, + { data: {"_": "email", + "sort": "email"}, title: "${_('Email')}", className: "td-email" }, + { data: {"_": "first_name", + "sort": "first_name"}, title: "${_('First Name')}", className: "td-user" }, + { data: {"_": "last_name", + "sort": "last_name"}, title: "${_('Last Name')}", className: "td-user" }, + { data: {"_": "last_login", + "sort": "last_login_raw", + "type": Number}, title: "${_('Last login')}", className: "td-time" }, + { data: {"_": "active", + "sort": "active_raw"}, title: "${_('Active')}", className: "td-active" }, + { data: {"_": "admin", + "sort": "admin_raw"}, title: "${_('Admin')}", className: "td-admin" }, + { data: {"_": "extern_type", + "sort": "extern_type"}, title: "${_('Authentication type')}", className: "td-type" }, + { data: {"_": "action", + "sort": "action"}, title: "${_('Action')}", className: "td-action" } + ], + language: { + paginate: DEFAULT_GRID_PAGINATION + }, + "initComplete": function( settings, json ) { + get_datatable_count(); + tooltip_activate(); + }, + "createdRow": function ( row, data, index ) { + if (!data['active_raw']){ + $(row).addClass('closed') + } + } + }); + + // update the counter when doing search + $('#user_list_table').on( 'search.dt', function (e,settings) { + get_datatable_count(); + }); + + // filter, filter both grids + $('#q_filter').on( 'keyup', function () { + var user_api = $('#user_list_table').dataTable().api(); + user_api + .draw(); + }); + + // refilter table if page load via back button + $("#q_filter").trigger('keyup'); + + }); + +</script> + +</%def> diff --git a/rhodecode/templates/base/base.html b/rhodecode/templates/base/base.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/base.html @@ -0,0 +1,652 @@ +## -*- coding: utf-8 -*- +<%inherit file="root.html"/> + +<div class="outerwrapper"> + <!-- HEADER --> + <div class="header"> + <div id="header-inner" class="wrapper"> + <div id="logo"> + <div class="logo-wrapper"> + <a href="${h.url('home')}"><img src="${h.url('/images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a> + </div> + %if c.rhodecode_name: + <div class="branding">- ${h.branding(c.rhodecode_name)}</div> + %endif + </div> + <!-- MENU BAR NAV --> + ${self.menu_bar_nav()} + <!-- END MENU BAR NAV --> + ${self.body()} + </div> + </div> + ${self.menu_bar_subnav()} + <!-- END HEADER --> + + <!-- CONTENT --> + <div id="content" class="wrapper"> + ${self.flash_msg()} + <div class="main"> + ${next.main()} + </div> + </div> + <!-- END CONTENT --> + +</div> +<!-- FOOTER --> +<div id="footer"> + <div id="footer-inner" class="title wrapper"> + <div> + <p class="footer-link-right"> + % if c.visual.show_version: + RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition} + % endif + © 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved. + % if c.visual.rhodecode_support_url: + <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a> + % endif + </p> + <% sid = 'block' if request.GET.get('showrcid') else 'none' %> + <p class="server-instance" style="display:${sid}"> + ## display hidden instance ID if specially defined + % if c.rhodecode_instanceid: + ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid} + % endif + </p> + </div> + </div> +</div> + +<!-- END FOOTER --> + +### MAKO DEFS ### + +<%def name="menu_bar_subnav()"> +</%def> + +<%def name="flash_msg()"> + <%include file="/base/flash_msg.html"/> +</%def> + +<%def name="breadcrumbs(class_='breadcrumbs')"> + <div class="${class_}"> + ${self.breadcrumbs_links()} + </div> +</%def> + +<%def name="admin_menu()"> + <ul class="admin_menu submenu"> + <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li> + <li><a href="${h.url('repos')}">${_('Repositories')}</a></li> + <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> + <li><a href="${h.url('users')}">${_('Users')}</a></li> + <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li> + <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li> + <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li> + <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li> + <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li> + </ul> +</%def> + + +<%def name="dt_info_panel(elements)"> + <dl class="dl-horizontal"> + %for dt, dd, title, show_items in elements: + <dt>${dt}:</dt> + <dd title="${title}"> + %if callable(dd): + ## allow lazy evaluation of elements + ${dd()} + %else: + ${dd} + %endif + %if show_items: + <span class="btn-collapse" data-toggle="item-${h.md5(dt)[:6]}-details">${_('Show More')} </span> + %endif + </dd> + + %if show_items: + <div class="collapsable-content" data-toggle="item-${h.md5(dt)[:6]}-details" style="display: none"> + %for item in show_items: + <dt></dt> + <dd>${item}</dd> + %endfor + </div> + %endif + + %endfor + </dl> +</%def> + + +<%def name="gravatar(email, size=16)"> + <% + if (size > 16): + gravatar_class = 'gravatar gravatar-large' + else: + gravatar_class = 'gravatar' + %> + <%doc> + TODO: johbo: For now we serve double size images to make it smooth + for retina. This is how it worked until now. Should be replaced + with a better solution at some point. + </%doc> + <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}"> +</%def> + + +<%def name="gravatar_with_user(contact, size=16)"> + <div class="rc-user tooltip" title="${contact}"> + ${self.gravatar(h.email_or_none(contact), size)} + <span class="user"> ${h.link_to_user(contact)}</span> + </div> +</%def> + + +## admin menu used for people that have some admin resources +<%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)"> + <ul class="submenu"> + %if repositories: + <li><a href="${h.url('repos')}">${_('Repositories')}</a></li> + %endif + %if repository_groups: + <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> + %endif + %if user_groups: + <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li> + %endif + </ul> +</%def> + +<%def name="repo_page_title(repo_instance)"> +<div class="title-content"> + <div class="title-main"> + ## SVN/HG/GIT icons + %if h.is_hg(repo_instance): + <i class="icon-hg"></i> + %endif + %if h.is_git(repo_instance): + <i class="icon-git"></i> + %endif + %if h.is_svn(repo_instance): + <i class="icon-svn"></i> + %endif + + ## public/private + %if repo_instance.private: + <i class="icon-repo-private"></i> + %else: + <i class="icon-repo-public"></i> + %endif + + ## repo name with group name + ${h.breadcrumb_repo_link(c.rhodecode_db_repo)} + + </div> + + ## FORKED + %if repo_instance.fork: + <p> + <i class="icon-code-fork"></i> ${_('Fork of')} + <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a> + </p> + %endif + + ## IMPORTED FROM REMOTE + %if repo_instance.clone_uri: + <p> + <i class="icon-code-fork"></i> ${_('Clone from')} + <a href="${h.url(str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a> + </p> + %endif + + ## LOCKING STATUS + %if repo_instance.locked[0]: + <p class="locking_locked"> + <i class="icon-repo-lock"></i> + ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}} + </p> + %elif repo_instance.enable_locking: + <p class="locking_unlocked"> + <i class="icon-repo-unlock"></i> + ${_('Repository not locked. Pull repository to lock it.')} + </p> + %endif + +</div> +</%def> + +<%def name="repo_menu(active=None)"> + <% + def is_active(selected): + if selected == active: + return "active" + %> + + <!--- CONTEXT BAR --> + <div id="context-bar"> + <div class="wrapper"> + <ul id="context-pages" class="horizontal-list navigation"> + <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li> + <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li> + <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li> + <li class="${is_active('compare')}"> + <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a> + </li> + ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()" + %if c.rhodecode_db_repo.repo_type in ['git','hg']: + <li class="${is_active('showpullrequest')}"> + <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> + %if c.repository_pull_requests: + <span class="pr_notifications">${c.repository_pull_requests}</span> + %endif + <div class="menulabel">${_('Pull Requests')}</div> + </a> + </li> + %endif + <li class="${is_active('options')}"> + <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a> + <ul class="submenu"> + %if h.HasRepoPermissionAll('repository.admin')(c.repo_name): + <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li> + %endif + %if c.rhodecode_db_repo.fork: + <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}"> + ${_('Compare fork')}</a></li> + %endif + + <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li> + + %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking: + %if c.rhodecode_db_repo.locked[0]: + <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li> + %else: + <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li> + %endif + %endif + %if c.rhodecode_user.username != h.DEFAULT_USER: + %if c.rhodecode_db_repo.repo_type in ['git','hg']: + <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li> + <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li> + %endif + %endif + </ul> + </li> + </ul> + </div> + <div class="clear"></div> + </div> + <!--- END CONTEXT BAR --> + +</%def> + +<%def name="usermenu()"> + ## USER MENU + <li id="quick_login_li"> + <a id="quick_login_link" class="menulink childs"> + ${gravatar(c.rhodecode_user.email, 20)} + <span class="user"> + %if c.rhodecode_user.username != h.DEFAULT_USER: + <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div> + %else: + <span>${_('Sign in')}</span> + %endif + </span> + </a> + + <div class="user-menu submenu"> + <div id="quick_login"> + %if c.rhodecode_user.username == h.DEFAULT_USER: + <h4>${_('Sign in to your account')}</h4> + ${h.form(h.url('login_home',came_from=h.url.current()), needs_csrf_token=False)} + <div class="form form-vertical"> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="username">${_('Username')}:</label> + </div> + <div class="input"> + ${h.text('username',class_='focus',tabindex=1)} + </div> + + </div> + <div class="field"> + <div class="label"> + <label for="password">${_('Password')}:</label> + <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.url('reset_password'))}</span> + </div> + <div class="input"> + ${h.password('password',class_='focus',tabindex=2)} + </div> + </div> + <div class="buttons"> + <div class="register"> + %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')(): + ${h.link_to(_("Don't have an account ?"),h.url('register'))} + %endif + </div> + <div class="submit"> + ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)} + </div> + </div> + </div> + </div> + ${h.end_form()} + %else: + <div class=""> + <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div> + <div class="full_name">${c.rhodecode_user.full_name_or_username}</div> + <div class="email">${c.rhodecode_user.email}</div> + </div> + <div class=""> + <ol class="links"> + <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li> + <li class="logout"> + ${h.secure_form(h.url('logout_home'))} + ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")} + ${h.end_form()} + </li> + </ol> + </div> + %endif + </div> + </div> + %if c.rhodecode_user.username != h.DEFAULT_USER: + <div class="pill_container"> + % if c.unread_notifications == 0: + <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a> + % else: + <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a> + % endif + </div> + % endif + </li> +</%def> + +<%def name="menu_items(active=None)"> + <% + def is_active(selected): + if selected == active: + return "active" + return "" + %> + <ul id="quick" class="main_nav navigation horizontal-list"> + <!-- repo switcher --> + <li class="${is_active('repositories')} repo_switcher_li has_select2"> + <input id="repo_switcher" name="repo_switcher" type="hidden"> + </li> + + ## ROOT MENU + %if c.rhodecode_user.username != h.DEFAULT_USER: + <li class="${is_active('journal')}"> + <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}"> + <div class="menulabel">${_('Journal')}</div> + </a> + </li> + %else: + <li class="${is_active('journal')}"> + <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}"> + <div class="menulabel">${_('Public journal')}</div> + </a> + </li> + %endif + <li class="${is_active('gists')}"> + <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}"> + <div class="menulabel">${_('Gists')}</div> + </a> + </li> + <li class="${is_active('search')}"> + <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}"> + <div class="menulabel">${_('Search')}</div> + </a> + </li> + % if h.HasPermissionAll('hg.admin')('access admin main page'): + <li class="${is_active('admin')}"> + <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;"> + <div class="menulabel">${_('Admin')} <div class="show_more"></div></div> + </a> + ${admin_menu()} + </li> + % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin: + <li class="${is_active('admin')}"> + <a class="menulink childs" title="${_('Delegated Admin settings')}"> + <div class="menulabel">${_('Admin')} <div class="show_more"></div></div> + </a> + ${admin_menu_simple(c.rhodecode_user.repositories_admin, + c.rhodecode_user.repository_groups_admin, + c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())} + </li> + % endif + % if c.debug_style: + <li class="${is_active('debug_style')}"> + <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}"> + <div class="menulabel">${_('Style')}</div> + </a> + </li> + % endif + ## render extra user menu + ${usermenu()} + </ul> + + <script type="text/javascript"> + var visual_show_public_icon = "${c.visual.show_public_icon}" == "True"; + + /*format the look of items in the list*/ + var format = function(state, escapeMarkup){ + if (!state.id){ + return state.text; // optgroup + } + var obj_dict = state.obj; + var tmpl = ''; + + if(obj_dict && state.type == 'repo'){ + if(obj_dict['repo_type'] === 'hg'){ + tmpl += '<i class="icon-hg"></i> '; + } + else if(obj_dict['repo_type'] === 'git'){ + tmpl += '<i class="icon-git"></i> '; + } + else if(obj_dict['repo_type'] === 'svn'){ + tmpl += '<i class="icon-svn"></i> '; + } + if(obj_dict['private']){ + tmpl += '<i class="icon-lock" ></i> '; + } + else if(visual_show_public_icon){ + tmpl += '<i class="icon-unlock-alt"></i> '; + } + } + if(obj_dict && state.type == 'group'){ + tmpl += '<i class="icon-folder-close"></i> '; + } + tmpl += escapeMarkup(state.text); + return tmpl; + }; + + var formatResult = function(result, container, query, escapeMarkup) { + return format(result, escapeMarkup); + }; + + var formatSelection = function(data, container, escapeMarkup) { + return format(data, escapeMarkup); + }; + + $("#repo_switcher").select2({ + cachedDataSource: {}, + minimumInputLength: 2, + placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>', + dropdownAutoWidth: true, + formatResult: formatResult, + formatSelection: formatSelection, + containerCssClass: "repo-switcher", + dropdownCssClass: "repo-switcher-dropdown", + escapeMarkup: function(m){ + // don't escape our custom placeholder + if(m.substr(0,23) == '<div class="menulabel">'){ + return m; + } + + return Select2.util.escapeMarkup(m); + }, + query: $.debounce(250, function(query){ + self = this; + var cacheKey = query.term; + var cachedData = self.cachedDataSource[cacheKey]; + + if (cachedData) { + query.callback({results: cachedData.results}); + } else { + $.ajax({ + url: "${h.url('repo_switcher_data')}", + data: {'query': query.term}, + dataType: 'json', + type: 'GET', + success: function(data) { + self.cachedDataSource[cacheKey] = data; + query.callback({results: data.results}); + }, + error: function(data, textStatus, errorThrown) { + alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText)); + } + }) + } + }) + }); + + $("#repo_switcher").on('select2-selecting', function(e){ + e.preventDefault(); + window.location = pyroutes.url('summary_home', {'repo_name': e.val}); + }); + + ## Global mouse bindings ## + + // general help "?" + Mousetrap.bind(['?'], function(e) { + $('#help_kb').modal({}) + }); + + // / open the quick filter + Mousetrap.bind(['/'], function(e) { + $("#repo_switcher").select2("open"); + + // return false to prevent default browser behavior + // and stop event from bubbling + return false; + }); + + // general nav g + action + Mousetrap.bind(['g h'], function(e) { + window.location = pyroutes.url('home'); + }); + Mousetrap.bind(['g g'], function(e) { + window.location = pyroutes.url('gists', {'private':1}); + }); + Mousetrap.bind(['g G'], function(e) { + window.location = pyroutes.url('gists', {'public':1}); + }); + Mousetrap.bind(['n g'], function(e) { + window.location = pyroutes.url('new_gist'); + }); + Mousetrap.bind(['n r'], function(e) { + window.location = pyroutes.url('new_repo'); + }); + + % if hasattr(c, 'repo_name') and hasattr(c, 'rhodecode_db_repo'): + // nav in repo context + Mousetrap.bind(['g s'], function(e) { + window.location = pyroutes.url('summary_home', {'repo_name': REPO_NAME}); + }); + Mousetrap.bind(['g c'], function(e) { + window.location = pyroutes.url('changelog_home', {'repo_name': REPO_NAME}); + }); + Mousetrap.bind(['g F'], function(e) { + window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': '', 'search': '1'}); + }); + Mousetrap.bind(['g f'], function(e) { + window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': ''}); + }); + Mousetrap.bind(['g p'], function(e) { + window.location = pyroutes.url('pullrequest_show_all', {'repo_name': REPO_NAME}); + }); + Mousetrap.bind(['g o'], function(e) { + window.location = pyroutes.url('edit_repo', {'repo_name': REPO_NAME}); + }); + Mousetrap.bind(['g O'], function(e) { + window.location = pyroutes.url('edit_repo_perms', {'repo_name': REPO_NAME}); + }); + % endif + + </script> + <script src="${h.url('/js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script> +</%def> + +<div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4> + </div> + <div class="modal-body"> + <div class="block-left"> + <table class="keyboard-mappings"> + <tbody> + <tr> + <th></th> + <th>${_('Site-wide shortcuts')}</th> + </tr> + <% + elems = [ + ('/', 'Open quick search box'), + ('g h', 'Goto home page'), + ('g g', 'Goto my private gists page'), + ('g G', 'Goto my public gists page'), + ('n r', 'New repository page'), + ('n g', 'New gist page'), + ] + %> + %for key, desc in elems: + <tr> + <td class="keys"> + <span class="key tag">${key}</span> + </td> + <td>${desc}</td> + </tr> + %endfor + </tbody> + </table> + </div> + <div class="block-left"> + <table class="keyboard-mappings"> + <tbody> + <tr> + <th></th> + <th>${_('Repositories')}</th> + </tr> + <% + elems = [ + ('g s', 'Goto summary page'), + ('g c', 'Goto changelog page'), + ('g f', 'Goto files page'), + ('g F', 'Goto files page with file search activated'), + ('g p', 'Goto pull requests page'), + ('g o', 'Goto repository settings'), + ('g O', 'Goto repository permissions settings'), + ] + %> + %for key, desc in elems: + <tr> + <td class="keys"> + <span class="key tag">${key}</span> + </td> + <td>${desc}</td> + </tr> + %endfor + </tbody> + </table> + </div> + </div> + <div class="modal-footer"> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> diff --git a/rhodecode/templates/base/default_perms_box.html b/rhodecode/templates/base/default_perms_box.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/default_perms_box.html @@ -0,0 +1,156 @@ +## snippet for displaying default permission box +## usage: +## <%namespace name="dpb" file="/base/default_perms_box.html"/> +## ${dpb.default_perms_box(<url_to_form>)} +## ${dpb.default_perms_radios()} + +<%def name="default_perms_radios(global_permissions_template = False, suffix='', **kwargs)"> +<div class="main-content-full-width"> + <div class="panel panel-default"> + + ## displayed according to checkbox selection + <div class="panel-heading"> + %if not global_permissions_template: + <h3 class="inherit_overlay_default panel-title">${_('Inherited Permissions')}</h3> + <h3 class="inherit_overlay panel-title">${_('Custom Permissions')}</h3> + %else: + <h3 class="panel-title">${_('Default Global Permissions')}</h3> + %endif + </div> + + <div class="panel-body"> + %if global_permissions_template: + <p>${_('The following options configure the default permissions each user or group will inherit. You can override these permissions for each individual user or user group using individual permissions settings.')}</p> + %endif + <div class="field"> + <div class="label"> + <label for="default_repo_create${suffix}">${_('Repository Creation')}:</label> + </div> + <div class="radios"> + ${h.radio('default_repo_create' + suffix, c.repo_create_choices[1][0], label=c.repo_create_choices[1][1], **kwargs)} + ${h.radio('default_repo_create' + suffix, c.repo_create_choices[0][0], label=c.repo_create_choices[0][1], **kwargs)} + <span class="help-block">${_('Permission to create root level repositories. When disabled, users can still create repositories inside their own repository groups.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_repo_create_on_write${suffix}">${_('Repository Creation With Group Write Access')}:</label> + </div> + <div class="radios"> + ${h.radio('default_repo_create_on_write' + suffix, c.repo_create_on_write_choices[1][0], label=c.repo_create_on_write_choices[1][1], **kwargs)} + ${h.radio('default_repo_create_on_write' + suffix, c.repo_create_on_write_choices[0][0], label=c.repo_create_on_write_choices[0][1], **kwargs)} + <span class="help-block">${_('Write permission given on a repository group will allow creating repositories inside that group.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_fork_create${suffix}">${_('Repository Forking')}:</label> + </div> + <div class="radios"> + ${h.radio('default_fork_create' + suffix, c.fork_choices[1][0], label=c.fork_choices[1][1], **kwargs)} + ${h.radio('default_fork_create' + suffix, c.fork_choices[0][0], label=c.fork_choices[0][1], **kwargs)} + <span class="help-block">${_('Permission to create root level repository forks. When disabled, users can still fork repositories inside their own repository groups.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_repo_group_create${suffix}">${_('Repository Group Creation')}:</label> + </div> + <div class="radios"> + ${h.radio('default_repo_group_create' + suffix, c.repo_group_create_choices[1][0], label=c.repo_group_create_choices[1][1], **kwargs)} + ${h.radio('default_repo_group_create' + suffix, c.repo_group_create_choices[0][0], label=c.repo_group_create_choices[0][1], **kwargs)} + <span class="help-block">${_('Permission to create root level repository groups. When disabled, repository group admins can still create repository subgroups within their repository groups.')}</span> + </div> + </div> + <div class="field"> + <div class="label"> + <label for="default_user_group_create${suffix}">${_('User Group Creation')}:</label> + </div> + <div class="radios"> + ${h.radio('default_user_group_create' + suffix, c.user_group_create_choices[1][0], label=c.user_group_create_choices[1][1], **kwargs)} + ${h.radio('default_user_group_create' + suffix, c.user_group_create_choices[0][0], label=c.user_group_create_choices[0][1], **kwargs)} + <span class="help-block">${_('Permission to allow user group creation. When disabled, user group admins can still create subgroups within their user groups.')}</span> + </div> + </div> + + <div class="field"> + <div class="label"> + <label for="default_inherit_default_permissions${suffix}">${_('Inherit Permissions From The Default User')}:</label> + </div> + <div class="radios"> + ${h.radio('default_inherit_default_permissions' + suffix, c.inherit_default_permission_choices[1][0], label=c.inherit_default_permission_choices[1][1], **kwargs)} + ${h.radio('default_inherit_default_permissions' + suffix, c.inherit_default_permission_choices[0][0], label=c.inherit_default_permission_choices[0][1], **kwargs)} + <span class="help-block">${_('Inherit default permissions from the default user. Turn off this option to force explicit permissions for users, even if they are more restrictive than the default user permissions.')}</span> + </div> + </div> + + <div class="buttons"> + ${h.submit('save',_('Save'),class_="btn")} + ${h.reset('reset',_('Reset'),class_="btn")} + </div> + </div> + </div> +</div> +</%def> + +<%def name="default_perms_box(form_url)"> + ${h.secure_form(form_url, method='put')} + <div class="form"> + <div class="fields"> + <div class="field panel panel-default panel-body"> + <div class="label label-checkbox"> + <label for="inherit_default_permissions">${_('Inherit from default settings')}:</label> + </div> + <div class="checkboxes"> + ${h.checkbox('inherit_default_permissions',value=True)} + <span class="help-block"> + ${h.literal(_('Select to inherit permissions from %s permissions settings, ' + 'including default IP address whitelist and inheritance of \npermission by members of user groups.') + % h.link_to('default user', url('admin_permissions_global')))} + </span> + </div> + </div> + + ## INHERITED permissions == the user permissions in admin + ## if inherit checkbox is set this is displayed in non-edit mode + <div class="inherit_overlay_default"> + ${default_perms_radios(global_permissions_template = False, suffix='_inherited', disabled="disabled")} + </div> + + ## CUSTOM permissions + <div class="inherit_overlay"> + ${default_perms_radios(global_permissions_template = False)} + </div> + </div> + </div> + ${h.end_form()} + + +## JS +<script> +var show_custom_perms = function(inherit_default){ + if(inherit_default) { + $('.inherit_overlay_default').show(); + $('.inherit_overlay').hide(); + } + else { + $('.inherit_overlay').show(); + $('.inherit_overlay_default').hide(); + } +}; +$(document).ready(function(e){ + var inherit_checkbox = $('#inherit_default_permissions'); + var defaults = inherit_checkbox.prop('checked'); + show_custom_perms(defaults); + inherit_checkbox.on('change', function(){ + if($(this).prop('checked')){ + show_custom_perms(true); + } + else{ + show_custom_perms(false); + } + }) +}) +</script> + +</%def> diff --git a/rhodecode/templates/base/flash_msg.html b/rhodecode/templates/base/flash_msg.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/flash_msg.html @@ -0,0 +1,16 @@ +<div class="flash_msg"> + <% messages = h.flash.pop_messages() %> + % if messages: + % for message in messages: + <div class="alert alert-dismissable alert-${message.category}"> + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> + ${message} + </div> + % endfor + % endif + <script> + if (typeof jQuery != 'undefined') { + $(".alert").alert(); + } + </script> +</div> diff --git a/rhodecode/templates/base/issue_tracker_settings.html b/rhodecode/templates/base/issue_tracker_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/issue_tracker_settings.html @@ -0,0 +1,219 @@ +## snippet for displaying issue tracker settings +## usage: +## <%namespace name="its" file="/base/issue_tracker_settings.html"/> +## ${its.issue_tracker_settings_table(patterns, form_url, delete_url)} +## ${its.issue_tracker_settings_test(test_url)} + +<%def name="issue_tracker_settings_table(patterns, form_url, delete_url)"> + <table class="rctable issuetracker"> + <tr> + <th>${_('Description')}</th> + <th>${_('Pattern')}</th> + <th>${_('Url')}</th> + <th>${_('Prefix')}</th> + <th ></th> + </tr> + <tr> + <td class="td-description issue-tracker-example">Example</td> + <td class="td-regex issue-tracker-example">${'(?:#)(?P<issue_id>\d+)'}</td> + <td class="td-url issue-tracker-example">${'https://myissueserver.com/${repo}/issue/${issue_id}'}</td> + <td class="td-prefix issue-tracker-example">#</td> + ## TODO(skreft): add a link to the correct location of the Issue Tracker documentation. + <td class="issue-tracker-example"><a href="https://rhodecode.com/docs" target="_blank">${_('Read more')}</a></td> + </tr> + %for uid, entry in patterns: + <tr id="entry_${uid}"> + <td class="td-description issuetracker_desc"> + <span class="entry"> + ${entry.desc} + </span> + <span class="edit"> + ${h.text('new_pattern_description_'+uid, class_='medium-inline', value=entry.desc or '')} + </span> + </td> + <td class="td-regex issuetracker_pat"> + <span class="entry"> + ${entry.pat} + </span> + <span class="edit"> + ${h.text('new_pattern_pattern_'+uid, class_='medium-inline', value=entry.pat or '')} + </span> + </td> + <td class="td-url issuetracker_url"> + <span class="entry"> + ${entry.url} + </span> + <span class="edit"> + ${h.text('new_pattern_url_'+uid, class_='medium-inline', value=entry.url or '')} + </span> + </td> + <td class="td-prefix issuetracker_pref"> + <span class="entry"> + ${entry.pref} + </span> + <span class="edit"> + ${h.text('new_pattern_prefix_'+uid, class_='medium-inline', value=entry.pref or '')} + </span> + </td> + <td class="td-action"> + <div class="grid_edit"> + <span class="entry"> + <a class="edit_issuetracker_entry" href="">${_('Edit')}</a> + </span> + <span class="edit"> + ${h.hidden('uid', uid)} + </span> + </div> + <div class="grid_delete"> + <span class="entry"> + <a class="btn btn-link btn-danger delete_issuetracker_entry" data-desc="${entry.desc}" data-uid="${uid}"> + ${_('Delete')} + </a> + </span> + <span class="edit"> + <a class="btn btn-link btn-danger edit_issuetracker_cancel" data-uid="${uid}">${_('Cancel')}</a> + </span> + </div> + </td> + </tr> + %endfor + <tr id="last-row"></tr> + </table> + <p> + <a id="add_pattern" class="link"> + ${_('Add new')} + </a> + </p> + + <script type="text/javascript"> + var newEntryLabel = $('label[for="new_entry"]'); + + var resetEntry = function() { + newEntryLabel.text("${_('New Entry')}:"); + }; + + var delete_pattern = function(entry) { + if (confirm("${_('Confirm to remove this pattern:')} "+$(entry).data('desc'))) { + var request = $.ajax({ + type: "POST", + url: "${delete_url}", + data: { + '_method': 'delete', + 'csrf_token': CSRF_TOKEN, + 'uid':$(entry).data('uid') + }, + success: function(){ + location.reload(); + }, + error: function(data, textStatus, errorThrown){ + alert("Error while deleting entry.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(entry)[0].url)); + } + }); + }; + } + + $('.delete_issuetracker_entry').on('click', function(e){ + e.preventDefault(); + delete_pattern(this); + }); + + $('.edit_issuetracker_entry').on('click', function(e){ + e.preventDefault(); + $(this).parents('tr').addClass('editopen'); + }); + + $('.edit_issuetracker_cancel').on('click', function(e){ + e.preventDefault(); + $(this).parents('tr').removeClass('editopen'); + // Reset to original value + var uid = $(this).data('uid'); + $('#'+uid+' input').each(function(e) { + this.value = this.defaultValue; + }); + }); + + $('input#reset').on('click', function(e) { + resetEntry(); + }); + + $('#add_pattern').on('click', function(e) { + addNewPatternInput(); + }); + </script> +</%def> + +<%def name="issue_tracker_new_row()"> + <table id="add-row-tmpl" style="display: none;"> + <tbody> + <tr class="new_pattern"> + <td class="td-description issuetracker_desc"> + <span class="entry"> + <input class="medium-inline" id="description_##UUID##" name="new_pattern_description_##UUID##" value="##DESCRIPTION##" type="text"> + </span> + </td> + <td class="td-regex issuetracker_pat"> + <span class="entry"> + <input class="medium-inline" id="pattern_##UUID##" name="new_pattern_pattern_##UUID##" placeholder="Pattern" + value="##PATTERN##" type="text"> + </span> + </td> + <td class="td-url issuetracker_url"> + <span class="entry"> + <input class="medium-inline" id="url_##UUID##" name="new_pattern_url_##UUID##" placeholder="Url" value="##URL##" type="text"> + </span> + </td> + <td class="td-prefix issuetracker_pref"> + <span class="entry"> + <input class="medium-inline" id="prefix_##UUID##" name="new_pattern_prefix_##UUID##" placeholder="Prefix" value="##PREFIX##" type="text"> + </span> + </td> + <td class="td-action"> + </td> + <input id="uid_##UUID##" name="uid_##UUID##" type="hidden" value=""> + </tr> + </tbody> + </table> +</%def> + +<%def name="issue_tracker_settings_test(test_url)"> + <div class="form-vertical"> + <div class="fields"> + <div class="field"> + <div class='textarea-full'> + <textarea id="test_pattern_data" > +This commit fixes ticket #451. +This is an example text for testing issue tracker patterns, add a pattern here and +hit preview to see the link + </textarea> + </div> + </div> + </div> + <div class="test_pattern_preview"> + <div id="test_pattern" class="btn btn-small" >${_('Preview')}</div> + <p>${_('Test Pattern Preview')}</p> + <div id="test_pattern_result"></div> + </div> + </div> + + <script type="text/javascript"> + $('#test_pattern').on('click', function(e) { + $.ajax({ + type: "POST", + url: "${test_url}", + data: { + 'test_text': $('#test_pattern_data').val(), + 'csrf_token': CSRF_TOKEN + }, + success: function(data){ + $('#test_pattern_result').html(data); + }, + error: function(jqXHR, textStatus, errorThrown){ + $('#test_pattern_result').html('Error: ' + errorThrown); + } + }); + $('#test_pattern_result').show(); + }); + </script> +</%def> + + diff --git a/rhodecode/templates/base/perms_summary.html b/rhodecode/templates/base/perms_summary.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/perms_summary.html @@ -0,0 +1,200 @@ +## snippet for displaying permissions overview for users +## usage: +## <%namespace name="p" file="/base/perms_summary.html"/> +## ${p.perms_summary(c.perm_user.permissions)} + +<%def name="perms_summary(permissions, show_all=False, actions=True)"> + +<div id="perms" class="table fields"> + %for section in sorted(permissions.keys()): + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3> + </div> + <div class="panel-body"> + <div class="perms_section_head field"> + <div class="radios"> + %if section != 'global': + <span class="permissions_boxes"> + <span class="desc">${_('show')}: </span> + ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_%s' % section}"><span class="perm_tag none">${_('none')}</span></label> + ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_%s' % section}"><span class="perm_tag read">${_('read')}</span></label> + ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_%s' % section}"> <span class="perm_tag write">${_('write')}</span></label> + ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_%s' % section}"><span class="perm_tag admin">${_('admin')}</span></label> + </span> + %endif + </div> + </div> + <div class="field"> + %if not permissions[section]: + <p class="empty_data help-block">${_('No permissions defined')}</p> + %else: + <div id='tbl_list_wrap_${section}'> + <table id="tbl_list_${section}" class="rctable"> + ## global permission box + %if section == 'global': + <thead> + <tr> + <th colspan="2" class="left">${_('Permission')}</th> + %if actions: + <th>${_('Edit Permission')}</th> + %endif + </thead> + <tbody> + + <% + def get_section_perms(prefix, opts): + _selected = [] + for op in opts: + if op.startswith(prefix) and not op.startswith('hg.create.write_on_repogroup'): + _selected.append(op) + admin = 'hg.admin' in opts + _selected_vals = [x.partition(prefix)[-1] for x in _selected] + return admin, _selected_vals, _selected + %> + <%def name="glob(lbl, val, val_lbl=None, custom_url=None)"> + <tr> + <td class="td-tags"> + ${lbl} + </td> + <td class="td-tags"> + %if val[0]: + %if not val_lbl: + ${h.bool2icon(True)} + %else: + <span class="perm_tag admin">${val_lbl}.admin</span> + %endif + %else: + %if not val_lbl: + ${h.bool2icon({'false': False, + 'true': True, + 'none': False, + 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false'))} + %else: + <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span> + %endif + %endif + </td> + %if actions: + <td class="td-action"> + <a href="${custom_url or h.url('admin_permissions_global')}">${_('edit')}</a> + </td> + %endif + </tr> + </%def> + + ${glob(_('Super admin'), get_section_perms('hg.admin', permissions[section]))} + + ${glob(_('Repository default permission'), get_section_perms('repository.', permissions[section]), 'repository', h.url('admin_permissions_object'))} + ${glob(_('Repository group default permission'), get_section_perms('group.', permissions[section]), 'group', h.url('admin_permissions_object'))} + ${glob(_('User group default permission'), get_section_perms('usergroup.', permissions[section]), 'usergroup', h.url('admin_permissions_object'))} + + ${glob(_('Create repositories'), get_section_perms('hg.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))} + ${glob(_('Fork repositories'), get_section_perms('hg.fork.', permissions[section]), custom_url=h.url('admin_permissions_global'))} + ${glob(_('Create repository groups'), get_section_perms('hg.repogroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))} + ${glob(_('Create user groups'), get_section_perms('hg.usergroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))} + + + </tbody> + %else: + ## none/read/write/admin permissions on groups/repos etc + <thead> + <tr> + <th>${_('Name')}</th> + <th>${_('Permission')}</th> + %if actions: + <th>${_('Edit Permission')}</th> + %endif + </thead> + <tbody class="section_${section}"> + <% + def sorter(permissions): + def custom_sorter(item): + ## read/write/admin + section = item[1].split('.')[-1] + section_importance = {'none': u'0', + 'read': u'1', + 'write':u'2', + 'admin':u'3'}.get(section) + ## sort by group importance+name + return section_importance+item[0] + return sorted(permissions, key=custom_sorter) + %> + %for k, section_perm in sorter(permissions[section].items()): + %if section_perm.split('.')[-1] != 'none' or show_all: + <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}"> + <td class="td-componentname"> + %if section == 'repositories': + <a href="${h.url('summary_home',repo_name=k)}">${k}</a> + %elif section == 'repositories_groups': + <a href="${h.url('repo_group_home',group_name=k)}">${k}</a> + %elif section == 'user_groups': + ##<a href="${h.url('edit_users_group',user_group_id=k)}">${k}</a> + ${k} + %endif + </td> + <td class="td-tags"> + <span class="perm_tag ${section_perm.split('.')[-1]}">${section_perm}</span> + </td> + %if actions: + <td class="td-action"> + %if section == 'repositories': + <a href="${h.url('edit_repo_perms',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> + %elif section == 'repositories_groups': + <a href="${h.url('edit_repo_group_perms',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> + %elif section == 'user_groups': + ##<a href="${h.url('edit_users_group',user_group_id=k)}">${_('edit')}</a> + %endif + </td> + %endif + </tr> + %endif + %endfor + + <tr id="empty_${section}" class="noborder" style="display:none;"> + <td colspan="6">${_('No permission defined')}</td> + </tr> + + </tbody> + %endif + </table> + </div> + %endif + </div> + </div> + </div> + %endfor +</div> + +<script> + $(document).ready(function(){ + var show_empty = function(section){ + var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length; + if(visible == 0){ + $('#empty_{0}'.format(section)).show(); + } + else{ + $('#empty_{0}'.format(section)).hide(); + } + }; + $('.perm_filter').on('change', function(e){ + var self = this; + var section = $(this).attr('section'); + + var opts = {}; + var elems = $('.filter_' + section).each(function(el){ + var perm_type = $(this).attr('perm_type'); + var checked = this.checked; + opts[perm_type] = checked; + if(checked){ + $('.'+section+'_'+perm_type).show(); + } + else{ + $('.'+section+'_'+perm_type).hide(); + } + }); + show_empty(section); + }) + }) +</script> +</%def> diff --git a/rhodecode/templates/base/root.html b/rhodecode/templates/base/root.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/root.html @@ -0,0 +1,169 @@ +## -*- coding: utf-8 -*- +<!DOCTYPE html> + +<%def name="get_template_context()" filter="n, trim">{ + + ## repo data + repo_name: "${getattr(c, 'repo_name', '')}", + % if hasattr(c, 'rhodecode_db_repo'): + repo_type: "${c.rhodecode_db_repo.repo_type}", + repo_landing_commit: "${c.rhodecode_db_repo.landing_rev[1]}", + % else: + repo_type: null, + repo_landing_commit: null, + % endif + + ## user data + % if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id: + rhodecode_user: { + username: "${c.rhodecode_user.username}", + email: "${c.rhodecode_user.email}", + }, + % else: + rhodecode_user: { + username: null, + email: null, + }, + % endif + + ## visual settings + visual: { + default_renderer: "${h.get_visual_attr(c, 'default_renderer')}" + }, + + ## current commit context, filled inside templates that expose that + commit_data: { + commit_id: null, + }, + + ## current pr context, filled inside templates that expose that + pull_request_data: { + pull_request_id: null, + }, + + ## timeago settings, can be overwritten by custom user settings later + timeago: { + refresh_time: ${120 * 1000}, + cutoff_limit: ${1000*60*60*24*7} + } +} + +</%def> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>${self.title()} + + <%def name="robots()"> + + + ${self.robots()} + + + ## CSS definitions + <%def name="css()"> + + + ## EXTRA FOR CSS + ${self.css_extra()} + + ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites + <%def name="css_extra()"> + + + ${self.css()} + + ## JAVASCRIPT + <%def name="js()"> + + + + + + + + ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates + ${self.js_extra()} + + + + + + ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates + <%def name="js_extra()"> + ${self.js()} + + <%def name="head_extra()"> + ${self.head_extra()} + + ## extra stuff + %if c.pre_code: + ${c.pre_code|n} + %endif + + + + ## IE hacks + + + + + ${next.body()} + %if c.post_code: + ${c.post_code|n} + %endif + + diff --git a/rhodecode/templates/base/social_buttons.html b/rhodecode/templates/base/social_buttons.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/social_buttons.html @@ -0,0 +1,13 @@ +<%def name="render_social_buttons(social_plugins, context_page=None)"> + + %for plugin in social_plugins: + + %if context_page == 'login': + ${_('Sign in with')} ${plugin.get_display_name()} + %elif context_page == 'register': + ${_('Connect with')} ${plugin.get_display_name()} + %endif + + %endfor + + diff --git a/rhodecode/templates/base/vcs_settings.html b/rhodecode/templates/base/vcs_settings.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/base/vcs_settings.html @@ -0,0 +1,216 @@ +## snippet for displaying vcs settings +## usage: +## <%namespace name="vcss" file="/base/vcssettings.html"/> +## ${vcss.vcs_settings_fields()} + +<%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)"> + % if display_globals: +
+
+

${_('General')}

+
+
+
+
+ ${h.checkbox('web_push_ssl' + suffix, 'True')} + +
+
+ ${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')} +
+
+
+
+ % endif + + % if display_globals: +
+
+

${_('Main Storage Location')}

+
+
+
+
+ %if allow_repo_location_change: + ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")} + +
+
+ %else: + ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')} + ## form still requires this but we cannot internally change it anyway + ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")} + %endif +
+
+
+ ${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')} +
+
+
+ % endif + + % if display_globals or repo_type in ['git', 'hg']: +
+
+

${_('Internal Hooks')}

+
+
+
+
+ ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)} + +
+ +
+ ${_('Trigger a hook that calculates repository size after each push.')} +
+
+ ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)} + +
+
+ ${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')} +
+
+ ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)} + +
+
+ ${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')} +
+
+
+
+ % endif + + % if display_globals or repo_type in ['hg']: +
+
+

${_('Mercurial Settings')}

+
+
+
+ ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)} + +
+
+ ${_('Enable Largefiles extensions for all repositories.')} +
+
+ ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)} + +
+
+ ${_('When this is enabled all commits in the repository are seen as public commits by clients.')} +
+ % if display_globals: +
+ ${h.checkbox('extensions_hgsubversion' + suffix,'True')} + +
+
+ ${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')} +
+ % endif +
+
+ % endif + + % if display_globals or repo_type in ['svn']: +
+
+

${_('Subversion Settings')}

+
+
+
+
+
+
+
+
+ ${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')} +
+ +
+
+
+
+ % if svn_branch_patterns: + % for branch in svn_branch_patterns: +
+ ${h.hidden('branch_ui_key' + suffix, branch.ui_key)} + ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')} + % if kwargs.get('disabled') != 'disabled': + + ${_('Delete')} + + % endif +
+ % endfor + %endif +
+ % if kwargs.get('disabled') != 'disabled': +
+
+ ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')} +
+
+ % endif +
+
+
+
+ % if svn_tag_patterns: + % for tag in svn_tag_patterns: +
+ ${h.hidden('tag_ui_key' + suffix, tag.ui_key)} + ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')} + % if kwargs.get('disabled') != 'disabled': + + ${_('Delete')} + + %endif +
+ % endfor + % endif +
+ % if kwargs.get('disabled') != 'disabled': +
+
+ ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')} +
+
+ %endif +
+
+ % else: + ${h.hidden('new_svn_branch' + suffix, '')} + ${h.hidden('new_svn_tag' + suffix, '')} + % endif + + % if display_globals or repo_type in ['hg', 'git']: +
+
+

${_('Pull Request Settings')}

+
+
+
+ ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)} + +
+
+ ${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')} +
+
+ ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)} + +
+
+ ${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')} +
+
+
+ % endif + diff --git a/rhodecode/templates/bookmarks/bookmarks.html b/rhodecode/templates/bookmarks/bookmarks.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/bookmarks/bookmarks.html @@ -0,0 +1,103 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Bookmarks') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + + 0 ${_('bookmarks')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + %if c.has_references: + + %endif + %if c.has_references: + ${self.breadcrumbs()} + %endif +
+
+
+ + + + diff --git a/rhodecode/templates/bookmarks/bookmarks_data.html b/rhodecode/templates/bookmarks/bookmarks_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/bookmarks/bookmarks_data.html @@ -0,0 +1,33 @@ +## DATA TABLE RE USABLE ELEMENTS FOR BOOKMARKS +## usage: +## <%namespace name="bookmarks" file="/bookmarks/bookmarks_data.html"/> +## bookmarks.(arg,arg2) + +<%def name="compare(commit_id)"> + + + + + +<%def name="name(name, files_url)"> + + + + ${name} + + + + +<%def name="date(date)"> + ${h.age_component(date)} + + +<%def name="author(author)"> + ${h.link_to_user(author)} + + +<%def name="commit(message, commit_id, commit_idx)"> + + diff --git a/rhodecode/templates/branches/branches.html b/rhodecode/templates/branches/branches.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/branches/branches.html @@ -0,0 +1,102 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Branches') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + + 0 ${_('branches')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + %if c.has_references: + + %endif + %if c.has_references: + ${self.breadcrumbs()} + %endif +
+
+
+ + + diff --git a/rhodecode/templates/branches/branches_data.html b/rhodecode/templates/branches/branches_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/branches/branches_data.html @@ -0,0 +1,33 @@ +## DATA TABLE RE USABLE ELEMENTS FOR BRANCHES +## usage: +## <%namespace name="branch" file="/branches/branches_data.html"/> +## branch.(arg,arg2) + +<%def name="compare(commit_id)"> + + + + +<%def name="name(name, files_url)"> + + ${name} + %if name in c.closed_branches: + [closed] + %endif + + + + +<%def name="date(date)"> + ${h.age_component(date)} + + +<%def name="author(author)"> + ${h.link_to_user(author)} + + +<%def name="commit(message, commit_id, commit_idx)"> + + diff --git a/rhodecode/templates/changelog/changelog.html b/rhodecode/templates/changelog/changelog.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changelog/changelog.html @@ -0,0 +1,415 @@ +## -*- coding: utf-8 -*- + +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Changelog') % c.repo_name} + %if c.changelog_for_path: + /${c.changelog_for_path} + %endif + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + %if c.changelog_for_path: + /${c.changelog_for_path} + %endif + ${ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='changelog')} + + +<%def name="main()"> + +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + +
+ + % if c.pagination: + +
+
+ ${h.hidden('branch_filter')} + %if c.selected_name: +
+ ${_('Clear filter')} +
+ %endif +
+ ${self.breadcrumbs('breadcrumbs_light')} +
+ +
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + %for cnt,commit in enumerate(c.pagination): + + + + + + + + + + + + + + + + + %endfor + +
${_('Author')}${_('Age')}${_('Commit Message')}${_('Commit')}${_('Refs')}
+ ${h.checkbox(commit.raw_id,class_="commit-range")} + + + %if c.statuses.get(commit.raw_id): +
+ %if c.statuses.get(commit.raw_id)[2]: + +
+
+ %else: + +
+
+ %endif +
+ %endif +
+ ${self.gravatar(h.email_or_none(commit.author))} + ${h.link_to_user(commit.author, length=22)} + + ${h.age_component(commit.date)} + +
+   +
+
+
+
${h.urlify_commit_message(commit.message, c.repo_name)}
+
+
+ + + ${h.show_id(commit)} + + + + %if c.comments.get(commit.raw_id): + + ${len(c.comments[commit.raw_id])} + + %endif + +
+ ## branch + %if commit.branch: + + ${h.shorter(commit.branch)} + + %endif + + ## bookmarks + %if h.is_hg(c.rhodecode_repo): + %for book in commit.bookmarks: + + ${h.shorter(book)} + + %endfor + %endif + + ## tags + %for tag in commit.tags: + + ${h.shorter(tag)} + + %endfor + +
+
+
+
+
+
+ ${c.pagination.pager('$link_previous ~2~ $link_next')} +
+ + + + %else: + ${_('There are no changes yet')} + %endif +
+
+ diff --git a/rhodecode/templates/changelog/changelog_details.html b/rhodecode/templates/changelog/changelog_details.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changelog/changelog_details.html @@ -0,0 +1,11 @@ +## small box that displays changed/added/removed details fetched by AJAX + +% if len(c.commit.affected_files) <= c.affected_files_cut_off: +${len(c.commit.removed)} +${len(c.commit.changed)} +${len(c.commit.added)} +% else: + ! + ! + ! +% endif diff --git a/rhodecode/templates/changelog/changelog_file_history.html b/rhodecode/templates/changelog/changelog_file_history.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changelog/changelog_file_history.html @@ -0,0 +1,45 @@ +<%namespace name="base" file="/base/base.html"/> +
+ + + %for cnt,cs in enumerate(c.pagination): + + + + + + + + %endfor +
+ ${base.gravatar_with_user(cs.author, 16)} + +
+ ${h.age_component(cs.date)} +
+
+
+ + %if cs.merge: + + ${_('merge')} + + %endif + +
+
+ + + ${h.show_id(cs)} + + + + + ${_('Show File')} + +
+
diff --git a/rhodecode/templates/changelog/changelog_summary_data.html b/rhodecode/templates/changelog/changelog_summary_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changelog/changelog_summary_data.html @@ -0,0 +1,127 @@ +## -*- coding: utf-8 -*- +<%namespace name="base" file="/base/base.html"/> +%if c.repo_commits: + + + + + + + + + +%for cnt,cs in enumerate(c.repo_commits): + + + + + + + + + + +%endfor + +
${_('Commit')}${_('Commit message')}${_('Age')}${_('Author')}${_('Refs')}
+
${h.show_id(cs)}
+
+ %if c.statuses.get(cs.raw_id): +
+ %if c.statuses.get(cs.raw_id)[2]: + +
+
+ %else: +
+ %endif +
+ %endif +
+ %if c.comments.get(cs.raw_id,[]): + + ${len(c.comments[cs.raw_id])} + + %endif + + ${h.urlify_commit_message(h.truncate(cs.message, 50), c.repo_name)} + + ${h.age_component(cs.date)} + + ${base.gravatar(h.email_or_none(cs.author), 16)} + ${h.link_to_user(cs.author, length=22)} + +
+ %if h.is_hg(c.rhodecode_repo): + %for book in cs.bookmarks: + + ${h.shorter(book)} + + %endfor + %endif + ## tags + %for tag in cs.tags: + + ${h.shorter(tag)} + + %endfor + + ## branch + %if cs.branch: + + ${h.shorter(cs.branch)} + + %endif +
+
+ + + +
+${c.repo_commits.pager('$link_previous ~2~ $link_next')} +
+%else: + +%if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): +
+
+
${_('Add or upload files directly via RhodeCode:')}
+ + %endif +
+ + %if not h.is_svn(c.rhodecode_repo): +
+
${_('Push new repo:')}
+
+
+${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
+${c.rhodecode_repo.alias} add README # add first file
+${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
+${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
+      
+
+
+
+
${_('Existing repository?')}
+
+
+      %if h.is_git(c.rhodecode_repo):
+git remote add origin ${c.clone_repo_url}
+git push -u origin master
+      %else:
+hg push ${c.clone_repo_url}
+      %endif
+      
+
+
+ %endif +
+%endif diff --git a/rhodecode/templates/changeset/changeset.html b/rhodecode/templates/changeset/changeset.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/changeset.html @@ -0,0 +1,395 @@ +## -*- coding: utf-8 -*- + +<%inherit file="/base/base.html"/> +<%namespace name="diff_block" file="/changeset/diff_block.html"/> + +<%def name="title()"> + ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='changelog')} + + +<%def name="main()"> + +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+ +
+
+
+ +

${_('Commit')} + + ${h.show_id(c.commit)} + +

+
+ + ${_('Parent')} + + | + + ${_('Child')} + +
+ +
+
+ ${_('Description')}: +
+
+
${h.urlify_commit_message(c.commit.message,c.repo_name)}
+ +
+
+ + %if c.statuses: +
+
+ ${_('Commit status')}: +
+
+
+
+
+
[${h.commit_status_lbl(c.statuses[0])}]
+
+
+ %endif + +
+
+ ${_('References')}: +
+
+
+ + %if c.commit.merge: + + ${_('merge')} + + %endif + + %if h.is_hg(c.rhodecode_repo): + %for book in c.commit.bookmarks: + + ${h.shorter(book)} + + %endfor + %endif + + %for tag in c.commit.tags: + + ${tag} + + %endfor + + %if c.commit.branch: + + ${h.shorter(c.commit.branch)} + + %endif +
+
+
+ +
+
+ ${_('Diffs')}: +
+
+
+ + ${_('Raw Diff')} + + | + + ${_('Patch Diff')} + + | + + ${_('Download Diff')} + + | + ${c.ignorews_url(request.GET)} + | + ${c.context_url(request.GET)} +
+
+
+ +
+
+ ${_('Comments')}: +
+
+
+ %if c.comments: + ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}, + %else: + ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)} + %endif + %if c.inline_cnt: + ## this is replaced with a proper link to first comment via JS linkifyComments() func + ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} + %else: + ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} + %endif +
+
+
+ +
+ + +
+
+ + ${_('Browse files')} | + + ${_('Expand All')} | ${_('Collapse All')} + +

+ ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} +

+
+
+ +
+ + %if not c.files: +

${_('No files')}

+ %endif + + + %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[c.commit.raw_id].iteritems(): + + + + + + + + + + + + + + + + + + %endfor +
+ + + + + + +
${h.fancy_file_stats(stats)}
+
+ +
+
+
+
+
+
+ ${diff|n} + % if file and file["is_limited_diff"]: + % if file["exceeds_limit"]: + ${diff_block.file_message()} + % else: +
${_('Diff was truncated. File content available only in full diff.')} ${_('Show full diff')}
+ % endif + % endif +
+
+
+
+
+ + % if c.limited_diff: + ${diff_block.changeset_message()} + % endif + + ## template for inline comment form + <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> + ${comment.comment_inline_form()} + + ## render comments and inlines + ${comment.generate_comments()} + + ## main comment form and it status + ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id), + h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))} + + ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS + + + diff --git a/rhodecode/templates/changeset/changeset_comment_block.html b/rhodecode/templates/changeset/changeset_comment_block.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/changeset_comment_block.html @@ -0,0 +1,4 @@ +## this is a dummy html file for partial rendering on server and sending +## generated output via ajax after comment submit +<%namespace name="comment" file="/changeset/changeset_file_comment.html"/> +${comment.comment_block(c.co, inline=True)} diff --git a/rhodecode/templates/changeset/changeset_file_comment.html b/rhodecode/templates/changeset/changeset_file_comment.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/changeset_file_comment.html @@ -0,0 +1,312 @@ +## -*- coding: utf-8 -*- +## usage: +## <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> +## ${comment.comment_block(comment)} +## +<%namespace name="base" file="/base/base.html"/> + +<%def name="comment_block(comment, inline=False)"> +
+
+
+ ${base.gravatar_with_user(comment.author.email, 16)} +
+
+ ${h.age_component(comment.modified_at)} +
+
+ %if comment.pull_request: + + %if comment.status_change: + ${_('Vote on pull request #%s') % comment.pull_request.pull_request_id}: + %else: + ${_('Comment on pull request #%s') % comment.pull_request.pull_request_id} + %endif + + %else: + %if comment.status_change: + ${_('Status change on commit')}: + %else: + ${_('Comment on commit')} + %endif + %endif +
+ %if comment.status_change: +
+
+ ${comment.status_change[0].status_lbl} +
+ %endif + + + + +
+
+ ${comment.render(mentions=True)|n} +
+
+ + +<%def name="comment_block_outdated(comment)"> +
+
+
+
+ ${base.gravatar_with_user(comment.author.email, 16)} +
+
+ ${h.age_component(comment.modified_at)} +
+ %if comment.status_change: + + +
+
+ ${comment.status_change[0].status_lbl} +
+ %endif + + ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed + ## only super-admin, repo admin OR comment owner can delete + %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): + + %endif +
+
+ ${comment.render(mentions=True)|n} +
+
+
+ + +<%def name="comment_inline_form()"> + + + + +## generates inlines taken from c.comments var +<%def name="inlines(is_pull_request=False)"> + %if is_pull_request: +

${ungettext("%d Pull Request Comment", "%d Pull Request Comments", len(c.comments)) % len(c.comments)}

+ %else: +

${ungettext("%d Commit Comment", "%d Commit Comments", len(c.comments)) % len(c.comments)}

+ %endif + %for path, lines_comments in c.inline_comments: + % for line, comments in lines_comments.iteritems(): + + %endfor + %endfor + + + +## generate inline comments and the main ones +<%def name="generate_comments(include_pull_request=False, is_pull_request=False)"> + ## generate inlines for this changeset + ${inlines(is_pull_request)} + + %for comment in c.comments: +
+ ## only render comments that are not from pull request, or from + ## pull request and a status change + %if not comment.pull_request or (comment.pull_request and comment.status_change) or include_pull_request: + ${comment_block(comment)} + %endif +
+ %endfor + ## to anchor ajax comments +
+ + +## MAIN COMMENT FORM +<%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> +%if is_compare: + <% form_id = "comments_form_compare" %> +%else: + <% form_id = "comments_form" %> +%endif + + +%if is_pull_request: +
+ %if c.allowed_to_merge: +
+
+ ${h.secure_form(url('pullrequest_merge', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id), id='merge_pull_request_form')} + ${c.pr_merge_msg} ${c.approval_msg if c.approval_msg else ''} + <% merge_disabled = ' disabled' if c.pr_merge_status is False else '' %> + + ${h.end_form()} +
+
+ %else: +
+
+ ${c.pr_merge_msg} ${c.approval_msg if c.approval_msg else ''} +
+
+ %endif +
+%endif +
+ %if c.rhodecode_user.username != h.DEFAULT_USER: +
+ ${h.secure_form(post_url, id_=form_id)} +
+
+ %if is_pull_request: + ${(_('Create a comment on this Pull Request.'))} + %elif is_compare: + ${(_('Create comments on this Commit range.'))} + %else: + ${(_('Create a comment on this Commit.'))} + %endif +
+
+ ${(_('Comments parsed using %s syntax with %s support.') % ( + ('%s' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())), + ('@mention' % _('Use @username inside this text to send notification to this RhodeCode user')) + ) + )|n + } +
+
+ ${h.textarea('text', class_="comment-block-ta")} +
+ + + +
+ %if form_extras and isinstance(form_extras, (list, tuple)): + % for form_ex_el in form_extras: + ${form_ex_el|n} + % endfor + %endif +
+ + ${h.end_form()} +
+ %endif +
+ + diff --git a/rhodecode/templates/changeset/changeset_range.html b/rhodecode/templates/changeset/changeset_range.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/changeset_range.html @@ -0,0 +1,126 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Commits') % c.repo_name} - + r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} + ... + r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} + ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Commits')} - + r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} + ... + r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} + ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='changelog')} + + +<%def name="main()"> +
+
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+
+ +
+ +
+
+

+ ${self.breadcrumbs_links()} +

+
+ +
+ ##CS + <%include file="../compare/compare_commits.html"/> + ## FILES +
+ + ${_('Expand All')} | ${_('Collapse All')} + +

+ ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} +

+
+
+
+ +
+ + <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> + <%namespace name="diff_block" file="/changeset/diff_block.html"/> + %for cs in c.commit_ranges: + + + + %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[cs.raw_id].iteritems(): + + + + + + + + + + + + + + + + + + %endfor + %endfor +
+ ${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))} | + ${h.age_component(cs.date)} +
+ + + + + + +
${h.fancy_file_stats(stats)}
+
+
+
+
+ ${diff|n} +
+
+
+
+
+## end summary detail + + \ No newline at end of file diff --git a/rhodecode/templates/changeset/diff_block.html b/rhodecode/templates/changeset/diff_block.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/diff_block.html @@ -0,0 +1,103 @@ +## -*- coding: utf-8 -*- +##usage: +## <%namespace name="diff_block" file="/changeset/diff_block.html"/> +## ${diff_block.diff_block_changeset_table(change)} +## +<%def name="changeset_message()"> +
${_('The requested commit is too big and content was truncated.')} ${_('Show full diff')}
+ +<%def name="file_message()"> +
${_('The requested file is too big and its content is not shown.')} ${_('Show full diff')}
+ + +<%def name="diff_block_changeset_table(change)"> +
+ %for FID,(cs1, cs2, change, filenode_path, diff, stats, file) in change.iteritems(): +
+
+
+ + ${diff|n} + % if file["is_limited_diff"]: + % if file["exceeds_limit"]: + ${self.file_message()} + % else: +
${_('Diff was truncated. File content available only in full diff.')} ${_('Show full diff')}
+ % endif + % endif +
+
+ %endfor +
+ + +<%def name="diff_block_simple(change)"> +
+ %for op,filenode_path,diff,file in change: +
+
+
+ + ${diff|n} + % if file["is_limited_diff"]: + % if file["exceeds_limit"]: + ${self.file_message()} + % else: +
${_('Diff was truncated. File content available only in full diff.')} ${_('Show full diff')}
+ % endif + % endif +
+
+ %endfor +
+ + +<%def name="diff_menu(repo_name, f_path, cs1, cs2, change, file=None)"> + <% + onclick_diff2way = '' + if (file and file["exceeds_limit"]): + onclick_diff2way = '''return confirm('%s');''' % _("Showing a big diff might take some time and resources, continue?") + %> + + % if change in ['A', 'M']: + + ${_('Show File')} + + % else: + + ${_('Show File')} + + % endif + | + + ${_('Unified Diff')} + + | + + ${_('Side-by-side Diff')} + + | + + ${_('Raw Diff')} + + | + + ${_('Download Diff')} + + + +<%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)"> + % if limited_diff: + ${ungettext('%(num)s file changed', '%(num)s files changed', changed_files) % {'num': changed_files}} + % else: + ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', + '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', changed_files) % {'num': changed_files, 'linesadd': lines_added, 'linesdel': lines_deleted}} + %endif + + diff --git a/rhodecode/templates/changeset/patch_changeset.html b/rhodecode/templates/changeset/patch_changeset.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/patch_changeset.html @@ -0,0 +1,25 @@ +%if h.is_hg(c.rhodecode_repo): +# ${c.rhodecode_repo.alias.upper()} changeset patch +# User ${c.commit.author |n} +# Date ${c.commit.date} +# Node ID ${c.commit.raw_id} +${c.parent_tmpl} +${c.commit.message |n} + +%elif h.is_git(c.rhodecode_repo): +From ${c.commit.raw_id} ${c.commit.date} +From: ${c.commit.author |n} +Date: ${c.commit.date} +Subject: [PATCH] ${c.commit.message |n} +--- + +%elif h.is_svn(c.rhodecode_repo): +# ${c.rhodecode_repo.alias.upper()} changeset patch +# User ${c.commit.author |n} +# Date ${c.commit.date} +# Revision ${c.commit.raw_id} + +${c.commit.message |n} + +%endif +${c.diff|n} \ No newline at end of file diff --git a/rhodecode/templates/compare/compare_commits.html b/rhodecode/templates/compare/compare_commits.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/compare/compare_commits.html @@ -0,0 +1,102 @@ +## Changesets table ! +<%namespace name="base" file="/base/base.html"/> +
+ %if not c.commit_ranges: +

${_('No Commits')}

+ %else: + + %if c.ancestor: +

${_('Common Ancestor Commit')}: + + ${h.short_id(c.ancestor)} + +

+ %endif + + + + + + + + + + %for commit in c.commit_ranges: + + + + + + + + %endfor +
${_('Time')}${_('Author')}${_('Commit')}${_('Description')}
+ ${h.age_component(commit.date)} + + ${base.gravatar_with_user(commit.author, 16)} + + + + r${commit.revision}:${h.short_id(commit.raw_id)} + + ${h.hidden('revisions',commit.raw_id)} + + +
+ +
+
+
+
+ ${h.urlify_commit_message(commit.message, c.repo_name)} +
+
+
+ %endif +
+ + diff --git a/rhodecode/templates/compare/compare_diff.html b/rhodecode/templates/compare/compare_diff.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/compare/compare_diff.html @@ -0,0 +1,322 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + %if c.compare_home: + ${_('%s Compare') % c.repo_name} + %else: + ${_('%s Compare') % c.repo_name} - ${'%s@%s' % (c.source_repo.repo_name, c.source_ref)} > ${'%s@%s' % (c.target_repo.repo_name, c.target_ref)} + %endif + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${ungettext('%s commit','%s commits', len(c.commit_ranges)) % len(c.commit_ranges)} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='compare')} + + +<%def name="main()"> + + +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + +
+ +
+
+
+
+ ## The hidden elements are replaced with a select2 widget +
${_('Target')}
${h.hidden('compare_source')} +
${_('Source')}
${h.hidden('compare_target')} + + %if not c.preview_mode: +
+
+ %if not c.compare_home: + ${_('Swap')} + %endif +
${_('Compare Commits')}
+ %if c.files: +
${_('Comment')}
+ %endif +
+ %endif +
+
+
+ ## use JS script to load it quickly before potentially large diffs render long time + ## this prevents from situation when large diffs block rendering of select2 fields + + + ## changeset status form + <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> + ## main comment form and it status + <% + def revs(_revs): + form_inputs = [] + for cs in _revs: + tmpl = '' % {'cid': cs.raw_id} + form_inputs.append(tmpl) + return form_inputs + %> + + + %if c.compare_home: +
+
${_('Compare commits, branches, bookmarks or tags.')}
+
+ %else: +
+ ##CS + <%include file="compare_commits.html"/> + + ## FILES +
+ + ${_('Expand All')} | ${_('Collapse All')} + +

+ ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} +

+
+
+ %if not c.files: +

${_('No files')}

+ %endif + + <%namespace name="diff_block" file="/changeset/diff_block.html"/> + %for FID, change, path, stats, file in c.files: + + + + + + + + + + + + + + + + + + %endfor +
+ + + + + + +
${h.fancy_file_stats(stats)}
+
+ +
+
+ ${diff_block.diff_block_simple([c.changes[FID]])} +
+ % if c.limited_diff: + ${diff_block.changeset_message()} + % endif +
+ %endif +
+
+
+ diff --git a/rhodecode/templates/data_table/_dt_elements.html b/rhodecode/templates/data_table/_dt_elements.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/data_table/_dt_elements.html @@ -0,0 +1,297 @@ +## DATA TABLE RE USABLE ELEMENTS +## usage: +## <%namespace name="dt" file="/data_table/_dt_elements.html"/> +<%namespace name="base" file="/base/base.html"/> + +## REPOSITORY RENDERERS +<%def name="quick_menu(repo_name)"> + + + + +<%def name="repo_name(name,rtype,rstate,private,fork_of,short_name=False,admin=False)"> + <% + def get_name(name,short_name=short_name): + if short_name: + return name.split('/')[-1] + else: + return name + %> + + + +<%def name="last_change(last_change)"> + ${h.age_component(last_change)} + + +<%def name="revision(name,rev,tip,author,last_msg)"> +
+ %if rev >= 0: + ${'r%s:%s' % (rev,h.short_id(tip))} + %else: + ${_('No commits yet')} + %endif +
+ + +<%def name="rss(name)"> + %if c.rhodecode_user.username != h.DEFAULT_USER: + + %else: + + %endif + + +<%def name="atom(name)"> + %if c.rhodecode_user.username != h.DEFAULT_USER: + + %else: + + %endif + + +<%def name="user_gravatar(email, size=16)"> + ${base.gravatar(email, 16)} + + +<%def name="repo_actions(repo_name, super_user=True)"> +
+
+ + Edit +
+
+ ${h.secure_form(h.url('repo', repo_name=repo_name),method='delete')} + ${h.submit('remove_%s' % repo_name,_('Delete'),class_="btn btn-link btn-danger", + onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")} + ${h.end_form()} +
+
+ + +<%def name="repo_state(repo_state)"> +
+ %if repo_state == 'repo_state_pending': +
${_('Creating')}
+ %elif repo_state == 'repo_state_created': +
${_('Created')}
+ %else: +
invalid
+ %endif +
+ + + +## REPO GROUP RENDERERS +<%def name="quick_repo_group_menu(repo_group_name)"> + + + + +<%def name="repo_group_name(repo_group_name, children_groups=None)"> + + + +<%def name="repo_group_actions(repo_group_id, repo_group_name, gr_count)"> +
+ Edit +
+
+ ${h.secure_form(h.url('delete_repo_group', group_name=repo_group_name),method='delete')} + ${h.submit('remove_%s' % repo_group_name,_('Delete'),class_="btn btn-link btn-danger", + onclick="return confirm('"+ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_count) % (repo_group_name, gr_count)+"');")} + ${h.end_form()} +
+ + + +<%def name="user_actions(user_id, username)"> +
+ + Edit +
+
+ ${h.secure_form(h.url('delete_user', user_id=user_id),method='delete')} + ${h.submit('remove_',_('Delete'),id="remove_user_%s" % user_id, class_="btn btn-link btn-danger", + onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")} + ${h.end_form()} +
+ + +<%def name="user_group_actions(user_group_id, user_group_name)"> +
+ Edit +
+
+ ${h.secure_form(h.url('delete_users_group', user_group_id=user_group_id),method='delete')} + ${h.submit('remove_',_('Delete'),id="remove_group_%s" % user_group_id, class_="btn btn-link btn-danger", + onclick="return confirm('"+_('Confirm to delete this user group: %s') % user_group_name+"');")} + ${h.end_form()} +
+ + + +<%def name="user_name(user_id, username)"> + ${h.link_to(h.person(username, 'username_or_name_or_email'), h.url('edit_user', user_id=user_id))} + + +<%def name="user_profile(username)"> + ${base.gravatar_with_user(username, 16)} + + +<%def name="user_group_name(user_group_id, user_group_name)"> + + + + +## GISTS + +<%def name="gist_gravatar(full_contact)"> +
+ ${base.gravatar(full_contact, 30)} +
+ + +<%def name="gist_access_id(gist_access_id, full_contact)"> + + + +<%def name="gist_author(full_contact, created_on, expires)"> + ${base.gravatar_with_user(full_contact, 16)} + + + +<%def name="gist_created(created_on)"> +
+ ${h.age_component(created_on)} +
+ + +<%def name="gist_expires(expires)"> +
+ %if expires == -1: + ${_('never')} + %else: + ${h.age_component(h.time_to_datetime(expires))} + %endif +
+ + +<%def name="gist_type(gist_type)"> + %if gist_type != 'public': +
${_('Private')}
+ %endif + + +<%def name="gist_description(gist_description)"> + ${gist_description} + + + +## PULL REQUESTS GRID RENDERERS +<%def name="pullrequest_status(status)"> +
+ + +<%def name="pullrequest_title(title, description)"> + ${title}
+ ${h.shorter(description, 40)} + + +<%def name="pullrequest_comments(comments_nr)"> + ${comments_nr} + + +<%def name="pullrequest_name(pull_request_id, target_repo_name)"> + + ${_('Pull request #%(pr_number)s') % {'pr_number': pull_request_id,}} + + + +<%def name="pullrequest_updated_on(updated_on)"> + ${h.age_component(h.time_to_datetime(updated_on))} + + +<%def name="pullrequest_author(full_contact)"> + ${base.gravatar_with_user(full_contact, 16)} + diff --git a/rhodecode/templates/debug_style/buttons.html b/rhodecode/templates/debug_style/buttons.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/buttons.html @@ -0,0 +1,197 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/code-block.html b/rhodecode/templates/debug_style/code-block.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/code-block.html @@ -0,0 +1,1162 @@ +## -*- coding: utf-8 -*- +<%namespace name="base" file="/base/base.html"/> +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + +<%def name="js_extra()"> + + + +<%def name="css_extra()"> + + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + ##main + +
+ diff --git a/rhodecode/templates/debug_style/collapsable-content.html b/rhodecode/templates/debug_style/collapsable-content.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/collapsable-content.html @@ -0,0 +1,967 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ + +
+ +
+ +
+
+

+ Diff: enable filename with spaces on diffs +

+

+ + + + rhodecode-momentum + +

+
+ +
+
+ +
+ + Pull request #720 From Tue, 17 Feb 2015 16:21:38 +
Show More
+
+
+ +
+
+ +
+
+
+ + Under Review + + +
+
+
+
+ +
+
+
Fixing issue # 574, changing regex for capturing filenames
+
+
+
+
+ +
+
+
+
+ 0 Pull request comments, + 0 Inline Comments +
+
+
+
+
+
+
+
+
+ Author +
+
+
+ +
+
+
+ Pull request reviewers + Show More +
+ +
+
+ + + +
+
+
+
+
+
+
+
+

Compare View: 6 commitsShow More

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeAuthorCommitTitle
+ 2015-02-18 10:13:34 + +
+ gravatar + brian (Brian Butler) +
+
+ + r395:7e83e5cd7812 + + +
+ +
+
+
+
rep: added how we doc to guide
+
+
+ 2015-02-18 09:18:31 + +
+ gravatar + brian (Brian Butler) +
+
+ + r394:48ce1581bdb3 + + +
+ +
+
+
+
repo 0004 - typo
+
+
+ 2015-02-18 09:14:45 + + + gravatar + + brian (Brian Butler) + + + r393:982d857aafb4 + + +
+ +
+
+
+
internals: how to doc section added
+
+
+ 2015-02-17 17:20:44 + + + gravatar + + brian (Brian Butler) + + + r392:4c7258ad1af6 + + +
+ +
+
+
+
REP: 0004 Documentation standards
+
+
+ 2015-02-17 16:18:49 + + + gravatar + + anderson (Anderson Santos) + + + r8743:46b3d50315f0 + + +
+ +
+
+
+
Diff: created tests for the diff with filenames with spaces
+ +
+
+ 2015-02-16 10:06:08 + + + gravatar + + anderson (Anderson Santos) + + + r8742:1e57d2549bd6 + + +
+ +
+
+
+
Diff: fix renaming files with spaces #574
+ +
+
+
+ + +
+ + Expand All | Collapse All + +

+ 7 files changed: 55 inserted, 9 deleted +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + rhodecode/tests/fixtures/git_diff_rename_file_with_spaces.diff + + + +
4
+
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
new file 100644
+
1 +
diff --git a/file_with_ spaces.txt b/file_with_  two spaces.txt
+
+
2 +
similarity index 100%
+
+
3 +
rename from file_with_ spaces.txt
+
+
4 +
rename to file_with_  two spaces.txt
+
+
...... +
 No newline at end of file
+
+
+
+
+ +
+ + + + + + rhodecode/tests/fixtures/hg_diff_copy_file_with_spaces.diff + + + +
3
+
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
new file 100644
+
1 +
diff --git a/file_changed_without_spaces.txt b/file_copied_ with  spaces.txt
+
+
2 +
copy from file_changed_without_spaces.txt
+
+
3 +
copy to file_copied_ with  spaces.txt
+
+
...... +
 No newline at end of file
+
+
+
+
+ +
+ + + + + + rhodecode/tests/fixtures/hg_diff_rename_file_with_spaces.diff + + + +
3
+
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
new file 100644
+
1 +
diff --git a/file_ with update.txt b/file_changed _.txt
+
+
2 +
rename from file_ with update.txt
+
+
3 +
rename to file_changed _.txt
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+ + + + + + + + +
+
+ +

0 Pull Request Comments

+ + +
+ +
+ + + + +
+
+
+
+
+
+
+
+ Create a comment on this Pull Request. +
+
+ Comments parsed using RST syntax with @mention support. +
+
+ +
+ + + +
+
+
+
+ Preview +
+ +
+ +
+
+
+
+
+ + + + + + + + + + + + diff --git a/rhodecode/templates/debug_style/form-elements-small.html b/rhodecode/templates/debug_style/form-elements-small.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/form-elements-small.html @@ -0,0 +1,295 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/form-elements.html b/rhodecode/templates/debug_style/form-elements.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/form-elements.html @@ -0,0 +1,631 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/form-inline.html b/rhodecode/templates/debug_style/form-inline.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/form-inline.html @@ -0,0 +1,174 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + + diff --git a/rhodecode/templates/debug_style/form-vertical.html b/rhodecode/templates/debug_style/form-vertical.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/form-vertical.html @@ -0,0 +1,144 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + ##main + +
+ diff --git a/rhodecode/templates/debug_style/forms.html b/rhodecode/templates/debug_style/forms.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/forms.html @@ -0,0 +1,279 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/icons.html b/rhodecode/templates/debug_style/icons.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/icons.html @@ -0,0 +1,96 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ \ No newline at end of file diff --git a/rhodecode/templates/debug_style/index.html b/rhodecode/templates/debug_style/index.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/index.html @@ -0,0 +1,78 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Debug Style')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Style')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='debug_style')} + + + +<%def name="main()"> +
+ ${self.real_main()} +
+ + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ + + +<%def name="sidebar()"> + + \ No newline at end of file diff --git a/rhodecode/templates/debug_style/labels.html b/rhodecode/templates/debug_style/labels.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/labels.html @@ -0,0 +1,84 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/layout-form-sidebar.html b/rhodecode/templates/debug_style/layout-form-sidebar.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/layout-form-sidebar.html @@ -0,0 +1,106 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/login.html b/rhodecode/templates/debug_style/login.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/login.html @@ -0,0 +1,74 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + ##main + +
+ + diff --git a/rhodecode/templates/debug_style/login2.html b/rhodecode/templates/debug_style/login2.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/login2.html @@ -0,0 +1,9 @@ +## -*- coding: utf-8 -*- + +<% + # Tweaks needed to simulate things + c.came_from = "" +%> + +## Include the original file here for easy operation +<%include file="/login.html" /> diff --git a/rhodecode/templates/debug_style/panels.html b/rhodecode/templates/debug_style/panels.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/panels.html @@ -0,0 +1,152 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/tables-wide.html b/rhodecode/templates/debug_style/tables-wide.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/tables-wide.html @@ -0,0 +1,130 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + ##main + +
+ diff --git a/rhodecode/templates/debug_style/tables.html b/rhodecode/templates/debug_style/tables.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/tables.html @@ -0,0 +1,545 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+ + +
+ diff --git a/rhodecode/templates/debug_style/typography.html b/rhodecode/templates/debug_style/typography.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/debug_style/typography.html @@ -0,0 +1,507 @@ +## -*- coding: utf-8 -*- +<%inherit file="/debug_style/index.html"/> + +<%def name="breadcrumbs_links()"> + ${h.link_to(_('Style'), h.url('debug_style_home'))} + » + ${c.active} + + +<%def name="real_main()"> +
+
+ ${self.breadcrumbs()} +
+
+ +##main + + diff --git a/rhodecode/templates/email_templates/base.mako b/rhodecode/templates/email_templates/base.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/base.mako @@ -0,0 +1,17 @@ +## -*- coding: utf-8 -*- + +## headers we additionally can set for email +<%def name="headers()" filter="n,trim"> + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> + +${self.body()} + + +
+-- +
+
+${_('This is a notification from RhodeCode. %(instance_url)s') % {'instance_url': instance_url}} +
diff --git a/rhodecode/templates/email_templates/commit_comment.mako b/rhodecode/templates/email_templates/commit_comment.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/commit_comment.mako @@ -0,0 +1,57 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> + ${_('[mention]') if mention else ''} ${_('%(user)s commented on commit of %(repo_name)s') % { + 'user': h.person(user), + 'repo_name': repo_name + } } + + +<%def name="body_plaintext()" filter="n,trim"> +${self.subject()} + +* ${_('Comment link')}: ${commit_comment_url} + +* ${_('Commit')}: ${h.show_id(commit)} + +%if comment_file: +* ${_('File: %(comment_file)s on line %(comment_line)s') % {'comment_file': comment_file, 'comment_line': comment_line}} +%endif + +--- + +${comment_body|n} + + +%if status_change: + ${_('Commit status was changed to')}: *${status_change}* +%endif + + + + +% if comment_file: +

${_('%(user)s commented on a file in commit of %(repo_url)s.') % {'user': h.person(user), 'repo_url': commit_target_repo} |n}

+% else: +

${_('%(user)s commented on a commit of %(repo_url)s.') % {'user': h.person(user), 'repo_url': commit_target_repo} |n}

+% endif + +
    +
  • ${_('Comment link')}: ${commit_comment_url}
  • + %if comment_file: +
  • ${_('File: %(comment_file)s on line %(comment_line)s') % {'comment_file': comment_file, 'comment_line': comment_line}}
  • + %endif +
  • ${_('Commit')}: ${h.show_id(commit)}
  • +
  • + ${_('Commit Description')}:

    ${h.urlify_commit_message(commit.message, repo_name)}

    +
  • +
+ +
+

${h.render(comment_body, renderer=renderer_type, mentions=True)}

+
+ +%if status_change: +

${_('Commit status was changed to')}: ${status_change}

+%endif diff --git a/rhodecode/templates/email_templates/email_test.mako b/rhodecode/templates/email_templates/email_test.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/email_test.mako @@ -0,0 +1,13 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> +RhodeCode test email: ${h.format_date(date)} + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> +Test Email from RhodeCode version: ${rhodecode_version}, sent by: ${user} + + +${body_plaintext()} \ No newline at end of file diff --git a/rhodecode/templates/email_templates/main.mako b/rhodecode/templates/email_templates/main.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/main.mako @@ -0,0 +1,16 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> + + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> +${body} + + +## BODY GOES BELOW +
+${body_plaintext()} +
\ No newline at end of file diff --git a/rhodecode/templates/email_templates/password_reset.mako b/rhodecode/templates/email_templates/password_reset.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/password_reset.mako @@ -0,0 +1,24 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> +RhodeCode Password reset + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> +Hi ${user.username}, + +There was a request to reset your password using the email address ${email} on ${h.format_date(date)} + +*If you didn't do this, please contact your RhodeCode administrator.* + +You can continue, and generate new password by clicking following URL: +${password_reset_url} + + + +## BODY GOES BELOW +
+${body_plaintext()} +
\ No newline at end of file diff --git a/rhodecode/templates/email_templates/password_reset_confirmation.mako b/rhodecode/templates/email_templates/password_reset_confirmation.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/password_reset_confirmation.mako @@ -0,0 +1,22 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> +Your new RhodeCode password + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> +Hi ${user.username}, + +Below is your new access password for RhodeCode. + +password: ${new_password} + +*If you didn't request a new password, please contact your RhodeCode administrator immediately.* + + +## BODY GOES BELOW +
+${body_plaintext()} +
\ No newline at end of file diff --git a/rhodecode/templates/email_templates/pull_request_comment.mako b/rhodecode/templates/email_templates/pull_request_comment.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/pull_request_comment.mako @@ -0,0 +1,66 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> + ${_('[mention]') if mention else ''} ${_('%(user)s commented on pull request #%(pr_id)s: "%(pr_title)s"') % { + 'user': h.person(user), + 'pr_title': pull_request.title, + 'pr_id': pull_request.pull_request_id + } |n} + + +<%def name="body_plaintext()" filter="n,trim"> +${self.subject()} + +* ${_('Comment link')}: ${pr_comment_url} + +* ${_('Source repository')}: ${pr_source_repo_url} + +%if comment_file: +* ${_('File: %(comment_file)s on line %(comment_line)s') % {'comment_file': comment_file, 'comment_line': comment_line}} +%endif + +--- + +${comment_body|n} + + +%if status_change and not closing_pr: + ${_('Pull request status was changed to')}: *${status_change}* +%elif status_change and closing_pr: + ${_('Pull request was closed with status')}: *${status_change}* +%endif + + + +% if comment_file: +

${_('%(user)s commented on a file on pull request #%(pr_id)s: "%(pr_title)s".') % { + 'user': h.person(user), + 'pr_title': pull_request.title, + 'pr_id': pull_request.pull_request_id + } |n}

+% else: +

${_('%(user)s commented on a pull request #%(pr_id)s "%(pr_title)s".') % { + 'user': h.person(user), + 'pr_title': pull_request.title, + 'pr_id': pull_request.pull_request_id + } |n}

+% endif + +
    +
  • ${_('Comment link')}: ${pr_comment_url}
  • +
  • ${_('Source repository')}: ${pr_source_repo.repo_name}
  • + %if comment_file: +
  • ${_('File: %(comment_file)s on line %(comment_line)s') % {'comment_file': comment_file, 'comment_line': comment_line}}
  • + %endif +
+ +
+

${h.render(comment_body, renderer=renderer_type, mentions=True)}

+
+ +%if status_change and not closing_pr: +

${_('Pull request status was changed to')}: ${status_change}

+%elif status_change and closing_pr: +

${_('Pull request was closed with status')}: ${status_change}

+%endif diff --git a/rhodecode/templates/email_templates/pull_request_review.mako b/rhodecode/templates/email_templates/pull_request_review.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/pull_request_review.mako @@ -0,0 +1,81 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> + ${_('%(user)s wants you to review pull request #%(pr_url)s: "%(pr_title)s"') % { + 'user': h.person(user), + 'pr_title': pull_request.title, + 'pr_url': pull_request.pull_request_id + } |n} + + + +<%def name="body_plaintext()" filter="n,trim"> +${self.subject()} + + +${h.literal(_('Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s into %(target_ref_type)s:%(target_ref_name)s') % { + 'source_ref_type': pull_request.source_ref_parts.type, + 'source_ref_name': pull_request.source_ref_parts.name, + 'target_ref_type': pull_request.target_ref_parts.type, + 'target_ref_name': pull_request.target_ref_parts.name, + 'repo_url': pull_request_source_repo_url +})} + + +* ${_('Link')}: ${pull_request_url} + +* ${_('Title')}: ${pull_request.title} + +* ${_('Description')}: + + ${pull_request.description} + + +* ${ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits) ) % {'num': len(pull_request_commits)}}: + +% for commit_id, message in pull_request_commits: + - ${h.short_id(commit_id)} + + ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')} +% endfor + + + + +

+${_('%(user)s wants you to review pull request #%(pr_id)s: "%(pr_title)s".') % { + 'user': h.person(user), + 'pr_title': pull_request.title, + 'pr_id': pull_request.pull_request_id + } } +

+ +

${h.literal(_('Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s into %(target_ref_type)s:%(target_ref_name)s') % { + 'source_ref_type': pull_request.source_ref_parts.type, + 'source_ref_name': pull_request.source_ref_parts.name, + 'target_ref_type': pull_request.target_ref_parts.type, + 'target_ref_name': pull_request.target_ref_parts.name, + 'repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url) + })} +

+ +

${_('Link')}: ${h.link_to(pull_request_url, pull_request_url)}

+ +

${_('Title')}: ${pull_request.title}

+

+ ${_('Description')}:
+ ${pull_request.description} +

+ +

+ ${ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits) ) % {'num': len(pull_request_commits)}}: +

    + % for commit_id, message in pull_request_commits: +
  1. +
    ${h.short_id(commit_id)}
    + ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')} +
  2. + % endfor +
+

diff --git a/rhodecode/templates/email_templates/test.mako b/rhodecode/templates/email_templates/test.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/test.mako @@ -0,0 +1,21 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> +Test "Subject" ${_('hello "world"')|n} + + +<%def name="headers()" filter="n,trim"> +X=Y + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> +Email Plaintext Body + + +## BODY GOES BELOW +Email Body + +${h.short_id('0' * 40)} +${_('Translation')} \ No newline at end of file diff --git a/rhodecode/templates/email_templates/user_registration.mako b/rhodecode/templates/email_templates/user_registration.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/email_templates/user_registration.mako @@ -0,0 +1,21 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.mako"/> + +<%def name="subject()" filter="n,trim"> +RhodeCode new user registration + + +## plain text version of the email. Empty by default +<%def name="body_plaintext()" filter="n,trim"> + +A new user `${user.username}` has registered on ${h.format_date(date)} + +- Username: ${user.username} +- Full Name: ${user.firstname} ${user.lastname} +- Email: ${user.email} + + +## BODY GOES BELOW +
+${body_plaintext()} +
\ No newline at end of file diff --git a/rhodecode/templates/errors/error_document.html b/rhodecode/templates/errors/error_document.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/errors/error_document.html @@ -0,0 +1,64 @@ +## -*- coding: utf-8 -*- + + + + Error - ${c.error_message} + + + + + + + %if c.redirect_time: + + %endif + + + + + + + + + <%include file="/base/flash_msg.html"/> + +
+ +
+

+ + ${h.branding(c.rhodecode_name)} +
+ ${c.error_message} | ${c.error_explanation} +

+ %if c.redirect_time: +

${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}

+ %endif +
+

Possible Cause

+
    +
  • The resource may have been deleted.
  • +
  • You may not have access to this repository.
  • +
  • The link may be incorrect.
  • +
+
+
+

Support

+

For support, go to ${_('Support')}. + It may be useful to include your log file; see the log file locations here. +

+
+
+

Documentation

+

For more information, see docs.rhodecode.com.

+
+
+
+ + + + diff --git a/rhodecode/templates/feed/atom_feed_entry.mako b/rhodecode/templates/feed/atom_feed_entry.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/feed/atom_feed_entry.mako @@ -0,0 +1,34 @@ +## -*- coding: utf-8 -*- + +${_('%(user)s commited on %(date)s UTC') % { +'user': h.person(commit.author), +'date': h.format_date(commit.date) +}} +
+% if commit.branch: + branch: ${commit.branch}
+% endif + +% for bookmark in getattr(commit, 'bookmarks', []): + bookmark: ${bookmark}
+% endfor + +% for tag in commit.tags: + tag: ${tag}
+% endfor + +commit: ${h.show_id(commit)} +
+${h.urlify_commit_message(commit.message)}
+
+% for change in parsed_diff:
+  % if limited_diff:
+  ${_('Commit was too big and was cut off...')}
+  % endif
+  ${change['operation']} ${change['filename']} ${'(%(added)s lines added, %(removed)s lines removed)' % {'added': change['stats']['added'], 'removed': change['stats']['deleted']}}
+% endfor
+
+% if feed_include_diff:
+${diff_processor.as_raw()}
+% endif
+
diff --git a/rhodecode/templates/files/base.html b/rhodecode/templates/files/base.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/base.html @@ -0,0 +1,28 @@ +<%def name="refs(commit)"> + %if commit.merge: + + ${_('merge')} + + %endif + + %if h.is_hg(c.rhodecode_repo): + %for book in commit.bookmarks: + + ${h.shorter(book)} + + %endfor + %endif + + %for tag in commit.tags: + + ${tag} + + %endfor + + %if commit.branch: + + ${h.shorter(commit.branch)} + + %endif + + diff --git a/rhodecode/templates/files/diff_2way.html b/rhodecode/templates/files/diff_2way.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/diff_2way.html @@ -0,0 +1,225 @@ +## -*- coding: utf-8 -*- + +<%inherit file="/base/base.html"/> +<%namespace name="diff_block" file="/changeset/diff_block.html"/> + +<%def name="js_extra()"> + + + +<%def name="css_extra()"> + + + +<%def name="title()"> + ${_('%s File side-by-side diff') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + r${c.commit_1.revision}:${h.short_id(c.commit_1.raw_id)} ... r${c.commit_2.revision}:${h.short_id(c.commit_2.raw_id)} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='changelog')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+ + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + +
${h.fancy_file_stats(c.diff_data['stats'])}
+
+ +
+
+
+
+
+
+
+
+ ${_('mode')}: plain | +
+
+
+
+
+
+
+
+
+ + + + +
+ diff --git a/rhodecode/templates/files/file_authors_box.html b/rhodecode/templates/files/file_authors_box.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/file_authors_box.html @@ -0,0 +1,36 @@ +<%namespace name="base" file="/base/base.html"/> + +
+

+ % if c.file_author: + ${_('Last Author')} + % else: + ${h.literal(ungettext(u'File Author (%s)',u'File Authors (%s)',len(c.authors)) % ('%s' % len(c.authors))) } + % endif +

+ ${_('Show All')} +
+ +% if c.authors: +
    + % for email, user in sorted(c.authors, key=lambda e: c.file_last_commit.author_email!=e[0]): +
  • +
    + ${base.gravatar(email, 16)} + + ## case initial page load we only have last commit author + % if c.file_author: + ${h.link_to_user(user)} - ${h.age_component(c.file_last_commit.date)} + % else: + % if c.file_last_commit.author_email==email: + ${h.link_to_user(user)} (${_('last author')}) + % else: + ${h.link_to_user(user)} + % endif + % endif + +
    +
  • + % endfor +
+% endif diff --git a/rhodecode/templates/files/file_diff.html b/rhodecode/templates/files/file_diff.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/file_diff.html @@ -0,0 +1,159 @@ +<%inherit file="/base/base.html"/> +<%namespace name="diff_block" file="/changeset/diff_block.html"/> +<%def name="title()"> + ${_('%s File Diff') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Compare')} + r${c.commit_1.revision}:${h.short_id(c.commit_1.raw_id)} + % if c.filename1 != c.filename: + ${c.filename1} + % endif + ... + r${c.commit_2.revision}:${h.short_id(c.commit_2.raw_id)} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='changelog')} + + +<%def name="breadcrumbs_links()"> + ${_('Compare')} + r${c.commit_1.revision}:${h.short_id(c.commit_1.raw_id)} + % if c.filename1 != c.filename: + ${c.filename1} + % endif + ... + r${c.commit_2.revision}:${h.short_id(c.commit_2.raw_id)} + % if c.filename1 == c.filename: + ${_('for')} ${c.filename1} + % endif + + +<%def name="main()"> +
+ +
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+ + ${self.breadcrumbs()} + +
+ + %if not c.commit_ranges: +

${_('No commits')}

+ + %else: +
${_('Target')}
+
+ + ${h.link_to('r%s:%s' % (c.commit_1.revision, h.short_id(c.commit_1.raw_id)), h.url('changeset_home',repo_name=c.repo_name, revision=c.commit_1.raw_id))} + +
+
${_('Source')}
+
+ + ${h.link_to('r%s:%s' % (c.commit_2.revision, h.short_id(c.commit_2.raw_id)), h.url('changeset_home',repo_name=c.repo_name, revision=c.commit_2.raw_id))} + +
+ %endif +
+ + ##CS + <%include file="../compare/compare_commits.html" /> + + ## FILES +
+ + ${_('Expand All')} | ${_('Collapse All')} + +

+ % if c.binary_file: + ${_('Cannot diff binary files')} + % elif (c.lines_added == 0 and c.lines_deleted == 0): + ${_('File was not changed in this commit range')} + % else: + ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted)} + % endif +

+
+ +% if (c.lines_added > 0 or c.lines_deleted > 0): +
+ + %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes.iteritems(): + + + + + + + + + + + + + + + + + + %endfor +
+ + + + + + + %if (stats): +
${h.fancy_file_stats(stats)}
+ %endif +
+ +
+
+
+
+
+
+ ${diff|n} + % if file and file["is_limited_diff"]: + % if file["exceeds_limit"]: + ${diff_block.file_message()} + % else: +
${_('Diff was truncated. File content available only in full diff.')} ${_('Show full diff')}
+ % endif + % endif +
+
+
+
+
+% endif +
+ diff --git a/rhodecode/templates/files/file_tree_author_box.html b/rhodecode/templates/files/file_tree_author_box.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/file_tree_author_box.html @@ -0,0 +1,14 @@ +<%namespace name="base" file="/base/base.html"/> + +
+

+ ${_('Commit Author')} +

+
+ + diff --git a/rhodecode/templates/files/file_tree_detail.html b/rhodecode/templates/files/file_tree_detail.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/file_tree_detail.html @@ -0,0 +1,37 @@ +<%namespace name="file_base" file="/files/base.html"/> + +
+
+ ${_('Description')}: +
+
${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}
+
+ +
+
+ ${_('Description')}: +
+
${h.urlify_commit_message(c.commit.message,c.repo_name)}
+
+ + + +
+
+ ${_('References')}: +
+
+
+ + ${h.show_id(c.commit)} + + + ${file_base.refs(c.commit)} +
+
+
+ + + diff --git a/rhodecode/templates/files/files.html b/rhodecode/templates/files/files.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files.html @@ -0,0 +1,336 @@ +<%inherit file="/base/base.html"/> + +<%def name="title(*args)"> + ${_('%s Files') % c.repo_name} + %if hasattr(c,'file'): + · ${h.safe_unicode(c.file.path) or '\\'} + %endif + + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Files')} + %if c.file: + @ ${h.show_id(c.commit)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='files')} + + +<%def name="main()"> +
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+ +
+
+ <%include file='files_pjax.html'/> +
+
+ + + + diff --git a/rhodecode/templates/files/files_add.html b/rhodecode/templates/files/files_add.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_add.html @@ -0,0 +1,232 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Files Add') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="breadcrumbs_links()"> + ${_('Add new file')} @ ${h.show_id(c.commit)} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='files')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+
+ ${self.breadcrumbs()} +
+ ${h.secure_form(h.url.current(),method='post',id='eform',enctype="multipart/form-data", class_="form-horizontal")} +
+
+
+ ${_('Path')}: +
+
+
+ ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} + ${_('Specify Custom Path')} +
+ +
+
+
+
+ ${_('Filename')}: +
+
+ +

${_('or')} ${_('Upload File')}

+
+
+ +
+
+
+
+
+
+ ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)} + + ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])} + + +
+
+
+

+                    
+                    
+
+
+
+
+ +
+
+
+ ${_('Commit Message')}: +
+
+
+ +
+
+
+
+ ${h.reset('reset',_('Cancel'),class_="btn btn-small")} + ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-success")} +
+
+ ${h.end_form()} +
+ + diff --git a/rhodecode/templates/files/files_browser.html b/rhodecode/templates/files/files_browser.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_browser.html @@ -0,0 +1,109 @@ + +
+
+
+ ${h.form(h.url.current(), method='GET', id='at_rev_form')} +
+ ${h.hidden('refs_filter')} + +
${h.text('at_rev',value=c.commit.revision)}
+ +
+ ${h.end_form()} + + + + % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): + + % endif +
+ + +
+ +
+ + + + + + + + + + + + + %if c.file.parent: + + + + + + + + %endif + %for cnt,node in enumerate(c.file): + + + %if node.is_file(): + + + + + %else: + + + + + %endif + + %endfor + + +
${_('Name')}${_('Size')}${_('Modified')}${_('Last Commit')}${_('Author')}
+ + .. + +
+ %if node.is_submodule(): + + ${h.link_to_if( + node.url.startswith('http://') or node.url.startswith('https://'), + node.name,node.url)} + + %else: + + ${node.name} + + %endif + + ${_('Loading...')} +
+
+
+ + diff --git a/rhodecode/templates/files/files_delete.html b/rhodecode/templates/files/files_delete.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_delete.html @@ -0,0 +1,75 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Files Delete') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="breadcrumbs_links()"> + ${_('Delete file')} @ ${h.show_id(c.commit)} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='files')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+
+ ${self.breadcrumbs()} +
+ ${h.secure_form(h.url.current(),method='post',class_="form-horizontal")} +
+
+
+ ${_('Path')}: +
+
+ ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} +
+
+
+ +
+
+ %if c.file.is_binary: + ${_('Binary file (%s)') % c.file.mimetype} + %else: + %if c.file.size < c.cut_off_limit: + ${h.pygmentize(c.file,linenos=True,anchorlinenos=False,cssclass="code-highlight")} + %else: + ${_('File is too big to display')} ${h.link_to(_('Show as raw'), + h.url('files_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path))} + %endif + %endif +
+
+ +
+
+
+ ${_('Commit Message')}: +
+
+
+ +
+
+
+
+ ${h.reset('reset',_('Cancel'),class_="btn btn-small btn-danger")} + ${h.submit('commit',_('Delete File'),class_="btn btn-small btn-danger-action")} +
+
+ ${h.end_form()} +
+ diff --git a/rhodecode/templates/files/files_detail.html b/rhodecode/templates/files/files_detail.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_detail.html @@ -0,0 +1,62 @@ +<%namespace name="file_base" file="/files/base.html"/> + +
+
+ ${_('Commit Description')}: +
+
${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}
+
+ +
+
+ ${_('Commit Description')}: +
+
${h.urlify_commit_message(c.commit.message,c.repo_name)}
+
+ + +
+
+ ${_('References')}: +
+
+
+ + ${h.show_id(c.commit)} + + + ${file_base.refs(c.commit)} +
+
+
+ +
+
+ ${_('File last commit')}: +
+
+
+ + ${h.show_id(c.file_last_commit)} + + + ${file_base.refs(c.file_last_commit)} +
+
+
+ + +
+ ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} + ${h.hidden('diff1')} + ${h.hidden('diff2',c.file_last_commit.raw_id)} + + ${h.submit('diff',_('Diff to Commit'),class_="btn disabled",disabled="true")} + ${h.submit('show_rev',_('Show at Commit'),class_="btn disabled",disabled="true")} + ${h.hidden('annotate', c.annotate)} + ${h.end_form()} +
+ + \ No newline at end of file diff --git a/rhodecode/templates/files/files_edit.html b/rhodecode/templates/files/files_edit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_edit.html @@ -0,0 +1,193 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s File Edit') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="breadcrumbs_links()"> + ${_('Edit file')} @ ${h.show_id(c.commit)} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='files')} + + +<%def name="main()"> +<% renderer = h.renderer_from_filename(c.f_path)%> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} +
+
+ ${self.breadcrumbs()} +
+
+
+
+ ${_('Path')}: +
+
+
+ ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} +
+
+
+
+ +
+ ${h.secure_form(h.url.current(),method='post',id='eform')} +
+
+
+ + ${h.link_to("r%s:%s" % (c.file.commit.idx,h.short_id(c.file.commit.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.commit.raw_id))} + ${h.format_byte_size_binary(c.file.size)} + ${c.file.mimetype} +
+ + ${_('history')} + + + % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): + % if not c.file.is_binary: + %if True: + ${h.link_to(_('source'), h.url('files_home', repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")} + %else: + ${h.link_to(_('annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")} + %endif + ${h.link_to(_('raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")} + + ${_('download')} + + % endif + % endif +
+
+
+ + ${'%s /' % c.file.dir_path if c.file.dir_path else c.file.dir_path} + + + ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)} + + ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])} + + +
+
+
+

+                
+                
+
+
+
+ +
+
+
+ ${_('Commit Message')}: +
+
+
+ +
+
+
+
+ ${h.reset('reset',_('Cancel'),class_="btn btn-small")} + ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-success")} +
+
+ ${h.end_form()} +
+ + + diff --git a/rhodecode/templates/files/files_pjax.html b/rhodecode/templates/files/files_pjax.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_pjax.html @@ -0,0 +1,52 @@ +<%def name="title(*args)"> + ${_('%s Files') % c.repo_name} + %if hasattr(c,'file'): + · ${h.safe_unicode(c.file.path) or '\\'} + %endif + + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +
+
+
+ +
+ ${_('Show More')} +
+
+ + % if c.file.is_submodule(): + Submodule ${h.escape(c.file.name)} + % elif c.file.is_dir(): + <%include file='file_tree_detail.html'/> + % else: + <%include file='files_detail.html'/> + % endif + +
+ + % if c.file.is_dir(): + + + ${c.file_tree} + % else: + + + <%include file='files_source.html'/> + % endif + +
\ No newline at end of file diff --git a/rhodecode/templates/files/files_source.html b/rhodecode/templates/files/files_source.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_source.html @@ -0,0 +1,70 @@ + +
+
+
+ ${c.file} + | ${c.file.lines()[0]} ${ungettext('line', 'lines', c.file.lines()[0])} + | ${h.format_byte_size_binary(c.file.size)} + | ${c.file.mimetype} +
+
+ + ${_('History')} + + | + %if c.annotate: + ${h.link_to(_('Source'), h.url('files_home', repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path))} + %else: + ${h.link_to(_('Annotation'), h.url('files_annotate_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path))} + %endif + | ${h.link_to(_('Raw'), h.url('files_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path))} + | + ${_('Download')} + + + %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): + | + %if c.on_branch_head and c.branch_or_raw_id and not c.file.is_binary: + + ${_('Edit on Branch:%s') % c.branch_or_raw_id} + + | ${_('Delete')} + + %elif c.on_branch_head and c.branch_or_raw_id and c.file.is_binary: + ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing binary files not allowed'))} + | ${h.link_to(_('Delete'), h.url('files_delete_home',repo_name=c.repo_name,revision=c.branch_or_raw_id,f_path=c.f_path, anchor='edit'),class_="btn-danger btn-link")} + %else: + ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing files allowed only when on branch head commit'))} + | ${h.link_to(_('Delete'), '#', class_="btn btn-danger btn-link disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))} + %endif + %endif +
+
+
+
+ %if c.file.is_binary: +
+ ${_('Binary file (%s)') % c.file.mimetype} +
+ %else: + % if c.file.size < c.cut_off_limit: + %if c.annotate: + ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")} + %elif c.renderer: + ${h.render(c.file.content, renderer=c.renderer)} + %else: + ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")} + %endif + %else: + ${_('File is too big to display')} ${h.link_to(_('Show as raw'), + h.url('files_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id,f_path=c.f_path))} + %endif + %endif +
+
+ + diff --git a/rhodecode/templates/followers/followers.html b/rhodecode/templates/followers/followers.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/followers/followers.html @@ -0,0 +1,36 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Followers') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Followers')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> +
+
+

+ ${_('%s Followers') % c.repo_name} +

+
+
+
+ ${c.followers_data} +
+
+
+ diff --git a/rhodecode/templates/followers/followers_data.html b/rhodecode/templates/followers/followers_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/followers/followers_data.html @@ -0,0 +1,31 @@ +## -*- coding: utf-8 -*- +<%namespace name="base" file="/base/base.html"/> + + + + + + % for f in c.followers_pager: + + + + + % endfor +
${_('Follower Name')}${_('Following Since')}
+ ${base.gravatar_with_user(f.user.email, 16)} + + ${h.age_component(f.follows_from)} +
+ +
+ +${c.followers_pager.pager('$link_previous ~2~ $link_next')} +
diff --git a/rhodecode/templates/forks/fork.html b/rhodecode/templates/forks/fork.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/forks/fork.html @@ -0,0 +1,127 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Fork repository %s') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('New Fork')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='options')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + ${self.breadcrumbs()} +
+ + ${h.secure_form(url('repo_fork_create_home',repo_name=c.repo_info.repo_name))} +
+ +
+ +
+
+ +
+
+ ${h.text('repo_name', class_="medium")} + ${h.hidden('repo_type',c.repo_info.repo_type)} + ${h.hidden('fork_parent_id',c.repo_info.repo_id)} +
+
+ +
+
+ +
+
+ ${h.textarea('description')} + ${_('Keep it short and to the point. Use a README file for longer descriptions.')} +
+
+ +
+
+ +
+
+ ${h.select('repo_group','',c.repo_groups,class_="medium")} + %if c.personal_repo_group: + ${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}} + %endif + ${_('Optionally select a group to put this repository into.')} +
+
+ +
+
+ +
+
+ ${h.select('landing_rev','',c.landing_revs,class_="medium")} + ${_('Default commit for files page, downloads, whoosh and readme')} +
+
+ +
+
+ +
+
+ ${h.checkbox('private',value="True")} + ${_('Private repositories are only visible to people explicitly added as collaborators.')} +
+
+ +
+
+ +
+
+ ${h.checkbox('copy_permissions',value="True", checked="checked")} + ${_('Copy permissions from forked repository')} +
+
+ +
+ ${h.submit('',_('Fork this Repository'),class_="btn")} +
+
+
+ ${h.end_form()} +
+ + diff --git a/rhodecode/templates/forks/forks.html b/rhodecode/templates/forks/forks.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/forks/forks.html @@ -0,0 +1,45 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Forks') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${_('Forks')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + +
+
+
+ ${c.forks_data} +
+
+
+ diff --git a/rhodecode/templates/forks/forks_data.html b/rhodecode/templates/forks/forks_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/forks/forks_data.html @@ -0,0 +1,47 @@ +## -*- coding: utf-8 -*- +<%namespace name="base" file="/base/base.html"/> + +% if c.forks_pager: + + + + + + + + % for f in c.forks_pager: + + + + + + + % endfor +
${_('Fork')}${_('Description')}${_('Forked')}
+ ${base.gravatar_with_user(f.user.email, 16)} + ⁄ + ${h.link_to(f.repo_name,h.url('summary_home',repo_name=f.repo_name))} + +
${f.description}
+
+ ${h.age_component(f.created_on)} + + ${_('Compare fork')} +
+
+ + ${c.forks_pager.pager('$link_previous ~2~ $link_next')} +
+% else: + ${_('There are no forks yet')} +% endif diff --git a/rhodecode/templates/index.html b/rhodecode/templates/index.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/index.html @@ -0,0 +1,15 @@ +## -*- coding: utf-8 -*- +<%inherit file="index_base.html"/> + +<%def name="title()"> + ${_('Dashboard')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs()"> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + diff --git a/rhodecode/templates/index_base.html b/rhodecode/templates/index_base.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/index_base.html @@ -0,0 +1,172 @@ +<%inherit file="/base/base.html"/> + +<%def name="main()"> +
+ +
+ + %if c.rhodecode_user.username != h.DEFAULT_USER: +
+ <% + is_admin = h.HasPermissionAny('hg.admin')('can create repos index page') + create_repo = h.HasPermissionAny('hg.create.repository')('can create repository index page') + create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')('can create repository groups index page') + create_user_group = h.HasPermissionAny('hg.usergroup.create.true')('can create user groups index page') + + gr_name = c.repo_group.group_name if c.repo_group else None + # create repositories with write permission on group is set to true + create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')() + group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page') + group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page') + %> + + %if not c.repo_group: + ## no repository group context here + %if is_admin or create_repo: + ${_('Add Repository')} + %endif + + %if is_admin or create_repo_group: + ${_(u'Add Repository Group')} + %endif + %else: + ##we're inside other repository group other terms apply + %if is_admin or group_admin or (group_write and create_on_write): + ${_('Add Repository')} + %endif + %if is_admin or group_admin: + ${_(u'Add Repository Group')} + %endif + %if is_admin or group_admin: + ${_('Edit Repository Group')} + %endif + %endif +
+ %endif +
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + diff --git a/rhodecode/templates/index_repo_group.html b/rhodecode/templates/index_repo_group.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/index_repo_group.html @@ -0,0 +1,23 @@ +## -*- coding: utf-8 -*- +<%inherit file="index_base.html"/> + +<%def name="title()"> + ${_('%s Repository group dashboard') % c.repo_group.group_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs()"> + + ${h.link_to(_(u'Home'),h.url('/'))} + %if c.repo_group.parent_group: + » ${h.link_to(c.repo_group.parent_group.name,h.url('repo_group_home',group_name=c.repo_group.parent_group.group_name))} + %endif + » ${c.repo_group.name} + + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + diff --git a/rhodecode/templates/journal/journal.html b/rhodecode/templates/journal/journal.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/journal/journal.html @@ -0,0 +1,56 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> +<%def name="title()"> + ${_('Journal')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + +<%def name="breadcrumbs()"> +

+ ${h.form(None, id_="filter_form", method="get")} + + + ${_('Journal')} - ${ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)} + ${h.end_form()} +

+

${_('Example Queries')}

+ +<%def name="menu_bar_nav()"> + ${self.menu_items(active='journal')} + +<%def name="head_extra()"> + + + +<%def name="main()"> + +
+ +
+ ${self.breadcrumbs()} + +
+
${c.journal_data}
+
+ + + diff --git a/rhodecode/templates/journal/journal_data.html b/rhodecode/templates/journal/journal_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/journal/journal_data.html @@ -0,0 +1,55 @@ +## -*- coding: utf-8 -*- +<%namespace name="base" file="/base/base.html"/> + +%if c.journal_day_aggreagate: + %for day,items in c.journal_day_aggreagate: +
${day}
+ % for user,entries in items: +
+ ${base.gravatar(user.email if user else '', 30)} + %if user: +
${h.link_to_user(user.username)}
+ %else: +
${entries[0].username}
+ %endif +
+ % for entry in entries: +
${h.action_parser(entry)[2]()}
+
${h.action_parser(entry)[0]()}
+
+ + %if entry.repository is not None: + ${h.link_to(entry.repository.repo_name, + h.url('summary_home',repo_name=entry.repository.repo_name))} + %else: + ${entry.repository_name} + %endif + +
+
${h.literal(h.action_parser(entry)[1]())}
+
+ ${h.age_component(entry.action_date)} +
+ %endfor +
+
+ %endfor + %endfor + +
+ ${c.journal_pager.pager('$link_previous ~2~ $link_next')} +
+ +%else: +
+ ${_('No entries yet')} +
+%endif diff --git a/rhodecode/templates/journal/public_journal.html b/rhodecode/templates/journal/public_journal.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/journal/public_journal.html @@ -0,0 +1,37 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> +<%def name="title()"> + ${_('Public Journal')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + +<%def name="breadcrumbs()"> + ${h.branding(c.rhodecode_name)} + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='journal')} + +<%def name="head_extra()"> + + + +<%def name="main()"> + +
+ +
+
${_('Public Journal')}
+ +
+ +
${c.journal_data}
+
+ + diff --git a/rhodecode/templates/login.html b/rhodecode/templates/login.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/login.html @@ -0,0 +1,72 @@ +## -*- coding: utf-8 -*- +<%inherit file="base/root.html"/> +<%namespace file="base/social_buttons.html" import="render_social_buttons"/> + +<%def name="title()"> + ${_('Sign In')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + + +
+
+
+ +
+
+ +
+
+ +
+ +
+ <%include file="/base/flash_msg.html"/> + + +
+ ${h.form(h.url.current(**request.GET), needs_csrf_token=False)} + + ${h.text('username',class_='focus')} + + ${h.password('password',class_='focus')} + + + + ${h.submit('sign_in',_('Sign In'),class_="btn sign-in")} + ${h.end_form()} + +
+ + % if c.social_plugins: +

${_('Sign In using one of external services')}:

+ +

+ ${render_social_buttons(c.social_plugins, 'login')} +

+ % endif + + +
+
+
diff --git a/rhodecode/templates/password_reset.html b/rhodecode/templates/password_reset.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/password_reset.html @@ -0,0 +1,70 @@ +## -*- coding: utf-8 -*- +<%inherit file="base/root.html"/> + +<%def name="title()"> + ${_('Create an Account')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + + +
+
+
+ +
+
+ +
+
+ +
+ +
+ <%include file="/base/flash_msg.html"/> + + +
+ ${h.form(url('password_reset'), needs_csrf_token=False)} + + ${h.text('email')} + + %if c.captcha_active: + + %endif + + ${h.submit('send',_('Send password reset email'),class_="btn sign-in")} +
${_('Password reset link will be send to matching email address')}
+ + ${h.end_form()} +
+
+
+
+ +%if c.captcha_active: + +%endif + \ No newline at end of file diff --git a/rhodecode/templates/password_reset_confirmation.html b/rhodecode/templates/password_reset_confirmation.html new file mode 100644 diff --git a/rhodecode/templates/pullrequests/pullrequest.html b/rhodecode/templates/pullrequests/pullrequest.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/pullrequests/pullrequest.html @@ -0,0 +1,540 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${c.repo_name} ${_('New pull request')} + + +<%def name="breadcrumbs_links()"> + ${_('New pull request')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='showpullrequest')} + + +<%def name="main()"> +
+
+ ${self.repo_page_title(c.rhodecode_db_repo)} + ${self.breadcrumbs()} +
+ + ${h.secure_form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')} +
+ +
+ +
+ + +
+ +
+
+ +
+
+ ${h.text('pullrequest_title', c.default_title, class_="medium autogenerated-title")} +
+
+ +
+
+ +
+
+ ${h.textarea('pullrequest_desc',size=30, )} + + ${_('Write a short description on this pull request')} + +
+
+ +
+
+ +
+ + ## TODO: johbo: Abusing the "content" class here to get the + ## desired effect. Should be replaced by a proper solution. + + ##ORG +
+ ${_('Origin repository')}: + ${c.rhodecode_db_repo.description} +
+
+ ${h.hidden('source_repo')} + ${h.hidden('source_ref')} +
+ + ##OTHER, most Probably the PARENT OF THIS FORK +
+ ## filled with JS +
+
+ +
+ ${h.hidden('target_repo')} + ${h.hidden('target_ref')} + +
+
+ +
+
+ +
+
+
+ ${h.submit('save',_('Submit Pull Request'),class_="btn")} +
+
+
+
+ +
+
+
+
+
+
+
+ ${_('Pull request reviewers')} +
+
+
+ ## members goes here, filled via JS based on initial selection ! +
    +
    +
    + ${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))} +
    +
    +
    +
    +
    +
    +
    +
    + ## overview pulled by ajax +
    +
    +
    + ${h.end_form()} +
    + + + + diff --git a/rhodecode/templates/pullrequests/pullrequest_show.html b/rhodecode/templates/pullrequests/pullrequest_show.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/pullrequests/pullrequest_show.html @@ -0,0 +1,568 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + + ${c.pull_request.title} + %if c.pull_request.is_closed(): + (${_('Closed')}) + %endif + + + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='showpullrequest')} + + +<%def name="main()"> + +
    +
    + ${self.repo_page_title(c.rhodecode_db_repo)} +
    + + ${self.breadcrumbs()} + + +
    +
    + <%summary = lambda n:{False:'summary-short'}.get(n)%> +
    + ${_('Pull request #%s') % c.pull_request.pull_request_id} ${_('From')} ${h.format_date(c.pull_request.created_on)} + %if c.allowed_to_update: + ${_('Edit')} + + %endif +
    + +
    +
    +
    + +
    +
    +
    + ## branch link is only valid if it is a branch + + %if c.pull_request.source_ref_parts.type == 'branch': + ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name} + %else: + ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name} + %endif + + + ${c.pull_request.source_repo.clone_url()} + +
    +
    + %if h.is_hg(c.pull_request.source_repo): + + %elif h.is_git(c.pull_request.source_repo): + + %endif +
    +
    +
    +
    +
    + +
    +
    +
    + ## branch link is only valid if it is a branch + + %if c.pull_request.target_ref_parts.type == 'branch': + ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name} + %else: + ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name} + %endif + + + ${c.pull_request.target_repo.clone_url()} + +
    +
    +
    +
    +
    + +
    +
    + %if c.pull_request_review_status: +
    + + %if c.pull_request.is_closed(): + ${_('Closed')}, + %endif + ${h.commit_status_lbl(c.pull_request_review_status)} + + - ${ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)} + %endif +
    +
    +
    +
    + +
    +
    +
    ${h.urlify_commit_message(c.pull_request.description, c.repo_name)}
    +
    + +
    +
    +
    + +
    +
    +
    +
    + %if c.comments: + ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}, + %else: + ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)} + %endif + %if c.inline_cnt: + ## this is replaced with a proper link to first comment via JS linkifyComments() func + ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} + %else: + ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} + %endif + + % if c.outdated_cnt: + ,${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} ${_('(Show)')} + % endif +
    +
    +
    +
    + +
    +
    +
    + ## AUTHOR +
    +
    + ${_('Author')} +
    +
    +
    +
      +
    • + ${self.gravatar_with_user(c.pull_request.author.email, 16)} +
    • +
    +
    + ## REVIEWERS +
    +
    + ${_('Pull request reviewers')} + %if c.allowed_to_update: + ${_('Edit')} + + %endif +
    +
    +
    + ## members goes here ! +
      + %for member,status in c.pull_request_reviewers: +
    • +
      +
      +
      +
      + + ${self.gravatar_with_user(member.email, 16)} + (${_('owner') if c.pull_request.user_id == member.user_id else _('reviewer')}) + + %if c.allowed_to_update: + + %endif +
      +
    • + %endfor +
    + %if not c.pull_request.is_closed(): + + %endif +
    +
    +
    +
    + ##DIFF +
    +
    + ##CS + % if c.missing_requirements: +
    +
    +
    + ${_('Missing requirements:')} + ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')} +
    +
    +
    + % elif c.missing_commits: +
    +
    +
    + ${_('Missing commits')}: + ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')} + ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')} +
    +
    +
    + % endif +
    + % if c.allowed_to_update and not c.pull_request.is_closed(): + + % endif + % if len(c.commit_ranges): +

    ${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}

    + % endif +
    + % if not c.missing_commits: + <%include file="/compare/compare_commits.html" /> + ## FILES +
    + + ${_('Expand All')} | ${_('Collapse All')} + +

    + ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} +

    +
    + % endif +
    + %if not c.files and not c.missing_commits: + ${_('No files')} + %endif + + <%namespace name="diff_block" file="/changeset/diff_block.html"/> + %for FID, change, path, stats in c.files: + + + + + + + + + + + + + + + + + + + ## Loop through inline comments + % if c.outdated_comments.get(path,False): + + + + + + + + + + + % endif + %endfor + ## Loop through inline comments for deleted files + %for path in c.deleted_files: + + + + + + + + + + + % if path in c.outdated_comments: + + + + + + + + + + + % endif + %endfor +
    + + + + + + +
    ${h.fancy_file_stats(stats)}
    +
    + +
    +
    + ${diff_block.diff_block_simple([c.changes[FID]])} +
    +

    ${_('Outdated Inline Comments')}:

    +
    + % for line, comments in c.outdated_comments[path].iteritems(): +
    + % for co in comments: + ${comment.comment_block_outdated(co)} + % endfor +
    + % endfor +
    ${path}
    (${_('Removed')})
    +

    ${_('Outdated Inline Comments')}:

    +
    + % for line, comments in c.outdated_comments[path].iteritems(): +
    + % for co in comments: + ${comment.comment_block_outdated(co)} + % endfor +
    + % endfor +
    +
    + % if c.limited_diff: +
    ${_('Commit was too big and was cut off...')} ${_('Show full diff')}
    + % endif +
    +
    + + % if c.limited_diff: +

    ${_('Commit was too big and was cut off...')} ${_('Show full diff')}

    + % endif + + ## template for inline comment form + <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> + ${comment.comment_inline_form()} + + ## render comments and inlines + ${comment.generate_comments(include_pull_request=True, is_pull_request=True)} + + % if not c.pull_request.is_closed(): + ## main comment form and it status + ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name, + pull_request_id=c.pull_request.pull_request_id), + c.pull_request_review_status, + is_pull_request=True, change_status=c.allowed_to_change_status)} + %endif + + + +
    +
    + + diff --git a/rhodecode/templates/pullrequests/pullrequests.html b/rhodecode/templates/pullrequests/pullrequests.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/pullrequests/pullrequests.html @@ -0,0 +1,132 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Pull Requests') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='showpullrequest')} + + + +<%def name="main()"> +
    +
    + ${self.repo_page_title(c.rhodecode_db_repo)} + + + + ${self.breadcrumbs()} +
    + + +
    + + + diff --git a/rhodecode/templates/register.html b/rhodecode/templates/register.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/register.html @@ -0,0 +1,98 @@ +## -*- coding: utf-8 -*- +<%inherit file="base/root.html"/> +<%namespace file="base/social_buttons.html" import="render_social_buttons"/> + +<%def name="title()"> + ${_('Create an Account')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + + +
    +
    +
    + +
    +
    + +
    +
    + +
    + +
    + <%include file="/base/flash_msg.html"/> + + +
    + ${h.form(url('register'), needs_csrf_token= False)} + + ${h.text('username', c.form_data.get('username'))} + + ${h.password('password', c.form_data.get('password'))} + + ${h.password('password_confirmation', c.form_data.get('password'))} + + ${h.text('firstname')} + + ${h.text('lastname')} + + ${h.text('email', c.form_data.get('email'))} + + %if c.captcha_active: +
    + + ${h.hidden('recaptcha_field')} +
    +
    + %endif + + %if not c.auto_active: +

    + ${_('Account activation requires admin approval.')} +

    + %endif +

    + ${c.register_message|n} +

    + + ${h.submit('sign_up',_('Create Account'),class_="btn sign-in")} + + ${h.end_form()} +
    + + % if c.social_plugins: +

    ${_('Register using one of external services')}:

    + +

    + ${render_social_buttons(c.social_plugins, 'register')} +

    + % endif + +
    +
    +
    + +%if c.captcha_active: + +%endif + diff --git a/rhodecode/templates/rst_templates/auto_status_change.mako b/rhodecode/templates/rst_templates/auto_status_change.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/rst_templates/auto_status_change.mako @@ -0,0 +1,4 @@ +## -*- coding: utf-8 -*- +Auto status change to |new_status| + +.. |new_status| replace:: *"${new_status_label}"* \ No newline at end of file diff --git a/rhodecode/templates/rst_templates/pull_request_update.mako b/rhodecode/templates/rst_templates/pull_request_update.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/rst_templates/pull_request_update.mako @@ -0,0 +1,27 @@ +## -*- coding: utf-8 -*- +Auto status change to |under_review| + +.. role:: added +.. role:: removed +.. parsed-literal:: + + Changed commits: + * :added:`${len(added_commits)} added` + * :removed:`${len(removed_commits)} removed` + + %if not changed_files: + No file changes found + %else: + Changed files: + %for file_name in added_files: + * `A ${file_name} <#${'a_' + h.FID('', file_name)}>`_ + %endfor + %for file_name in modified_files: + * `M ${file_name} <#${'a_' + h.FID('', file_name)}>`_ + %endfor + %for file_name in removed_files: + * R ${file_name} + %endfor + %endif + +.. |under_review| replace:: *"${under_review_label}"* \ No newline at end of file diff --git a/rhodecode/templates/search/search.html b/rhodecode/templates/search/search.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/search/search.html @@ -0,0 +1,101 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + %if c.repo_name: + ${_('Search inside repository %(repo_name)s') % {'repo_name': c.repo_name}} + %else: + ${_('Search inside all accessible repositories')} + %endif + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + %if c.repo_name: + ${_('Search inside repository %(repo_name)s') % {'repo_name': c.repo_name}} + %else: + ${_('Search inside all accessible repositories')} + %endif + %if c.cur_query: + » + ${c.cur_query} + %endif + + +<%def name="menu_bar_nav()"> + %if c.repo_name: + ${self.menu_items(active='repositories')} + %else: + ${self.menu_items(active='search')} + %endif + + +<%def name="menu_bar_subnav()"> + %if c.repo_name: + ${self.repo_menu(active='options')} + %endif + + +<%def name="main()"> +
    + %if c.repo_name: + +
    + ${self.repo_page_title(c.rhodecode_db_repo)} +
    + ${h.form(h.url('search_repo_home',repo_name=c.repo_name),method='get')} + %else: + +
    + ${self.breadcrumbs()} + +
    + + ${h.form(h.url('search'),method='get')} + %endif +
    +
    + + ${h.text('q', c.cur_query)} + + ${h.select('type',c.search_type,[('content',_('File contents')), ('commit',_('Commit messages')), ('path',_('File names')),],id='id_search_type')} + +
    +
    + % for error in c.errors: + + % for k,v in error.asdict().items(): + ${k} - ${v} + % endfor + + % endfor +
    ${c.runtime}
    +
    +
    +
    + ${h.end_form()} + +
    + + diff --git a/rhodecode/templates/search/search_commit.html b/rhodecode/templates/search/search_commit.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/search/search_commit.html @@ -0,0 +1,76 @@ +<%namespace name="base" file="/base/base.html"/> + + + + + + + + + + + %for entry in c.formatted_results: + ## search results are additionally filtered, and this check is just a safe gate + % if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(entry['repository'], 'search results commit check'): + + + + + + + + + + % endif + %endfor +
    ${_('Repository')}${_('Commit')}${_('Commit message')}${_('Age')}${_('Author')}
    + %if h.get_repo_type_by_name(entry.get('repository')) == 'hg': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'git': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': + + %endif + ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))} + + ${h.link_to(h._shorten_commit_id(entry['commit_id']), + h.url('changeset_home',repo_name=entry['repository'],revision=entry['commit_id']))} + + %if entry['message_hl']: + ${h.literal(entry['message_hl'])} + %else: + ${h.urlify_commit_message(entry['message'], entry['repository'])} + %endif + + ${h.age_component(h.time_to_datetime(entry['date']))} + + ${base.gravatar_with_user(entry['author'])} +
    + +%if c.cur_query and c.formatted_results: +
    + ${c.formatted_results.pager('$link_previous ~2~ $link_next')} +
    +%endif + + diff --git a/rhodecode/templates/search/search_content.html b/rhodecode/templates/search/search_content.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/search/search_content.html @@ -0,0 +1,51 @@ +
    +%for entry in c.formatted_results: + ## search results are additionally filtered, and this check is just a safe gate + % if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(entry['repository'], 'search results content check'): +
    +
    +

    + %if h.get_repo_type_by_name(entry.get('repository')) == 'hg': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'git': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': + + %endif + ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))} +

    +
    + ${h.link_to(h.literal(entry['f_path']), h.url('files_home',repo_name=entry['repository'],revision=entry.get('commit_id', 'tip'),f_path=entry['f_path']))} + %if entry.get('lines'): + | ${entry.get('lines', 0.)} ${ungettext('line', 'lines', entry.get('lines', 0.))} + %endif + %if entry.get('size'): + | ${h.format_byte_size_binary(entry['size'])} + %endif + %if entry.get('mimetype'): + | ${entry.get('mimetype', "unknown mimetype")} + %endif +
    +
    + + ${_('Show Full History')} + | + ${h.link_to(_('Annotation'), h.url('files_annotate_home', repo_name=entry.get('repository',''),revision=entry.get('commit_id', 'tip'),f_path=entry.get('f_path','')))} + | ${h.link_to(_('Raw'), h.url('files_raw_home', repo_name=entry.get('repository',''),revision=entry.get('commit_id', 'tip'),f_path=entry.get('f_path','')))} + | + ${_('Download')} + +
    +
    +
    +
    ${h.literal(entry['content_short_hl'])}
    +
    +
    + % endif +%endfor +
    +%if c.cur_query and c.formatted_results: +
    + ${c.formatted_results.pager('$link_previous ~2~ $link_next')} +
    +%endif diff --git a/rhodecode/templates/search/search_path.html b/rhodecode/templates/search/search_path.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/search/search_path.html @@ -0,0 +1,34 @@ + + + + + ##TODO: add 'Last Change' and 'Author' here + + %for entry in c.formatted_results: + ## search results are additionally filtered, and this check is just a safe gate + % if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(entry['repository'], 'search results path check'): + + + + + % endif + %endfor +
    ${_('Repository')}${_('File')}
    + %if h.get_repo_type_by_name(entry.get('repository')) == 'hg': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'git': + + %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': + + %endif + ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))} + + ${h.link_to(h.literal(entry['f_path']), + h.url('files_home',repo_name=entry['repository'],revision='tip',f_path=entry['f_path']))} +
    + +%if c.cur_query and c.formatted_results: +
    + ${c.formatted_results.pager('$link_previous ~2~ $link_next')} +
    +%endif \ No newline at end of file diff --git a/rhodecode/templates/search/search_repository.html b/rhodecode/templates/search/search_repository.html new file mode 100644 diff --git a/rhodecode/templates/summary/base.html b/rhodecode/templates/summary/base.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/summary/base.html @@ -0,0 +1,29 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ## represents page title + ${_('%s Summary') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + + +<%def name="head_extra()"> + + + + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + + +<%def name="breadcrumbs_links()"> + + + +<%def name="main()"> + ${next.main()} + diff --git a/rhodecode/templates/summary/components.html b/rhodecode/templates/summary/components.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/summary/components.html @@ -0,0 +1,202 @@ +<%def name="refs_counters(branches, closed_branches, tags, bookmarks)"> + + + ${ungettext( + '%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}} + + + %if closed_branches: + + + ${ungettext( + '%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}} + + %endif + + + + ${ungettext( + '%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}} + + + %if bookmarks: + + + ${ungettext( + '%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}} + + %endif + + +<%def name="summary_detail(breadcrumbs_links, show_downloads=True)"> + <% summary = lambda n:{False:'summary-short'}.get(n) %> + +
    +
    + +
    + ${_('Show More')} +
    +
    + +
    + %if h.is_svn_without_proxy(c.rhodecode_db_repo): +
    + ${_('Read-only url')}: +
    +
    + + + + ${_('Show by ID')} +

    ${_('SVN Protocol is disabled. To enable it, see the')} ${_('documentation here')}.

    +
    + %else: +
    + ${_('Clone url')}: +
    + + %endif +
    + + + + + + + + % if show_downloads: + + % endif + +
    + + +<%def name="summary_stats(gravatar_function)"> + + diff --git a/rhodecode/templates/summary/missing_requirements.html b/rhodecode/templates/summary/missing_requirements.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/summary/missing_requirements.html @@ -0,0 +1,26 @@ +<%inherit file="/summary/base.html"/> + +<%namespace name="components" file="/summary/components.html"/> + +<%def name="main()"> +
    + ${self.repo_page_title(c.rhodecode_db_repo)} +
    + +
    + ${components.summary_detail(breadcrumbs_links=self.breadcrumbs_links(), show_downloads=False)} + ${components.summary_stats(gravatar_function=self.gravatar_with_user)} +
    + +
    + Missing requirements + These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled. + Please enable this extension in settings, or contact the repository owner for help. +
    + + + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + diff --git a/rhodecode/templates/summary/summary.html b/rhodecode/templates/summary/summary.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/summary/summary.html @@ -0,0 +1,130 @@ +<%inherit file="/summary/base.html"/> + +<%namespace name="components" file="/summary/components.html"/> + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> + +
    + ${self.repo_page_title(c.rhodecode_db_repo)} + +
    + +
    + ${components.summary_detail(breadcrumbs_links=self.breadcrumbs_links(), show_downloads=True)} + ${components.summary_stats(gravatar_function=self.gravatar_with_user)} +
    + + +
    + %if not c.repo_commits: +
    +

    ${_('Quick start')}

    +
    + %endif +
    +
    + <%include file='../changelog/changelog_summary_data.html'/> +
    +
    +
    + +%if c.readme_data: +
    +
    + +
    +
    + ${c.readme_data|n} +
    +
    +
    +
    +%endif + + + + diff --git a/rhodecode/templates/tags/tags.html b/rhodecode/templates/tags/tags.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/tags/tags.html @@ -0,0 +1,102 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('%s Tags') % c.repo_name} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + + 0 ${_('tags')} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='summary')} + + +<%def name="main()"> +
    +
    + ${self.repo_page_title(c.rhodecode_db_repo)} + %if c.has_references: + + %endif + %if c.has_references: + ${self.breadcrumbs()} + %endif +
    +
    +
    + + + + diff --git a/rhodecode/templates/tags/tags_data.html b/rhodecode/templates/tags/tags_data.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/tags/tags_data.html @@ -0,0 +1,29 @@ +## DATA TABLE RE USABLE ELEMENTS FOR TAGS +## usage: +## <%namespace name="tags" file="/tags/tags_data.html"/> +## tags.(arg,arg2) + +<%def name="compare(commit_id)"> + + + + +<%def name="name(name, files_url)"> + + ${name} + + + +<%def name="date(date)"> + ${h.age_component(date)} + + +<%def name="author(author)"> + ${h.link_to_user(author)} + + +<%def name="commit(message, commit_id, commit_idx)"> + + diff --git a/rhodecode/templates/users/user.html b/rhodecode/templates/users/user.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/users/user.html @@ -0,0 +1,46 @@ +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${c.user.username} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + ${c.user.username} + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} + + +<%def name="main()"> +
    +
    + ${self.breadcrumbs()} +
    + + +
    + + diff --git a/rhodecode/templates/users/user_profile.html b/rhodecode/templates/users/user_profile.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/users/user_profile.html @@ -0,0 +1,58 @@ +<%namespace name="base" file="/base/base.html"/> + + \ No newline at end of file diff --git a/rhodecode/tests/__init__.py b/rhodecode/tests/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/__init__.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import os +import time +import logging +import datetime +import hashlib +import tempfile +from os.path import join as jn + +from tempfile import _RandomNameSequence + +from paste.deploy import loadapp +from paste.script.appinstall import SetupCommand + +import pylons +import pylons.test +from pylons import config, url +from pylons.i18n.translation import _get_translator +from pylons.util import ContextObj + +from routes.util import URLGenerator +from webtest import TestApp +from nose.plugins.skip import SkipTest +import pytest + +from rhodecode import is_windows +from rhodecode.model.meta import Session +from rhodecode.model.db import User +from rhodecode.lib import auth +from rhodecode.lib.helpers import flash, link_to +from rhodecode.lib.utils2 import safe_unicode, safe_str + +# TODO: johbo: Solve time zone related issues and remove this tweak +os.environ['TZ'] = 'UTC' +if not is_windows: + time.tzset() + +log = logging.getLogger(__name__) + +__all__ = [ + 'get_new_dir', 'TestController', 'SkipTest', + 'url', 'link_to', 'ldap_lib_installed', 'clear_all_caches', + 'assert_session_flash', 'login_user', + 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO', + 'NEW_HG_REPO', 'NEW_GIT_REPO', + 'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS', + 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS', + 'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN', + 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO', + 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO', + 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'SCM_TESTS', +] + +# Invoke websetup with the current config file +# SetupCommand('setup-app').run([config_file]) + +# SOME GLOBALS FOR TESTS +TEST_DIR = tempfile.gettempdir() + +TESTS_TMP_PATH = jn(TEST_DIR, 'rc_test_%s' % _RandomNameSequence().next()) +TEST_USER_ADMIN_LOGIN = 'test_admin' +TEST_USER_ADMIN_PASS = 'test12' +TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com' + +TEST_USER_REGULAR_LOGIN = 'test_regular' +TEST_USER_REGULAR_PASS = 'test12' +TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com' + +TEST_USER_REGULAR2_LOGIN = 'test_regular2' +TEST_USER_REGULAR2_PASS = 'test12' +TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com' + +HG_REPO = 'vcs_test_hg' +GIT_REPO = 'vcs_test_git' +SVN_REPO = 'vcs_test_svn' + +NEW_HG_REPO = 'vcs_test_hg_new' +NEW_GIT_REPO = 'vcs_test_git_new' + +HG_FORK = 'vcs_test_hg_fork' +GIT_FORK = 'vcs_test_git_fork' + +## VCS +SCM_TESTS = ['hg', 'git'] +uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple()))) + +TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO) +TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix) +TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix) + +TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO) +TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix) +TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix) + +TEST_REPO_PREFIX = 'vcs-test' + + +# skip ldap tests if LDAP lib is not installed +ldap_lib_installed = False +try: + import ldap + ldap_lib_installed = True +except ImportError: + # means that python-ldap is not installed + pass + + +def clear_all_caches(): + from beaker.cache import cache_managers + for _cache in cache_managers.values(): + _cache.clear() + + +def get_new_dir(title): + """ + Returns always new directory path. + """ + from rhodecode.tests.vcs.utils import get_normalized_path + name_parts = [TEST_REPO_PREFIX] + if title: + name_parts.append(title) + hex_str = hashlib.sha1('%s %s' % (os.getpid(), time.time())).hexdigest() + name_parts.append(hex_str) + name = '-'.join(name_parts) + path = os.path.join(TEST_DIR, name) + return get_normalized_path(path) + + +@pytest.mark.usefixtures('app', 'index_location') +class TestController(object): + + maxDiff = None + + def log_user(self, username=TEST_USER_ADMIN_LOGIN, + password=TEST_USER_ADMIN_PASS): + self._logged_username = username + self._session = login_user_session(self.app, username, password) + self.csrf_token = auth.get_csrf_token(self._session) + + return self._session['rhodecode_user'] + + def logout_user(self): + logout_user_session(self.app, auth.get_csrf_token(self._session)) + self.csrf_token = None + self._logged_username = None + self._session = None + + def _get_logged_user(self): + return User.get_by_username(self._logged_username) + + # TODO: remove, use plain assert in tests + def assertEqual(self, a, b, msg=None): + if msg: + assert a == b, msg + else: + assert a == b + + +def login_user_session( + app, username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS): + response = app.post(url(controller='login', action='index'), + {'username': username, + 'password': password}) + + if 'invalid user name' in response.body: + pytest.fail('could not login using %s %s' % (username, password)) + + assert response.status == '302 Found' + ses = response.session['rhodecode_user'] + assert ses.get('username') == username + response = response.follow() + assert ses.get('is_authenticated') + + return response.session + + +def logout_user_session(app, csrf_token): + app.post( + url(controller='login', action='logout'), + {'csrf_token': csrf_token}, status=302) + + +def login_user(app, username=TEST_USER_ADMIN_LOGIN, + password=TEST_USER_ADMIN_PASS): + return login_user_session(app, username, password)['rhodecode_user'] + + +def assert_session_flash(response=None, msg=None, category=None): + """ + Assert on a flash message in the current session. + + :param msg: Required. The expected message. Will be evaluated if a + :class:`LazyString` is passed in. + :param response: Optional. For functional testing, pass in the response + object. Otherwise don't pass in any value. + :param category: Optional. If passed, the message category will be + checked as well. + """ + if msg is None: + raise ValueError("Parameter msg is required.") + + messages = flash.pop_messages() + message = messages[0] + + msg = _eval_if_lazy(msg) + message_text = _eval_if_lazy(message.message) + + if msg not in message_text: + msg = u'msg `%s` not found in session flash: got `%s` instead' % ( + msg, message_text) + pytest.fail(safe_str(msg)) + if category: + assert category == message.category + + +def _eval_if_lazy(value): + return value.eval() if hasattr(value, 'eval') else value + + +def assert_not_in_session_flash(response, msg, category=None): + assert 'flash' in response.session, 'Response session has no flash key' + message_category, message_text = response.session['flash'][0] + if msg in message_text: + msg = u'msg `%s` found in session flash: got `%s` instead' % ( + msg, message_text) + pytest.fail(safe_str(msg)) + if category: + assert category == message_category + + +def assert_session_flash_is_empty(response): + if 'flash' in response.session: + msg = 'flash messages are present in session:%s' % \ + response.session['flash'][0] + pytest.fail(safe_str(msg)) diff --git a/rhodecode/tests/auth_external_test.py b/rhodecode/tests/auth_external_test.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/auth_external_test.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +External module for testing plugins + +rhodecode.tests.auth_external_test + +""" +import logging +import traceback + +from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin +from sqlalchemy.ext.hybrid import hybrid_property +from rhodecode.model.db import User +from rhodecode.lib.ext_json import formatted_json + +log = logging.getLogger(__name__) + + +class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): + def __init__(self): + self._logger = logging.getLogger(__name__) + + @hybrid_property + def allows_creating_users(self): + return True + + @hybrid_property + def name(self): + return "external_test" + + def settings(self): + settings = [ + ] + return settings + + def use_fake_password(self): + return True + + def user_activation_state(self): + def_user_perms = User.get_default_user().AuthUser.permissions['global'] + return 'hg.extern_activate.auto' in def_user_perms + + def auth(self, userobj, username, password, settings, **kwargs): + """ + Given a user object (which may be null), username, a plaintext password, + and a settings object (containing all the keys needed as listed in settings()), + authenticate this user's login attempt. + + Return None on failure. On success, return a dictionary of the form: + + see: RhodeCodeAuthPluginBase.auth_func_attrs + This is later validated for correctness + """ + + if not username or not password: + log.debug('Empty username or password skipping...') + return None + + try: + user_dn = username + + # # old attrs fetched from RhodeCode database + admin = getattr(userobj, 'admin', False) + active = getattr(userobj, 'active', True) + email = getattr(userobj, 'email', '') + firstname = getattr(userobj, 'firstname', '') + lastname = getattr(userobj, 'lastname', '') + extern_type = getattr(userobj, 'extern_type', '') + # + user_attrs = { + 'username': username, + 'firstname': firstname, + 'lastname': lastname, + 'groups': [], + 'email': '%s@rhodecode.com' % username, + 'admin': admin, + 'active': active, + "active_from_extern": None, + 'extern_name': user_dn, + 'extern_type': extern_type, + } + + log.debug('EXTERNAL user: \n%s' % formatted_json(user_attrs)) + log.info('user %s authenticated correctly' % user_attrs['username']) + + return user_attrs + + except (Exception,): + log.error(traceback.format_exc()) + return None diff --git a/rhodecode/tests/config/__init__.py b/rhodecode/tests/config/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/config/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ diff --git a/rhodecode/tests/config/test_environment.py b/rhodecode/tests/config/test_environment.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/config/test_environment.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +import mock +import pytest + +from rhodecode.config import environment + + +class TestUseDirectHookCalls(object): + @pytest.mark.parametrize('config', [ + { + 'vcs.hooks.direct_calls': 'true', + 'base_path': 'fake_base_path' + } + ]) + def test_returns_true_when_conditions_are_met(self, config): + result = environment._use_direct_hook_calls(config) + assert result is True + + @pytest.mark.parametrize('config', [ + { + 'vcs.hooks.direct_calls': 'false', + 'base_path': 'fake_base_path' + }, + { + 'base_path': 'fake_base_path' + } + ]) + def test_returns_false_when_conditions_are_not_met(self, config): + result = environment._use_direct_hook_calls(config) + assert result is False + + +class TestGetVcsHooksProtocol(object): + def test_returns_pyro4_by_default(self): + config = {} + result = environment._get_vcs_hooks_protocol(config) + assert result == 'pyro4' + + @pytest.mark.parametrize('protocol', ['PYRO4', 'HTTP', 'Pyro4', 'Http']) + def test_returns_lower_case_value(self, protocol): + config = { + 'vcs.hooks.protocol': protocol + } + result = environment._get_vcs_hooks_protocol(config) + assert result == protocol.lower() + + +class TestLoadEnvironment(object): + def test_calls_use_direct_hook_calls(self, _external_calls_patcher): + global_conf = { + 'here': '', + 'vcs.connection_timeout': '0', + 'vcs.server.enable': 'false' + } + app_conf = { + 'cache_dir': '/tmp/', + '__file__': '/tmp/abcde.ini' + } + direct_calls_patcher = mock.patch.object( + environment, '_use_direct_hook_calls', return_value=True) + protocol_patcher = mock.patch.object( + environment, '_get_vcs_hooks_protocol', return_value='http') + with direct_calls_patcher as direct_calls_mock, \ + protocol_patcher as protocol_mock: + environment.load_environment(global_conf, app_conf) + direct_calls_mock.call_count == 1 + protocol_mock.call_count == 1 + + +@pytest.fixture +def _external_calls_patcher(request): + # TODO: mikhail: This is a temporary solution. Ideally load_environment + # should be split into multiple small testable functions. + utils_patcher = mock.patch.object(environment, 'utils') + + rhodecode_patcher = mock.patch.object(environment, 'rhodecode') + + db_config = mock.Mock() + db_config.items.return_value = { + 'paths': [['/tmp/abc', '/tmp/def']] + } + db_config_patcher = mock.patch.object( + environment, 'make_db_config', return_value=db_config) + + set_config_patcher = mock.patch.object(environment, 'set_rhodecode_config') + + utils_patcher.start() + rhodecode_patcher.start() + db_config_patcher.start() + set_config_patcher.start() + + request.addfinalizer(utils_patcher.stop) + request.addfinalizer(rhodecode_patcher.stop) + request.addfinalizer(db_config_patcher.stop) + request.addfinalizer(set_config_patcher.stop) diff --git a/rhodecode/tests/config/test_routing_links.py b/rhodecode/tests/config/test_routing_links.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/config/test_routing_links.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock + +from rhodecode.config import routing_links + + +def test_connect_redirection_links(): + link_config = [ + {"name": "example_link", + "external_target": "http://example.com", + "target": "https://rhodecode.com/r/v1/enterprise/example", + }, + ] + + rmap = mock.Mock() + with mock.patch.object(routing_links, 'link_config', link_config): + routing_links.connect_redirection_links(rmap) + + rmap.connect.assert_called_with( + link_config[0]['name'], link_config[0]['target'], + _static=True) diff --git a/rhodecode/tests/config/test_utils.py b/rhodecode/tests/config/test_utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/config/test_utils.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.config.utils import set_instance_id + + +@pytest.mark.parametrize('instance_id', ['', None, '*', 'custom-id']) +def test_set_instance_id(instance_id): + config = {'instance_id': instance_id} + set_instance_id(config) + + if instance_id == 'custom-id': + assert config['instance_id'] == instance_id + else: + assert isinstance(config['instance_id'], basestring) + assert len(config['instance_id']) + assert instance_id != config['instance_id'] diff --git a/rhodecode/tests/controllers/test_compare.py b/rhodecode/tests/controllers/test_compare.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_compare.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from rhodecode.tests import url + + +def test_compare_index_is_reached_at_least_once( + app, backend): + repo = backend.repo + app.get(url( + controller="compare", action='index', repo_name=repo.repo_name)) diff --git a/rhodecode/tests/controllers/test_error.py b/rhodecode/tests/controllers/test_error.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_error.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.tests import url + + +@pytest.mark.usefixtures('app') +class TestErrorController(object): + def test_direct_document_call(self): + self.app.get(url(controller='error', action='document'), status=404) diff --git a/rhodecode/tests/controllers/test_pullrequests.py b/rhodecode/tests/controllers/test_pullrequests.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_pullrequests.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock + +from rhodecode.controllers import pullrequests +from rhodecode.lib.vcs.backends.base import ( + MergeFailureReason, MergeResponse) +from rhodecode.model.pull_request import PullRequestModel +from rhodecode.tests import assert_session_flash + + +def test_merge_pull_request_renders_failure_reason(user_regular): + pull_request = mock.Mock() + controller = pullrequests.PullrequestsController() + model_patcher = mock.patch.multiple( + PullRequestModel, + merge=mock.Mock(return_value=MergeResponse( + True, False, 'STUB_COMMIT_ID', MergeFailureReason.PUSH_FAILED)), + merge_status=mock.Mock(return_value=(True, 'WRONG_MESSAGE'))) + with model_patcher: + controller._merge_pull_request(pull_request, user_regular, extras={}) + + assert_session_flash(msg=PullRequestModel.MERGE_STATUS_MESSAGES[ + MergeFailureReason.PUSH_FAILED]) diff --git a/rhodecode/tests/controllers/test_repo_groups.py b/rhodecode/tests/controllers/test_repo_groups.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_repo_groups.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import mock +import pylons +import pytest +from pylons import tmpl_context as c + + +@pytest.fixture +def current_user(request, user_util): + user = user_util.create_user() + + request_mock = mock.Mock(user=user) + pylons.request._push_object(request_mock) + + @request.addfinalizer + def cleanup(): + pylons.request._pop_object() + return user + + +@pytest.fixture +def personal_group_with_parent(user_util, current_user): + group_read_only = user_util.create_repo_group() + user_util.grant_user_permission_to_repo_group( + group_read_only, current_user, 'group.read') + + # TODO: johbo: This should go into the business models + group_as_admin = user_util.create_repo_group( + owner=current_user) + group_as_admin.parent_group = group_read_only + group_as_admin.group_name = group_as_admin.get_new_name( + group_as_admin.group_name) + + return group_as_admin + + +@pytest.fixture +def controller(): + from rhodecode.controllers.admin import repo_groups + return repo_groups.RepoGroupsController() + + +def test_repo_groups_load_defaults( + current_user, personal_group_with_parent, controller): + personal_group = personal_group_with_parent + controller._RepoGroupsController__load_defaults(True, personal_group) + + expected_list = ['-1', personal_group.parent_group.group_id] + returned_group_ids = [group[0] for group in c.repo_groups] + assert returned_group_ids == expected_list + + +def test_repo_groups_load_defaults_with_missing_group( + current_user, personal_group_with_parent, controller): + personal_group = personal_group_with_parent + controller._RepoGroupsController__load_defaults(True) + + expected_list = sorted(['-1', personal_group.group_id]) + returned_group_ids = sorted([group[0] for group in c.repo_groups]) + assert returned_group_ids == expected_list diff --git a/rhodecode/tests/controllers/test_search.py b/rhodecode/tests/controllers/test_search.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_search.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from __future__ import unicode_literals + +import time + +from whoosh import index +import mock +import pytest + +import rhodecode +from rhodecode.lib.auth import AuthUser +from rhodecode.lib.index import whoosh, searcher_from_config + + +@pytest.mark.parametrize("name_suffix", [ + "", + "UpPeRcAsE", +]) +def test_search_finds_results( + tmpdir, backend_random, user_regular, name_suffix): + repo = backend_random.create_repo(name_suffix=name_suffix) + + search_location = tmpdir.strpath + create_commit_index_with_one_document( + search_location, repo_name=repo.repo_name) + + auth_user = AuthUser(user_id=user_regular.user_id) + with mock.patch.dict(rhodecode.CONFIG, + {'search.location': search_location}): + searcher = searcher_from_config(rhodecode.CONFIG) + + search_result = searcher.search( + "Test", document_type='commit', search_user=auth_user, repo_name=None) + results = list(search_result['results']) + assert len(results) == 1 + assert results[0]['repository'] == repo.repo_name + + +def create_commit_index_with_one_document(search_location, repo_name): + """ + Provides a test index based on our search schema. + + The full details of index creation are found inside of `rhodecode-tools`. + The intention of this function is to provide just enough so that the + search works. + """ + test_index = index.create_in( + search_location, whoosh.COMMIT_SCHEMA, + indexname=whoosh.COMMIT_INDEX_NAME) + writer = test_index.writer() + + writer.add_document( + commit_id="fake_commit_id", + commit_idx=1, + owner="Test Owner", + date=time.time(), + repository=repo_name, + author="Test Author", + message="Test Message", + added="added_1.txt added_2.txt", + removed="removed_1.txt removed_2.txt", + changed="changed_1.txt changed_2.txt", + parents="fake_parent_1_id fake_parent_2_id", + ) + writer.commit() diff --git a/rhodecode/tests/controllers/test_utils.py b/rhodecode/tests/controllers/test_utils.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/controllers/test_utils.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + +from rhodecode.controllers import utils +from rhodecode.lib.vcs.exceptions import RepositoryError +import mock + + +@pytest.mark.parametrize('alias, expected', [ + ('hg', [None, 'name']), + ('git', [None, 'name']), + ('svn', ['name', 'raw_id']), +]) +def test_parse_path_ref_understands_format_ref_id_result(alias, expected): + repo = mock.Mock(alias=alias) + + # Formatting of reference ids as it is used by controllers + format_ref_id = utils.get_format_ref_id(repo) + formatted_ref_id = format_ref_id(name='name', raw_id='raw_id') + + # Parsing such a reference back as it is used by controllers + result = utils.parse_path_ref(formatted_ref_id) + + assert list(result) == expected + + +@pytest.mark.parametrize('ref, default_path, expected', [ + ('a', None, (None, 'a')), + ('a', 'path', ('path', 'a')), + ('p@a', 'path', ('p', 'a')), + ('p@a', None, ('p', 'a')), +]) +def test_parse_path_ref(ref, default_path, expected): + result = utils.parse_path_ref(ref, default_path) + assert list(result) == list(expected) + + +@pytest.mark.parametrize('alias, expected', [ + ('hg', 'name'), + ('git', 'name'), + ('svn', 'name@raw_id'), +]) +def test_format_ref_id(alias, expected): + repo = mock.Mock(alias=alias) + format_ref_id = utils.get_format_ref_id(repo) + result = format_ref_id(name='name', raw_id='raw_id') + assert result == expected + + +class TestGetCommit(object): + @pytest.mark.parametrize('ref_type', [None, 'book', 'tag', 'branch']) + def test_get_commit_from_ref_name_found(self, ref_type): + ref_name = 'a_None_id' + repo = mock.Mock() + scm_instance = repo.scm_instance() + scm_instance.branches = {ref_name: 'a_branch_id'} + scm_instance.tags = {ref_name: 'a_tag_id'} + scm_instance.bookmarks = {ref_name: 'a_book_id'} + + scm_instance.get_commit.return_value = 'test' + commit = utils.get_commit_from_ref_name(repo, ref_name, ref_type) + scm_instance.get_commit.assert_called_once_with('a_%s_id' % ref_type) + assert commit == 'test' + + @pytest.mark.parametrize('ref_type', ['book', 'tag', 'branch']) + def test_get_commit_from_ref_name_not_found(self, ref_type): + ref_name = 'invalid_ref' + repo = mock.Mock() + scm_instance = repo.scm_instance() + repo.scm_instance().branches = {} + repo.scm_instance().tags = {} + repo.scm_instance().bookmarks = {} + with pytest.raises(RepositoryError): + utils.get_commit_from_ref_name(repo, ref_name, ref_type) diff --git a/rhodecode/tests/database/conftest.py b/rhodecode/tests/database/conftest.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/conftest.py @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +from subprocess import Popen, PIPE +import os +import shutil +import sys +import tempfile + +import pytest +from sqlalchemy.engine import url + +from rhodecode.tests.fixture import TestINI + + +def _get_dbs_from_metafunc(metafunc): + if hasattr(metafunc.function, 'dbs'): + # Supported backends by this test function, created from + # pytest.mark.dbs + backends = metafunc.function.dbs.args + else: + backends = metafunc.config.getoption('--dbs') + return backends + + +def pytest_generate_tests(metafunc): + # Support test generation based on --dbs parameter + if 'db_backend' in metafunc.fixturenames: + requested_backends = set(metafunc.config.getoption('--dbs')) + backends = _get_dbs_from_metafunc(metafunc) + backends = requested_backends.intersection(backends) + # TODO: johbo: Disabling a backend did not work out with + # parametrization, find better way to achieve this. + if not backends: + metafunc.function._skip = True + metafunc.parametrize('db_backend_name', backends) + + +def pytest_collection_modifyitems(session, config, items): + remaining = [ + i for i in items if not getattr(i.obj, '_skip', False)] + items[:] = remaining + + +@pytest.fixture +def db_backend( + request, db_backend_name, pylons_config, tmpdir_factory): + basetemp = tmpdir_factory.getbasetemp().strpath + klass = _get_backend(db_backend_name) + + option_name = '--{}-connection-string'.format(db_backend_name) + connection_string = request.config.getoption(option_name) or None + + return klass( + config_file=pylons_config, basetemp=basetemp, + connection_string=connection_string) + + +def _get_backend(backend_type): + return { + 'sqlite': SQLiteDBBackend, + 'postgres': PostgresDBBackend, + 'mysql': MySQLDBBackend, + '': EmptyDBBackend + }[backend_type] + + +class DBBackend(object): + _store = os.path.dirname(os.path.abspath(__file__)) + _type = None + _base_ini_config = [{'app:main': {'vcs.start_server': 'false'}}] + _db_url = [{'app:main': {'sqlalchemy.db1.url': ''}}] + _base_db_name = 'rhodecode_test_db_backend' + + def __init__( + self, config_file, db_name=None, basetemp=None, + connection_string=None): + self.fixture_store = os.path.join(self._store, self._type) + self.db_name = db_name or self._base_db_name + self._base_ini_file = config_file + self.stderr = '' + self.stdout = '' + self._basetemp = basetemp or tempfile.gettempdir() + self._repos_location = os.path.join(self._basetemp, 'rc_test_repos') + self.connection_string = connection_string + + @property + def connection_string(self): + return self._connection_string + + @connection_string.setter + def connection_string(self, new_connection_string): + if not new_connection_string: + new_connection_string = self.get_default_connection_string() + else: + new_connection_string = new_connection_string.format( + db_name=self.db_name) + url_parts = url.make_url(new_connection_string) + self._connection_string = new_connection_string + self.user = url_parts.username + self.password = url_parts.password + self.host = url_parts.host + + def get_default_connection_string(self): + raise NotImplementedError('default connection_string is required.') + + def execute(self, cmd, env=None, *args): + """ + Runs command on the system with given ``args``. + """ + + command = cmd + ' ' + ' '.join(args) + sys.stdout.write(command) + + # Tell Python to use UTF-8 encoding out stdout + _env = os.environ.copy() + _env['PYTHONIOENCODING'] = 'UTF-8' + if env: + _env.update(env) + self.p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, env=_env) + self.stdout, self.stderr = self.p.communicate() + sys.stdout.write('COMMAND:'+command+'\n') + sys.stdout.write(self.stdout) + return self.stdout, self.stderr + + def assert_returncode_success(self): + assert self.p.returncode == 0, self.stderr + + def setup_rhodecode_db(self, ini_params=None, env=None): + if not ini_params: + ini_params = self._base_ini_config + + ini_params.extend(self._db_url) + with TestINI(self._base_ini_file, ini_params, + self._type, destroy=True) as _ini_file: + if not os.path.isdir(self._repos_location): + os.makedirs(self._repos_location) + self.execute( + "paster setup-rhodecode {0} --user=marcink " + "--email=marcin@rhodeocode.com --password={1} " + "--repos={2} --force-yes".format( + _ini_file, 'qweqwe', self._repos_location), env=env) + + def upgrade_database(self, ini_params=None): + if not ini_params: + ini_params = self._base_ini_config + ini_params.extend(self._db_url) + + test_ini = TestINI( + self._base_ini_file, ini_params, self._type, destroy=True) + with test_ini as ini_file: + if not os.path.isdir(self._repos_location): + os.makedirs(self._repos_location) + self.execute( + "paster upgrade-db {} --force-yes".format(ini_file)) + + def setup_db(self): + raise NotImplementedError + + def teardown_db(self): + raise NotImplementedError + + def import_dump(self, dumpname): + raise NotImplementedError + + +class EmptyDBBackend(DBBackend): + _type = '' + + def setup_db(self): + pass + + def teardown_db(self): + pass + + def import_dump(self, dumpname): + pass + + def assert_returncode_success(self): + assert True + + +class SQLiteDBBackend(DBBackend): + _type = 'sqlite' + + def get_default_connection_string(self): + return 'sqlite:///{}/{}.sqlite'.format(self._basetemp, self.db_name) + + def setup_db(self): + # dump schema for tests + # cp -v $TEST_DB_NAME + self._db_url = [{'app:main': { + 'sqlalchemy.db1.url': self.connection_string}}] + + def import_dump(self, dumpname): + dump = os.path.join(self.fixture_store, dumpname) + shutil.copy( + dump, + os.path.join(self._basetemp, '{0.db_name}.sqlite'.format(self))) + + def teardown_db(self): + self.execute("rm -rf {}.sqlite".format( + os.path.join(self._basetemp, self.db_name))) + + +class MySQLDBBackend(DBBackend): + _type = 'mysql' + + def get_default_connection_string(self): + return 'mysql://root:qweqwe@127.0.0.1/{}'.format(self.db_name) + + def setup_db(self): + # dump schema for tests + # mysqldump -uroot -pqweqwe $TEST_DB_NAME + self._db_url = [{'app:main': { + 'sqlalchemy.db1.url': self.connection_string}}] + self.execute("mysql -v -u{} -p{} -e 'create database '{}';'".format( + self.user, self.password, self.db_name)) + + def import_dump(self, dumpname): + dump = os.path.join(self.fixture_store, dumpname) + self.execute("mysql -u{} -p{} {} < {}".format( + self.user, self.password, self.db_name, dump)) + + def teardown_db(self): + self.execute("mysql -v -u{} -p{} -e 'drop database '{}';'".format( + self.user, self.password, self.db_name)) + + +class PostgresDBBackend(DBBackend): + _type = 'postgres' + + def get_default_connection_string(self): + return 'postgresql://postgres:qweqwe@localhost/{}'.format(self.db_name) + + def setup_db(self): + # dump schema for tests + # pg_dump -U postgres -h localhost $TEST_DB_NAME + self._db_url = [{'app:main': { + 'sqlalchemy.db1.url': + self.connection_string}}] + self.execute("PGPASSWORD={} psql -U {} -h localhost " + "-c 'create database '{}';'".format( + self.password, self.user, self.db_name)) + + def teardown_db(self): + self.execute("PGPASSWORD={} psql -U {} -h localhost " + "-c 'drop database if exists '{}';'".format( + self.password, self.user, self.db_name)) + + def import_dump(self, dumpname): + dump = os.path.join(self.fixture_store, dumpname) + self.execute( + "PGPASSWORD={} psql -U {} -h localhost -d {} -1 " + "-f {}".format( + self.password, self.user, self.db_name, dump)) diff --git a/rhodecode/tests/database/mysql/1.4.4.sql b/rhodecode/tests/database/mysql/1.4.4.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/mysql/1.4.4.sql @@ -0,0 +1,864 @@ +-- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: rhodecode +-- ------------------------------------------------------ +-- Server version 5.5.31-0ubuntu0.12.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `cache_invalidation` +-- + +DROP TABLE IF EXISTS `cache_invalidation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `cache_invalidation` ( + `cache_id` int(11) NOT NULL AUTO_INCREMENT, + `cache_key` varchar(255) DEFAULT NULL, + `cache_args` varchar(255) DEFAULT NULL, + `cache_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`cache_id`), + UNIQUE KEY `cache_id` (`cache_id`), + UNIQUE KEY `cache_key` (`cache_key`), + KEY `key_idx` (`cache_key`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_invalidation` +-- + +LOCK TABLES `cache_invalidation` WRITE; +/*!40000 ALTER TABLE `cache_invalidation` DISABLE KEYS */; +INSERT INTO `cache_invalidation` VALUES (1,'1RC/fakeclone','RC/fakeclone',0),(2,'1RC/muay','RC/muay',0),(3,'1RC/rc2/test2','RC/rc2/test2',0),(4,'1RC/rc2/test3','RC/rc2/test3',0),(5,'1RC/rc2/test4','RC/rc2/test4',0),(6,'1rhodecode-cli-gist','rhodecode-cli-gist',1),(7,'1RC/new','RC/new',0),(8,'1.rc_gist_store/32','.rc_gist_store/32',0),(9,'1vcs','vcs',1),(10,'1.rc_gist_store/36','.rc_gist_store/36',0),(11,'1.rc_gist_store/37','.rc_gist_store/37',0),(12,'1.rc_gist_store/39','.rc_gist_store/39',0),(13,'1remote-salt','remote-salt',1),(14,'1RC/INRC/trololo','RC/INRC/trololo',0),(15,'1quest','quest',1),(16,'1csa-hyperion','csa-hyperion',1),(17,'1rhodecode','rhodecode',1),(18,'1RC/origin-fork-fork','RC/origin-fork-fork',0),(19,'1.rc_gist_store/45','.rc_gist_store/45',0),(20,'1.rc_gist_store/44','.rc_gist_store/44',0),(21,'1.rc_gist_store/46','.rc_gist_store/46',0),(22,'1.rc_gist_store/41','.rc_gist_store/41',0),(23,'1.rc_gist_store/40','.rc_gist_store/40',0),(24,'1RC/gogo2','RC/gogo2',0),(25,'1.rc_gist_store/42','.rc_gist_store/42',0),(26,'1.rc_gist_store/49','.rc_gist_store/49',0),(27,'1.rc_gist_store/48','.rc_gist_store/48',0),(28,'1csa-collins','csa-collins',1),(29,'1.rc_gist_store/54','.rc_gist_store/54',0),(30,'1.rc_gist_store/55','.rc_gist_store/55',0),(31,'1.rc_gist_store/52','.rc_gist_store/52',0),(32,'1.rc_gist_store/53','.rc_gist_store/53',0),(33,'1.rc_gist_store/50','.rc_gist_store/50',0),(34,'1.rc_gist_store/51','.rc_gist_store/51',0),(35,'1BIG/android','BIG/android',0),(36,'1RC/gogo-fork','RC/gogo-fork',0),(37,'1RC/mygr/lol','RC/mygr/lol',0),(38,'1RC/hg-repo','RC/hg-repo',0),(39,'1RC/bin-ops','RC/bin-ops',0),(40,'1.rc_gist_store/xFvj6dFqqVK5vfsGP8PU','.rc_gist_store/xFvj6dFqqVK5vfsGP8PU',0),(41,'1rhodecode-git','rhodecode-git',1),(42,'1csa-io','csa-io',1),(43,'1RC/qweqwe-fork','RC/qweqwe-fork',0),(44,'1csa-libcloud','csa-libcloud',1),(45,'1waitress','waitress',1),(46,'1.rc_gist_store/8','.rc_gist_store/8',0),(47,'1.rc_gist_store/9','.rc_gist_store/9',0),(48,'1RC/foobar','RC/foobar',0),(49,'1.rc_gist_store/1','.rc_gist_store/1',0),(50,'1.rc_gist_store/3','.rc_gist_store/3',0),(51,'1.rc_gist_store/4','.rc_gist_store/4',0),(52,'1.rc_gist_store/5','.rc_gist_store/5',0),(53,'1.rc_gist_store/6','.rc_gist_store/6',0),(54,'1.rc_gist_store/7','.rc_gist_store/7',0),(55,'1csa-harmony','csa-harmony',1),(56,'1rhodecode-extensions','rhodecode-extensions',1),(57,'1csa-prometheus','csa-prometheus',1),(58,'1RC/empty-git','RC/empty-git',0),(59,'1csa-salt-states','csa-salt-states',1),(60,'1RC/Å‚Ä™cina','RC/Å‚Ä™cina',0),(61,'1rhodecode-premium','rhodecode-premium',1),(62,'1RC/qweqwe-fork2','RC/qweqwe-fork2',0),(63,'1RC/INRC/L2_NEW/lalalal','RC/INRC/L2_NEW/lalalal',0),(64,'1RC/INRC/L2_NEW/L3/repo_test_move','RC/INRC/L2_NEW/L3/repo_test_move',0),(65,'1RC/jap','RC/jap',0),(66,'1RC/origin','RC/origin',0),(67,'1rhodecode-cli-api','rhodecode-cli-api',1),(68,'1csa-armstrong','csa-armstrong',1),(69,'1.rc_gist_store/NAsB8cacjxnqdyZ8QUl3','.rc_gist_store/NAsB8cacjxnqdyZ8QUl3',0),(70,'1RC/lol/haha','RC/lol/haha',0),(71,'1enc-envelope','enc-envelope',1),(72,'1.rc_gist_store/43','.rc_gist_store/43',0),(73,'1RC/test','RC/test',0),(74,'1BIG/git','BIG/git',0),(75,'1RC/origin-fork','RC/origin-fork',0),(76,'1RC/trololo','RC/trololo',0),(77,'1.rc_gist_store/FLj8GunafFAVBnuTWDxU','.rc_gist_store/FLj8GunafFAVBnuTWDxU',0),(78,'1csa-unity','csa-unity',1),(79,'1RC/vcs-git','RC/vcs-git',0),(80,'1.rc_gist_store/12','.rc_gist_store/12',0),(81,'1.rc_gist_store/13','.rc_gist_store/13',0),(82,'1.rc_gist_store/10','.rc_gist_store/10',0),(83,'1.rc_gist_store/11','.rc_gist_store/11',0),(84,'1RC/kiall-nova','RC/kiall-nova',0),(85,'1RC/rc2/test','RC/rc2/test',0),(86,'1DOCS','DOCS',1),(87,'1RC/fork-remote','RC/fork-remote',0),(88,'1RC/git-pull-test','RC/git-pull-test',0),(89,'1pyramidpypi','pyramidpypi',1),(90,'1.rc_gist_store/aQpbufbhSac6FyvVHhmS','.rc_gist_store/aQpbufbhSac6FyvVHhmS',0),(91,'1csa-aldrin','csa-aldrin',1),(92,'1RC/Ä…qweqwe','RC/Ä…qweqwe',0),(93,'1.rc_gist_store/QL2GhrlKymNmrUJJy5js','.rc_gist_store/QL2GhrlKymNmrUJJy5js',0),(94,'1RC/git-test','RC/git-test',0),(95,'1salt','salt',1); +/*!40000 ALTER TABLE `cache_invalidation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_comments` +-- + +DROP TABLE IF EXISTS `changeset_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_comments` ( + `comment_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `revision` varchar(40) DEFAULT NULL, + `pull_request_id` int(11) DEFAULT NULL, + `line_no` varchar(10) DEFAULT NULL, + `hl_lines` varchar(512) DEFAULT NULL, + `f_path` varchar(1000) DEFAULT NULL, + `user_id` int(11) NOT NULL, + `text` mediumtext NOT NULL, + `created_on` datetime NOT NULL, + `modified_at` datetime NOT NULL, + PRIMARY KEY (`comment_id`), + KEY `repo_id` (`repo_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `cc_revision_idx` (`revision`), + CONSTRAINT `changeset_comments_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_comments_ibfk_2` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `changeset_comments_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_comments` +-- + +LOCK TABLES `changeset_comments` WRITE; +/*!40000 ALTER TABLE `changeset_comments` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_comments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_statuses` +-- + +DROP TABLE IF EXISTS `changeset_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_statuses` ( + `changeset_status_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `revision` varchar(40) NOT NULL, + `status` varchar(128) NOT NULL, + `changeset_comment_id` int(11) DEFAULT NULL, + `modified_at` datetime NOT NULL, + `version` int(11) NOT NULL, + `pull_request_id` int(11) DEFAULT NULL, + PRIMARY KEY (`changeset_status_id`), + UNIQUE KEY `repo_id` (`repo_id`,`revision`,`version`), + KEY `user_id` (`user_id`), + KEY `changeset_comment_id` (`changeset_comment_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `cs_version_idx` (`version`), + KEY `cs_revision_idx` (`revision`), + CONSTRAINT `changeset_statuses_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_statuses_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `changeset_statuses_ibfk_3` FOREIGN KEY (`changeset_comment_id`) REFERENCES `changeset_comments` (`comment_id`), + CONSTRAINT `changeset_statuses_ibfk_4` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_statuses` +-- + +LOCK TABLES `changeset_statuses` WRITE; +/*!40000 ALTER TABLE `changeset_statuses` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_statuses` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `db_migrate_version` +-- + +DROP TABLE IF EXISTS `db_migrate_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `db_migrate_version` ( + `repository_id` varchar(250) NOT NULL, + `repository_path` text, + `version` int(11) DEFAULT NULL, + PRIMARY KEY (`repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `db_migrate_version` +-- + +LOCK TABLES `db_migrate_version` WRITE; +/*!40000 ALTER TABLE `db_migrate_version` DISABLE KEYS */; +INSERT INTO `db_migrate_version` VALUES ('rhodecode_db_migrations','versions',7); +/*!40000 ALTER TABLE `db_migrate_version` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `groups` +-- + +DROP TABLE IF EXISTS `groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `groups` ( + `group_id` int(11) NOT NULL AUTO_INCREMENT, + `group_name` varchar(255) NOT NULL, + `group_parent_id` int(11) DEFAULT NULL, + `group_description` varchar(10000) DEFAULT NULL, + `enable_locking` tinyint(1) NOT NULL, + PRIMARY KEY (`group_id`), + UNIQUE KEY `group_id` (`group_id`), + UNIQUE KEY `group_name_2` (`group_name`), + UNIQUE KEY `group_name` (`group_name`,`group_parent_id`), + KEY `group_parent_id` (`group_parent_id`), + CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`group_parent_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `groups` +-- + +LOCK TABLES `groups` WRITE; +/*!40000 ALTER TABLE `groups` DISABLE KEYS */; +INSERT INTO `groups` VALUES (1,'RC',NULL,'RC group',0),(2,'RC/rc2',1,'RC/rc2 group',0),(3,'.rc_gist_store',NULL,'.rc_gist_store group',0),(4,'RC/INRC',1,'RC/INRC group',0),(5,'BIG',NULL,'BIG group',0),(6,'RC/mygr',1,'RC/mygr group',0),(7,'RC/INRC/L2_NEW',4,'RC/INRC/L2_NEW group',0),(8,'RC/INRC/L2_NEW/L3',7,'RC/INRC/L2_NEW/L3 group',0),(9,'RC/lol',1,'RC/lol group',0); +/*!40000 ALTER TABLE `groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notifications` +-- + +DROP TABLE IF EXISTS `notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `notifications` ( + `notification_id` int(11) NOT NULL AUTO_INCREMENT, + `subject` varchar(512) DEFAULT NULL, + `body` mediumtext, + `created_by` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `type` varchar(256) DEFAULT NULL, + PRIMARY KEY (`notification_id`), + KEY `created_by` (`created_by`), + KEY `notification_type_idx` (`type`(255)), + CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notifications` +-- + +LOCK TABLES `notifications` WRITE; +/*!40000 ALTER TABLE `notifications` DISABLE KEYS */; +/*!40000 ALTER TABLE `notifications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `permissions` +-- + +DROP TABLE IF EXISTS `permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `permissions` ( + `permission_id` int(11) NOT NULL AUTO_INCREMENT, + `permission_name` varchar(255) DEFAULT NULL, + `permission_longname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`permission_id`), + UNIQUE KEY `permission_id` (`permission_id`), + KEY `p_perm_name_idx` (`permission_name`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `permissions` +-- + +LOCK TABLES `permissions` WRITE; +/*!40000 ALTER TABLE `permissions` DISABLE KEYS */; +INSERT INTO `permissions` VALUES (1,'repository.none','repository.none'),(2,'repository.read','repository.read'),(3,'repository.write','repository.write'),(4,'repository.admin','repository.admin'),(5,'group.none','group.none'),(6,'group.read','group.read'),(7,'group.write','group.write'),(8,'group.admin','group.admin'),(9,'hg.admin','hg.admin'),(10,'hg.create.none','hg.create.none'),(11,'hg.create.repository','hg.create.repository'),(12,'hg.fork.none','hg.fork.none'),(13,'hg.fork.repository','hg.fork.repository'),(14,'hg.register.none','hg.register.none'),(15,'hg.register.manual_activate','hg.register.manual_activate'),(16,'hg.register.auto_activate','hg.register.auto_activate'); +/*!40000 ALTER TABLE `permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_request_reviewers` +-- + +DROP TABLE IF EXISTS `pull_request_reviewers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_request_reviewers` ( + `pull_requests_reviewers_id` int(11) NOT NULL AUTO_INCREMENT, + `pull_request_id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`pull_requests_reviewers_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `pull_request_reviewers_ibfk_1` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `pull_request_reviewers_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_request_reviewers` +-- + +LOCK TABLES `pull_request_reviewers` WRITE; +/*!40000 ALTER TABLE `pull_request_reviewers` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_request_reviewers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_requests` +-- + +DROP TABLE IF EXISTS `pull_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_requests` ( + `pull_request_id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(256) DEFAULT NULL, + `description` text, + `status` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `user_id` int(11) NOT NULL, + `revisions` text, + `org_repo_id` int(11) NOT NULL, + `org_ref` varchar(256) NOT NULL, + `other_repo_id` int(11) NOT NULL, + `other_ref` varchar(256) NOT NULL, + PRIMARY KEY (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `org_repo_id` (`org_repo_id`), + KEY `other_repo_id` (`other_repo_id`), + CONSTRAINT `pull_requests_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `pull_requests_ibfk_2` FOREIGN KEY (`org_repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `pull_requests_ibfk_3` FOREIGN KEY (`other_repo_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_requests` +-- + +LOCK TABLES `pull_requests` WRITE; +/*!40000 ALTER TABLE `pull_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repo_to_perm` +-- + +DROP TABLE IF EXISTS `repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repo_to_perm` ( + `repo_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`repo_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`repository_id`,`permission_id`), + UNIQUE KEY `repo_to_perm_id` (`repo_to_perm_id`), + KEY `permission_id` (`permission_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `repo_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repo_to_perm` +-- + +LOCK TABLES `repo_to_perm` WRITE; +/*!40000 ALTER TABLE `repo_to_perm` DISABLE KEYS */; +INSERT INTO `repo_to_perm` VALUES (1,1,2,1),(2,1,2,2),(3,1,2,3),(4,1,2,4),(5,1,2,5),(6,1,2,6),(7,1,2,7),(8,1,2,8),(9,1,2,9),(10,1,2,10),(11,1,2,11),(12,1,2,12),(13,1,2,13),(14,1,2,14),(15,1,2,15),(16,1,2,16),(17,1,2,17),(18,1,2,18),(19,1,2,19),(20,1,2,20),(21,1,2,21),(22,1,2,22),(23,1,2,23),(24,1,2,24),(25,1,2,25),(26,1,2,26),(27,1,2,27),(28,1,2,28),(29,1,2,29),(30,1,2,30),(31,1,2,31),(32,1,2,32),(33,1,2,33),(34,1,2,34),(35,1,2,35),(36,1,2,36),(37,1,2,37),(38,1,2,38),(39,1,2,39),(40,1,2,40),(41,1,2,41),(42,1,2,42),(43,1,2,43),(44,1,2,44),(45,1,2,45),(46,1,2,46),(47,1,2,47),(48,1,2,48),(49,1,2,49),(50,1,2,50),(51,1,2,51),(52,1,2,52),(53,1,2,53),(54,1,2,54),(55,1,2,55),(56,1,2,56),(57,1,2,57),(58,1,2,58),(59,1,2,59),(60,1,2,60),(61,1,2,61),(62,1,2,62),(63,1,2,63),(64,1,2,64),(65,1,2,65),(66,1,2,66),(67,1,2,67),(68,1,2,68),(69,1,2,69),(70,1,2,70),(71,1,2,71),(72,1,2,72),(73,1,2,73),(74,1,2,74),(75,1,2,75),(76,1,2,76),(77,1,2,77),(78,1,2,78),(79,1,2,79),(80,1,2,80),(81,1,2,81),(82,1,2,82),(83,1,2,83),(84,1,2,84),(85,1,2,85),(86,1,2,86),(87,1,2,87),(88,1,2,88),(89,1,2,89),(90,1,2,90),(91,1,2,91),(92,1,2,92),(93,1,2,93),(94,1,2,94),(95,1,2,95); +/*!40000 ALTER TABLE `repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories` +-- + +DROP TABLE IF EXISTS `repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories` ( + `repo_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_name` varchar(255) NOT NULL, + `clone_uri` varchar(255) DEFAULT NULL, + `repo_type` varchar(255) NOT NULL, + `user_id` int(11) NOT NULL, + `private` tinyint(1) DEFAULT NULL, + `statistics` tinyint(1) DEFAULT NULL, + `downloads` tinyint(1) DEFAULT NULL, + `description` varchar(10000) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `landing_revision` varchar(255) NOT NULL, + `enable_locking` tinyint(1) NOT NULL, + `locked` varchar(255) DEFAULT NULL, + `fork_id` int(11) DEFAULT NULL, + `group_id` int(11) DEFAULT NULL, + PRIMARY KEY (`repo_id`), + UNIQUE KEY `repo_name` (`repo_name`), + UNIQUE KEY `repo_id` (`repo_id`), + UNIQUE KEY `repo_name_2` (`repo_name`), + KEY `user_id` (`user_id`), + KEY `fork_id` (`fork_id`), + KEY `group_id` (`group_id`), + KEY `r_repo_name_idx` (`repo_name`), + CONSTRAINT `repositories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repositories_ibfk_2` FOREIGN KEY (`fork_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `repositories_ibfk_3` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories` +-- + +LOCK TABLES `repositories` WRITE; +/*!40000 ALTER TABLE `repositories` DISABLE KEYS */; +INSERT INTO `repositories` VALUES (1,'RC/fakeclone','http://user@vm/RC/fakeclone','git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:03','2013-05-29 14:10:03','tip',0,NULL,NULL,1),(2,'RC/muay',NULL,'hg',2,0,0,1,'RC/muay repository','2013-05-29 14:10:03','2013-05-29 14:10:03','tip',0,NULL,NULL,1),(3,'RC/rc2/test2',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,2),(4,'RC/rc2/test3',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,2),(5,'RC/rc2/test4',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,2),(6,'rhodecode-cli-gist',NULL,'hg',2,0,0,1,'rhodecode-cli-gist repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(7,'RC/new',NULL,'hg',2,0,0,1,'RC/new repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,1),(8,'.rc_gist_store/32',NULL,'hg',2,0,0,1,'.rc_gist_store/32 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(9,'vcs',NULL,'hg',2,0,0,1,'vcs repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(10,'.rc_gist_store/36',NULL,'hg',2,0,0,1,'.rc_gist_store/36 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(11,'.rc_gist_store/37',NULL,'hg',2,0,0,1,'.rc_gist_store/37 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(12,'.rc_gist_store/39',NULL,'hg',2,0,0,1,'.rc_gist_store/39 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(13,'remote-salt',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(14,'RC/INRC/trololo',NULL,'hg',2,0,0,1,'RC/INRC/trololo repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,4),(15,'quest',NULL,'hg',2,0,0,1,'quest repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(16,'csa-hyperion',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(17,'rhodecode',NULL,'hg',2,0,0,1,'rhodecode repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(18,'RC/origin-fork-fork',NULL,'hg',2,0,0,1,'RC/origin-fork-fork repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,1),(19,'.rc_gist_store/45',NULL,'hg',2,0,0,1,'.rc_gist_store/45 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(20,'.rc_gist_store/44',NULL,'hg',2,0,0,1,'.rc_gist_store/44 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(21,'.rc_gist_store/46',NULL,'hg',2,0,0,1,'.rc_gist_store/46 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(22,'.rc_gist_store/41',NULL,'hg',2,0,0,1,'.rc_gist_store/41 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(23,'.rc_gist_store/40',NULL,'hg',2,0,0,1,'.rc_gist_store/40 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(24,'RC/gogo2',NULL,'hg',2,0,0,1,'RC/gogo2 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,1),(25,'.rc_gist_store/42',NULL,'hg',2,0,0,1,'.rc_gist_store/42 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(26,'.rc_gist_store/49',NULL,'hg',2,0,0,1,'.rc_gist_store/49 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(27,'.rc_gist_store/48',NULL,'hg',2,0,0,1,'.rc_gist_store/48 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(28,'csa-collins',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,NULL),(29,'.rc_gist_store/54',NULL,'hg',2,0,0,1,'.rc_gist_store/54 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(30,'.rc_gist_store/55',NULL,'hg',2,0,0,1,'.rc_gist_store/55 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(31,'.rc_gist_store/52',NULL,'hg',2,0,0,1,'.rc_gist_store/52 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(32,'.rc_gist_store/53',NULL,'hg',2,0,0,1,'.rc_gist_store/53 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(33,'.rc_gist_store/50',NULL,'hg',2,0,0,1,'.rc_gist_store/50 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(34,'.rc_gist_store/51',NULL,'hg',2,0,0,1,'.rc_gist_store/51 repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,3),(35,'BIG/android',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,5),(36,'RC/gogo-fork',NULL,'hg',2,0,0,1,'RC/gogo-fork repository','2013-05-29 14:10:04','2013-05-29 14:10:04','tip',0,NULL,NULL,1),(37,'RC/mygr/lol',NULL,'hg',2,0,0,1,'RC/mygr/lol repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,6),(38,'RC/hg-repo',NULL,'hg',2,0,0,1,'RC/hg-repo repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(39,'RC/bin-ops',NULL,'hg',2,0,0,1,'RC/bin-ops repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(40,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU',NULL,'hg',2,0,0,1,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(41,'rhodecode-git',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(42,'csa-io',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(43,'RC/qweqwe-fork',NULL,'hg',2,0,0,1,'RC/qweqwe-fork repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(44,'csa-libcloud',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(45,'waitress',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(46,'.rc_gist_store/8',NULL,'hg',2,0,0,1,'.rc_gist_store/8 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(47,'.rc_gist_store/9',NULL,'hg',2,0,0,1,'.rc_gist_store/9 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(48,'RC/foobar',NULL,'hg',2,0,0,1,'RC/foobar repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(49,'.rc_gist_store/1',NULL,'hg',2,0,0,1,'.rc_gist_store/1 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(50,'.rc_gist_store/3',NULL,'hg',2,0,0,1,'.rc_gist_store/3 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(51,'.rc_gist_store/4',NULL,'hg',2,0,0,1,'.rc_gist_store/4 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(52,'.rc_gist_store/5',NULL,'hg',2,0,0,1,'.rc_gist_store/5 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(53,'.rc_gist_store/6',NULL,'hg',2,0,0,1,'.rc_gist_store/6 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(54,'.rc_gist_store/7',NULL,'hg',2,0,0,1,'.rc_gist_store/7 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,3),(55,'csa-harmony',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(56,'rhodecode-extensions',NULL,'hg',2,0,0,1,'rhodecode-extensions repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(57,'csa-prometheus',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(58,'RC/empty-git',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(59,'csa-salt-states',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(60,'RC/Å‚Ä™cina',NULL,'hg',2,0,0,1,'RC/Å‚Ä™cina repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(61,'rhodecode-premium',NULL,'hg',2,0,0,1,'rhodecode-premium repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,NULL),(62,'RC/qweqwe-fork2',NULL,'hg',2,0,0,1,'RC/qweqwe-fork2 repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(63,'RC/INRC/L2_NEW/lalalal',NULL,'hg',2,0,0,1,'RC/INRC/L2_NEW/lalalal repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,7),(64,'RC/INRC/L2_NEW/L3/repo_test_move',NULL,'hg',2,0,0,1,'RC/INRC/L2_NEW/L3/repo_test_move repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,8),(65,'RC/jap',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(66,'RC/origin',NULL,'hg',2,0,0,1,'RC/origin repository','2013-05-29 14:10:05','2013-05-29 14:10:05','tip',0,NULL,NULL,1),(67,'rhodecode-cli-api',NULL,'hg',2,0,0,1,'rhodecode-cli-api repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(68,'csa-armstrong',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(69,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3',NULL,'hg',2,0,0,1,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(70,'RC/lol/haha',NULL,'hg',2,0,0,1,'RC/lol/haha repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,9),(71,'enc-envelope',NULL,'hg',2,0,0,1,'enc-envelope repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(72,'.rc_gist_store/43',NULL,'hg',2,0,0,1,'.rc_gist_store/43 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(73,'RC/test',NULL,'hg',2,0,0,1,'RC/test repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(74,'BIG/git',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,5),(75,'RC/origin-fork',NULL,'hg',2,0,0,1,'RC/origin-fork repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(76,'RC/trololo',NULL,'hg',2,0,0,1,'RC/trololo repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(77,'.rc_gist_store/FLj8GunafFAVBnuTWDxU',NULL,'hg',2,0,0,1,'.rc_gist_store/FLj8GunafFAVBnuTWDxU repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(78,'csa-unity',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(79,'RC/vcs-git',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(80,'.rc_gist_store/12',NULL,'hg',2,0,0,1,'.rc_gist_store/12 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(81,'.rc_gist_store/13',NULL,'hg',2,0,0,1,'.rc_gist_store/13 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(82,'.rc_gist_store/10',NULL,'hg',2,0,0,1,'.rc_gist_store/10 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(83,'.rc_gist_store/11',NULL,'hg',2,0,0,1,'.rc_gist_store/11 repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(84,'RC/kiall-nova',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(85,'RC/rc2/test',NULL,'hg',2,0,0,1,'RC/rc2/test repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,2),(86,'DOCS',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(87,'RC/fork-remote',NULL,'hg',2,0,0,1,'RC/fork-remote repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(88,'RC/git-pull-test',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(89,'pyramidpypi',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(90,'.rc_gist_store/aQpbufbhSac6FyvVHhmS',NULL,'hg',2,0,0,1,'.rc_gist_store/aQpbufbhSac6FyvVHhmS repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(91,'csa-aldrin',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL),(92,'RC/Ä…qweqwe',NULL,'hg',2,0,0,1,'RC/Ä…qweqwe repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(93,'.rc_gist_store/QL2GhrlKymNmrUJJy5js',NULL,'hg',2,0,0,1,'.rc_gist_store/QL2GhrlKymNmrUJJy5js repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,3),(94,'RC/git-test',NULL,'git',2,0,0,1,'Unnamed repository','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,1),(95,'salt',NULL,'git',2,0,0,1,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:10:06','2013-05-29 14:10:06','tip',0,NULL,NULL,NULL); +/*!40000 ALTER TABLE `repositories` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_settings` +-- + +DROP TABLE IF EXISTS `rhodecode_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_settings` ( + `app_settings_id` int(11) NOT NULL AUTO_INCREMENT, + `app_settings_name` varchar(255) DEFAULT NULL, + `app_settings_value` varchar(255) DEFAULT NULL, + PRIMARY KEY (`app_settings_id`), + UNIQUE KEY `app_settings_id` (`app_settings_id`), + UNIQUE KEY `app_settings_name` (`app_settings_name`) +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_settings` +-- + +LOCK TABLES `rhodecode_settings` WRITE; +/*!40000 ALTER TABLE `rhodecode_settings` DISABLE KEYS */; +INSERT INTO `rhodecode_settings` VALUES (1,'realm','RhodeCode authentication'),(2,'title','RhodeCode'),(3,'ga_code',''),(4,'show_public_icon','True'),(5,'show_private_icon','True'),(6,'stylify_metatags','True'),(7,'ldap_active','false'),(8,'ldap_host',''),(9,'ldap_port','389'),(10,'ldap_tls_kind','PLAIN'),(11,'ldap_tls_reqcert',''),(12,'ldap_dn_user',''),(13,'ldap_dn_pass',''),(14,'ldap_base_dn',''),(15,'ldap_filter',''),(16,'ldap_search_scope',''),(17,'ldap_attr_login',''),(18,'ldap_attr_firstname',''),(19,'ldap_attr_lastname',''),(20,'ldap_attr_email',''); +/*!40000 ALTER TABLE `rhodecode_settings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_ui` +-- + +DROP TABLE IF EXISTS `rhodecode_ui`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_ui` ( + `ui_id` int(11) NOT NULL AUTO_INCREMENT, + `ui_section` varchar(255) DEFAULT NULL, + `ui_key` varchar(255) DEFAULT NULL, + `ui_value` varchar(255) DEFAULT NULL, + `ui_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ui_id`), + UNIQUE KEY `ui_id` (`ui_id`), + UNIQUE KEY `ui_key` (`ui_key`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_ui` +-- + +LOCK TABLES `rhodecode_ui` WRITE; +/*!40000 ALTER TABLE `rhodecode_ui` DISABLE KEYS */; +INSERT INTO `rhodecode_ui` VALUES (1,'hooks','changegroup.update','hg update >&2',1),(2,'hooks','changegroup.repo_size','python:rhodecode.lib.hooks.repo_size',1),(3,'hooks','changegroup.push_logger','python:rhodecode.lib.hooks.log_push_action',1),(4,'hooks','prechangegroup.pre_push','python:rhodecode.lib.hooks.pre_push',1),(5,'hooks','outgoing.pull_logger','python:rhodecode.lib.hooks.log_pull_action',1),(6,'hooks','preoutgoing.pre_pull','python:rhodecode.lib.hooks.pre_pull',1),(7,'extensions','largefiles','',1),(8,'extensions','hgsubversion','',0),(9,'extensions','hggit','',0),(10,'web','push_ssl','1',1),(11,'web','allow_archive','gz zip bz2',1),(12,'web','allow_push','*',1),(13,'web','baseurl','/',1),(14,'paths','/','/mnt/hgfs/workspace-python',1); +/*!40000 ALTER TABLE `rhodecode_ui` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `statistics` +-- + +DROP TABLE IF EXISTS `statistics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `statistics` ( + `stat_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `stat_on_revision` int(11) NOT NULL, + `commit_activity` mediumblob NOT NULL, + `commit_activity_combined` blob NOT NULL, + `languages` mediumblob NOT NULL, + PRIMARY KEY (`stat_id`), + UNIQUE KEY `repository_id` (`repository_id`), + UNIQUE KEY `stat_id` (`stat_id`), + UNIQUE KEY `repository_id_2` (`repository_id`), + CONSTRAINT `statistics_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `statistics` +-- + +LOCK TABLES `statistics` WRITE; +/*!40000 ALTER TABLE `statistics` DISABLE KEYS */; +/*!40000 ALTER TABLE `statistics` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_email_map` +-- + +DROP TABLE IF EXISTS `user_email_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_email_map` ( + `email_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + PRIMARY KEY (`email_id`), + UNIQUE KEY `email_id` (`email_id`), + UNIQUE KEY `email` (`email`), + KEY `user_id` (`user_id`), + KEY `uem_email_idx` (`email`), + CONSTRAINT `user_email_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_email_map` +-- + +LOCK TABLES `user_email_map` WRITE; +/*!40000 ALTER TABLE `user_email_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_email_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_followings` +-- + +DROP TABLE IF EXISTS `user_followings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_followings` ( + `user_following_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `follows_repository_id` int(11) DEFAULT NULL, + `follows_user_id` int(11) DEFAULT NULL, + `follows_from` datetime DEFAULT NULL, + PRIMARY KEY (`user_following_id`), + UNIQUE KEY `user_following_id` (`user_following_id`), + UNIQUE KEY `user_id` (`user_id`,`follows_repository_id`), + UNIQUE KEY `user_id_2` (`user_id`,`follows_user_id`), + KEY `follows_repository_id` (`follows_repository_id`), + KEY `follows_user_id` (`follows_user_id`), + CONSTRAINT `user_followings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_followings_ibfk_2` FOREIGN KEY (`follows_repository_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `user_followings_ibfk_3` FOREIGN KEY (`follows_user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_followings` +-- + +LOCK TABLES `user_followings` WRITE; +/*!40000 ALTER TABLE `user_followings` DISABLE KEYS */; +INSERT INTO `user_followings` VALUES (1,2,1,NULL,'2013-05-29 14:10:03'),(2,2,2,NULL,'2013-05-29 14:10:03'),(3,2,3,NULL,'2013-05-29 14:10:04'),(4,2,4,NULL,'2013-05-29 14:10:04'),(5,2,5,NULL,'2013-05-29 14:10:04'),(6,2,6,NULL,'2013-05-29 14:10:04'),(7,2,7,NULL,'2013-05-29 14:10:04'),(8,2,8,NULL,'2013-05-29 14:10:04'),(9,2,9,NULL,'2013-05-29 14:10:04'),(10,2,10,NULL,'2013-05-29 14:10:04'),(11,2,11,NULL,'2013-05-29 14:10:04'),(12,2,12,NULL,'2013-05-29 14:10:04'),(13,2,13,NULL,'2013-05-29 14:10:04'),(14,2,14,NULL,'2013-05-29 14:10:04'),(15,2,15,NULL,'2013-05-29 14:10:04'),(16,2,16,NULL,'2013-05-29 14:10:04'),(17,2,17,NULL,'2013-05-29 14:10:04'),(18,2,18,NULL,'2013-05-29 14:10:04'),(19,2,19,NULL,'2013-05-29 14:10:04'),(20,2,20,NULL,'2013-05-29 14:10:04'),(21,2,21,NULL,'2013-05-29 14:10:04'),(22,2,22,NULL,'2013-05-29 14:10:04'),(23,2,23,NULL,'2013-05-29 14:10:04'),(24,2,24,NULL,'2013-05-29 14:10:04'),(25,2,25,NULL,'2013-05-29 14:10:04'),(26,2,26,NULL,'2013-05-29 14:10:04'),(27,2,27,NULL,'2013-05-29 14:10:04'),(28,2,28,NULL,'2013-05-29 14:10:04'),(29,2,29,NULL,'2013-05-29 14:10:04'),(30,2,30,NULL,'2013-05-29 14:10:04'),(31,2,31,NULL,'2013-05-29 14:10:04'),(32,2,32,NULL,'2013-05-29 14:10:04'),(33,2,33,NULL,'2013-05-29 14:10:04'),(34,2,34,NULL,'2013-05-29 14:10:04'),(35,2,35,NULL,'2013-05-29 14:10:04'),(36,2,36,NULL,'2013-05-29 14:10:05'),(37,2,37,NULL,'2013-05-29 14:10:05'),(38,2,38,NULL,'2013-05-29 14:10:05'),(39,2,39,NULL,'2013-05-29 14:10:05'),(40,2,40,NULL,'2013-05-29 14:10:05'),(41,2,41,NULL,'2013-05-29 14:10:05'),(42,2,42,NULL,'2013-05-29 14:10:05'),(43,2,43,NULL,'2013-05-29 14:10:05'),(44,2,44,NULL,'2013-05-29 14:10:05'),(45,2,45,NULL,'2013-05-29 14:10:05'),(46,2,46,NULL,'2013-05-29 14:10:05'),(47,2,47,NULL,'2013-05-29 14:10:05'),(48,2,48,NULL,'2013-05-29 14:10:05'),(49,2,49,NULL,'2013-05-29 14:10:05'),(50,2,50,NULL,'2013-05-29 14:10:05'),(51,2,51,NULL,'2013-05-29 14:10:05'),(52,2,52,NULL,'2013-05-29 14:10:05'),(53,2,53,NULL,'2013-05-29 14:10:05'),(54,2,54,NULL,'2013-05-29 14:10:05'),(55,2,55,NULL,'2013-05-29 14:10:05'),(56,2,56,NULL,'2013-05-29 14:10:05'),(57,2,57,NULL,'2013-05-29 14:10:05'),(58,2,58,NULL,'2013-05-29 14:10:05'),(59,2,59,NULL,'2013-05-29 14:10:05'),(60,2,60,NULL,'2013-05-29 14:10:05'),(61,2,61,NULL,'2013-05-29 14:10:05'),(62,2,62,NULL,'2013-05-29 14:10:05'),(63,2,63,NULL,'2013-05-29 14:10:05'),(64,2,64,NULL,'2013-05-29 14:10:05'),(65,2,65,NULL,'2013-05-29 14:10:05'),(66,2,66,NULL,'2013-05-29 14:10:06'),(67,2,67,NULL,'2013-05-29 14:10:06'),(68,2,68,NULL,'2013-05-29 14:10:06'),(69,2,69,NULL,'2013-05-29 14:10:06'),(70,2,70,NULL,'2013-05-29 14:10:06'),(71,2,71,NULL,'2013-05-29 14:10:06'),(72,2,72,NULL,'2013-05-29 14:10:06'),(73,2,73,NULL,'2013-05-29 14:10:06'),(74,2,74,NULL,'2013-05-29 14:10:06'),(75,2,75,NULL,'2013-05-29 14:10:06'),(76,2,76,NULL,'2013-05-29 14:10:06'),(77,2,77,NULL,'2013-05-29 14:10:06'),(78,2,78,NULL,'2013-05-29 14:10:06'),(79,2,79,NULL,'2013-05-29 14:10:06'),(80,2,80,NULL,'2013-05-29 14:10:06'),(81,2,81,NULL,'2013-05-29 14:10:06'),(82,2,82,NULL,'2013-05-29 14:10:06'),(83,2,83,NULL,'2013-05-29 14:10:06'),(84,2,84,NULL,'2013-05-29 14:10:06'),(85,2,85,NULL,'2013-05-29 14:10:06'),(86,2,86,NULL,'2013-05-29 14:10:06'),(87,2,87,NULL,'2013-05-29 14:10:06'),(88,2,88,NULL,'2013-05-29 14:10:06'),(89,2,89,NULL,'2013-05-29 14:10:06'),(90,2,90,NULL,'2013-05-29 14:10:06'),(91,2,91,NULL,'2013-05-29 14:10:06'),(92,2,92,NULL,'2013-05-29 14:10:06'),(93,2,93,NULL,'2013-05-29 14:10:06'),(94,2,94,NULL,'2013-05-29 14:10:06'),(95,2,95,NULL,'2013-05-29 14:10:06'); +/*!40000 ALTER TABLE `user_followings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_logs` +-- + +DROP TABLE IF EXISTS `user_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_logs` ( + `user_log_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `repository_id` int(11) DEFAULT NULL, + `repository_name` varchar(255) DEFAULT NULL, + `user_ip` varchar(255) DEFAULT NULL, + `action` mediumtext, + `action_date` datetime DEFAULT NULL, + PRIMARY KEY (`user_log_id`), + UNIQUE KEY `user_log_id` (`user_log_id`), + KEY `user_id` (`user_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `user_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_logs_ibfk_2` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=99 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_logs` +-- + +LOCK TABLES `user_logs` WRITE; +/*!40000 ALTER TABLE `user_logs` DISABLE KEYS */; +INSERT INTO `user_logs` VALUES (1,2,1,'RC/fakeclone','','started_following_repo','2013-05-29 14:10:03'),(2,2,2,'RC/muay','','started_following_repo','2013-05-29 14:10:03'),(3,2,3,'RC/rc2/test2','','started_following_repo','2013-05-29 14:10:04'),(4,2,4,'RC/rc2/test3','','started_following_repo','2013-05-29 14:10:04'),(5,2,5,'RC/rc2/test4','','started_following_repo','2013-05-29 14:10:04'),(6,2,6,'rhodecode-cli-gist','','started_following_repo','2013-05-29 14:10:04'),(7,2,7,'RC/new','','started_following_repo','2013-05-29 14:10:04'),(8,2,8,'.rc_gist_store/32','','started_following_repo','2013-05-29 14:10:04'),(9,2,9,'vcs','','started_following_repo','2013-05-29 14:10:04'),(10,2,10,'.rc_gist_store/36','','started_following_repo','2013-05-29 14:10:04'),(11,2,11,'.rc_gist_store/37','','started_following_repo','2013-05-29 14:10:04'),(12,2,12,'.rc_gist_store/39','','started_following_repo','2013-05-29 14:10:04'),(13,2,13,'remote-salt','','started_following_repo','2013-05-29 14:10:04'),(14,2,14,'RC/INRC/trololo','','started_following_repo','2013-05-29 14:10:04'),(15,2,15,'quest','','started_following_repo','2013-05-29 14:10:04'),(16,2,16,'csa-hyperion','','started_following_repo','2013-05-29 14:10:04'),(17,2,17,'rhodecode','','started_following_repo','2013-05-29 14:10:04'),(18,2,18,'RC/origin-fork-fork','','started_following_repo','2013-05-29 14:10:04'),(19,2,19,'.rc_gist_store/45','','started_following_repo','2013-05-29 14:10:04'),(20,2,20,'.rc_gist_store/44','','started_following_repo','2013-05-29 14:10:04'),(21,2,21,'.rc_gist_store/46','','started_following_repo','2013-05-29 14:10:04'),(22,2,22,'.rc_gist_store/41','','started_following_repo','2013-05-29 14:10:04'),(23,2,23,'.rc_gist_store/40','','started_following_repo','2013-05-29 14:10:04'),(24,2,24,'RC/gogo2','','started_following_repo','2013-05-29 14:10:04'),(25,2,25,'.rc_gist_store/42','','started_following_repo','2013-05-29 14:10:04'),(26,2,26,'.rc_gist_store/49','','started_following_repo','2013-05-29 14:10:04'),(27,2,27,'.rc_gist_store/48','','started_following_repo','2013-05-29 14:10:04'),(28,2,28,'csa-collins','','started_following_repo','2013-05-29 14:10:04'),(29,2,29,'.rc_gist_store/54','','started_following_repo','2013-05-29 14:10:04'),(30,2,30,'.rc_gist_store/55','','started_following_repo','2013-05-29 14:10:04'),(31,2,31,'.rc_gist_store/52','','started_following_repo','2013-05-29 14:10:04'),(32,2,32,'.rc_gist_store/53','','started_following_repo','2013-05-29 14:10:04'),(33,2,33,'.rc_gist_store/50','','started_following_repo','2013-05-29 14:10:04'),(34,2,34,'.rc_gist_store/51','','started_following_repo','2013-05-29 14:10:04'),(35,2,35,'BIG/android','','started_following_repo','2013-05-29 14:10:04'),(36,2,36,'RC/gogo-fork','','started_following_repo','2013-05-29 14:10:05'),(37,2,37,'RC/mygr/lol','','started_following_repo','2013-05-29 14:10:05'),(38,2,38,'RC/hg-repo','','started_following_repo','2013-05-29 14:10:05'),(39,2,39,'RC/bin-ops','','started_following_repo','2013-05-29 14:10:05'),(40,2,40,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU','','started_following_repo','2013-05-29 14:10:05'),(41,2,41,'rhodecode-git','','started_following_repo','2013-05-29 14:10:05'),(42,2,42,'csa-io','','started_following_repo','2013-05-29 14:10:05'),(43,2,43,'RC/qweqwe-fork','','started_following_repo','2013-05-29 14:10:05'),(44,2,44,'csa-libcloud','','started_following_repo','2013-05-29 14:10:05'),(45,2,45,'waitress','','started_following_repo','2013-05-29 14:10:05'),(46,2,46,'.rc_gist_store/8','','started_following_repo','2013-05-29 14:10:05'),(47,2,47,'.rc_gist_store/9','','started_following_repo','2013-05-29 14:10:05'),(48,2,48,'RC/foobar','','started_following_repo','2013-05-29 14:10:05'),(49,2,49,'.rc_gist_store/1','','started_following_repo','2013-05-29 14:10:05'),(50,2,50,'.rc_gist_store/3','','started_following_repo','2013-05-29 14:10:05'),(51,2,51,'.rc_gist_store/4','','started_following_repo','2013-05-29 14:10:05'),(52,2,52,'.rc_gist_store/5','','started_following_repo','2013-05-29 14:10:05'),(53,2,53,'.rc_gist_store/6','','started_following_repo','2013-05-29 14:10:05'),(54,2,54,'.rc_gist_store/7','','started_following_repo','2013-05-29 14:10:05'),(55,2,55,'csa-harmony','','started_following_repo','2013-05-29 14:10:05'),(56,2,56,'rhodecode-extensions','','started_following_repo','2013-05-29 14:10:05'),(57,2,57,'csa-prometheus','','started_following_repo','2013-05-29 14:10:05'),(58,2,58,'RC/empty-git','','started_following_repo','2013-05-29 14:10:05'),(59,2,59,'csa-salt-states','','started_following_repo','2013-05-29 14:10:05'),(60,2,60,'RC/Å‚Ä™cina','','started_following_repo','2013-05-29 14:10:05'),(61,2,61,'rhodecode-premium','','started_following_repo','2013-05-29 14:10:05'),(62,2,62,'RC/qweqwe-fork2','','started_following_repo','2013-05-29 14:10:05'),(63,2,63,'RC/INRC/L2_NEW/lalalal','','started_following_repo','2013-05-29 14:10:05'),(64,2,64,'RC/INRC/L2_NEW/L3/repo_test_move','','started_following_repo','2013-05-29 14:10:05'),(65,2,65,'RC/jap','','started_following_repo','2013-05-29 14:10:05'),(66,2,66,'RC/origin','','started_following_repo','2013-05-29 14:10:05'),(67,2,67,'rhodecode-cli-api','','started_following_repo','2013-05-29 14:10:06'),(68,2,68,'csa-armstrong','','started_following_repo','2013-05-29 14:10:06'),(69,2,69,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3','','started_following_repo','2013-05-29 14:10:06'),(70,2,70,'RC/lol/haha','','started_following_repo','2013-05-29 14:10:06'),(71,2,71,'enc-envelope','','started_following_repo','2013-05-29 14:10:06'),(72,2,72,'.rc_gist_store/43','','started_following_repo','2013-05-29 14:10:06'),(73,2,73,'RC/test','','started_following_repo','2013-05-29 14:10:06'),(74,2,74,'BIG/git','','started_following_repo','2013-05-29 14:10:06'),(75,2,75,'RC/origin-fork','','started_following_repo','2013-05-29 14:10:06'),(76,2,76,'RC/trololo','','started_following_repo','2013-05-29 14:10:06'),(77,2,77,'.rc_gist_store/FLj8GunafFAVBnuTWDxU','','started_following_repo','2013-05-29 14:10:06'),(78,2,78,'csa-unity','','started_following_repo','2013-05-29 14:10:06'),(79,2,79,'RC/vcs-git','','started_following_repo','2013-05-29 14:10:06'),(80,2,80,'.rc_gist_store/12','','started_following_repo','2013-05-29 14:10:06'),(81,2,81,'.rc_gist_store/13','','started_following_repo','2013-05-29 14:10:06'),(82,2,82,'.rc_gist_store/10','','started_following_repo','2013-05-29 14:10:06'),(83,2,83,'.rc_gist_store/11','','started_following_repo','2013-05-29 14:10:06'),(84,2,84,'RC/kiall-nova','','started_following_repo','2013-05-29 14:10:06'),(85,2,85,'RC/rc2/test','','started_following_repo','2013-05-29 14:10:06'),(86,2,86,'DOCS','','started_following_repo','2013-05-29 14:10:06'),(87,2,87,'RC/fork-remote','','started_following_repo','2013-05-29 14:10:06'),(88,2,88,'RC/git-pull-test','','started_following_repo','2013-05-29 14:10:06'),(89,2,89,'pyramidpypi','','started_following_repo','2013-05-29 14:10:06'),(90,2,90,'.rc_gist_store/aQpbufbhSac6FyvVHhmS','','started_following_repo','2013-05-29 14:10:06'),(91,2,91,'csa-aldrin','','started_following_repo','2013-05-29 14:10:06'),(92,2,92,'RC/Ä…qweqwe','','started_following_repo','2013-05-29 14:10:06'),(93,2,93,'.rc_gist_store/QL2GhrlKymNmrUJJy5js','','started_following_repo','2013-05-29 14:10:06'),(94,2,94,'RC/git-test','','started_following_repo','2013-05-29 14:10:06'),(95,2,95,'salt','','started_following_repo','2013-05-29 14:10:06'),(96,2,NULL,'','','admin_created_users_group:group2','2013-05-29 14:10:52'),(97,2,NULL,'','','admin_updated_users_group:group2','2013-05-29 14:10:57'),(98,2,NULL,'','','admin_created_user:qwe','2013-05-29 14:11:08'); +/*!40000 ALTER TABLE `user_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `user_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_repo_group_to_perm` ( + `group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`group_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`group_id`,`permission_id`), + UNIQUE KEY `group_to_perm_id` (`group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_repo_group_to_perm` +-- + +LOCK TABLES `user_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `user_repo_group_to_perm` DISABLE KEYS */; +INSERT INTO `user_repo_group_to_perm` VALUES (1,1,1,6),(2,1,2,6),(3,1,3,6),(4,1,4,6),(5,1,5,6),(6,1,6,6),(7,1,7,6),(8,1,8,6),(9,1,9,6); +/*!40000 ALTER TABLE `user_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_notification` +-- + +DROP TABLE IF EXISTS `user_to_notification`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_notification` ( + `user_id` int(11) NOT NULL, + `notification_id` int(11) NOT NULL, + `read` tinyint(1) DEFAULT NULL, + `sent_on` datetime DEFAULT NULL, + PRIMARY KEY (`user_id`,`notification_id`), + UNIQUE KEY `user_id` (`user_id`,`notification_id`), + KEY `notification_id` (`notification_id`), + CONSTRAINT `user_to_notification_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_notification_ibfk_2` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`notification_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_notification` +-- + +LOCK TABLES `user_to_notification` WRITE; +/*!40000 ALTER TABLE `user_to_notification` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_to_notification` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_perm` +-- + +DROP TABLE IF EXISTS `user_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_perm` ( + `user_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`user_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`permission_id`), + UNIQUE KEY `user_to_perm_id` (`user_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_perm` +-- + +LOCK TABLES `user_to_perm` WRITE; +/*!40000 ALTER TABLE `user_to_perm` DISABLE KEYS */; +INSERT INTO `user_to_perm` VALUES (4,1,2),(2,1,11),(3,1,13),(1,1,15); +/*!40000 ALTER TABLE `user_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + `admin` tinyint(1) DEFAULT NULL, + `firstname` varchar(255) DEFAULT NULL, + `lastname` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `last_login` datetime DEFAULT NULL, + `ldap_dn` varchar(255) DEFAULT NULL, + `api_key` varchar(255) DEFAULT NULL, + `inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `user_id` (`user_id`), + UNIQUE KEY `username` (`username`), + UNIQUE KEY `email` (`email`), + KEY `u_username_idx` (`username`), + KEY `u_email_idx` (`email`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'default','$2a$10$.kEwJNTCxwIh0ReQphLNi..a1EwNg/xhTzZCTlYanrJbe4hvCRVem',1,0,'Anonymous','User','anonymous@rhodecode.org',NULL,NULL,'14256045ac36c160e6b260d0ee75afaf035eee33',1),(2,'marcink','$2a$10$OsOsKSTCj7KdhqExE3NuV.cuduXJLH0ZOgglMq0nBP0Tjo6xD7KYS',1,1,'RhodeCode','Admin','marcin@appzonaut.com',NULL,NULL,'1bb94114e81e70a1a039260c9b4eb477c06c9b88',1),(3,'qwe','$2a$10$bN/GP86J2DMChvwI/0OmpeXJmD2B/Lchkju4PhXBCh6dCadoPv9tO',1,0,'qweqwe','qweqw','qweqwe@qwe.org',NULL,NULL,'6f5b83382ec01bd9ee728bd41db69c7dd90a63a2',1); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_group_to_perm` ( + `users_group_repo_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_repo_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`group_id`), + UNIQUE KEY `users_group_repo_group_to_perm_id` (`users_group_repo_group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_group_to_perm` +-- + +LOCK TABLES `users_group_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `repository_id` (`repository_id`,`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `users_group_id` (`users_group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_to_perm` +-- + +LOCK TABLES `users_group_repo_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_to_perm` +-- + +LOCK TABLES `users_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups` +-- + +DROP TABLE IF EXISTS `users_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups` ( + `users_group_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_name` varchar(255) NOT NULL, + `users_group_active` tinyint(1) DEFAULT NULL, + `users_group_inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`users_group_id`), + UNIQUE KEY `users_group_id` (`users_group_id`), + UNIQUE KEY `users_group_name` (`users_group_name`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups` +-- + +LOCK TABLES `users_groups` WRITE; +/*!40000 ALTER TABLE `users_groups` DISABLE KEYS */; +INSERT INTO `users_groups` VALUES (1,'group2',1,1); +/*!40000 ALTER TABLE `users_groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups_members` +-- + +DROP TABLE IF EXISTS `users_groups_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups_members` ( + `users_group_member_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_member_id`), + UNIQUE KEY `users_group_member_id` (`users_group_member_id`), + KEY `users_group_id` (`users_group_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `users_groups_members_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_groups_members_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups_members` +-- + +LOCK TABLES `users_groups_members` WRITE; +/*!40000 ALTER TABLE `users_groups_members` DISABLE KEYS */; +INSERT INTO `users_groups_members` VALUES (1,1,1),(2,1,2); +/*!40000 ALTER TABLE `users_groups_members` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2013-05-29 14:13:26 diff --git a/rhodecode/tests/database/mysql/1.5.0.sql b/rhodecode/tests/database/mysql/1.5.0.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/mysql/1.5.0.sql @@ -0,0 +1,863 @@ +-- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: rhodecode +-- ------------------------------------------------------ +-- Server version 5.5.31-0ubuntu0.12.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `cache_invalidation` +-- + +DROP TABLE IF EXISTS `cache_invalidation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `cache_invalidation` ( + `cache_id` int(11) NOT NULL AUTO_INCREMENT, + `cache_key` varchar(255) DEFAULT NULL, + `cache_args` varchar(255) DEFAULT NULL, + `cache_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`cache_id`), + UNIQUE KEY `cache_id` (`cache_id`), + UNIQUE KEY `cache_key` (`cache_key`), + KEY `key_idx` (`cache_key`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_invalidation` +-- + +LOCK TABLES `cache_invalidation` WRITE; +/*!40000 ALTER TABLE `cache_invalidation` DISABLE KEYS */; +INSERT INTO `cache_invalidation` VALUES (1,'1RC/fakeclone','RC/fakeclone',1),(2,'1RC/muay','RC/muay',0),(3,'1RC/rc2/test2','RC/rc2/test2',1),(4,'1RC/rc2/test3','RC/rc2/test3',1),(5,'1RC/rc2/test4','RC/rc2/test4',1),(6,'1rhodecode-cli-gist','rhodecode-cli-gist',0),(7,'1RC/new','RC/new',0),(8,'1.rc_gist_store/32','.rc_gist_store/32',0),(9,'1vcs','vcs',0),(10,'1.rc_gist_store/36','.rc_gist_store/36',0),(11,'1.rc_gist_store/37','.rc_gist_store/37',0),(12,'1.rc_gist_store/39','.rc_gist_store/39',0),(13,'1remote-salt','remote-salt',1),(14,'1RC/INRC/trololo','RC/INRC/trololo',0),(15,'1quest','quest',0),(16,'1csa-hyperion','csa-hyperion',1),(17,'1rhodecode','rhodecode',0),(18,'1RC/origin-fork-fork','RC/origin-fork-fork',0),(19,'1.rc_gist_store/45','.rc_gist_store/45',0),(20,'1.rc_gist_store/44','.rc_gist_store/44',0),(21,'1.rc_gist_store/46','.rc_gist_store/46',0),(22,'1.rc_gist_store/41','.rc_gist_store/41',0),(23,'1.rc_gist_store/40','.rc_gist_store/40',0),(24,'1RC/gogo2','RC/gogo2',0),(25,'1.rc_gist_store/42','.rc_gist_store/42',0),(26,'1.rc_gist_store/49','.rc_gist_store/49',0),(27,'1.rc_gist_store/48','.rc_gist_store/48',0),(28,'1csa-collins','csa-collins',1),(29,'1.rc_gist_store/54','.rc_gist_store/54',0),(30,'1.rc_gist_store/55','.rc_gist_store/55',0),(31,'1.rc_gist_store/52','.rc_gist_store/52',0),(32,'1.rc_gist_store/53','.rc_gist_store/53',0),(33,'1.rc_gist_store/50','.rc_gist_store/50',0),(34,'1.rc_gist_store/51','.rc_gist_store/51',0),(35,'1BIG/android','BIG/android',1),(36,'1RC/gogo-fork','RC/gogo-fork',0),(37,'1RC/mygr/lol','RC/mygr/lol',0),(38,'1RC/hg-repo','RC/hg-repo',0),(39,'1RC/bin-ops','RC/bin-ops',0),(40,'1.rc_gist_store/xFvj6dFqqVK5vfsGP8PU','.rc_gist_store/xFvj6dFqqVK5vfsGP8PU',0),(41,'1rhodecode-git','rhodecode-git',1),(42,'1csa-io','csa-io',1),(43,'1RC/qweqwe-fork','RC/qweqwe-fork',0),(44,'1csa-libcloud','csa-libcloud',1),(45,'1waitress','waitress',1),(46,'1.rc_gist_store/8','.rc_gist_store/8',0),(47,'1.rc_gist_store/9','.rc_gist_store/9',0),(48,'1RC/foobar','RC/foobar',0),(49,'1.rc_gist_store/1','.rc_gist_store/1',0),(50,'1.rc_gist_store/3','.rc_gist_store/3',0),(51,'1.rc_gist_store/4','.rc_gist_store/4',0),(52,'1.rc_gist_store/5','.rc_gist_store/5',0),(53,'1.rc_gist_store/6','.rc_gist_store/6',0),(54,'1.rc_gist_store/7','.rc_gist_store/7',0),(55,'1csa-harmony','csa-harmony',1),(56,'1RC/Å‚Ä™cina','RC/Å‚Ä™cina',0),(57,'1rhodecode-extensions','rhodecode-extensions',0),(58,'1csa-prometheus','csa-prometheus',1),(59,'1RC/empty-git','RC/empty-git',1),(60,'1csa-salt-states','csa-salt-states',1),(61,'1rhodecode-premium','rhodecode-premium',0),(62,'1RC/qweqwe-fork2','RC/qweqwe-fork2',0),(63,'1RC/INRC/L2_NEW/lalalal','RC/INRC/L2_NEW/lalalal',0),(64,'1RC/INRC/L2_NEW/L3/repo_test_move','RC/INRC/L2_NEW/L3/repo_test_move',0),(65,'1RC/jap','RC/jap',1),(66,'1RC/origin','RC/origin',0),(67,'1rhodecode-cli-api','rhodecode-cli-api',0),(68,'1csa-armstrong','csa-armstrong',1),(69,'1.rc_gist_store/NAsB8cacjxnqdyZ8QUl3','.rc_gist_store/NAsB8cacjxnqdyZ8QUl3',0),(70,'1RC/lol/haha','RC/lol/haha',0),(71,'1enc-envelope','enc-envelope',0),(72,'1.rc_gist_store/43','.rc_gist_store/43',0),(73,'1RC/test','RC/test',0),(74,'1BIG/git','BIG/git',1),(75,'1RC/origin-fork','RC/origin-fork',0),(76,'1RC/trololo','RC/trololo',0),(77,'1.rc_gist_store/FLj8GunafFAVBnuTWDxU','.rc_gist_store/FLj8GunafFAVBnuTWDxU',0),(78,'1RC/Ä…qweqwe','RC/Ä…qweqwe',0),(79,'1csa-unity','csa-unity',1),(80,'1RC/vcs-git','RC/vcs-git',1),(81,'1.rc_gist_store/12','.rc_gist_store/12',0),(82,'1.rc_gist_store/13','.rc_gist_store/13',0),(83,'1.rc_gist_store/10','.rc_gist_store/10',0),(84,'1.rc_gist_store/11','.rc_gist_store/11',0),(85,'1RC/kiall-nova','RC/kiall-nova',1),(86,'1RC/rc2/test','RC/rc2/test',0),(87,'1DOCS','DOCS',1),(88,'1RC/fork-remote','RC/fork-remote',0),(89,'1RC/git-pull-test','RC/git-pull-test',1),(90,'1pyramidpypi','pyramidpypi',1),(91,'1.rc_gist_store/aQpbufbhSac6FyvVHhmS','.rc_gist_store/aQpbufbhSac6FyvVHhmS',0),(92,'1csa-aldrin','csa-aldrin',1),(93,'1.rc_gist_store/QL2GhrlKymNmrUJJy5js','.rc_gist_store/QL2GhrlKymNmrUJJy5js',0),(94,'1RC/git-test','RC/git-test',1),(95,'1salt','salt',1); +/*!40000 ALTER TABLE `cache_invalidation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_comments` +-- + +DROP TABLE IF EXISTS `changeset_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_comments` ( + `comment_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `revision` varchar(40) DEFAULT NULL, + `pull_request_id` int(11) DEFAULT NULL, + `line_no` varchar(10) DEFAULT NULL, + `hl_lines` varchar(512) DEFAULT NULL, + `f_path` varchar(1000) DEFAULT NULL, + `user_id` int(11) NOT NULL, + `text` mediumtext NOT NULL, + `created_on` datetime NOT NULL, + `modified_at` datetime NOT NULL, + PRIMARY KEY (`comment_id`), + KEY `repo_id` (`repo_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `cc_revision_idx` (`revision`), + CONSTRAINT `changeset_comments_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_comments_ibfk_2` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `changeset_comments_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_comments` +-- + +LOCK TABLES `changeset_comments` WRITE; +/*!40000 ALTER TABLE `changeset_comments` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_comments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_statuses` +-- + +DROP TABLE IF EXISTS `changeset_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_statuses` ( + `changeset_status_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `revision` varchar(40) NOT NULL, + `status` varchar(128) NOT NULL, + `changeset_comment_id` int(11) DEFAULT NULL, + `modified_at` datetime NOT NULL, + `version` int(11) NOT NULL, + `pull_request_id` int(11) DEFAULT NULL, + PRIMARY KEY (`changeset_status_id`), + UNIQUE KEY `repo_id` (`repo_id`,`revision`,`version`), + KEY `user_id` (`user_id`), + KEY `changeset_comment_id` (`changeset_comment_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `cs_version_idx` (`version`), + KEY `cs_revision_idx` (`revision`), + CONSTRAINT `changeset_statuses_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_statuses_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `changeset_statuses_ibfk_3` FOREIGN KEY (`changeset_comment_id`) REFERENCES `changeset_comments` (`comment_id`), + CONSTRAINT `changeset_statuses_ibfk_4` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_statuses` +-- + +LOCK TABLES `changeset_statuses` WRITE; +/*!40000 ALTER TABLE `changeset_statuses` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_statuses` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `db_migrate_version` +-- + +DROP TABLE IF EXISTS `db_migrate_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `db_migrate_version` ( + `repository_id` varchar(250) NOT NULL, + `repository_path` text, + `version` int(11) DEFAULT NULL, + PRIMARY KEY (`repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `db_migrate_version` +-- + +LOCK TABLES `db_migrate_version` WRITE; +/*!40000 ALTER TABLE `db_migrate_version` DISABLE KEYS */; +INSERT INTO `db_migrate_version` VALUES ('rhodecode_db_migrations','versions',8); +/*!40000 ALTER TABLE `db_migrate_version` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `groups` +-- + +DROP TABLE IF EXISTS `groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `groups` ( + `group_id` int(11) NOT NULL AUTO_INCREMENT, + `group_name` varchar(255) NOT NULL, + `group_parent_id` int(11) DEFAULT NULL, + `group_description` varchar(10000) DEFAULT NULL, + `enable_locking` tinyint(1) NOT NULL, + PRIMARY KEY (`group_id`), + UNIQUE KEY `group_id` (`group_id`), + UNIQUE KEY `group_name_2` (`group_name`), + UNIQUE KEY `group_name` (`group_name`,`group_parent_id`), + KEY `group_parent_id` (`group_parent_id`), + CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`group_parent_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `groups` +-- + +LOCK TABLES `groups` WRITE; +/*!40000 ALTER TABLE `groups` DISABLE KEYS */; +INSERT INTO `groups` VALUES (1,'RC',NULL,'RC group',0),(2,'RC/rc2',1,'RC/rc2 group',0),(3,'.rc_gist_store',NULL,'.rc_gist_store group',0),(4,'RC/INRC',1,'RC/INRC group',0),(5,'BIG',NULL,'BIG group',0),(6,'RC/mygr',1,'RC/mygr group',0),(7,'RC/INRC/L2_NEW',4,'RC/INRC/L2_NEW group',0),(8,'RC/INRC/L2_NEW/L3',7,'RC/INRC/L2_NEW/L3 group',0),(9,'RC/lol',1,'RC/lol group',0); +/*!40000 ALTER TABLE `groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notifications` +-- + +DROP TABLE IF EXISTS `notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `notifications` ( + `notification_id` int(11) NOT NULL AUTO_INCREMENT, + `subject` varchar(512) DEFAULT NULL, + `body` mediumtext, + `created_by` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `type` varchar(256) DEFAULT NULL, + PRIMARY KEY (`notification_id`), + KEY `created_by` (`created_by`), + KEY `notification_type_idx` (`type`(255)), + CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notifications` +-- + +LOCK TABLES `notifications` WRITE; +/*!40000 ALTER TABLE `notifications` DISABLE KEYS */; +/*!40000 ALTER TABLE `notifications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `permissions` +-- + +DROP TABLE IF EXISTS `permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `permissions` ( + `permission_id` int(11) NOT NULL AUTO_INCREMENT, + `permission_name` varchar(255) DEFAULT NULL, + `permission_longname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`permission_id`), + UNIQUE KEY `permission_id` (`permission_id`), + KEY `p_perm_name_idx` (`permission_name`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `permissions` +-- + +LOCK TABLES `permissions` WRITE; +/*!40000 ALTER TABLE `permissions` DISABLE KEYS */; +INSERT INTO `permissions` VALUES (1,'repository.none','repository.none'),(2,'repository.read','repository.read'),(3,'repository.write','repository.write'),(4,'repository.admin','repository.admin'),(5,'group.none','group.none'),(6,'group.read','group.read'),(7,'group.write','group.write'),(8,'group.admin','group.admin'),(9,'hg.admin','hg.admin'),(10,'hg.create.none','hg.create.none'),(11,'hg.create.repository','hg.create.repository'),(12,'hg.fork.none','hg.fork.none'),(13,'hg.fork.repository','hg.fork.repository'),(14,'hg.register.none','hg.register.none'),(15,'hg.register.manual_activate','hg.register.manual_activate'),(16,'hg.register.auto_activate','hg.register.auto_activate'); +/*!40000 ALTER TABLE `permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_request_reviewers` +-- + +DROP TABLE IF EXISTS `pull_request_reviewers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_request_reviewers` ( + `pull_requests_reviewers_id` int(11) NOT NULL AUTO_INCREMENT, + `pull_request_id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`pull_requests_reviewers_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `pull_request_reviewers_ibfk_1` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `pull_request_reviewers_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_request_reviewers` +-- + +LOCK TABLES `pull_request_reviewers` WRITE; +/*!40000 ALTER TABLE `pull_request_reviewers` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_request_reviewers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_requests` +-- + +DROP TABLE IF EXISTS `pull_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_requests` ( + `pull_request_id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(256) DEFAULT NULL, + `description` text, + `status` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `user_id` int(11) NOT NULL, + `revisions` text, + `org_repo_id` int(11) NOT NULL, + `org_ref` varchar(256) NOT NULL, + `other_repo_id` int(11) NOT NULL, + `other_ref` varchar(256) NOT NULL, + PRIMARY KEY (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `org_repo_id` (`org_repo_id`), + KEY `other_repo_id` (`other_repo_id`), + CONSTRAINT `pull_requests_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `pull_requests_ibfk_2` FOREIGN KEY (`org_repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `pull_requests_ibfk_3` FOREIGN KEY (`other_repo_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_requests` +-- + +LOCK TABLES `pull_requests` WRITE; +/*!40000 ALTER TABLE `pull_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repo_to_perm` +-- + +DROP TABLE IF EXISTS `repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repo_to_perm` ( + `repo_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`repo_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`repository_id`,`permission_id`), + UNIQUE KEY `repo_to_perm_id` (`repo_to_perm_id`), + KEY `permission_id` (`permission_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `repo_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repo_to_perm` +-- + +LOCK TABLES `repo_to_perm` WRITE; +/*!40000 ALTER TABLE `repo_to_perm` DISABLE KEYS */; +INSERT INTO `repo_to_perm` VALUES (1,1,2,1),(2,1,2,2),(3,1,2,3),(4,1,2,4),(5,1,2,5),(6,1,2,6),(7,1,2,7),(8,1,2,8),(9,1,2,9),(10,1,2,10),(11,1,2,11),(12,1,2,12),(13,1,2,13),(14,1,2,14),(15,1,2,15),(16,1,2,16),(17,1,2,17),(18,1,2,18),(19,1,2,19),(20,1,2,20),(21,1,2,21),(22,1,2,22),(23,1,2,23),(24,1,2,24),(25,1,2,25),(26,1,2,26),(27,1,2,27),(28,1,2,28),(29,1,2,29),(30,1,2,30),(31,1,2,31),(32,1,2,32),(33,1,2,33),(34,1,2,34),(35,1,2,35),(36,1,2,36),(37,1,2,37),(38,1,2,38),(39,1,2,39),(40,1,2,40),(41,1,2,41),(42,1,2,42),(43,1,2,43),(44,1,2,44),(45,1,2,45),(46,1,2,46),(47,1,2,47),(48,1,2,48),(49,1,2,49),(50,1,2,50),(51,1,2,51),(52,1,2,52),(53,1,2,53),(54,1,2,54),(55,1,2,55),(56,1,2,56),(57,1,2,57),(58,1,2,58),(59,1,2,59),(60,1,2,60),(61,1,2,61),(62,1,2,62),(63,1,2,63),(64,1,2,64),(65,1,2,65),(66,1,2,66),(67,1,2,67),(68,1,2,68),(69,1,2,69),(70,1,2,70),(71,1,2,71),(72,1,2,72),(73,1,2,73),(74,1,2,74),(75,1,2,75),(76,1,2,76),(77,1,2,77),(78,1,2,78),(79,1,2,79),(80,1,2,80),(81,1,2,81),(82,1,2,82),(83,1,2,83),(84,1,2,84),(85,1,2,85),(86,1,2,86),(87,1,2,87),(88,1,2,88),(89,1,2,89),(90,1,2,90),(91,1,2,91),(92,1,2,92),(93,1,2,93),(94,1,2,94),(95,1,2,95); +/*!40000 ALTER TABLE `repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories` +-- + +DROP TABLE IF EXISTS `repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories` ( + `repo_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_name` varchar(255) NOT NULL, + `clone_uri` varchar(255) DEFAULT NULL, + `repo_type` varchar(255) NOT NULL, + `user_id` int(11) NOT NULL, + `private` tinyint(1) DEFAULT NULL, + `statistics` tinyint(1) DEFAULT NULL, + `downloads` tinyint(1) DEFAULT NULL, + `description` varchar(10000) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `landing_revision` varchar(255) NOT NULL, + `enable_locking` tinyint(1) NOT NULL, + `locked` varchar(255) DEFAULT NULL, + `fork_id` int(11) DEFAULT NULL, + `group_id` int(11) DEFAULT NULL, + PRIMARY KEY (`repo_id`), + UNIQUE KEY `repo_name` (`repo_name`), + UNIQUE KEY `repo_id` (`repo_id`), + UNIQUE KEY `repo_name_2` (`repo_name`), + KEY `user_id` (`user_id`), + KEY `fork_id` (`fork_id`), + KEY `group_id` (`group_id`), + KEY `r_repo_name_idx` (`repo_name`), + CONSTRAINT `repositories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repositories_ibfk_2` FOREIGN KEY (`fork_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `repositories_ibfk_3` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories` +-- + +LOCK TABLES `repositories` WRITE; +/*!40000 ALTER TABLE `repositories` DISABLE KEYS */; +INSERT INTO `repositories` VALUES (1,'RC/fakeclone','http://user@vm/RC/fakeclone','git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:30','2013-05-29 14:15:30','tip',0,NULL,NULL,1),(2,'RC/muay',NULL,'hg',2,0,0,0,'RC/muay repository','2013-05-29 14:15:30','2013-05-29 14:15:30','tip',0,NULL,NULL,1),(3,'RC/rc2/test2',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:30','2013-05-29 14:15:30','tip',0,NULL,NULL,2),(4,'RC/rc2/test3',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:30','2013-05-29 14:15:30','tip',0,NULL,NULL,2),(5,'RC/rc2/test4',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,2),(6,'rhodecode-cli-gist',NULL,'hg',2,0,0,0,'rhodecode-cli-gist repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(7,'RC/new',NULL,'hg',2,0,0,0,'RC/new repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,1),(8,'.rc_gist_store/32',NULL,'hg',2,0,0,0,'.rc_gist_store/32 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(9,'vcs',NULL,'hg',2,0,0,0,'vcs repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(10,'.rc_gist_store/36',NULL,'hg',2,0,0,0,'.rc_gist_store/36 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(11,'.rc_gist_store/37',NULL,'hg',2,0,0,0,'.rc_gist_store/37 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(12,'.rc_gist_store/39',NULL,'hg',2,0,0,0,'.rc_gist_store/39 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(13,'remote-salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(14,'RC/INRC/trololo',NULL,'hg',2,0,0,0,'RC/INRC/trololo repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,4),(15,'quest',NULL,'hg',2,0,0,0,'quest repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(16,'csa-hyperion',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(17,'rhodecode',NULL,'hg',2,0,0,0,'rhodecode repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(18,'RC/origin-fork-fork',NULL,'hg',2,0,0,0,'RC/origin-fork-fork repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,1),(19,'.rc_gist_store/45',NULL,'hg',2,0,0,0,'.rc_gist_store/45 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(20,'.rc_gist_store/44',NULL,'hg',2,0,0,0,'.rc_gist_store/44 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(21,'.rc_gist_store/46',NULL,'hg',2,0,0,0,'.rc_gist_store/46 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(22,'.rc_gist_store/41',NULL,'hg',2,0,0,0,'.rc_gist_store/41 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(23,'.rc_gist_store/40',NULL,'hg',2,0,0,0,'.rc_gist_store/40 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(24,'RC/gogo2',NULL,'hg',2,0,0,0,'RC/gogo2 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,1),(25,'.rc_gist_store/42',NULL,'hg',2,0,0,0,'.rc_gist_store/42 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(26,'.rc_gist_store/49',NULL,'hg',2,0,0,0,'.rc_gist_store/49 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(27,'.rc_gist_store/48',NULL,'hg',2,0,0,0,'.rc_gist_store/48 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(28,'csa-collins',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,NULL),(29,'.rc_gist_store/54',NULL,'hg',2,0,0,0,'.rc_gist_store/54 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(30,'.rc_gist_store/55',NULL,'hg',2,0,0,0,'.rc_gist_store/55 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(31,'.rc_gist_store/52',NULL,'hg',2,0,0,0,'.rc_gist_store/52 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(32,'.rc_gist_store/53',NULL,'hg',2,0,0,0,'.rc_gist_store/53 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(33,'.rc_gist_store/50',NULL,'hg',2,0,0,0,'.rc_gist_store/50 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(34,'.rc_gist_store/51',NULL,'hg',2,0,0,0,'.rc_gist_store/51 repository','2013-05-29 14:15:31','2013-05-29 14:15:31','tip',0,NULL,NULL,3),(35,'BIG/android',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,5),(36,'RC/gogo-fork',NULL,'hg',2,0,0,0,'RC/gogo-fork repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(37,'RC/mygr/lol',NULL,'hg',2,0,0,0,'RC/mygr/lol repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,6),(38,'RC/hg-repo',NULL,'hg',2,0,0,0,'RC/hg-repo repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(39,'RC/bin-ops',NULL,'hg',2,0,0,0,'RC/bin-ops repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(40,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU',NULL,'hg',2,0,0,0,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(41,'rhodecode-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(42,'csa-io',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(43,'RC/qweqwe-fork',NULL,'hg',2,0,0,0,'RC/qweqwe-fork repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(44,'csa-libcloud',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(45,'waitress',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(46,'.rc_gist_store/8',NULL,'hg',2,0,0,0,'.rc_gist_store/8 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(47,'.rc_gist_store/9',NULL,'hg',2,0,0,0,'.rc_gist_store/9 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(48,'RC/foobar',NULL,'hg',2,0,0,0,'RC/foobar repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(49,'.rc_gist_store/1',NULL,'hg',2,0,0,0,'.rc_gist_store/1 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(50,'.rc_gist_store/3',NULL,'hg',2,0,0,0,'.rc_gist_store/3 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(51,'.rc_gist_store/4',NULL,'hg',2,0,0,0,'.rc_gist_store/4 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(52,'.rc_gist_store/5',NULL,'hg',2,0,0,0,'.rc_gist_store/5 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(53,'.rc_gist_store/6',NULL,'hg',2,0,0,0,'.rc_gist_store/6 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(54,'.rc_gist_store/7',NULL,'hg',2,0,0,0,'.rc_gist_store/7 repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,3),(55,'csa-harmony',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(56,'RC/Å‚Ä™cina',NULL,'hg',2,0,0,0,'RC/Å‚Ä™cina repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(57,'rhodecode-extensions',NULL,'hg',2,0,0,0,'rhodecode-extensions repository','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(58,'csa-prometheus',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,NULL),(59,'RC/empty-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:32','2013-05-29 14:15:32','tip',0,NULL,NULL,1),(60,'csa-salt-states',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(61,'rhodecode-premium',NULL,'hg',2,0,0,0,'rhodecode-premium repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(62,'RC/qweqwe-fork2',NULL,'hg',2,0,0,0,'RC/qweqwe-fork2 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(63,'RC/INRC/L2_NEW/lalalal',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/lalalal repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,7),(64,'RC/INRC/L2_NEW/L3/repo_test_move',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/L3/repo_test_move repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,8),(65,'RC/jap',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(66,'RC/origin',NULL,'hg',2,0,0,0,'RC/origin repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(67,'rhodecode-cli-api',NULL,'hg',2,0,0,0,'rhodecode-cli-api repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(68,'csa-armstrong',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(69,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3',NULL,'hg',2,0,0,0,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(70,'RC/lol/haha',NULL,'hg',2,0,0,0,'RC/lol/haha repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,9),(71,'enc-envelope',NULL,'hg',2,0,0,0,'enc-envelope repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(72,'.rc_gist_store/43',NULL,'hg',2,0,0,0,'.rc_gist_store/43 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(73,'RC/test',NULL,'hg',2,0,0,0,'RC/test repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(74,'BIG/git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,5),(75,'RC/origin-fork',NULL,'hg',2,0,0,0,'RC/origin-fork repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(76,'RC/trololo',NULL,'hg',2,0,0,0,'RC/trololo repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(77,'.rc_gist_store/FLj8GunafFAVBnuTWDxU',NULL,'hg',2,0,0,0,'.rc_gist_store/FLj8GunafFAVBnuTWDxU repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(78,'RC/Ä…qweqwe',NULL,'hg',2,0,0,0,'RC/Ä…qweqwe repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(79,'csa-unity',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,NULL),(80,'RC/vcs-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(81,'.rc_gist_store/12',NULL,'hg',2,0,0,0,'.rc_gist_store/12 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(82,'.rc_gist_store/13',NULL,'hg',2,0,0,0,'.rc_gist_store/13 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(83,'.rc_gist_store/10',NULL,'hg',2,0,0,0,'.rc_gist_store/10 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(84,'.rc_gist_store/11',NULL,'hg',2,0,0,0,'.rc_gist_store/11 repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,3),(85,'RC/kiall-nova',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,1),(86,'RC/rc2/test',NULL,'hg',2,0,0,0,'RC/rc2/test repository','2013-05-29 14:15:33','2013-05-29 14:15:33','tip',0,NULL,NULL,2),(87,'DOCS',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,NULL),(88,'RC/fork-remote',NULL,'hg',2,0,0,0,'RC/fork-remote repository','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,1),(89,'RC/git-pull-test',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,1),(90,'pyramidpypi',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,NULL),(91,'.rc_gist_store/aQpbufbhSac6FyvVHhmS',NULL,'hg',2,0,0,0,'.rc_gist_store/aQpbufbhSac6FyvVHhmS repository','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,3),(92,'csa-aldrin',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,NULL),(93,'.rc_gist_store/QL2GhrlKymNmrUJJy5js',NULL,'hg',2,0,0,0,'.rc_gist_store/QL2GhrlKymNmrUJJy5js repository','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,3),(94,'RC/git-test',NULL,'git',2,0,0,0,'Unnamed repository','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,1),(95,'salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:15:34','2013-05-29 14:15:34','tip',0,NULL,NULL,NULL); +/*!40000 ALTER TABLE `repositories` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_settings` +-- + +DROP TABLE IF EXISTS `rhodecode_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_settings` ( + `app_settings_id` int(11) NOT NULL AUTO_INCREMENT, + `app_settings_name` varchar(255) DEFAULT NULL, + `app_settings_value` varchar(255) DEFAULT NULL, + PRIMARY KEY (`app_settings_id`), + UNIQUE KEY `app_settings_id` (`app_settings_id`), + UNIQUE KEY `app_settings_name` (`app_settings_name`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_settings` +-- + +LOCK TABLES `rhodecode_settings` WRITE; +/*!40000 ALTER TABLE `rhodecode_settings` DISABLE KEYS */; +INSERT INTO `rhodecode_settings` VALUES (1,'realm','RhodeCode authentication'),(2,'title','RhodeCode'),(3,'ga_code',''),(4,'show_public_icon','True'),(5,'show_private_icon','True'),(6,'stylify_metatags','False'),(7,'ldap_active','false'),(8,'ldap_host',''),(9,'ldap_port','389'),(10,'ldap_tls_kind','PLAIN'),(11,'ldap_tls_reqcert',''),(12,'ldap_dn_user',''),(13,'ldap_dn_pass',''),(14,'ldap_base_dn',''),(15,'ldap_filter',''),(16,'ldap_search_scope',''),(17,'ldap_attr_login',''),(18,'ldap_attr_firstname',''),(19,'ldap_attr_lastname',''),(20,'ldap_attr_email',''),(21,'default_repo_enable_locking','False'),(22,'default_repo_enable_downloads','False'),(23,'default_repo_enable_statistics','False'),(24,'default_repo_private','False'),(25,'default_repo_type','hg'); +/*!40000 ALTER TABLE `rhodecode_settings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_ui` +-- + +DROP TABLE IF EXISTS `rhodecode_ui`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_ui` ( + `ui_id` int(11) NOT NULL AUTO_INCREMENT, + `ui_section` varchar(255) DEFAULT NULL, + `ui_key` varchar(255) DEFAULT NULL, + `ui_value` varchar(255) DEFAULT NULL, + `ui_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ui_id`), + UNIQUE KEY `ui_id` (`ui_id`), + UNIQUE KEY `ui_key` (`ui_key`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_ui` +-- + +LOCK TABLES `rhodecode_ui` WRITE; +/*!40000 ALTER TABLE `rhodecode_ui` DISABLE KEYS */; +INSERT INTO `rhodecode_ui` VALUES (1,'hooks','changegroup.update','hg update >&2',0),(2,'hooks','changegroup.repo_size','python:rhodecode.lib.hooks.repo_size',1),(3,'hooks','changegroup.push_logger','python:rhodecode.lib.hooks.log_push_action',1),(4,'hooks','prechangegroup.pre_push','python:rhodecode.lib.hooks.pre_push',1),(5,'hooks','outgoing.pull_logger','python:rhodecode.lib.hooks.log_pull_action',1),(6,'hooks','preoutgoing.pre_pull','python:rhodecode.lib.hooks.pre_pull',1),(7,'extensions','largefiles','',1),(8,'extensions','hgsubversion','',0),(9,'extensions','hggit','',0),(10,'web','push_ssl','false',1),(11,'web','allow_archive','gz zip bz2',1),(12,'web','allow_push','*',1),(13,'web','baseurl','/',1),(14,'paths','/','/mnt/hgfs/workspace-python',1); +/*!40000 ALTER TABLE `rhodecode_ui` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `statistics` +-- + +DROP TABLE IF EXISTS `statistics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `statistics` ( + `stat_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `stat_on_revision` int(11) NOT NULL, + `commit_activity` mediumblob NOT NULL, + `commit_activity_combined` blob NOT NULL, + `languages` mediumblob NOT NULL, + PRIMARY KEY (`stat_id`), + UNIQUE KEY `repository_id` (`repository_id`), + UNIQUE KEY `stat_id` (`stat_id`), + UNIQUE KEY `repository_id_2` (`repository_id`), + CONSTRAINT `statistics_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `statistics` +-- + +LOCK TABLES `statistics` WRITE; +/*!40000 ALTER TABLE `statistics` DISABLE KEYS */; +/*!40000 ALTER TABLE `statistics` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_email_map` +-- + +DROP TABLE IF EXISTS `user_email_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_email_map` ( + `email_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + PRIMARY KEY (`email_id`), + UNIQUE KEY `email_id` (`email_id`), + UNIQUE KEY `email` (`email`), + KEY `user_id` (`user_id`), + KEY `uem_email_idx` (`email`), + CONSTRAINT `user_email_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_email_map` +-- + +LOCK TABLES `user_email_map` WRITE; +/*!40000 ALTER TABLE `user_email_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_email_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_followings` +-- + +DROP TABLE IF EXISTS `user_followings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_followings` ( + `user_following_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `follows_repository_id` int(11) DEFAULT NULL, + `follows_user_id` int(11) DEFAULT NULL, + `follows_from` datetime DEFAULT NULL, + PRIMARY KEY (`user_following_id`), + UNIQUE KEY `user_following_id` (`user_following_id`), + UNIQUE KEY `user_id` (`user_id`,`follows_repository_id`), + UNIQUE KEY `user_id_2` (`user_id`,`follows_user_id`), + KEY `follows_repository_id` (`follows_repository_id`), + KEY `follows_user_id` (`follows_user_id`), + CONSTRAINT `user_followings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_followings_ibfk_2` FOREIGN KEY (`follows_repository_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `user_followings_ibfk_3` FOREIGN KEY (`follows_user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_followings` +-- + +LOCK TABLES `user_followings` WRITE; +/*!40000 ALTER TABLE `user_followings` DISABLE KEYS */; +INSERT INTO `user_followings` VALUES (1,2,1,NULL,'2013-05-29 14:15:30'),(2,2,2,NULL,'2013-05-29 14:15:30'),(3,2,3,NULL,'2013-05-29 14:15:30'),(4,2,4,NULL,'2013-05-29 14:15:31'),(5,2,5,NULL,'2013-05-29 14:15:31'),(6,2,6,NULL,'2013-05-29 14:15:31'),(7,2,7,NULL,'2013-05-29 14:15:31'),(8,2,8,NULL,'2013-05-29 14:15:31'),(9,2,9,NULL,'2013-05-29 14:15:31'),(10,2,10,NULL,'2013-05-29 14:15:31'),(11,2,11,NULL,'2013-05-29 14:15:31'),(12,2,12,NULL,'2013-05-29 14:15:31'),(13,2,13,NULL,'2013-05-29 14:15:31'),(14,2,14,NULL,'2013-05-29 14:15:31'),(15,2,15,NULL,'2013-05-29 14:15:31'),(16,2,16,NULL,'2013-05-29 14:15:31'),(17,2,17,NULL,'2013-05-29 14:15:31'),(18,2,18,NULL,'2013-05-29 14:15:31'),(19,2,19,NULL,'2013-05-29 14:15:31'),(20,2,20,NULL,'2013-05-29 14:15:31'),(21,2,21,NULL,'2013-05-29 14:15:31'),(22,2,22,NULL,'2013-05-29 14:15:31'),(23,2,23,NULL,'2013-05-29 14:15:31'),(24,2,24,NULL,'2013-05-29 14:15:31'),(25,2,25,NULL,'2013-05-29 14:15:31'),(26,2,26,NULL,'2013-05-29 14:15:31'),(27,2,27,NULL,'2013-05-29 14:15:31'),(28,2,28,NULL,'2013-05-29 14:15:31'),(29,2,29,NULL,'2013-05-29 14:15:31'),(30,2,30,NULL,'2013-05-29 14:15:31'),(31,2,31,NULL,'2013-05-29 14:15:31'),(32,2,32,NULL,'2013-05-29 14:15:31'),(33,2,33,NULL,'2013-05-29 14:15:31'),(34,2,34,NULL,'2013-05-29 14:15:31'),(35,2,35,NULL,'2013-05-29 14:15:32'),(36,2,36,NULL,'2013-05-29 14:15:32'),(37,2,37,NULL,'2013-05-29 14:15:32'),(38,2,38,NULL,'2013-05-29 14:15:32'),(39,2,39,NULL,'2013-05-29 14:15:32'),(40,2,40,NULL,'2013-05-29 14:15:32'),(41,2,41,NULL,'2013-05-29 14:15:32'),(42,2,42,NULL,'2013-05-29 14:15:32'),(43,2,43,NULL,'2013-05-29 14:15:32'),(44,2,44,NULL,'2013-05-29 14:15:32'),(45,2,45,NULL,'2013-05-29 14:15:32'),(46,2,46,NULL,'2013-05-29 14:15:32'),(47,2,47,NULL,'2013-05-29 14:15:32'),(48,2,48,NULL,'2013-05-29 14:15:32'),(49,2,49,NULL,'2013-05-29 14:15:32'),(50,2,50,NULL,'2013-05-29 14:15:32'),(51,2,51,NULL,'2013-05-29 14:15:32'),(52,2,52,NULL,'2013-05-29 14:15:32'),(53,2,53,NULL,'2013-05-29 14:15:32'),(54,2,54,NULL,'2013-05-29 14:15:32'),(55,2,55,NULL,'2013-05-29 14:15:32'),(56,2,56,NULL,'2013-05-29 14:15:32'),(57,2,57,NULL,'2013-05-29 14:15:32'),(58,2,58,NULL,'2013-05-29 14:15:32'),(59,2,59,NULL,'2013-05-29 14:15:32'),(60,2,60,NULL,'2013-05-29 14:15:33'),(61,2,61,NULL,'2013-05-29 14:15:33'),(62,2,62,NULL,'2013-05-29 14:15:33'),(63,2,63,NULL,'2013-05-29 14:15:33'),(64,2,64,NULL,'2013-05-29 14:15:33'),(65,2,65,NULL,'2013-05-29 14:15:33'),(66,2,66,NULL,'2013-05-29 14:15:33'),(67,2,67,NULL,'2013-05-29 14:15:33'),(68,2,68,NULL,'2013-05-29 14:15:33'),(69,2,69,NULL,'2013-05-29 14:15:33'),(70,2,70,NULL,'2013-05-29 14:15:33'),(71,2,71,NULL,'2013-05-29 14:15:33'),(72,2,72,NULL,'2013-05-29 14:15:33'),(73,2,73,NULL,'2013-05-29 14:15:33'),(74,2,74,NULL,'2013-05-29 14:15:33'),(75,2,75,NULL,'2013-05-29 14:15:33'),(76,2,76,NULL,'2013-05-29 14:15:33'),(77,2,77,NULL,'2013-05-29 14:15:33'),(78,2,78,NULL,'2013-05-29 14:15:33'),(79,2,79,NULL,'2013-05-29 14:15:33'),(80,2,80,NULL,'2013-05-29 14:15:33'),(81,2,81,NULL,'2013-05-29 14:15:33'),(82,2,82,NULL,'2013-05-29 14:15:33'),(83,2,83,NULL,'2013-05-29 14:15:33'),(84,2,84,NULL,'2013-05-29 14:15:33'),(85,2,85,NULL,'2013-05-29 14:15:33'),(86,2,86,NULL,'2013-05-29 14:15:33'),(87,2,87,NULL,'2013-05-29 14:15:34'),(88,2,88,NULL,'2013-05-29 14:15:34'),(89,2,89,NULL,'2013-05-29 14:15:34'),(90,2,90,NULL,'2013-05-29 14:15:34'),(91,2,91,NULL,'2013-05-29 14:15:34'),(92,2,92,NULL,'2013-05-29 14:15:34'),(93,2,93,NULL,'2013-05-29 14:15:34'),(94,2,94,NULL,'2013-05-29 14:15:34'),(95,2,95,NULL,'2013-05-29 14:15:34'); +/*!40000 ALTER TABLE `user_followings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_logs` +-- + +DROP TABLE IF EXISTS `user_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_logs` ( + `user_log_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `repository_id` int(11) DEFAULT NULL, + `repository_name` varchar(255) DEFAULT NULL, + `user_ip` varchar(255) DEFAULT NULL, + `action` mediumtext, + `action_date` datetime DEFAULT NULL, + PRIMARY KEY (`user_log_id`), + UNIQUE KEY `user_log_id` (`user_log_id`), + KEY `user_id` (`user_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `user_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_logs_ibfk_2` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_logs` +-- + +LOCK TABLES `user_logs` WRITE; +/*!40000 ALTER TABLE `user_logs` DISABLE KEYS */; +INSERT INTO `user_logs` VALUES (1,2,'marcink',1,'RC/fakeclone','','started_following_repo','2013-05-29 14:15:30'),(2,2,'marcink',2,'RC/muay','','started_following_repo','2013-05-29 14:15:30'),(3,2,'marcink',3,'RC/rc2/test2','','started_following_repo','2013-05-29 14:15:30'),(4,2,'marcink',4,'RC/rc2/test3','','started_following_repo','2013-05-29 14:15:30'),(5,2,'marcink',5,'RC/rc2/test4','','started_following_repo','2013-05-29 14:15:31'),(6,2,'marcink',6,'rhodecode-cli-gist','','started_following_repo','2013-05-29 14:15:31'),(7,2,'marcink',7,'RC/new','','started_following_repo','2013-05-29 14:15:31'),(8,2,'marcink',8,'.rc_gist_store/32','','started_following_repo','2013-05-29 14:15:31'),(9,2,'marcink',9,'vcs','','started_following_repo','2013-05-29 14:15:31'),(10,2,'marcink',10,'.rc_gist_store/36','','started_following_repo','2013-05-29 14:15:31'),(11,2,'marcink',11,'.rc_gist_store/37','','started_following_repo','2013-05-29 14:15:31'),(12,2,'marcink',12,'.rc_gist_store/39','','started_following_repo','2013-05-29 14:15:31'),(13,2,'marcink',13,'remote-salt','','started_following_repo','2013-05-29 14:15:31'),(14,2,'marcink',14,'RC/INRC/trololo','','started_following_repo','2013-05-29 14:15:31'),(15,2,'marcink',15,'quest','','started_following_repo','2013-05-29 14:15:31'),(16,2,'marcink',16,'csa-hyperion','','started_following_repo','2013-05-29 14:15:31'),(17,2,'marcink',17,'rhodecode','','started_following_repo','2013-05-29 14:15:31'),(18,2,'marcink',18,'RC/origin-fork-fork','','started_following_repo','2013-05-29 14:15:31'),(19,2,'marcink',19,'.rc_gist_store/45','','started_following_repo','2013-05-29 14:15:31'),(20,2,'marcink',20,'.rc_gist_store/44','','started_following_repo','2013-05-29 14:15:31'),(21,2,'marcink',21,'.rc_gist_store/46','','started_following_repo','2013-05-29 14:15:31'),(22,2,'marcink',22,'.rc_gist_store/41','','started_following_repo','2013-05-29 14:15:31'),(23,2,'marcink',23,'.rc_gist_store/40','','started_following_repo','2013-05-29 14:15:31'),(24,2,'marcink',24,'RC/gogo2','','started_following_repo','2013-05-29 14:15:31'),(25,2,'marcink',25,'.rc_gist_store/42','','started_following_repo','2013-05-29 14:15:31'),(26,2,'marcink',26,'.rc_gist_store/49','','started_following_repo','2013-05-29 14:15:31'),(27,2,'marcink',27,'.rc_gist_store/48','','started_following_repo','2013-05-29 14:15:31'),(28,2,'marcink',28,'csa-collins','','started_following_repo','2013-05-29 14:15:31'),(29,2,'marcink',29,'.rc_gist_store/54','','started_following_repo','2013-05-29 14:15:31'),(30,2,'marcink',30,'.rc_gist_store/55','','started_following_repo','2013-05-29 14:15:31'),(31,2,'marcink',31,'.rc_gist_store/52','','started_following_repo','2013-05-29 14:15:31'),(32,2,'marcink',32,'.rc_gist_store/53','','started_following_repo','2013-05-29 14:15:31'),(33,2,'marcink',33,'.rc_gist_store/50','','started_following_repo','2013-05-29 14:15:31'),(34,2,'marcink',34,'.rc_gist_store/51','','started_following_repo','2013-05-29 14:15:31'),(35,2,'marcink',35,'BIG/android','','started_following_repo','2013-05-29 14:15:32'),(36,2,'marcink',36,'RC/gogo-fork','','started_following_repo','2013-05-29 14:15:32'),(37,2,'marcink',37,'RC/mygr/lol','','started_following_repo','2013-05-29 14:15:32'),(38,2,'marcink',38,'RC/hg-repo','','started_following_repo','2013-05-29 14:15:32'),(39,2,'marcink',39,'RC/bin-ops','','started_following_repo','2013-05-29 14:15:32'),(40,2,'marcink',40,'.rc_gist_store/xFvj6dFqqVK5vfsGP8PU','','started_following_repo','2013-05-29 14:15:32'),(41,2,'marcink',41,'rhodecode-git','','started_following_repo','2013-05-29 14:15:32'),(42,2,'marcink',42,'csa-io','','started_following_repo','2013-05-29 14:15:32'),(43,2,'marcink',43,'RC/qweqwe-fork','','started_following_repo','2013-05-29 14:15:32'),(44,2,'marcink',44,'csa-libcloud','','started_following_repo','2013-05-29 14:15:32'),(45,2,'marcink',45,'waitress','','started_following_repo','2013-05-29 14:15:32'),(46,2,'marcink',46,'.rc_gist_store/8','','started_following_repo','2013-05-29 14:15:32'),(47,2,'marcink',47,'.rc_gist_store/9','','started_following_repo','2013-05-29 14:15:32'),(48,2,'marcink',48,'RC/foobar','','started_following_repo','2013-05-29 14:15:32'),(49,2,'marcink',49,'.rc_gist_store/1','','started_following_repo','2013-05-29 14:15:32'),(50,2,'marcink',50,'.rc_gist_store/3','','started_following_repo','2013-05-29 14:15:32'),(51,2,'marcink',51,'.rc_gist_store/4','','started_following_repo','2013-05-29 14:15:32'),(52,2,'marcink',52,'.rc_gist_store/5','','started_following_repo','2013-05-29 14:15:32'),(53,2,'marcink',53,'.rc_gist_store/6','','started_following_repo','2013-05-29 14:15:32'),(54,2,'marcink',54,'.rc_gist_store/7','','started_following_repo','2013-05-29 14:15:32'),(55,2,'marcink',55,'csa-harmony','','started_following_repo','2013-05-29 14:15:32'),(56,2,'marcink',56,'RC/Å‚Ä™cina','','started_following_repo','2013-05-29 14:15:32'),(57,2,'marcink',57,'rhodecode-extensions','','started_following_repo','2013-05-29 14:15:32'),(58,2,'marcink',58,'csa-prometheus','','started_following_repo','2013-05-29 14:15:32'),(59,2,'marcink',59,'RC/empty-git','','started_following_repo','2013-05-29 14:15:32'),(60,2,'marcink',60,'csa-salt-states','','started_following_repo','2013-05-29 14:15:33'),(61,2,'marcink',61,'rhodecode-premium','','started_following_repo','2013-05-29 14:15:33'),(62,2,'marcink',62,'RC/qweqwe-fork2','','started_following_repo','2013-05-29 14:15:33'),(63,2,'marcink',63,'RC/INRC/L2_NEW/lalalal','','started_following_repo','2013-05-29 14:15:33'),(64,2,'marcink',64,'RC/INRC/L2_NEW/L3/repo_test_move','','started_following_repo','2013-05-29 14:15:33'),(65,2,'marcink',65,'RC/jap','','started_following_repo','2013-05-29 14:15:33'),(66,2,'marcink',66,'RC/origin','','started_following_repo','2013-05-29 14:15:33'),(67,2,'marcink',67,'rhodecode-cli-api','','started_following_repo','2013-05-29 14:15:33'),(68,2,'marcink',68,'csa-armstrong','','started_following_repo','2013-05-29 14:15:33'),(69,2,'marcink',69,'.rc_gist_store/NAsB8cacjxnqdyZ8QUl3','','started_following_repo','2013-05-29 14:15:33'),(70,2,'marcink',70,'RC/lol/haha','','started_following_repo','2013-05-29 14:15:33'),(71,2,'marcink',71,'enc-envelope','','started_following_repo','2013-05-29 14:15:33'),(72,2,'marcink',72,'.rc_gist_store/43','','started_following_repo','2013-05-29 14:15:33'),(73,2,'marcink',73,'RC/test','','started_following_repo','2013-05-29 14:15:33'),(74,2,'marcink',74,'BIG/git','','started_following_repo','2013-05-29 14:15:33'),(75,2,'marcink',75,'RC/origin-fork','','started_following_repo','2013-05-29 14:15:33'),(76,2,'marcink',76,'RC/trololo','','started_following_repo','2013-05-29 14:15:33'),(77,2,'marcink',77,'.rc_gist_store/FLj8GunafFAVBnuTWDxU','','started_following_repo','2013-05-29 14:15:33'),(78,2,'marcink',78,'RC/Ä…qweqwe','','started_following_repo','2013-05-29 14:15:33'),(79,2,'marcink',79,'csa-unity','','started_following_repo','2013-05-29 14:15:33'),(80,2,'marcink',80,'RC/vcs-git','','started_following_repo','2013-05-29 14:15:33'),(81,2,'marcink',81,'.rc_gist_store/12','','started_following_repo','2013-05-29 14:15:33'),(82,2,'marcink',82,'.rc_gist_store/13','','started_following_repo','2013-05-29 14:15:33'),(83,2,'marcink',83,'.rc_gist_store/10','','started_following_repo','2013-05-29 14:15:33'),(84,2,'marcink',84,'.rc_gist_store/11','','started_following_repo','2013-05-29 14:15:33'),(85,2,'marcink',85,'RC/kiall-nova','','started_following_repo','2013-05-29 14:15:33'),(86,2,'marcink',86,'RC/rc2/test','','started_following_repo','2013-05-29 14:15:33'),(87,2,'marcink',87,'DOCS','','started_following_repo','2013-05-29 14:15:34'),(88,2,'marcink',88,'RC/fork-remote','','started_following_repo','2013-05-29 14:15:34'),(89,2,'marcink',89,'RC/git-pull-test','','started_following_repo','2013-05-29 14:15:34'),(90,2,'marcink',90,'pyramidpypi','','started_following_repo','2013-05-29 14:15:34'),(91,2,'marcink',91,'.rc_gist_store/aQpbufbhSac6FyvVHhmS','','started_following_repo','2013-05-29 14:15:34'),(92,2,'marcink',92,'csa-aldrin','','started_following_repo','2013-05-29 14:15:34'),(93,2,'marcink',93,'.rc_gist_store/QL2GhrlKymNmrUJJy5js','','started_following_repo','2013-05-29 14:15:34'),(94,2,'marcink',94,'RC/git-test','','started_following_repo','2013-05-29 14:15:34'),(95,2,'marcink',95,'salt','','started_following_repo','2013-05-29 14:15:34'); +/*!40000 ALTER TABLE `user_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `user_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_repo_group_to_perm` ( + `group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`group_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`group_id`,`permission_id`), + UNIQUE KEY `group_to_perm_id` (`group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_repo_group_to_perm` +-- + +LOCK TABLES `user_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `user_repo_group_to_perm` DISABLE KEYS */; +INSERT INTO `user_repo_group_to_perm` VALUES (1,1,1,6),(2,1,2,6),(3,1,3,6),(4,1,4,6),(5,1,5,6),(6,1,6,6),(7,1,7,6),(8,1,8,6),(9,1,9,6); +/*!40000 ALTER TABLE `user_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_notification` +-- + +DROP TABLE IF EXISTS `user_to_notification`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_notification` ( + `user_id` int(11) NOT NULL, + `notification_id` int(11) NOT NULL, + `read` tinyint(1) DEFAULT NULL, + `sent_on` datetime DEFAULT NULL, + PRIMARY KEY (`user_id`,`notification_id`), + UNIQUE KEY `user_id` (`user_id`,`notification_id`), + KEY `notification_id` (`notification_id`), + CONSTRAINT `user_to_notification_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_notification_ibfk_2` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`notification_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_notification` +-- + +LOCK TABLES `user_to_notification` WRITE; +/*!40000 ALTER TABLE `user_to_notification` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_to_notification` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_perm` +-- + +DROP TABLE IF EXISTS `user_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_perm` ( + `user_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`user_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`permission_id`), + UNIQUE KEY `user_to_perm_id` (`user_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_perm` +-- + +LOCK TABLES `user_to_perm` WRITE; +/*!40000 ALTER TABLE `user_to_perm` DISABLE KEYS */; +INSERT INTO `user_to_perm` VALUES (4,1,2),(5,1,6),(2,1,11),(3,1,13),(1,1,15); +/*!40000 ALTER TABLE `user_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + `admin` tinyint(1) DEFAULT NULL, + `firstname` varchar(255) DEFAULT NULL, + `lastname` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `last_login` datetime DEFAULT NULL, + `ldap_dn` varchar(255) DEFAULT NULL, + `api_key` varchar(255) DEFAULT NULL, + `inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `user_id` (`user_id`), + UNIQUE KEY `username` (`username`), + UNIQUE KEY `email` (`email`), + KEY `u_username_idx` (`username`), + KEY `u_email_idx` (`email`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'default','$2a$10$H9jd01.Elb7uAckLZ7HGL.Ue6AvC/pbMS3oR3.hT7uN3Gp2RIIKF.',1,0,'Anonymous','User','anonymous@rhodecode.org',NULL,NULL,'c975634648424bb781d0b4329f8b17cef5c03c73',1),(2,'marcink','$2a$10$7GAtHG19SebcR1nwEDEAsOjmJcnTcbwJ0eGEZhJT/crgxy2rPl6om',1,1,'RhodeCode','Admin','marcin',NULL,NULL,'63690794a1344bc9e8129a2f9c2deffe649529da',1); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_group_to_perm` ( + `users_group_repo_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_repo_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`group_id`), + UNIQUE KEY `users_group_repo_group_to_perm_id` (`users_group_repo_group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_group_to_perm` +-- + +LOCK TABLES `users_group_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `repository_id` (`repository_id`,`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `users_group_id` (`users_group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_to_perm` +-- + +LOCK TABLES `users_group_repo_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_to_perm` +-- + +LOCK TABLES `users_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups` +-- + +DROP TABLE IF EXISTS `users_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups` ( + `users_group_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_name` varchar(255) NOT NULL, + `users_group_active` tinyint(1) DEFAULT NULL, + `users_group_inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`users_group_id`), + UNIQUE KEY `users_group_id` (`users_group_id`), + UNIQUE KEY `users_group_name` (`users_group_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups` +-- + +LOCK TABLES `users_groups` WRITE; +/*!40000 ALTER TABLE `users_groups` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups_members` +-- + +DROP TABLE IF EXISTS `users_groups_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups_members` ( + `users_group_member_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_member_id`), + UNIQUE KEY `users_group_member_id` (`users_group_member_id`), + KEY `users_group_id` (`users_group_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `users_groups_members_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_groups_members_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups_members` +-- + +LOCK TABLES `users_groups_members` WRITE; +/*!40000 ALTER TABLE `users_groups_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups_members` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2013-05-29 14:15:42 diff --git a/rhodecode/tests/database/mysql/1.6.0.sql b/rhodecode/tests/database/mysql/1.6.0.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/mysql/1.6.0.sql @@ -0,0 +1,924 @@ +-- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: rhodecode +-- ------------------------------------------------------ +-- Server version 5.5.31-0ubuntu0.12.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `cache_invalidation` +-- + +DROP TABLE IF EXISTS `cache_invalidation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `cache_invalidation` ( + `cache_id` int(11) NOT NULL AUTO_INCREMENT, + `cache_key` varchar(255) DEFAULT NULL, + `cache_args` varchar(255) DEFAULT NULL, + `cache_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`cache_id`), + UNIQUE KEY `cache_id` (`cache_id`), + UNIQUE KEY `cache_key` (`cache_key`), + KEY `key_idx` (`cache_key`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_invalidation` +-- + +LOCK TABLES `cache_invalidation` WRITE; +/*!40000 ALTER TABLE `cache_invalidation` DISABLE KEYS */; +INSERT INTO `cache_invalidation` VALUES (1,'1RC/mygr/lol','RC/mygr/lol',0),(2,'1RC/fakeclone','RC/fakeclone',1),(3,'1RC/muay','RC/muay',0),(4,'1BIG/git','BIG/git',1),(5,'1RC/origin-fork','RC/origin-fork',0),(6,'1RC/trololo','RC/trololo',0),(7,'1csa-collins','csa-collins',1),(8,'1csa-harmony','csa-harmony',1),(9,'1RC/Ä…qweqwe','RC/Ä…qweqwe',0),(10,'1rhodecode','rhodecode',0),(11,'1csa-unity','csa-unity',1),(12,'1RC/Å‚Ä™cina','RC/Å‚Ä™cina',0),(13,'1waitress','waitress',1),(14,'1RC/rc2/test2','RC/rc2/test2',1),(15,'1RC/origin-fork-fork','RC/origin-fork-fork',0),(16,'1RC/rc2/test4','RC/rc2/test4',1),(17,'1RC/vcs-git','RC/vcs-git',1),(18,'1rhodecode-extensions','rhodecode-extensions',0),(19,'1rhodecode-cli-gist','rhodecode-cli-gist',0),(20,'1RC/new','RC/new',0),(21,'1csa-aldrin','csa-aldrin',1),(22,'1vcs','vcs',0),(23,'1csa-prometheus','csa-prometheus',1),(24,'1RC/INRC/trololo','RC/INRC/trololo',0),(25,'1RC/empty-git','RC/empty-git',1),(26,'1RC/bin-ops','RC/bin-ops',0),(27,'1csa-salt-states','csa-salt-states',1),(28,'1rhodecode-premium','rhodecode-premium',0),(29,'1RC/qweqwe-fork','RC/qweqwe-fork',0),(30,'1RC/test','RC/test',0),(31,'1remote-salt','remote-salt',1),(32,'1BIG/android','BIG/android',1),(33,'1DOCS','DOCS',1),(34,'1rhodecode-git','rhodecode-git',1),(35,'1RC/fork-remote','RC/fork-remote',0),(36,'1RC/INRC/L2_NEW/lalalal','RC/INRC/L2_NEW/lalalal',0),(37,'1RC/INRC/L2_NEW/L3/repo_test_move','RC/INRC/L2_NEW/L3/repo_test_move',0),(38,'1RC/gogo-fork','RC/gogo-fork',0),(39,'1quest','quest',0),(40,'1RC/foobar','RC/foobar',0),(41,'1csa-hyperion','csa-hyperion',1),(42,'1RC/git-pull-test','RC/git-pull-test',1),(43,'1RC/qweqwe-fork2','RC/qweqwe-fork2',0),(44,'1RC/jap','RC/jap',1),(45,'1RC/hg-repo','RC/hg-repo',0),(46,'1RC/origin','RC/origin',0),(47,'1rhodecode-cli-api','rhodecode-cli-api',0),(48,'1RC/rc2/test3','RC/rc2/test3',1),(49,'1csa-armstrong','csa-armstrong',1),(50,'1pyramidpypi','pyramidpypi',1),(51,'1RC/lol/haha','RC/lol/haha',0),(52,'1csa-io','csa-io',1),(53,'1enc-envelope','enc-envelope',0),(54,'1RC/gogo2','RC/gogo2',0),(55,'1csa-libcloud','csa-libcloud',1),(56,'1RC/git-test','RC/git-test',1),(57,'1RC/rc2/test','RC/rc2/test',0),(58,'1salt','salt',1),(59,'1RC/kiall-nova','RC/kiall-nova',1); +/*!40000 ALTER TABLE `cache_invalidation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_comments` +-- + +DROP TABLE IF EXISTS `changeset_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_comments` ( + `comment_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `revision` varchar(40) DEFAULT NULL, + `pull_request_id` int(11) DEFAULT NULL, + `line_no` varchar(10) DEFAULT NULL, + `hl_lines` varchar(512) DEFAULT NULL, + `f_path` varchar(1000) DEFAULT NULL, + `user_id` int(11) NOT NULL, + `text` mediumtext NOT NULL, + `created_on` datetime NOT NULL, + `modified_at` datetime NOT NULL, + PRIMARY KEY (`comment_id`), + KEY `repo_id` (`repo_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `cc_revision_idx` (`revision`), + CONSTRAINT `changeset_comments_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_comments_ibfk_2` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `changeset_comments_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_comments` +-- + +LOCK TABLES `changeset_comments` WRITE; +/*!40000 ALTER TABLE `changeset_comments` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_comments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_statuses` +-- + +DROP TABLE IF EXISTS `changeset_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_statuses` ( + `changeset_status_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `revision` varchar(40) NOT NULL, + `status` varchar(128) NOT NULL, + `changeset_comment_id` int(11) DEFAULT NULL, + `modified_at` datetime NOT NULL, + `version` int(11) NOT NULL, + `pull_request_id` int(11) DEFAULT NULL, + PRIMARY KEY (`changeset_status_id`), + UNIQUE KEY `repo_id` (`repo_id`,`revision`,`version`), + KEY `user_id` (`user_id`), + KEY `changeset_comment_id` (`changeset_comment_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `cs_revision_idx` (`revision`), + KEY `cs_version_idx` (`version`), + CONSTRAINT `changeset_statuses_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_statuses_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `changeset_statuses_ibfk_3` FOREIGN KEY (`changeset_comment_id`) REFERENCES `changeset_comments` (`comment_id`), + CONSTRAINT `changeset_statuses_ibfk_4` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_statuses` +-- + +LOCK TABLES `changeset_statuses` WRITE; +/*!40000 ALTER TABLE `changeset_statuses` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_statuses` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `db_migrate_version` +-- + +DROP TABLE IF EXISTS `db_migrate_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `db_migrate_version` ( + `repository_id` varchar(250) NOT NULL, + `repository_path` text, + `version` int(11) DEFAULT NULL, + PRIMARY KEY (`repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `db_migrate_version` +-- + +LOCK TABLES `db_migrate_version` WRITE; +/*!40000 ALTER TABLE `db_migrate_version` DISABLE KEYS */; +INSERT INTO `db_migrate_version` VALUES ('rhodecode_db_migrations','versions',11); +/*!40000 ALTER TABLE `db_migrate_version` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `groups` +-- + +DROP TABLE IF EXISTS `groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `groups` ( + `group_id` int(11) NOT NULL AUTO_INCREMENT, + `group_name` varchar(255) NOT NULL, + `group_parent_id` int(11) DEFAULT NULL, + `group_description` varchar(10000) DEFAULT NULL, + `enable_locking` tinyint(1) NOT NULL, + PRIMARY KEY (`group_id`), + UNIQUE KEY `group_id` (`group_id`), + UNIQUE KEY `group_name_2` (`group_name`), + UNIQUE KEY `group_name` (`group_name`,`group_parent_id`), + KEY `group_parent_id` (`group_parent_id`), + CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`group_parent_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `groups` +-- + +LOCK TABLES `groups` WRITE; +/*!40000 ALTER TABLE `groups` DISABLE KEYS */; +INSERT INTO `groups` VALUES (1,'RC',NULL,'RC group',0),(2,'RC/mygr',1,'RC/mygr group',0),(3,'BIG',NULL,'BIG group',0),(4,'RC/rc2',1,'RC/rc2 group',0),(5,'RC/INRC',1,'RC/INRC group',0),(6,'RC/INRC/L2_NEW',5,'RC/INRC/L2_NEW group',0),(7,'RC/INRC/L2_NEW/L3',6,'RC/INRC/L2_NEW/L3 group',0),(8,'RC/lol',1,'RC/lol group',0); +/*!40000 ALTER TABLE `groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notifications` +-- + +DROP TABLE IF EXISTS `notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `notifications` ( + `notification_id` int(11) NOT NULL AUTO_INCREMENT, + `subject` varchar(512) DEFAULT NULL, + `body` mediumtext, + `created_by` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `type` varchar(256) DEFAULT NULL, + PRIMARY KEY (`notification_id`), + KEY `created_by` (`created_by`), + KEY `notification_type_idx` (`type`(255)), + CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notifications` +-- + +LOCK TABLES `notifications` WRITE; +/*!40000 ALTER TABLE `notifications` DISABLE KEYS */; +/*!40000 ALTER TABLE `notifications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `permissions` +-- + +DROP TABLE IF EXISTS `permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `permissions` ( + `permission_id` int(11) NOT NULL AUTO_INCREMENT, + `permission_name` varchar(255) DEFAULT NULL, + `permission_longname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`permission_id`), + UNIQUE KEY `permission_id` (`permission_id`), + KEY `p_perm_name_idx` (`permission_name`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `permissions` +-- + +LOCK TABLES `permissions` WRITE; +/*!40000 ALTER TABLE `permissions` DISABLE KEYS */; +INSERT INTO `permissions` VALUES (1,'repository.none','repository.none'),(2,'repository.read','repository.read'),(3,'repository.write','repository.write'),(4,'repository.admin','repository.admin'),(5,'group.none','group.none'),(6,'group.read','group.read'),(7,'group.write','group.write'),(8,'group.admin','group.admin'),(9,'hg.admin','hg.admin'),(10,'hg.create.none','hg.create.none'),(11,'hg.create.repository','hg.create.repository'),(12,'hg.fork.none','hg.fork.none'),(13,'hg.fork.repository','hg.fork.repository'),(14,'hg.register.none','hg.register.none'),(15,'hg.register.manual_activate','hg.register.manual_activate'),(16,'hg.register.auto_activate','hg.register.auto_activate'); +/*!40000 ALTER TABLE `permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_request_reviewers` +-- + +DROP TABLE IF EXISTS `pull_request_reviewers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_request_reviewers` ( + `pull_requests_reviewers_id` int(11) NOT NULL AUTO_INCREMENT, + `pull_request_id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`pull_requests_reviewers_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `pull_request_reviewers_ibfk_1` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `pull_request_reviewers_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_request_reviewers` +-- + +LOCK TABLES `pull_request_reviewers` WRITE; +/*!40000 ALTER TABLE `pull_request_reviewers` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_request_reviewers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_requests` +-- + +DROP TABLE IF EXISTS `pull_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_requests` ( + `pull_request_id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(256) DEFAULT NULL, + `description` text, + `status` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `user_id` int(11) NOT NULL, + `revisions` text, + `org_repo_id` int(11) NOT NULL, + `org_ref` varchar(256) NOT NULL, + `other_repo_id` int(11) NOT NULL, + `other_ref` varchar(256) NOT NULL, + PRIMARY KEY (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `org_repo_id` (`org_repo_id`), + KEY `other_repo_id` (`other_repo_id`), + CONSTRAINT `pull_requests_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `pull_requests_ibfk_2` FOREIGN KEY (`org_repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `pull_requests_ibfk_3` FOREIGN KEY (`other_repo_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_requests` +-- + +LOCK TABLES `pull_requests` WRITE; +/*!40000 ALTER TABLE `pull_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repo_to_perm` +-- + +DROP TABLE IF EXISTS `repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repo_to_perm` ( + `repo_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`repo_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`repository_id`,`permission_id`), + UNIQUE KEY `repo_to_perm_id` (`repo_to_perm_id`), + KEY `permission_id` (`permission_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `repo_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repo_to_perm` +-- + +LOCK TABLES `repo_to_perm` WRITE; +/*!40000 ALTER TABLE `repo_to_perm` DISABLE KEYS */; +INSERT INTO `repo_to_perm` VALUES (1,1,2,1),(2,1,2,2),(3,1,2,3),(4,1,2,4),(5,1,2,5),(6,1,2,6),(7,1,2,7),(8,1,2,8),(9,1,2,9),(10,1,2,10),(11,1,2,11),(12,1,2,12),(13,1,2,13),(14,1,2,14),(15,1,2,15),(16,1,2,16),(17,1,2,17),(18,1,2,18),(19,1,2,19),(20,1,2,20),(21,1,2,21),(22,1,2,22),(23,1,2,23),(24,1,2,24),(25,1,2,25),(26,1,2,26),(27,1,2,27),(28,1,2,28),(29,1,2,29),(30,1,2,30),(31,1,2,31),(32,1,2,32),(33,1,2,33),(34,1,2,34),(35,1,2,35),(36,1,2,36),(37,1,2,37),(38,1,2,38),(39,1,2,39),(40,1,2,40),(41,1,2,41),(42,1,2,42),(43,1,2,43),(44,1,2,44),(45,1,2,45),(46,1,2,46),(47,1,2,47),(48,1,2,48),(49,1,2,49),(50,1,2,50),(51,1,2,51),(52,1,2,52),(53,1,2,53),(54,1,2,54),(55,1,2,55),(56,1,2,56),(57,1,2,57),(58,1,2,58),(59,1,2,59); +/*!40000 ALTER TABLE `repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories` +-- + +DROP TABLE IF EXISTS `repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories` ( + `repo_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_name` varchar(255) NOT NULL, + `clone_uri` varchar(255) DEFAULT NULL, + `repo_type` varchar(255) NOT NULL, + `user_id` int(11) NOT NULL, + `private` tinyint(1) DEFAULT NULL, + `statistics` tinyint(1) DEFAULT NULL, + `downloads` tinyint(1) DEFAULT NULL, + `description` varchar(10000) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `landing_revision` varchar(255) NOT NULL, + `enable_locking` tinyint(1) NOT NULL, + `locked` varchar(255) DEFAULT NULL, + `changeset_cache` blob, + `fork_id` int(11) DEFAULT NULL, + `group_id` int(11) DEFAULT NULL, + PRIMARY KEY (`repo_id`), + UNIQUE KEY `repo_name` (`repo_name`), + UNIQUE KEY `repo_id` (`repo_id`), + UNIQUE KEY `repo_name_2` (`repo_name`), + KEY `user_id` (`user_id`), + KEY `fork_id` (`fork_id`), + KEY `group_id` (`group_id`), + KEY `r_repo_name_idx` (`repo_name`), + CONSTRAINT `repositories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repositories_ibfk_2` FOREIGN KEY (`fork_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `repositories_ibfk_3` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories` +-- + +LOCK TABLES `repositories` WRITE; +/*!40000 ALTER TABLE `repositories` DISABLE KEYS */; +INSERT INTO `repositories` VALUES (1,'RC/mygr/lol','http://user@vm/RC/mygr/lol','hg',2,0,0,0,'RC/mygr/lol repository','2013-05-29 14:16:09','2013-05-29 14:16:09','tip',0,NULL,NULL,NULL,2),(2,'RC/fakeclone',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:09','2013-05-09 01:48:00','tip',0,NULL,'{\"raw_id\": \"dfa7d376778d681d1818f41b17706efa6033b407\", \"short_id\": \"dfa7d376778d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-09T01:48:00\", \"message\": \"fixed\\n\", \"revision\": 293}',NULL,1),(3,'RC/muay',NULL,'hg',2,0,0,0,'RC/muay repository','2013-05-29 14:16:09','2013-05-29 14:16:09','tip',0,NULL,NULL,NULL,1),(4,'BIG/git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:10','2012-10-21 23:47:54','tip',0,NULL,'{\"raw_id\": \"30f4c66e634760a81ab27a236fe1f2482f6f7856\", \"short_id\": \"30f4c66e6347\", \"author\": \"Junio C Hamano \", \"date\": \"2012-10-21T23:47:54\", \"message\": \"What\'s cooking (2012/10 #07)\\n\", \"revision\": 32160}',NULL,3),(5,'RC/origin-fork',NULL,'hg',2,0,0,0,'RC/origin-fork repository','2013-05-29 14:16:11','2013-03-06 20:16:20','tip',0,NULL,'{\"raw_id\": \"f0ce39a6f9edfc6392d4d6137f05bb3871e41780\", \"short_id\": \"f0ce39a6f9ed\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-06T20:16:20\", \"message\": \"Edited file via options\\n- fixed 1\\n-f xied 2\\nand so on so on trallalala\", \"revision\": 21}',NULL,1),(6,'RC/trololo',NULL,'hg',2,0,0,0,'RC/trololo repository','2013-05-29 14:16:11','2013-03-28 02:35:50','tip',0,NULL,'{\"raw_id\": \"890d7469abac360637c8cf79f158b170415e1653\", \"short_id\": \"890d7469abac\", \"author\": \"demo user \", \"date\": \"2013-03-28T02:35:50\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(7,'csa-collins',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-02-25 17:31:39','tip',0,NULL,'{\"raw_id\": \"8be6a10d645c8dda5f1f331496228118ae872ce8\", \"short_id\": \"8be6a10d645c\", \"author\": \"Bastian Albers \", \"date\": \"2013-02-25T17:31:39\", \"message\": \"Merge branch \'stage\' into stage2\\n\", \"revision\": 2731}',NULL,NULL),(8,'csa-harmony',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-05-22 14:49:45','tip',0,NULL,'{\"raw_id\": \"27b59603618b07259ca0db6b00990feeba96930f\", \"short_id\": \"27b59603618b\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-22T14:49:45\", \"message\": \"Added kwargs to setup functions for later optional params\\n\", \"revision\": 339}',NULL,NULL),(9,'RC/Ä…qweqwe',NULL,'hg',2,0,0,0,'RC/Ä…qweqwe repository','2013-05-29 14:16:11','2013-05-29 00:06:28','tip',0,NULL,'{\"raw_id\": \"6c94b338a07134922f042f000f991d47a14bebf9\", \"short_id\": \"6c94b338a071\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-29T00:06:28\", \"message\": \"Edited file \\u0142\\u00f3\\u015b via RhodeCode\", \"revision\": 1}',NULL,1),(10,'rhodecode',NULL,'hg',2,0,0,0,'rhodecode repository','2013-05-29 14:16:11','2013-05-29 12:13:02','tip',0,NULL,'{\"raw_id\": \"424b6c711a7f63680abd1474b66ddf42c0345a16\", \"short_id\": \"424b6c711a7f\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-29T12:13:02\", \"message\": \"allow underscores in usernames. Helps creating special internal users\", \"revision\": 4053}',NULL,NULL),(11,'csa-unity',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-04-29 14:38:23','tip',0,NULL,'{\"raw_id\": \"093708759ebf4fd2bb1bdcad61fb611bc32933d3\", \"short_id\": \"093708759ebf\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-29T14:38:23\", \"message\": \"revert to logbook 0.3.0\", \"revision\": 28}',NULL,NULL),(12,'RC/Å‚Ä™cina',NULL,'hg',2,0,0,0,'RC/Å‚Ä™cina repository','2013-05-29 14:16:12','2013-03-06 16:17:49','tip',0,NULL,'{\"raw_id\": \"1ee589bcfa9212c5110ea5c1fe2cc8ff6eaf1303\", \"short_id\": \"1ee589bcfa92\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-06T16:17:49\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(13,'waitress',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-05-28 13:21:35','tip',0,NULL,'{\"raw_id\": \"e5d138ce3f754e6031e7abd76e5f527363fdaf42\", \"short_id\": \"e5d138ce3f75\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-28T13:21:35\", \"message\": \"Added docs and new flag into runner\\n\", \"revision\": 272}',NULL,NULL),(14,'RC/rc2/test2',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-03-03 00:29:35','tip',0,NULL,'{\"raw_id\": \"0eb3304fc33d05d328f8627b9ad44dae83f313a2\", \"short_id\": \"0eb3304fc33d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-03T00:29:35\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n fix requests 1.1 json method\\n fixed tests\\n moved tests into package\\n -bump distribute\\n update .gitignore\\n version freeze of libs\\n remove gevent from IO as dependency\\n add unity as deps\\n fully delegate AUTH back to armstrong\\n\", \"revision\": 50}',NULL,4),(15,'RC/origin-fork-fork',NULL,'hg',2,0,0,0,'RC/origin-fork-fork repository','2013-05-29 14:16:12','2013-05-06 23:44:50','tip',0,NULL,'{\"raw_id\": \"6d99e0d4dfcc4a5afa5c138fea2098470634f773\", \"short_id\": \"6d99e0d4dfcc\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-06T23:44:50\", \"message\": \"Issue #17094: Clear stale thread states after fork().\\n\\nNote that this is a potentially disruptive change since it may\\nrelease some system resources which would otherwise remain\\nperpetually alive (e.g. database connections kept in thread-local\\nstorage).\", \"revision\": 25}',NULL,1),(16,'RC/rc2/test4',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-03-21 22:55:29','tip',0,NULL,'{\"raw_id\": \"3b6ac7f5e932d4dd13871a0b23d6ca98510d88c2\", \"short_id\": \"3b6ac7f5e932\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-21T22:55:29\", \"message\": \"dsadas\", \"revision\": 51}',NULL,4),(17,'RC/vcs-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-04-26 23:34:15','tip',0,NULL,'{\"raw_id\": \"90da1f69a6c60f7d4d5646ee39ac5f6108bc077c\", \"short_id\": \"90da1f69a6c6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-26T23:34:15\", \"message\": \"merge with GIT vcs\\n\", \"revision\": 648}',NULL,1),(18,'rhodecode-extensions',NULL,'hg',2,0,0,0,'rhodecode-extensions repository','2013-05-29 14:16:12','2013-02-13 16:50:33','tip',0,NULL,'{\"raw_id\": \"da7e5f7a39d3203ff0b4af5018ac4a80d94ed1d4\", \"short_id\": \"da7e5f7a39d3\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-02-13T16:50:33\", \"message\": \"Linkify hipchat messages\", \"revision\": 2}',NULL,NULL),(19,'rhodecode-cli-gist',NULL,'hg',2,0,0,0,'rhodecode-cli-gist repository','2013-05-29 14:16:12','2013-05-29 14:16:12','tip',0,NULL,NULL,NULL,NULL),(20,'RC/new',NULL,'hg',2,0,0,0,'RC/new repository','2013-05-29 14:16:12','2013-04-17 13:02:59','tip',0,NULL,'{\"raw_id\": \"93192e03a3552b8da4fee40e001c60304723bb42\", \"short_id\": \"93192e03a355\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-17T13:02:59\", \"message\": \"rename\", \"revision\": 1}',NULL,1),(21,'csa-aldrin',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-05-02 23:47:52','tip',0,NULL,'{\"raw_id\": \"67ee9e830c225921ec15974ac1dfde17a930e2fb\", \"short_id\": \"67ee9e830c22\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-02T23:47:52\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n moved gevent into out internal server\\n stupid assholes in gevent should learn how to package...\\n fixed gevent dependency link\\n added separate call for session validation\\n\", \"revision\": 293}',NULL,NULL),(22,'vcs',NULL,'hg',2,0,0,0,'vcs repository','2013-05-29 14:16:13','2013-05-09 00:28:54','tip',0,NULL,'{\"raw_id\": \"6fba59f9f7806a545a0e5ebac936991828436260\", \"short_id\": \"6fba59f9f780\", \"author\": \"Lukasz Balcerzak \", \"date\": \"2013-05-09T00:28:54\", \"message\": \"Merge pull request #117 from niedbalski/master\\n\\nKeyError: \'all\'\", \"revision\": 707}',NULL,NULL),(23,'csa-prometheus',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-04-29 14:37:43','tip',0,NULL,'{\"raw_id\": \"a719bd82d25e7411fdb7979c12c083f59a206a6c\", \"short_id\": \"a719bd82d25e\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-29T14:37:43\", \"message\": \"revert logbook to 0.3.0\", \"revision\": 79}',NULL,NULL),(24,'RC/INRC/trololo',NULL,'hg',2,0,0,0,'RC/INRC/trololo repository','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,5),(25,'RC/empty-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,1),(26,'RC/bin-ops',NULL,'hg',2,0,0,0,'RC/bin-ops repository','2013-05-29 14:16:13','2013-05-12 12:39:34','tip',0,NULL,'{\"raw_id\": \"4231762d8c1aaca5be3db15991071236c32e7654\", \"short_id\": \"4231762d8c1a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-12T12:39:34\", \"message\": \"Edited file file1 via RhodeCode\", \"revision\": 23}',NULL,1),(27,'csa-salt-states',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-05-06 14:48:48','tip',0,NULL,'{\"raw_id\": \"0c20dc72baeedc3ce840c611174c7e1cd3b04919\", \"short_id\": \"0c20dc72baee\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-06T14:48:48\", \"message\": \"increase sampling of CPU time to 0.5s for more realistic data.\", \"revision\": 71}',NULL,NULL),(28,'rhodecode-premium',NULL,'hg',2,0,0,0,'rhodecode-premium repository','2013-05-29 14:16:13','2013-03-21 22:58:11','tip',0,NULL,'{\"raw_id\": \"ded35bf017f16bcad6611c7ffe3b1b1c10942f50\", \"short_id\": \"ded35bf017f1\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-21T22:58:11\", \"message\": \"version bump to 1.5.4p2\", \"revision\": 3674}',NULL,NULL),(29,'RC/qweqwe-fork',NULL,'hg',2,0,0,0,'RC/qweqwe-fork repository','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,1),(30,'RC/test',NULL,'hg',2,0,0,0,'RC/test repository','2013-05-29 14:16:13','2013-01-30 22:56:03','tip',0,NULL,'{\"raw_id\": \"e5025e316d9acb39e5f861c494240be4f5d56de6\", \"short_id\": \"e5025e316d9a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-01-30T22:56:03\", \"message\": \" fixes #700\", \"revision\": 2}',NULL,1),(31,'remote-salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2012-10-14 22:04:05','tip',0,NULL,'{\"raw_id\": \"d661dc72492e66cab7a647dcb5652009067aa8cd\", \"short_id\": \"d661dc72492e\", \"author\": \"Marcin Kuzminski \", \"date\": \"2012-10-14T22:04:05\", \"message\": \"Logging\\nOn-the-fly msg encryption using googles keyCzar lib\", \"revision\": 3}',NULL,NULL),(32,'BIG/android',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2012-06-17 00:44:46','tip',0,NULL,'{\"raw_id\": \"e86b147e4b6908a7c5ab0963d77fb0867679b1ee\", \"short_id\": \"e86b147e4b69\", \"author\": \"Bernhard Rosenkraenzer \", \"date\": \"2012-06-17T00:44:46\", \"message\": \"panda: Backport HDMI vs. DVI patch from kernel/panda.git\\n\\nThis patch allows switching the primary display output device.\\n\\nChange-Id: I6e30e87bbc7aa72b5acc6e6c4ed34019835e6524\\nSigned-off-by: Bernhard Rosenkraenzer \\n\", \"revision\": 294896}',NULL,3),(33,'DOCS',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:24','2013-04-25 16:45:59','tip',0,NULL,'{\"raw_id\": \"1e4a728ee7a6aa88be11260d6479a446eb865de3\", \"short_id\": \"1e4a728ee7a6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-25T16:45:59\", \"message\": \"sync docs with armstrong\", \"revision\": 15}',NULL,NULL),(34,'rhodecode-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:24','2013-01-04 00:24:22','tip',0,NULL,'{\"raw_id\": \"629f1538ad4800ff05113516f6a933e2b243f205\", \"short_id\": \"629f1538ad48\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-01-04T00:24:22\", \"message\": \"nicer representation of list of rescanned repositories\\n\\n--HG--\\nbranch : beta\\n\", \"revision\": 3142}',NULL,NULL),(35,'RC/fork-remote',NULL,'hg',2,0,0,0,'RC/fork-remote repository','2013-05-29 14:16:24','2013-03-10 22:47:24','tip',0,NULL,'{\"raw_id\": \"60555484a0a0d6e525e9d7ab1b1dce5ab9eb9487\", \"short_id\": \"60555484a0a0\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-10T22:47:24\", \"message\": \"aaa\", \"revision\": 26}',NULL,1),(36,'RC/INRC/L2_NEW/lalalal',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/lalalal repository','2013-05-29 14:16:24','2013-05-29 14:16:24','tip',0,NULL,NULL,NULL,6),(37,'RC/INRC/L2_NEW/L3/repo_test_move',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/L3/repo_test_move repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,7),(38,'RC/gogo-fork',NULL,'hg',2,0,0,0,'RC/gogo-fork repository','2013-05-29 14:16:25','2013-05-28 21:33:55','tip',0,NULL,'{\"raw_id\": \"d72044a6e192f89de3f2b723557942eecb420308\", \"short_id\": \"d72044a6e192\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-28T21:33:55\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(39,'quest',NULL,'hg',2,0,0,0,'quest repository','2013-05-29 14:16:25','2013-03-04 23:01:40','tip',0,NULL,'{\"raw_id\": \"54b01cfdea25bf41cd8e9a184c5852c5d48d864c\", \"short_id\": \"54b01cfdea25\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-04T23:01:40\", \"message\": \"template and version 0.0.1\", \"revision\": 41}',NULL,NULL),(40,'RC/foobar',NULL,'hg',2,0,0,0,'RC/foobar repository','2013-05-29 14:16:25','2013-04-15 21:34:57','tip',0,NULL,'{\"raw_id\": \"c17dc3c566952813e84037dfd62a4755ed3c912c\", \"short_id\": \"c17dc3c56695\", \"author\": \"Mirek Kott \", \"date\": \"2013-04-15T21:34:57\", \"message\": \"Edited file lol.rst via RhodeCode\", \"revision\": 1}',NULL,1),(41,'csa-hyperion',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-05-20 21:58:28','tip',0,NULL,'{\"raw_id\": \"252c926d10702e6ef7c2456f2fc23892808e53a0\", \"short_id\": \"252c926d1070\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-20T21:58:28\", \"message\": \"fixes for new code\\n\", \"revision\": 57}',NULL,NULL),(42,'RC/git-pull-test',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-05-20 13:03:02','tip',0,NULL,'{\"raw_id\": \"b2cf1136f09fa61df90469b43310615984bc7d55\", \"short_id\": \"b2cf1136f09f\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-20T13:03:02\", \"message\": \"added\\n\", \"revision\": 13}',NULL,1),(43,'RC/qweqwe-fork2',NULL,'hg',2,0,0,0,'RC/qweqwe-fork2 repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,1),(44,'RC/jap',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-04-24 11:15:30','tip',0,NULL,'{\"raw_id\": \"2f62ce22453a67eefd6fab1d4e053520e8debdf6\", \"short_id\": \"2f62ce22453a\", \"author\": \"Demo User \", \"date\": \"2013-04-24T11:15:30\", \"message\": \"\\u30d5\\u30a1\\u30a4\\u30eb\\u8ffd\\u52a0\", \"revision\": 5}',NULL,1),(45,'RC/hg-repo',NULL,'hg',2,0,0,0,'RC/hg-repo repository','2013-05-29 14:16:25','2013-05-08 22:54:45','tip',0,NULL,'{\"raw_id\": \"d63d40e8b0685af6db5f2cf7700e80216af5c739\", \"short_id\": \"d63d40e8b068\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-08T22:54:45\", \"message\": \"Edited file haha via RhodeCode\", \"revision\": 25}',NULL,1),(46,'RC/origin',NULL,'hg',2,0,0,0,'RC/origin repository','2013-05-29 14:16:25','2013-04-05 13:05:02','tip',0,NULL,'{\"raw_id\": \"5fbf2f0eada43bc33a94e483503335d8f6757093\", \"short_id\": \"5fbf2f0eada4\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-05T13:05:02\", \"message\": \"fixed\", \"revision\": 29}',NULL,1),(47,'rhodecode-cli-api',NULL,'hg',2,0,0,0,'rhodecode-cli-api repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,NULL),(48,'RC/rc2/test3',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-03-03 00:29:35','tip',0,NULL,'{\"raw_id\": \"0eb3304fc33d05d328f8627b9ad44dae83f313a2\", \"short_id\": \"0eb3304fc33d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-03T00:29:35\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n fix requests 1.1 json method\\n fixed tests\\n moved tests into package\\n -bump distribute\\n update .gitignore\\n version freeze of libs\\n remove gevent from IO as dependency\\n add unity as deps\\n fully delegate AUTH back to armstrong\\n\", \"revision\": 50}',NULL,4),(49,'csa-armstrong',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-05-22 18:10:20','tip',0,NULL,'{\"raw_id\": \"60ffa2018fa120c97c0c5fcab93ecd82e2c3a691\", \"short_id\": \"60ffa2018fa1\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-22T18:10:20\", \"message\": \"fix actual progress increase in salt calls\\n\", \"revision\": 1140}',NULL,NULL),(50,'pyramidpypi',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-04-25 16:34:48','tip',0,NULL,'{\"raw_id\": \"ed9aceffada3ef38509c5d7010b016ba45e82944\", \"short_id\": \"ed9aceffada3\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-25T16:34:48\", \"message\": \"version bump\", \"revision\": 28}',NULL,NULL),(51,'RC/lol/haha',NULL,'hg',2,0,0,0,'RC/lol/haha repository','2013-05-29 14:16:26','2013-05-29 14:16:26','tip',0,NULL,NULL,NULL,8),(52,'csa-io',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-05-02 22:52:54','tip',0,NULL,'{\"raw_id\": \"bd0ef71fcfd088a82b8627e60aaa1f2020ed33ba\", \"short_id\": \"bd0ef71fcfd0\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-02T22:52:54\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n Use ext_json instead of plain simplejson serializer\\n log errors on restfull json parsers/decoders\\n fixed some serialization problems\\n version bump\\n Repository revisions API\\n mercurial version bump\\n Bump VCS version to 0.4.0 and move it to code.appzonaut.com\\n fix logging on changes json module in requests 1.X\\n\", \"revision\": 59}',NULL,NULL),(53,'enc-envelope',NULL,'hg',2,0,0,0,'enc-envelope repository','2013-05-29 14:16:26','2013-03-07 15:37:40','tip',0,NULL,'{\"raw_id\": \"810066f835d6c082950fc7828ded50b9b8d9c229\", \"short_id\": \"810066f835d6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-07T15:37:40\", \"message\": \"show more detailed info about wrong stream\", \"revision\": 5}',NULL,NULL),(54,'RC/gogo2',NULL,'hg',2,0,0,0,'RC/gogo2 repository','2013-05-29 14:16:26','2013-05-28 21:33:39','tip',0,NULL,'{\"raw_id\": \"07f1002bc22aff4231f7c94b54715547c29c37c6\", \"short_id\": \"07f1002bc22a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-28T21:33:39\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(55,'csa-libcloud',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2013-04-17 16:42:42','tip',0,NULL,'{\"raw_id\": \"a2fa551633ce3697ac63a935aa71f1e7b80222ae\", \"short_id\": \"a2fa551633ce\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-17T16:42:42\", \"message\": \"filter only listeners Brightbox can process\", \"revision\": 1895}',NULL,NULL),(56,'RC/git-test',NULL,'git',2,0,0,0,'Unnamed repository','2013-05-29 14:16:27','2013-05-29 00:10:16','tip',0,NULL,'{\"raw_id\": \"c0d94361073eaf60106b60af628949a1bad45f2d\", \"short_id\": \"c0d94361073e\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-29T00:10:16\", \"message\": \"Edited file \\u0142\\u00f3\\u015b via RhodeCode\", \"revision\": 11}',NULL,1),(57,'RC/rc2/test',NULL,'hg',2,0,0,0,'RC/rc2/test repository','2013-05-29 14:16:27','2013-05-29 14:16:27','tip',0,NULL,NULL,NULL,4),(58,'salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2012-10-15 05:20:58','tip',0,NULL,'{\"raw_id\": \"bd44832230fc19eb80fe49ef01badb477ef8ca6c\", \"short_id\": \"bd44832230fc\", \"author\": \"Thomas S Hatch \", \"date\": \"2012-10-15T05:20:58\", \"message\": \"Merge pull request #2244 from FireHost/toplevel_wmi_import\\n\\nToplevel wmi import\", \"revision\": 6957}',NULL,NULL),(59,'RC/kiall-nova',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2012-10-23 10:22:06','tip',0,NULL,'{\"raw_id\": \"a0fcd1248071ad66b610eac4903adf36b314390b\", \"short_id\": \"a0fcd1248071\", \"author\": \"Jenkins \", \"date\": \"2012-10-23T10:22:06\", \"message\": \"Merge \\\"Fix nova-volume-usage-audit\\\"\", \"revision\": 17253}',NULL,1); +/*!40000 ALTER TABLE `repositories` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories_fields` +-- + +DROP TABLE IF EXISTS `repositories_fields`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories_fields` ( + `repo_field_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `field_key` varchar(250) DEFAULT NULL, + `field_label` varchar(1024) NOT NULL, + `field_value` varchar(10000) NOT NULL, + `field_desc` varchar(1024) NOT NULL, + `field_type` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + PRIMARY KEY (`repo_field_id`), + UNIQUE KEY `repo_field_id` (`repo_field_id`), + UNIQUE KEY `repository_id` (`repository_id`,`field_key`), + CONSTRAINT `repositories_fields_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories_fields` +-- + +LOCK TABLES `repositories_fields` WRITE; +/*!40000 ALTER TABLE `repositories_fields` DISABLE KEYS */; +/*!40000 ALTER TABLE `repositories_fields` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_settings` +-- + +DROP TABLE IF EXISTS `rhodecode_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_settings` ( + `app_settings_id` int(11) NOT NULL AUTO_INCREMENT, + `app_settings_name` varchar(255) DEFAULT NULL, + `app_settings_value` varchar(255) DEFAULT NULL, + PRIMARY KEY (`app_settings_id`), + UNIQUE KEY `app_settings_id` (`app_settings_id`), + UNIQUE KEY `app_settings_name` (`app_settings_name`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_settings` +-- + +LOCK TABLES `rhodecode_settings` WRITE; +/*!40000 ALTER TABLE `rhodecode_settings` DISABLE KEYS */; +INSERT INTO `rhodecode_settings` VALUES (1,'realm','RhodeCode authentication'),(2,'title','RhodeCode'),(3,'ga_code',''),(4,'show_public_icon','True'),(5,'show_private_icon','True'),(6,'stylify_metatags','False'),(7,'ldap_active','false'),(8,'ldap_host',''),(9,'ldap_port','389'),(10,'ldap_tls_kind','PLAIN'),(11,'ldap_tls_reqcert',''),(12,'ldap_dn_user',''),(13,'ldap_dn_pass',''),(14,'ldap_base_dn',''),(15,'ldap_filter',''),(16,'ldap_search_scope',''),(17,'ldap_attr_login',''),(18,'ldap_attr_firstname',''),(19,'ldap_attr_lastname',''),(20,'ldap_attr_email',''),(21,'default_repo_enable_locking','False'),(22,'default_repo_enable_downloads','False'),(23,'default_repo_enable_statistics','False'),(24,'default_repo_private','False'),(25,'default_repo_type','hg'); +/*!40000 ALTER TABLE `rhodecode_settings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_ui` +-- + +DROP TABLE IF EXISTS `rhodecode_ui`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_ui` ( + `ui_id` int(11) NOT NULL AUTO_INCREMENT, + `ui_section` varchar(255) DEFAULT NULL, + `ui_key` varchar(255) DEFAULT NULL, + `ui_value` varchar(255) DEFAULT NULL, + `ui_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ui_id`), + UNIQUE KEY `ui_id` (`ui_id`), + UNIQUE KEY `ui_key` (`ui_key`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_ui` +-- + +LOCK TABLES `rhodecode_ui` WRITE; +/*!40000 ALTER TABLE `rhodecode_ui` DISABLE KEYS */; +INSERT INTO `rhodecode_ui` VALUES (1,'hooks','changegroup.update','hg update >&2',0),(2,'hooks','changegroup.repo_size','python:rhodecode.lib.hooks.repo_size',1),(3,'hooks','changegroup.push_logger','python:rhodecode.lib.hooks.log_push_action',1),(4,'hooks','prechangegroup.pre_push','python:rhodecode.lib.hooks.pre_push',1),(5,'hooks','outgoing.pull_logger','python:rhodecode.lib.hooks.log_pull_action',1),(6,'hooks','preoutgoing.pre_pull','python:rhodecode.lib.hooks.pre_pull',1),(7,'extensions','largefiles','',1),(8,'extensions','hgsubversion','',0),(9,'extensions','hggit','',0),(10,'web','push_ssl','false',1),(11,'web','allow_archive','gz zip bz2',1),(12,'web','allow_push','*',1),(13,'web','baseurl','/',1),(14,'paths','/','/mnt/hgfs/workspace-python',1); +/*!40000 ALTER TABLE `rhodecode_ui` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `statistics` +-- + +DROP TABLE IF EXISTS `statistics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `statistics` ( + `stat_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `stat_on_revision` int(11) NOT NULL, + `commit_activity` mediumblob NOT NULL, + `commit_activity_combined` blob NOT NULL, + `languages` mediumblob NOT NULL, + PRIMARY KEY (`stat_id`), + UNIQUE KEY `repository_id` (`repository_id`), + UNIQUE KEY `stat_id` (`stat_id`), + UNIQUE KEY `repository_id_2` (`repository_id`), + CONSTRAINT `statistics_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `statistics` +-- + +LOCK TABLES `statistics` WRITE; +/*!40000 ALTER TABLE `statistics` DISABLE KEYS */; +/*!40000 ALTER TABLE `statistics` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_email_map` +-- + +DROP TABLE IF EXISTS `user_email_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_email_map` ( + `email_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + PRIMARY KEY (`email_id`), + UNIQUE KEY `email_id` (`email_id`), + UNIQUE KEY `email` (`email`), + KEY `user_id` (`user_id`), + KEY `uem_email_idx` (`email`), + CONSTRAINT `user_email_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_email_map` +-- + +LOCK TABLES `user_email_map` WRITE; +/*!40000 ALTER TABLE `user_email_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_email_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_followings` +-- + +DROP TABLE IF EXISTS `user_followings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_followings` ( + `user_following_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `follows_repository_id` int(11) DEFAULT NULL, + `follows_user_id` int(11) DEFAULT NULL, + `follows_from` datetime DEFAULT NULL, + PRIMARY KEY (`user_following_id`), + UNIQUE KEY `user_following_id` (`user_following_id`), + UNIQUE KEY `user_id` (`user_id`,`follows_repository_id`), + UNIQUE KEY `user_id_2` (`user_id`,`follows_user_id`), + KEY `follows_repository_id` (`follows_repository_id`), + KEY `follows_user_id` (`follows_user_id`), + CONSTRAINT `user_followings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_followings_ibfk_2` FOREIGN KEY (`follows_repository_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `user_followings_ibfk_3` FOREIGN KEY (`follows_user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_followings` +-- + +LOCK TABLES `user_followings` WRITE; +/*!40000 ALTER TABLE `user_followings` DISABLE KEYS */; +INSERT INTO `user_followings` VALUES (1,2,1,NULL,'2013-05-29 14:16:09'),(2,2,2,NULL,'2013-05-29 14:16:09'),(3,2,3,NULL,'2013-05-29 14:16:10'),(4,2,4,NULL,'2013-05-29 14:16:10'),(5,2,5,NULL,'2013-05-29 14:16:11'),(6,2,6,NULL,'2013-05-29 14:16:11'),(7,2,7,NULL,'2013-05-29 14:16:11'),(8,2,8,NULL,'2013-05-29 14:16:11'),(9,2,9,NULL,'2013-05-29 14:16:11'),(10,2,10,NULL,'2013-05-29 14:16:11'),(11,2,11,NULL,'2013-05-29 14:16:11'),(12,2,12,NULL,'2013-05-29 14:16:12'),(13,2,13,NULL,'2013-05-29 14:16:12'),(14,2,14,NULL,'2013-05-29 14:16:12'),(15,2,15,NULL,'2013-05-29 14:16:12'),(16,2,16,NULL,'2013-05-29 14:16:12'),(17,2,17,NULL,'2013-05-29 14:16:12'),(18,2,18,NULL,'2013-05-29 14:16:12'),(19,2,19,NULL,'2013-05-29 14:16:12'),(20,2,20,NULL,'2013-05-29 14:16:12'),(21,2,21,NULL,'2013-05-29 14:16:12'),(22,2,22,NULL,'2013-05-29 14:16:13'),(23,2,23,NULL,'2013-05-29 14:16:13'),(24,2,24,NULL,'2013-05-29 14:16:13'),(25,2,25,NULL,'2013-05-29 14:16:13'),(26,2,26,NULL,'2013-05-29 14:16:13'),(27,2,27,NULL,'2013-05-29 14:16:13'),(28,2,28,NULL,'2013-05-29 14:16:13'),(29,2,29,NULL,'2013-05-29 14:16:13'),(30,2,30,NULL,'2013-05-29 14:16:13'),(31,2,31,NULL,'2013-05-29 14:16:13'),(32,2,32,NULL,'2013-05-29 14:16:13'),(33,2,33,NULL,'2013-05-29 14:16:24'),(34,2,34,NULL,'2013-05-29 14:16:24'),(35,2,35,NULL,'2013-05-29 14:16:24'),(36,2,36,NULL,'2013-05-29 14:16:24'),(37,2,37,NULL,'2013-05-29 14:16:25'),(38,2,38,NULL,'2013-05-29 14:16:25'),(39,2,39,NULL,'2013-05-29 14:16:25'),(40,2,40,NULL,'2013-05-29 14:16:25'),(41,2,41,NULL,'2013-05-29 14:16:25'),(42,2,42,NULL,'2013-05-29 14:16:25'),(43,2,43,NULL,'2013-05-29 14:16:25'),(44,2,44,NULL,'2013-05-29 14:16:25'),(45,2,45,NULL,'2013-05-29 14:16:25'),(46,2,46,NULL,'2013-05-29 14:16:25'),(47,2,47,NULL,'2013-05-29 14:16:25'),(48,2,48,NULL,'2013-05-29 14:16:25'),(49,2,49,NULL,'2013-05-29 14:16:26'),(50,2,50,NULL,'2013-05-29 14:16:26'),(51,2,51,NULL,'2013-05-29 14:16:26'),(52,2,52,NULL,'2013-05-29 14:16:26'),(53,2,53,NULL,'2013-05-29 14:16:26'),(54,2,54,NULL,'2013-05-29 14:16:26'),(55,2,55,NULL,'2013-05-29 14:16:27'),(56,2,56,NULL,'2013-05-29 14:16:27'),(57,2,57,NULL,'2013-05-29 14:16:27'),(58,2,58,NULL,'2013-05-29 14:16:27'),(59,2,59,NULL,'2013-05-29 14:16:27'); +/*!40000 ALTER TABLE `user_followings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_ip_map` +-- + +DROP TABLE IF EXISTS `user_ip_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_ip_map` ( + `ip_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `ip_addr` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ip_id`), + UNIQUE KEY `ip_id` (`ip_id`), + UNIQUE KEY `user_id` (`user_id`,`ip_addr`), + CONSTRAINT `user_ip_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_ip_map` +-- + +LOCK TABLES `user_ip_map` WRITE; +/*!40000 ALTER TABLE `user_ip_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_ip_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_logs` +-- + +DROP TABLE IF EXISTS `user_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_logs` ( + `user_log_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `repository_id` int(11) DEFAULT NULL, + `repository_name` varchar(255) DEFAULT NULL, + `user_ip` varchar(255) DEFAULT NULL, + `action` mediumtext, + `action_date` datetime DEFAULT NULL, + PRIMARY KEY (`user_log_id`), + UNIQUE KEY `user_log_id` (`user_log_id`), + KEY `user_id` (`user_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `user_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_logs_ibfk_2` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_logs` +-- + +LOCK TABLES `user_logs` WRITE; +/*!40000 ALTER TABLE `user_logs` DISABLE KEYS */; +INSERT INTO `user_logs` VALUES (1,2,'marcink',1,'RC/mygr/lol','','started_following_repo','2013-05-29 14:16:09'),(2,2,'marcink',2,'RC/fakeclone','','started_following_repo','2013-05-29 14:16:09'),(3,2,'marcink',3,'RC/muay','','started_following_repo','2013-05-29 14:16:09'),(4,2,'marcink',4,'BIG/git','','started_following_repo','2013-05-29 14:16:10'),(5,2,'marcink',5,'RC/origin-fork','','started_following_repo','2013-05-29 14:16:11'),(6,2,'marcink',6,'RC/trololo','','started_following_repo','2013-05-29 14:16:11'),(7,2,'marcink',7,'csa-collins','','started_following_repo','2013-05-29 14:16:11'),(8,2,'marcink',8,'csa-harmony','','started_following_repo','2013-05-29 14:16:11'),(9,2,'marcink',9,'RC/Ä…qweqwe','','started_following_repo','2013-05-29 14:16:11'),(10,2,'marcink',10,'rhodecode','','started_following_repo','2013-05-29 14:16:11'),(11,2,'marcink',11,'csa-unity','','started_following_repo','2013-05-29 14:16:11'),(12,2,'marcink',12,'RC/Å‚Ä™cina','','started_following_repo','2013-05-29 14:16:12'),(13,2,'marcink',13,'waitress','','started_following_repo','2013-05-29 14:16:12'),(14,2,'marcink',14,'RC/rc2/test2','','started_following_repo','2013-05-29 14:16:12'),(15,2,'marcink',15,'RC/origin-fork-fork','','started_following_repo','2013-05-29 14:16:12'),(16,2,'marcink',16,'RC/rc2/test4','','started_following_repo','2013-05-29 14:16:12'),(17,2,'marcink',17,'RC/vcs-git','','started_following_repo','2013-05-29 14:16:12'),(18,2,'marcink',18,'rhodecode-extensions','','started_following_repo','2013-05-29 14:16:12'),(19,2,'marcink',19,'rhodecode-cli-gist','','started_following_repo','2013-05-29 14:16:12'),(20,2,'marcink',20,'RC/new','','started_following_repo','2013-05-29 14:16:12'),(21,2,'marcink',21,'csa-aldrin','','started_following_repo','2013-05-29 14:16:12'),(22,2,'marcink',22,'vcs','','started_following_repo','2013-05-29 14:16:13'),(23,2,'marcink',23,'csa-prometheus','','started_following_repo','2013-05-29 14:16:13'),(24,2,'marcink',24,'RC/INRC/trololo','','started_following_repo','2013-05-29 14:16:13'),(25,2,'marcink',25,'RC/empty-git','','started_following_repo','2013-05-29 14:16:13'),(26,2,'marcink',26,'RC/bin-ops','','started_following_repo','2013-05-29 14:16:13'),(27,2,'marcink',27,'csa-salt-states','','started_following_repo','2013-05-29 14:16:13'),(28,2,'marcink',28,'rhodecode-premium','','started_following_repo','2013-05-29 14:16:13'),(29,2,'marcink',29,'RC/qweqwe-fork','','started_following_repo','2013-05-29 14:16:13'),(30,2,'marcink',30,'RC/test','','started_following_repo','2013-05-29 14:16:13'),(31,2,'marcink',31,'remote-salt','','started_following_repo','2013-05-29 14:16:13'),(32,2,'marcink',32,'BIG/android','','started_following_repo','2013-05-29 14:16:13'),(33,2,'marcink',33,'DOCS','','started_following_repo','2013-05-29 14:16:24'),(34,2,'marcink',34,'rhodecode-git','','started_following_repo','2013-05-29 14:16:24'),(35,2,'marcink',35,'RC/fork-remote','','started_following_repo','2013-05-29 14:16:24'),(36,2,'marcink',36,'RC/INRC/L2_NEW/lalalal','','started_following_repo','2013-05-29 14:16:24'),(37,2,'marcink',37,'RC/INRC/L2_NEW/L3/repo_test_move','','started_following_repo','2013-05-29 14:16:25'),(38,2,'marcink',38,'RC/gogo-fork','','started_following_repo','2013-05-29 14:16:25'),(39,2,'marcink',39,'quest','','started_following_repo','2013-05-29 14:16:25'),(40,2,'marcink',40,'RC/foobar','','started_following_repo','2013-05-29 14:16:25'),(41,2,'marcink',41,'csa-hyperion','','started_following_repo','2013-05-29 14:16:25'),(42,2,'marcink',42,'RC/git-pull-test','','started_following_repo','2013-05-29 14:16:25'),(43,2,'marcink',43,'RC/qweqwe-fork2','','started_following_repo','2013-05-29 14:16:25'),(44,2,'marcink',44,'RC/jap','','started_following_repo','2013-05-29 14:16:25'),(45,2,'marcink',45,'RC/hg-repo','','started_following_repo','2013-05-29 14:16:25'),(46,2,'marcink',46,'RC/origin','','started_following_repo','2013-05-29 14:16:25'),(47,2,'marcink',47,'rhodecode-cli-api','','started_following_repo','2013-05-29 14:16:25'),(48,2,'marcink',48,'RC/rc2/test3','','started_following_repo','2013-05-29 14:16:25'),(49,2,'marcink',49,'csa-armstrong','','started_following_repo','2013-05-29 14:16:26'),(50,2,'marcink',50,'pyramidpypi','','started_following_repo','2013-05-29 14:16:26'),(51,2,'marcink',51,'RC/lol/haha','','started_following_repo','2013-05-29 14:16:26'),(52,2,'marcink',52,'csa-io','','started_following_repo','2013-05-29 14:16:26'),(53,2,'marcink',53,'enc-envelope','','started_following_repo','2013-05-29 14:16:26'),(54,2,'marcink',54,'RC/gogo2','','started_following_repo','2013-05-29 14:16:26'),(55,2,'marcink',55,'csa-libcloud','','started_following_repo','2013-05-29 14:16:27'),(56,2,'marcink',56,'RC/git-test','','started_following_repo','2013-05-29 14:16:27'),(57,2,'marcink',57,'RC/rc2/test','','started_following_repo','2013-05-29 14:16:27'),(58,2,'marcink',58,'salt','','started_following_repo','2013-05-29 14:16:27'),(59,2,'marcink',59,'RC/kiall-nova','','started_following_repo','2013-05-29 14:16:27'); +/*!40000 ALTER TABLE `user_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `user_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_repo_group_to_perm` ( + `group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`group_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`group_id`,`permission_id`), + UNIQUE KEY `group_to_perm_id` (`group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_repo_group_to_perm` +-- + +LOCK TABLES `user_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `user_repo_group_to_perm` DISABLE KEYS */; +INSERT INTO `user_repo_group_to_perm` VALUES (1,1,1,6),(2,1,2,6),(3,1,3,6),(4,1,4,6),(5,1,5,6),(6,1,6,6),(7,1,7,6),(8,1,8,6); +/*!40000 ALTER TABLE `user_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_notification` +-- + +DROP TABLE IF EXISTS `user_to_notification`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_notification` ( + `user_id` int(11) NOT NULL, + `notification_id` int(11) NOT NULL, + `read` tinyint(1) DEFAULT NULL, + `sent_on` datetime DEFAULT NULL, + PRIMARY KEY (`user_id`,`notification_id`), + UNIQUE KEY `user_id` (`user_id`,`notification_id`), + KEY `notification_id` (`notification_id`), + CONSTRAINT `user_to_notification_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_notification_ibfk_2` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`notification_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_notification` +-- + +LOCK TABLES `user_to_notification` WRITE; +/*!40000 ALTER TABLE `user_to_notification` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_to_notification` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_perm` +-- + +DROP TABLE IF EXISTS `user_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_perm` ( + `user_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`user_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`permission_id`), + UNIQUE KEY `user_to_perm_id` (`user_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_perm` +-- + +LOCK TABLES `user_to_perm` WRITE; +/*!40000 ALTER TABLE `user_to_perm` DISABLE KEYS */; +INSERT INTO `user_to_perm` VALUES (4,1,2),(5,1,6),(2,1,11),(3,1,13),(1,1,15); +/*!40000 ALTER TABLE `user_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + `admin` tinyint(1) DEFAULT NULL, + `firstname` varchar(255) DEFAULT NULL, + `lastname` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `last_login` datetime DEFAULT NULL, + `ldap_dn` varchar(255) DEFAULT NULL, + `api_key` varchar(255) DEFAULT NULL, + `inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `user_id` (`user_id`), + UNIQUE KEY `username` (`username`), + UNIQUE KEY `email` (`email`), + KEY `u_email_idx` (`email`), + KEY `u_username_idx` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'default','$2a$10$k/day.yz9z8QtPF1Mj8ZzOJ794CJS3e4bJ2OCHftGCfCCdRfGKRPm',1,0,'Anonymous','User','anonymous@rhodecode.org',NULL,NULL,'4fc339e026489778a8b80deb0ef2cce571bf02d0',1),(2,'marcink','$2a$10$piApcGV3vLj1hC6oEH6MROyDMwt5MAnu6vaN8Rwq.069FJCdgfNUC',1,1,'RhodeCode','Admin','marcin@appzonaut.com',NULL,NULL,'e69148c8899d2ae291fe0bd79be7f085bf4cb2a6',1); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_group_to_perm` ( + `users_group_repo_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_repo_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`group_id`), + UNIQUE KEY `users_group_repo_group_to_perm_id` (`users_group_repo_group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_group_to_perm` +-- + +LOCK TABLES `users_group_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `repository_id` (`repository_id`,`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `users_group_id` (`users_group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_to_perm` +-- + +LOCK TABLES `users_group_repo_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_to_perm` +-- + +LOCK TABLES `users_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups` +-- + +DROP TABLE IF EXISTS `users_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups` ( + `users_group_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_name` varchar(255) NOT NULL, + `users_group_active` tinyint(1) DEFAULT NULL, + `users_group_inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`users_group_id`), + UNIQUE KEY `users_group_id` (`users_group_id`), + UNIQUE KEY `users_group_name` (`users_group_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups` +-- + +LOCK TABLES `users_groups` WRITE; +/*!40000 ALTER TABLE `users_groups` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups_members` +-- + +DROP TABLE IF EXISTS `users_groups_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups_members` ( + `users_group_member_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_member_id`), + UNIQUE KEY `users_group_member_id` (`users_group_member_id`), + KEY `users_group_id` (`users_group_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `users_groups_members_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_groups_members_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups_members` +-- + +LOCK TABLES `users_groups_members` WRITE; +/*!40000 ALTER TABLE `users_groups_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups_members` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2013-05-29 14:16:34 diff --git a/rhodecode/tests/database/mysql/1.6.0_no_repo_name_index.sql b/rhodecode/tests/database/mysql/1.6.0_no_repo_name_index.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/mysql/1.6.0_no_repo_name_index.sql @@ -0,0 +1,923 @@ +-- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: rhodecode +-- ------------------------------------------------------ +-- Server version 5.5.31-0ubuntu0.12.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `cache_invalidation` +-- + +DROP TABLE IF EXISTS `cache_invalidation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `cache_invalidation` ( + `cache_id` int(11) NOT NULL AUTO_INCREMENT, + `cache_key` varchar(255) DEFAULT NULL, + `cache_args` varchar(255) DEFAULT NULL, + `cache_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`cache_id`), + UNIQUE KEY `cache_id` (`cache_id`), + UNIQUE KEY `cache_key` (`cache_key`), + KEY `key_idx` (`cache_key`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_invalidation` +-- + +LOCK TABLES `cache_invalidation` WRITE; +/*!40000 ALTER TABLE `cache_invalidation` DISABLE KEYS */; +INSERT INTO `cache_invalidation` VALUES (1,'1RC/mygr/lol','RC/mygr/lol',0),(2,'1RC/fakeclone','RC/fakeclone',1),(3,'1RC/muay','RC/muay',0),(4,'1BIG/git','BIG/git',1),(5,'1RC/origin-fork','RC/origin-fork',0),(6,'1RC/trololo','RC/trololo',0),(7,'1csa-collins','csa-collins',1),(8,'1csa-harmony','csa-harmony',1),(9,'1RC/Ä…qweqwe','RC/Ä…qweqwe',0),(10,'1rhodecode','rhodecode',0),(11,'1csa-unity','csa-unity',1),(12,'1RC/Å‚Ä™cina','RC/Å‚Ä™cina',0),(13,'1waitress','waitress',1),(14,'1RC/rc2/test2','RC/rc2/test2',1),(15,'1RC/origin-fork-fork','RC/origin-fork-fork',0),(16,'1RC/rc2/test4','RC/rc2/test4',1),(17,'1RC/vcs-git','RC/vcs-git',1),(18,'1rhodecode-extensions','rhodecode-extensions',0),(19,'1rhodecode-cli-gist','rhodecode-cli-gist',0),(20,'1RC/new','RC/new',0),(21,'1csa-aldrin','csa-aldrin',1),(22,'1vcs','vcs',0),(23,'1csa-prometheus','csa-prometheus',1),(24,'1RC/INRC/trololo','RC/INRC/trololo',0),(25,'1RC/empty-git','RC/empty-git',1),(26,'1RC/bin-ops','RC/bin-ops',0),(27,'1csa-salt-states','csa-salt-states',1),(28,'1rhodecode-premium','rhodecode-premium',0),(29,'1RC/qweqwe-fork','RC/qweqwe-fork',0),(30,'1RC/test','RC/test',0),(31,'1remote-salt','remote-salt',1),(32,'1BIG/android','BIG/android',1),(33,'1DOCS','DOCS',1),(34,'1rhodecode-git','rhodecode-git',1),(35,'1RC/fork-remote','RC/fork-remote',0),(36,'1RC/INRC/L2_NEW/lalalal','RC/INRC/L2_NEW/lalalal',0),(37,'1RC/INRC/L2_NEW/L3/repo_test_move','RC/INRC/L2_NEW/L3/repo_test_move',0),(38,'1RC/gogo-fork','RC/gogo-fork',0),(39,'1quest','quest',0),(40,'1RC/foobar','RC/foobar',0),(41,'1csa-hyperion','csa-hyperion',1),(42,'1RC/git-pull-test','RC/git-pull-test',1),(43,'1RC/qweqwe-fork2','RC/qweqwe-fork2',0),(44,'1RC/jap','RC/jap',1),(45,'1RC/hg-repo','RC/hg-repo',0),(46,'1RC/origin','RC/origin',0),(47,'1rhodecode-cli-api','rhodecode-cli-api',0),(48,'1RC/rc2/test3','RC/rc2/test3',1),(49,'1csa-armstrong','csa-armstrong',1),(50,'1pyramidpypi','pyramidpypi',1),(51,'1RC/lol/haha','RC/lol/haha',0),(52,'1csa-io','csa-io',1),(53,'1enc-envelope','enc-envelope',0),(54,'1RC/gogo2','RC/gogo2',0),(55,'1csa-libcloud','csa-libcloud',1),(56,'1RC/git-test','RC/git-test',1),(57,'1RC/rc2/test','RC/rc2/test',0),(58,'1salt','salt',1),(59,'1RC/kiall-nova','RC/kiall-nova',1); +/*!40000 ALTER TABLE `cache_invalidation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_comments` +-- + +DROP TABLE IF EXISTS `changeset_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_comments` ( + `comment_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `revision` varchar(40) DEFAULT NULL, + `pull_request_id` int(11) DEFAULT NULL, + `line_no` varchar(10) DEFAULT NULL, + `hl_lines` varchar(512) DEFAULT NULL, + `f_path` varchar(1000) DEFAULT NULL, + `user_id` int(11) NOT NULL, + `text` mediumtext NOT NULL, + `created_on` datetime NOT NULL, + `modified_at` datetime NOT NULL, + PRIMARY KEY (`comment_id`), + KEY `repo_id` (`repo_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `cc_revision_idx` (`revision`), + CONSTRAINT `changeset_comments_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_comments_ibfk_2` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `changeset_comments_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_comments` +-- + +LOCK TABLES `changeset_comments` WRITE; +/*!40000 ALTER TABLE `changeset_comments` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_comments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `changeset_statuses` +-- + +DROP TABLE IF EXISTS `changeset_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_statuses` ( + `changeset_status_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `revision` varchar(40) NOT NULL, + `status` varchar(128) NOT NULL, + `changeset_comment_id` int(11) DEFAULT NULL, + `modified_at` datetime NOT NULL, + `version` int(11) NOT NULL, + `pull_request_id` int(11) DEFAULT NULL, + PRIMARY KEY (`changeset_status_id`), + UNIQUE KEY `repo_id` (`repo_id`,`revision`,`version`), + KEY `user_id` (`user_id`), + KEY `changeset_comment_id` (`changeset_comment_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `cs_revision_idx` (`revision`), + KEY `cs_version_idx` (`version`), + CONSTRAINT `changeset_statuses_ibfk_1` FOREIGN KEY (`repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `changeset_statuses_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `changeset_statuses_ibfk_3` FOREIGN KEY (`changeset_comment_id`) REFERENCES `changeset_comments` (`comment_id`), + CONSTRAINT `changeset_statuses_ibfk_4` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `changeset_statuses` +-- + +LOCK TABLES `changeset_statuses` WRITE; +/*!40000 ALTER TABLE `changeset_statuses` DISABLE KEYS */; +/*!40000 ALTER TABLE `changeset_statuses` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `db_migrate_version` +-- + +DROP TABLE IF EXISTS `db_migrate_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `db_migrate_version` ( + `repository_id` varchar(250) NOT NULL, + `repository_path` text, + `version` int(11) DEFAULT NULL, + PRIMARY KEY (`repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `db_migrate_version` +-- + +LOCK TABLES `db_migrate_version` WRITE; +/*!40000 ALTER TABLE `db_migrate_version` DISABLE KEYS */; +INSERT INTO `db_migrate_version` VALUES ('rhodecode_db_migrations','versions',11); +/*!40000 ALTER TABLE `db_migrate_version` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `groups` +-- + +DROP TABLE IF EXISTS `groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `groups` ( + `group_id` int(11) NOT NULL AUTO_INCREMENT, + `group_name` varchar(255) NOT NULL, + `group_parent_id` int(11) DEFAULT NULL, + `group_description` varchar(10000) DEFAULT NULL, + `enable_locking` tinyint(1) NOT NULL, + PRIMARY KEY (`group_id`), + UNIQUE KEY `group_id` (`group_id`), + UNIQUE KEY `group_name_2` (`group_name`), + UNIQUE KEY `group_name` (`group_name`,`group_parent_id`), + KEY `group_parent_id` (`group_parent_id`), + CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`group_parent_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `groups` +-- + +LOCK TABLES `groups` WRITE; +/*!40000 ALTER TABLE `groups` DISABLE KEYS */; +INSERT INTO `groups` VALUES (1,'RC',NULL,'RC group',0),(2,'RC/mygr',1,'RC/mygr group',0),(3,'BIG',NULL,'BIG group',0),(4,'RC/rc2',1,'RC/rc2 group',0),(5,'RC/INRC',1,'RC/INRC group',0),(6,'RC/INRC/L2_NEW',5,'RC/INRC/L2_NEW group',0),(7,'RC/INRC/L2_NEW/L3',6,'RC/INRC/L2_NEW/L3 group',0),(8,'RC/lol',1,'RC/lol group',0); +/*!40000 ALTER TABLE `groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notifications` +-- + +DROP TABLE IF EXISTS `notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `notifications` ( + `notification_id` int(11) NOT NULL AUTO_INCREMENT, + `subject` varchar(512) DEFAULT NULL, + `body` mediumtext, + `created_by` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `type` varchar(256) DEFAULT NULL, + PRIMARY KEY (`notification_id`), + KEY `created_by` (`created_by`), + KEY `notification_type_idx` (`type`(255)), + CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notifications` +-- + +LOCK TABLES `notifications` WRITE; +/*!40000 ALTER TABLE `notifications` DISABLE KEYS */; +/*!40000 ALTER TABLE `notifications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `permissions` +-- + +DROP TABLE IF EXISTS `permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `permissions` ( + `permission_id` int(11) NOT NULL AUTO_INCREMENT, + `permission_name` varchar(255) DEFAULT NULL, + `permission_longname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`permission_id`), + UNIQUE KEY `permission_id` (`permission_id`), + KEY `p_perm_name_idx` (`permission_name`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `permissions` +-- + +LOCK TABLES `permissions` WRITE; +/*!40000 ALTER TABLE `permissions` DISABLE KEYS */; +INSERT INTO `permissions` VALUES (1,'repository.none','repository.none'),(2,'repository.read','repository.read'),(3,'repository.write','repository.write'),(4,'repository.admin','repository.admin'),(5,'group.none','group.none'),(6,'group.read','group.read'),(7,'group.write','group.write'),(8,'group.admin','group.admin'),(9,'hg.admin','hg.admin'),(10,'hg.create.none','hg.create.none'),(11,'hg.create.repository','hg.create.repository'),(12,'hg.fork.none','hg.fork.none'),(13,'hg.fork.repository','hg.fork.repository'),(14,'hg.register.none','hg.register.none'),(15,'hg.register.manual_activate','hg.register.manual_activate'),(16,'hg.register.auto_activate','hg.register.auto_activate'); +/*!40000 ALTER TABLE `permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_request_reviewers` +-- + +DROP TABLE IF EXISTS `pull_request_reviewers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_request_reviewers` ( + `pull_requests_reviewers_id` int(11) NOT NULL AUTO_INCREMENT, + `pull_request_id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`pull_requests_reviewers_id`), + KEY `pull_request_id` (`pull_request_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `pull_request_reviewers_ibfk_1` FOREIGN KEY (`pull_request_id`) REFERENCES `pull_requests` (`pull_request_id`), + CONSTRAINT `pull_request_reviewers_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_request_reviewers` +-- + +LOCK TABLES `pull_request_reviewers` WRITE; +/*!40000 ALTER TABLE `pull_request_reviewers` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_request_reviewers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pull_requests` +-- + +DROP TABLE IF EXISTS `pull_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_requests` ( + `pull_request_id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(256) DEFAULT NULL, + `description` text, + `status` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `user_id` int(11) NOT NULL, + `revisions` text, + `org_repo_id` int(11) NOT NULL, + `org_ref` varchar(256) NOT NULL, + `other_repo_id` int(11) NOT NULL, + `other_ref` varchar(256) NOT NULL, + PRIMARY KEY (`pull_request_id`), + KEY `user_id` (`user_id`), + KEY `org_repo_id` (`org_repo_id`), + KEY `other_repo_id` (`other_repo_id`), + CONSTRAINT `pull_requests_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `pull_requests_ibfk_2` FOREIGN KEY (`org_repo_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `pull_requests_ibfk_3` FOREIGN KEY (`other_repo_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pull_requests` +-- + +LOCK TABLES `pull_requests` WRITE; +/*!40000 ALTER TABLE `pull_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `pull_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repo_to_perm` +-- + +DROP TABLE IF EXISTS `repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repo_to_perm` ( + `repo_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`repo_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`repository_id`,`permission_id`), + UNIQUE KEY `repo_to_perm_id` (`repo_to_perm_id`), + KEY `permission_id` (`permission_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `repo_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repo_to_perm` +-- + +LOCK TABLES `repo_to_perm` WRITE; +/*!40000 ALTER TABLE `repo_to_perm` DISABLE KEYS */; +INSERT INTO `repo_to_perm` VALUES (1,1,2,1),(2,1,2,2),(3,1,2,3),(4,1,2,4),(5,1,2,5),(6,1,2,6),(7,1,2,7),(8,1,2,8),(9,1,2,9),(10,1,2,10),(11,1,2,11),(12,1,2,12),(13,1,2,13),(14,1,2,14),(15,1,2,15),(16,1,2,16),(17,1,2,17),(18,1,2,18),(19,1,2,19),(20,1,2,20),(21,1,2,21),(22,1,2,22),(23,1,2,23),(24,1,2,24),(25,1,2,25),(26,1,2,26),(27,1,2,27),(28,1,2,28),(29,1,2,29),(30,1,2,30),(31,1,2,31),(32,1,2,32),(33,1,2,33),(34,1,2,34),(35,1,2,35),(36,1,2,36),(37,1,2,37),(38,1,2,38),(39,1,2,39),(40,1,2,40),(41,1,2,41),(42,1,2,42),(43,1,2,43),(44,1,2,44),(45,1,2,45),(46,1,2,46),(47,1,2,47),(48,1,2,48),(49,1,2,49),(50,1,2,50),(51,1,2,51),(52,1,2,52),(53,1,2,53),(54,1,2,54),(55,1,2,55),(56,1,2,56),(57,1,2,57),(58,1,2,58),(59,1,2,59); +/*!40000 ALTER TABLE `repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories` +-- + +DROP TABLE IF EXISTS `repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories` ( + `repo_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_name` varchar(255) NOT NULL, + `clone_uri` varchar(255) DEFAULT NULL, + `repo_type` varchar(255) NOT NULL, + `user_id` int(11) NOT NULL, + `private` tinyint(1) DEFAULT NULL, + `statistics` tinyint(1) DEFAULT NULL, + `downloads` tinyint(1) DEFAULT NULL, + `description` varchar(10000) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `landing_revision` varchar(255) NOT NULL, + `enable_locking` tinyint(1) NOT NULL, + `locked` varchar(255) DEFAULT NULL, + `changeset_cache` blob, + `fork_id` int(11) DEFAULT NULL, + `group_id` int(11) DEFAULT NULL, + PRIMARY KEY (`repo_id`), + UNIQUE KEY `repo_name` (`repo_name`), + UNIQUE KEY `repo_id` (`repo_id`), + UNIQUE KEY `repo_name_2` (`repo_name`), + KEY `user_id` (`user_id`), + KEY `fork_id` (`fork_id`), + KEY `group_id` (`group_id`), + CONSTRAINT `repositories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `repositories_ibfk_2` FOREIGN KEY (`fork_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `repositories_ibfk_3` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories` +-- + +LOCK TABLES `repositories` WRITE; +/*!40000 ALTER TABLE `repositories` DISABLE KEYS */; +INSERT INTO `repositories` VALUES (1,'RC/mygr/lol','http://user@vm/RC/mygr/lol','hg',2,0,0,0,'RC/mygr/lol repository','2013-05-29 14:16:09','2013-05-29 14:16:09','tip',0,NULL,NULL,NULL,2),(2,'RC/fakeclone',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:09','2013-05-09 01:48:00','tip',0,NULL,'{\"raw_id\": \"dfa7d376778d681d1818f41b17706efa6033b407\", \"short_id\": \"dfa7d376778d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-09T01:48:00\", \"message\": \"fixed\\n\", \"revision\": 293}',NULL,1),(3,'RC/muay',NULL,'hg',2,0,0,0,'RC/muay repository','2013-05-29 14:16:09','2013-05-29 14:16:09','tip',0,NULL,NULL,NULL,1),(4,'BIG/git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:10','2012-10-21 23:47:54','tip',0,NULL,'{\"raw_id\": \"30f4c66e634760a81ab27a236fe1f2482f6f7856\", \"short_id\": \"30f4c66e6347\", \"author\": \"Junio C Hamano \", \"date\": \"2012-10-21T23:47:54\", \"message\": \"What\'s cooking (2012/10 #07)\\n\", \"revision\": 32160}',NULL,3),(5,'RC/origin-fork',NULL,'hg',2,0,0,0,'RC/origin-fork repository','2013-05-29 14:16:11','2013-03-06 20:16:20','tip',0,NULL,'{\"raw_id\": \"f0ce39a6f9edfc6392d4d6137f05bb3871e41780\", \"short_id\": \"f0ce39a6f9ed\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-06T20:16:20\", \"message\": \"Edited file via options\\n- fixed 1\\n-f xied 2\\nand so on so on trallalala\", \"revision\": 21}',NULL,1),(6,'RC/trololo',NULL,'hg',2,0,0,0,'RC/trololo repository','2013-05-29 14:16:11','2013-03-28 02:35:50','tip',0,NULL,'{\"raw_id\": \"890d7469abac360637c8cf79f158b170415e1653\", \"short_id\": \"890d7469abac\", \"author\": \"demo user \", \"date\": \"2013-03-28T02:35:50\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(7,'csa-collins',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-02-25 17:31:39','tip',0,NULL,'{\"raw_id\": \"8be6a10d645c8dda5f1f331496228118ae872ce8\", \"short_id\": \"8be6a10d645c\", \"author\": \"Bastian Albers \", \"date\": \"2013-02-25T17:31:39\", \"message\": \"Merge branch \'stage\' into stage2\\n\", \"revision\": 2731}',NULL,NULL),(8,'csa-harmony',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-05-22 14:49:45','tip',0,NULL,'{\"raw_id\": \"27b59603618b07259ca0db6b00990feeba96930f\", \"short_id\": \"27b59603618b\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-22T14:49:45\", \"message\": \"Added kwargs to setup functions for later optional params\\n\", \"revision\": 339}',NULL,NULL),(9,'RC/Ä…qweqwe',NULL,'hg',2,0,0,0,'RC/Ä…qweqwe repository','2013-05-29 14:16:11','2013-05-29 00:06:28','tip',0,NULL,'{\"raw_id\": \"6c94b338a07134922f042f000f991d47a14bebf9\", \"short_id\": \"6c94b338a071\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-29T00:06:28\", \"message\": \"Edited file \\u0142\\u00f3\\u015b via RhodeCode\", \"revision\": 1}',NULL,1),(10,'rhodecode',NULL,'hg',2,0,0,0,'rhodecode repository','2013-05-29 14:16:11','2013-05-29 12:13:02','tip',0,NULL,'{\"raw_id\": \"424b6c711a7f63680abd1474b66ddf42c0345a16\", \"short_id\": \"424b6c711a7f\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-29T12:13:02\", \"message\": \"allow underscores in usernames. Helps creating special internal users\", \"revision\": 4053}',NULL,NULL),(11,'csa-unity',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:11','2013-04-29 14:38:23','tip',0,NULL,'{\"raw_id\": \"093708759ebf4fd2bb1bdcad61fb611bc32933d3\", \"short_id\": \"093708759ebf\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-29T14:38:23\", \"message\": \"revert to logbook 0.3.0\", \"revision\": 28}',NULL,NULL),(12,'RC/Å‚Ä™cina',NULL,'hg',2,0,0,0,'RC/Å‚Ä™cina repository','2013-05-29 14:16:12','2013-03-06 16:17:49','tip',0,NULL,'{\"raw_id\": \"1ee589bcfa9212c5110ea5c1fe2cc8ff6eaf1303\", \"short_id\": \"1ee589bcfa92\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-06T16:17:49\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(13,'waitress',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-05-28 13:21:35','tip',0,NULL,'{\"raw_id\": \"e5d138ce3f754e6031e7abd76e5f527363fdaf42\", \"short_id\": \"e5d138ce3f75\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-28T13:21:35\", \"message\": \"Added docs and new flag into runner\\n\", \"revision\": 272}',NULL,NULL),(14,'RC/rc2/test2',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-03-03 00:29:35','tip',0,NULL,'{\"raw_id\": \"0eb3304fc33d05d328f8627b9ad44dae83f313a2\", \"short_id\": \"0eb3304fc33d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-03T00:29:35\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n fix requests 1.1 json method\\n fixed tests\\n moved tests into package\\n -bump distribute\\n update .gitignore\\n version freeze of libs\\n remove gevent from IO as dependency\\n add unity as deps\\n fully delegate AUTH back to armstrong\\n\", \"revision\": 50}',NULL,4),(15,'RC/origin-fork-fork',NULL,'hg',2,0,0,0,'RC/origin-fork-fork repository','2013-05-29 14:16:12','2013-05-06 23:44:50','tip',0,NULL,'{\"raw_id\": \"6d99e0d4dfcc4a5afa5c138fea2098470634f773\", \"short_id\": \"6d99e0d4dfcc\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-06T23:44:50\", \"message\": \"Issue #17094: Clear stale thread states after fork().\\n\\nNote that this is a potentially disruptive change since it may\\nrelease some system resources which would otherwise remain\\nperpetually alive (e.g. database connections kept in thread-local\\nstorage).\", \"revision\": 25}',NULL,1),(16,'RC/rc2/test4',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-03-21 22:55:29','tip',0,NULL,'{\"raw_id\": \"3b6ac7f5e932d4dd13871a0b23d6ca98510d88c2\", \"short_id\": \"3b6ac7f5e932\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-03-21T22:55:29\", \"message\": \"dsadas\", \"revision\": 51}',NULL,4),(17,'RC/vcs-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-04-26 23:34:15','tip',0,NULL,'{\"raw_id\": \"90da1f69a6c60f7d4d5646ee39ac5f6108bc077c\", \"short_id\": \"90da1f69a6c6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-26T23:34:15\", \"message\": \"merge with GIT vcs\\n\", \"revision\": 648}',NULL,1),(18,'rhodecode-extensions',NULL,'hg',2,0,0,0,'rhodecode-extensions repository','2013-05-29 14:16:12','2013-02-13 16:50:33','tip',0,NULL,'{\"raw_id\": \"da7e5f7a39d3203ff0b4af5018ac4a80d94ed1d4\", \"short_id\": \"da7e5f7a39d3\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-02-13T16:50:33\", \"message\": \"Linkify hipchat messages\", \"revision\": 2}',NULL,NULL),(19,'rhodecode-cli-gist',NULL,'hg',2,0,0,0,'rhodecode-cli-gist repository','2013-05-29 14:16:12','2013-05-29 14:16:12','tip',0,NULL,NULL,NULL,NULL),(20,'RC/new',NULL,'hg',2,0,0,0,'RC/new repository','2013-05-29 14:16:12','2013-04-17 13:02:59','tip',0,NULL,'{\"raw_id\": \"93192e03a3552b8da4fee40e001c60304723bb42\", \"short_id\": \"93192e03a355\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-17T13:02:59\", \"message\": \"rename\", \"revision\": 1}',NULL,1),(21,'csa-aldrin',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:12','2013-05-02 23:47:52','tip',0,NULL,'{\"raw_id\": \"67ee9e830c225921ec15974ac1dfde17a930e2fb\", \"short_id\": \"67ee9e830c22\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-02T23:47:52\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n moved gevent into out internal server\\n stupid assholes in gevent should learn how to package...\\n fixed gevent dependency link\\n added separate call for session validation\\n\", \"revision\": 293}',NULL,NULL),(22,'vcs',NULL,'hg',2,0,0,0,'vcs repository','2013-05-29 14:16:13','2013-05-09 00:28:54','tip',0,NULL,'{\"raw_id\": \"6fba59f9f7806a545a0e5ebac936991828436260\", \"short_id\": \"6fba59f9f780\", \"author\": \"Lukasz Balcerzak \", \"date\": \"2013-05-09T00:28:54\", \"message\": \"Merge pull request #117 from niedbalski/master\\n\\nKeyError: \'all\'\", \"revision\": 707}',NULL,NULL),(23,'csa-prometheus',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-04-29 14:37:43','tip',0,NULL,'{\"raw_id\": \"a719bd82d25e7411fdb7979c12c083f59a206a6c\", \"short_id\": \"a719bd82d25e\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-29T14:37:43\", \"message\": \"revert logbook to 0.3.0\", \"revision\": 79}',NULL,NULL),(24,'RC/INRC/trololo',NULL,'hg',2,0,0,0,'RC/INRC/trololo repository','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,5),(25,'RC/empty-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,1),(26,'RC/bin-ops',NULL,'hg',2,0,0,0,'RC/bin-ops repository','2013-05-29 14:16:13','2013-05-12 12:39:34','tip',0,NULL,'{\"raw_id\": \"4231762d8c1aaca5be3db15991071236c32e7654\", \"short_id\": \"4231762d8c1a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-12T12:39:34\", \"message\": \"Edited file file1 via RhodeCode\", \"revision\": 23}',NULL,1),(27,'csa-salt-states',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2013-05-06 14:48:48','tip',0,NULL,'{\"raw_id\": \"0c20dc72baeedc3ce840c611174c7e1cd3b04919\", \"short_id\": \"0c20dc72baee\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-06T14:48:48\", \"message\": \"increase sampling of CPU time to 0.5s for more realistic data.\", \"revision\": 71}',NULL,NULL),(28,'rhodecode-premium',NULL,'hg',2,0,0,0,'rhodecode-premium repository','2013-05-29 14:16:13','2013-03-21 22:58:11','tip',0,NULL,'{\"raw_id\": \"ded35bf017f16bcad6611c7ffe3b1b1c10942f50\", \"short_id\": \"ded35bf017f1\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-21T22:58:11\", \"message\": \"version bump to 1.5.4p2\", \"revision\": 3674}',NULL,NULL),(29,'RC/qweqwe-fork',NULL,'hg',2,0,0,0,'RC/qweqwe-fork repository','2013-05-29 14:16:13','2013-05-29 14:16:13','tip',0,NULL,NULL,NULL,1),(30,'RC/test',NULL,'hg',2,0,0,0,'RC/test repository','2013-05-29 14:16:13','2013-01-30 22:56:03','tip',0,NULL,'{\"raw_id\": \"e5025e316d9acb39e5f861c494240be4f5d56de6\", \"short_id\": \"e5025e316d9a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-01-30T22:56:03\", \"message\": \" fixes #700\", \"revision\": 2}',NULL,1),(31,'remote-salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2012-10-14 22:04:05','tip',0,NULL,'{\"raw_id\": \"d661dc72492e66cab7a647dcb5652009067aa8cd\", \"short_id\": \"d661dc72492e\", \"author\": \"Marcin Kuzminski \", \"date\": \"2012-10-14T22:04:05\", \"message\": \"Logging\\nOn-the-fly msg encryption using googles keyCzar lib\", \"revision\": 3}',NULL,NULL),(32,'BIG/android',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:13','2012-06-17 00:44:46','tip',0,NULL,'{\"raw_id\": \"e86b147e4b6908a7c5ab0963d77fb0867679b1ee\", \"short_id\": \"e86b147e4b69\", \"author\": \"Bernhard Rosenkraenzer \", \"date\": \"2012-06-17T00:44:46\", \"message\": \"panda: Backport HDMI vs. DVI patch from kernel/panda.git\\n\\nThis patch allows switching the primary display output device.\\n\\nChange-Id: I6e30e87bbc7aa72b5acc6e6c4ed34019835e6524\\nSigned-off-by: Bernhard Rosenkraenzer \\n\", \"revision\": 294896}',NULL,3),(33,'DOCS',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:24','2013-04-25 16:45:59','tip',0,NULL,'{\"raw_id\": \"1e4a728ee7a6aa88be11260d6479a446eb865de3\", \"short_id\": \"1e4a728ee7a6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-25T16:45:59\", \"message\": \"sync docs with armstrong\", \"revision\": 15}',NULL,NULL),(34,'rhodecode-git',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:24','2013-01-04 00:24:22','tip',0,NULL,'{\"raw_id\": \"629f1538ad4800ff05113516f6a933e2b243f205\", \"short_id\": \"629f1538ad48\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-01-04T00:24:22\", \"message\": \"nicer representation of list of rescanned repositories\\n\\n--HG--\\nbranch : beta\\n\", \"revision\": 3142}',NULL,NULL),(35,'RC/fork-remote',NULL,'hg',2,0,0,0,'RC/fork-remote repository','2013-05-29 14:16:24','2013-03-10 22:47:24','tip',0,NULL,'{\"raw_id\": \"60555484a0a0d6e525e9d7ab1b1dce5ab9eb9487\", \"short_id\": \"60555484a0a0\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-10T22:47:24\", \"message\": \"aaa\", \"revision\": 26}',NULL,1),(36,'RC/INRC/L2_NEW/lalalal',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/lalalal repository','2013-05-29 14:16:24','2013-05-29 14:16:24','tip',0,NULL,NULL,NULL,6),(37,'RC/INRC/L2_NEW/L3/repo_test_move',NULL,'hg',2,0,0,0,'RC/INRC/L2_NEW/L3/repo_test_move repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,7),(38,'RC/gogo-fork',NULL,'hg',2,0,0,0,'RC/gogo-fork repository','2013-05-29 14:16:25','2013-05-28 21:33:55','tip',0,NULL,'{\"raw_id\": \"d72044a6e192f89de3f2b723557942eecb420308\", \"short_id\": \"d72044a6e192\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-28T21:33:55\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(39,'quest',NULL,'hg',2,0,0,0,'quest repository','2013-05-29 14:16:25','2013-03-04 23:01:40','tip',0,NULL,'{\"raw_id\": \"54b01cfdea25bf41cd8e9a184c5852c5d48d864c\", \"short_id\": \"54b01cfdea25\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-04T23:01:40\", \"message\": \"template and version 0.0.1\", \"revision\": 41}',NULL,NULL),(40,'RC/foobar',NULL,'hg',2,0,0,0,'RC/foobar repository','2013-05-29 14:16:25','2013-04-15 21:34:57','tip',0,NULL,'{\"raw_id\": \"c17dc3c566952813e84037dfd62a4755ed3c912c\", \"short_id\": \"c17dc3c56695\", \"author\": \"Mirek Kott \", \"date\": \"2013-04-15T21:34:57\", \"message\": \"Edited file lol.rst via RhodeCode\", \"revision\": 1}',NULL,1),(41,'csa-hyperion',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-05-20 21:58:28','tip',0,NULL,'{\"raw_id\": \"252c926d10702e6ef7c2456f2fc23892808e53a0\", \"short_id\": \"252c926d1070\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-20T21:58:28\", \"message\": \"fixes for new code\\n\", \"revision\": 57}',NULL,NULL),(42,'RC/git-pull-test',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-05-20 13:03:02','tip',0,NULL,'{\"raw_id\": \"b2cf1136f09fa61df90469b43310615984bc7d55\", \"short_id\": \"b2cf1136f09f\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-20T13:03:02\", \"message\": \"added\\n\", \"revision\": 13}',NULL,1),(43,'RC/qweqwe-fork2',NULL,'hg',2,0,0,0,'RC/qweqwe-fork2 repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,1),(44,'RC/jap',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-04-24 11:15:30','tip',0,NULL,'{\"raw_id\": \"2f62ce22453a67eefd6fab1d4e053520e8debdf6\", \"short_id\": \"2f62ce22453a\", \"author\": \"Demo User \", \"date\": \"2013-04-24T11:15:30\", \"message\": \"\\u30d5\\u30a1\\u30a4\\u30eb\\u8ffd\\u52a0\", \"revision\": 5}',NULL,1),(45,'RC/hg-repo',NULL,'hg',2,0,0,0,'RC/hg-repo repository','2013-05-29 14:16:25','2013-05-08 22:54:45','tip',0,NULL,'{\"raw_id\": \"d63d40e8b0685af6db5f2cf7700e80216af5c739\", \"short_id\": \"d63d40e8b068\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-08T22:54:45\", \"message\": \"Edited file haha via RhodeCode\", \"revision\": 25}',NULL,1),(46,'RC/origin',NULL,'hg',2,0,0,0,'RC/origin repository','2013-05-29 14:16:25','2013-04-05 13:05:02','tip',0,NULL,'{\"raw_id\": \"5fbf2f0eada43bc33a94e483503335d8f6757093\", \"short_id\": \"5fbf2f0eada4\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-05T13:05:02\", \"message\": \"fixed\", \"revision\": 29}',NULL,1),(47,'rhodecode-cli-api',NULL,'hg',2,0,0,0,'rhodecode-cli-api repository','2013-05-29 14:16:25','2013-05-29 14:16:25','tip',0,NULL,NULL,NULL,NULL),(48,'RC/rc2/test3',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:25','2013-03-03 00:29:35','tip',0,NULL,'{\"raw_id\": \"0eb3304fc33d05d328f8627b9ad44dae83f313a2\", \"short_id\": \"0eb3304fc33d\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-03T00:29:35\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n fix requests 1.1 json method\\n fixed tests\\n moved tests into package\\n -bump distribute\\n update .gitignore\\n version freeze of libs\\n remove gevent from IO as dependency\\n add unity as deps\\n fully delegate AUTH back to armstrong\\n\", \"revision\": 50}',NULL,4),(49,'csa-armstrong',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-05-22 18:10:20','tip',0,NULL,'{\"raw_id\": \"60ffa2018fa120c97c0c5fcab93ecd82e2c3a691\", \"short_id\": \"60ffa2018fa1\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-22T18:10:20\", \"message\": \"fix actual progress increase in salt calls\\n\", \"revision\": 1140}',NULL,NULL),(50,'pyramidpypi',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-04-25 16:34:48','tip',0,NULL,'{\"raw_id\": \"ed9aceffada3ef38509c5d7010b016ba45e82944\", \"short_id\": \"ed9aceffada3\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-25T16:34:48\", \"message\": \"version bump\", \"revision\": 28}',NULL,NULL),(51,'RC/lol/haha',NULL,'hg',2,0,0,0,'RC/lol/haha repository','2013-05-29 14:16:26','2013-05-29 14:16:26','tip',0,NULL,NULL,NULL,8),(52,'csa-io',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:26','2013-05-02 22:52:54','tip',0,NULL,'{\"raw_id\": \"bd0ef71fcfd088a82b8627e60aaa1f2020ed33ba\", \"short_id\": \"bd0ef71fcfd0\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-05-02T22:52:54\", \"message\": \"Merge branch \'stage\'\\n\\n* stage:\\n Use ext_json instead of plain simplejson serializer\\n log errors on restfull json parsers/decoders\\n fixed some serialization problems\\n version bump\\n Repository revisions API\\n mercurial version bump\\n Bump VCS version to 0.4.0 and move it to code.appzonaut.com\\n fix logging on changes json module in requests 1.X\\n\", \"revision\": 59}',NULL,NULL),(53,'enc-envelope',NULL,'hg',2,0,0,0,'enc-envelope repository','2013-05-29 14:16:26','2013-03-07 15:37:40','tip',0,NULL,'{\"raw_id\": \"810066f835d6c082950fc7828ded50b9b8d9c229\", \"short_id\": \"810066f835d6\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-03-07T15:37:40\", \"message\": \"show more detailed info about wrong stream\", \"revision\": 5}',NULL,NULL),(54,'RC/gogo2',NULL,'hg',2,0,0,0,'RC/gogo2 repository','2013-05-29 14:16:26','2013-05-28 21:33:39','tip',0,NULL,'{\"raw_id\": \"07f1002bc22aff4231f7c94b54715547c29c37c6\", \"short_id\": \"07f1002bc22a\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-28T21:33:39\", \"message\": \"Added file via RhodeCode\", \"revision\": 0}',NULL,1),(55,'csa-libcloud',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2013-04-17 16:42:42','tip',0,NULL,'{\"raw_id\": \"a2fa551633ce3697ac63a935aa71f1e7b80222ae\", \"short_id\": \"a2fa551633ce\", \"author\": \"Marcin Kuzminski \", \"date\": \"2013-04-17T16:42:42\", \"message\": \"filter only listeners Brightbox can process\", \"revision\": 1895}',NULL,NULL),(56,'RC/git-test',NULL,'git',2,0,0,0,'Unnamed repository','2013-05-29 14:16:27','2013-05-29 00:10:16','tip',0,NULL,'{\"raw_id\": \"c0d94361073eaf60106b60af628949a1bad45f2d\", \"short_id\": \"c0d94361073e\", \"author\": \"RhodeCode Admin \", \"date\": \"2013-05-29T00:10:16\", \"message\": \"Edited file \\u0142\\u00f3\\u015b via RhodeCode\", \"revision\": 11}',NULL,1),(57,'RC/rc2/test',NULL,'hg',2,0,0,0,'RC/rc2/test repository','2013-05-29 14:16:27','2013-05-29 14:16:27','tip',0,NULL,NULL,NULL,4),(58,'salt',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2012-10-15 05:20:58','tip',0,NULL,'{\"raw_id\": \"bd44832230fc19eb80fe49ef01badb477ef8ca6c\", \"short_id\": \"bd44832230fc\", \"author\": \"Thomas S Hatch \", \"date\": \"2012-10-15T05:20:58\", \"message\": \"Merge pull request #2244 from FireHost/toplevel_wmi_import\\n\\nToplevel wmi import\", \"revision\": 6957}',NULL,NULL),(59,'RC/kiall-nova',NULL,'git',2,0,0,0,'Unnamed repository; edit this file \'description\' to name the repository.\n','2013-05-29 14:16:27','2012-10-23 10:22:06','tip',0,NULL,'{\"raw_id\": \"a0fcd1248071ad66b610eac4903adf36b314390b\", \"short_id\": \"a0fcd1248071\", \"author\": \"Jenkins \", \"date\": \"2012-10-23T10:22:06\", \"message\": \"Merge \\\"Fix nova-volume-usage-audit\\\"\", \"revision\": 17253}',NULL,1); +/*!40000 ALTER TABLE `repositories` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `repositories_fields` +-- + +DROP TABLE IF EXISTS `repositories_fields`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories_fields` ( + `repo_field_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `field_key` varchar(250) DEFAULT NULL, + `field_label` varchar(1024) NOT NULL, + `field_value` varchar(10000) NOT NULL, + `field_desc` varchar(1024) NOT NULL, + `field_type` varchar(256) NOT NULL, + `created_on` datetime NOT NULL, + PRIMARY KEY (`repo_field_id`), + UNIQUE KEY `repo_field_id` (`repo_field_id`), + UNIQUE KEY `repository_id` (`repository_id`,`field_key`), + CONSTRAINT `repositories_fields_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `repositories_fields` +-- + +LOCK TABLES `repositories_fields` WRITE; +/*!40000 ALTER TABLE `repositories_fields` DISABLE KEYS */; +/*!40000 ALTER TABLE `repositories_fields` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_settings` +-- + +DROP TABLE IF EXISTS `rhodecode_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_settings` ( + `app_settings_id` int(11) NOT NULL AUTO_INCREMENT, + `app_settings_name` varchar(255) DEFAULT NULL, + `app_settings_value` varchar(255) DEFAULT NULL, + PRIMARY KEY (`app_settings_id`), + UNIQUE KEY `app_settings_id` (`app_settings_id`), + UNIQUE KEY `app_settings_name` (`app_settings_name`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_settings` +-- + +LOCK TABLES `rhodecode_settings` WRITE; +/*!40000 ALTER TABLE `rhodecode_settings` DISABLE KEYS */; +INSERT INTO `rhodecode_settings` VALUES (1,'realm','RhodeCode authentication'),(2,'title','RhodeCode'),(3,'ga_code',''),(4,'show_public_icon','True'),(5,'show_private_icon','True'),(6,'stylify_metatags','False'),(7,'ldap_active','false'),(8,'ldap_host',''),(9,'ldap_port','389'),(10,'ldap_tls_kind','PLAIN'),(11,'ldap_tls_reqcert',''),(12,'ldap_dn_user',''),(13,'ldap_dn_pass',''),(14,'ldap_base_dn',''),(15,'ldap_filter',''),(16,'ldap_search_scope',''),(17,'ldap_attr_login',''),(18,'ldap_attr_firstname',''),(19,'ldap_attr_lastname',''),(20,'ldap_attr_email',''),(21,'default_repo_enable_locking','False'),(22,'default_repo_enable_downloads','False'),(23,'default_repo_enable_statistics','False'),(24,'default_repo_private','False'),(25,'default_repo_type','hg'); +/*!40000 ALTER TABLE `rhodecode_settings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rhodecode_ui` +-- + +DROP TABLE IF EXISTS `rhodecode_ui`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rhodecode_ui` ( + `ui_id` int(11) NOT NULL AUTO_INCREMENT, + `ui_section` varchar(255) DEFAULT NULL, + `ui_key` varchar(255) DEFAULT NULL, + `ui_value` varchar(255) DEFAULT NULL, + `ui_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ui_id`), + UNIQUE KEY `ui_id` (`ui_id`), + UNIQUE KEY `ui_key` (`ui_key`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rhodecode_ui` +-- + +LOCK TABLES `rhodecode_ui` WRITE; +/*!40000 ALTER TABLE `rhodecode_ui` DISABLE KEYS */; +INSERT INTO `rhodecode_ui` VALUES (1,'hooks','changegroup.update','hg update >&2',0),(2,'hooks','changegroup.repo_size','python:rhodecode.lib.hooks.repo_size',1),(3,'hooks','changegroup.push_logger','python:rhodecode.lib.hooks.log_push_action',1),(4,'hooks','prechangegroup.pre_push','python:rhodecode.lib.hooks.pre_push',1),(5,'hooks','outgoing.pull_logger','python:rhodecode.lib.hooks.log_pull_action',1),(6,'hooks','preoutgoing.pre_pull','python:rhodecode.lib.hooks.pre_pull',1),(7,'extensions','largefiles','',1),(8,'extensions','hgsubversion','',0),(9,'extensions','hggit','',0),(10,'web','push_ssl','false',1),(11,'web','allow_archive','gz zip bz2',1),(12,'web','allow_push','*',1),(13,'web','baseurl','/',1),(14,'paths','/','/mnt/hgfs/workspace-python',1); +/*!40000 ALTER TABLE `rhodecode_ui` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `statistics` +-- + +DROP TABLE IF EXISTS `statistics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `statistics` ( + `stat_id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `stat_on_revision` int(11) NOT NULL, + `commit_activity` mediumblob NOT NULL, + `commit_activity_combined` blob NOT NULL, + `languages` mediumblob NOT NULL, + PRIMARY KEY (`stat_id`), + UNIQUE KEY `repository_id` (`repository_id`), + UNIQUE KEY `stat_id` (`stat_id`), + UNIQUE KEY `repository_id_2` (`repository_id`), + CONSTRAINT `statistics_ibfk_1` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `statistics` +-- + +LOCK TABLES `statistics` WRITE; +/*!40000 ALTER TABLE `statistics` DISABLE KEYS */; +/*!40000 ALTER TABLE `statistics` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_email_map` +-- + +DROP TABLE IF EXISTS `user_email_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_email_map` ( + `email_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + PRIMARY KEY (`email_id`), + UNIQUE KEY `email_id` (`email_id`), + UNIQUE KEY `email` (`email`), + KEY `user_id` (`user_id`), + KEY `uem_email_idx` (`email`), + CONSTRAINT `user_email_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_email_map` +-- + +LOCK TABLES `user_email_map` WRITE; +/*!40000 ALTER TABLE `user_email_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_email_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_followings` +-- + +DROP TABLE IF EXISTS `user_followings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_followings` ( + `user_following_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `follows_repository_id` int(11) DEFAULT NULL, + `follows_user_id` int(11) DEFAULT NULL, + `follows_from` datetime DEFAULT NULL, + PRIMARY KEY (`user_following_id`), + UNIQUE KEY `user_following_id` (`user_following_id`), + UNIQUE KEY `user_id` (`user_id`,`follows_repository_id`), + UNIQUE KEY `user_id_2` (`user_id`,`follows_user_id`), + KEY `follows_repository_id` (`follows_repository_id`), + KEY `follows_user_id` (`follows_user_id`), + CONSTRAINT `user_followings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_followings_ibfk_2` FOREIGN KEY (`follows_repository_id`) REFERENCES `repositories` (`repo_id`), + CONSTRAINT `user_followings_ibfk_3` FOREIGN KEY (`follows_user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_followings` +-- + +LOCK TABLES `user_followings` WRITE; +/*!40000 ALTER TABLE `user_followings` DISABLE KEYS */; +INSERT INTO `user_followings` VALUES (1,2,1,NULL,'2013-05-29 14:16:09'),(2,2,2,NULL,'2013-05-29 14:16:09'),(3,2,3,NULL,'2013-05-29 14:16:10'),(4,2,4,NULL,'2013-05-29 14:16:10'),(5,2,5,NULL,'2013-05-29 14:16:11'),(6,2,6,NULL,'2013-05-29 14:16:11'),(7,2,7,NULL,'2013-05-29 14:16:11'),(8,2,8,NULL,'2013-05-29 14:16:11'),(9,2,9,NULL,'2013-05-29 14:16:11'),(10,2,10,NULL,'2013-05-29 14:16:11'),(11,2,11,NULL,'2013-05-29 14:16:11'),(12,2,12,NULL,'2013-05-29 14:16:12'),(13,2,13,NULL,'2013-05-29 14:16:12'),(14,2,14,NULL,'2013-05-29 14:16:12'),(15,2,15,NULL,'2013-05-29 14:16:12'),(16,2,16,NULL,'2013-05-29 14:16:12'),(17,2,17,NULL,'2013-05-29 14:16:12'),(18,2,18,NULL,'2013-05-29 14:16:12'),(19,2,19,NULL,'2013-05-29 14:16:12'),(20,2,20,NULL,'2013-05-29 14:16:12'),(21,2,21,NULL,'2013-05-29 14:16:12'),(22,2,22,NULL,'2013-05-29 14:16:13'),(23,2,23,NULL,'2013-05-29 14:16:13'),(24,2,24,NULL,'2013-05-29 14:16:13'),(25,2,25,NULL,'2013-05-29 14:16:13'),(26,2,26,NULL,'2013-05-29 14:16:13'),(27,2,27,NULL,'2013-05-29 14:16:13'),(28,2,28,NULL,'2013-05-29 14:16:13'),(29,2,29,NULL,'2013-05-29 14:16:13'),(30,2,30,NULL,'2013-05-29 14:16:13'),(31,2,31,NULL,'2013-05-29 14:16:13'),(32,2,32,NULL,'2013-05-29 14:16:13'),(33,2,33,NULL,'2013-05-29 14:16:24'),(34,2,34,NULL,'2013-05-29 14:16:24'),(35,2,35,NULL,'2013-05-29 14:16:24'),(36,2,36,NULL,'2013-05-29 14:16:24'),(37,2,37,NULL,'2013-05-29 14:16:25'),(38,2,38,NULL,'2013-05-29 14:16:25'),(39,2,39,NULL,'2013-05-29 14:16:25'),(40,2,40,NULL,'2013-05-29 14:16:25'),(41,2,41,NULL,'2013-05-29 14:16:25'),(42,2,42,NULL,'2013-05-29 14:16:25'),(43,2,43,NULL,'2013-05-29 14:16:25'),(44,2,44,NULL,'2013-05-29 14:16:25'),(45,2,45,NULL,'2013-05-29 14:16:25'),(46,2,46,NULL,'2013-05-29 14:16:25'),(47,2,47,NULL,'2013-05-29 14:16:25'),(48,2,48,NULL,'2013-05-29 14:16:25'),(49,2,49,NULL,'2013-05-29 14:16:26'),(50,2,50,NULL,'2013-05-29 14:16:26'),(51,2,51,NULL,'2013-05-29 14:16:26'),(52,2,52,NULL,'2013-05-29 14:16:26'),(53,2,53,NULL,'2013-05-29 14:16:26'),(54,2,54,NULL,'2013-05-29 14:16:26'),(55,2,55,NULL,'2013-05-29 14:16:27'),(56,2,56,NULL,'2013-05-29 14:16:27'),(57,2,57,NULL,'2013-05-29 14:16:27'),(58,2,58,NULL,'2013-05-29 14:16:27'),(59,2,59,NULL,'2013-05-29 14:16:27'); +/*!40000 ALTER TABLE `user_followings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_ip_map` +-- + +DROP TABLE IF EXISTS `user_ip_map`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_ip_map` ( + `ip_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `ip_addr` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`ip_id`), + UNIQUE KEY `ip_id` (`ip_id`), + UNIQUE KEY `user_id` (`user_id`,`ip_addr`), + CONSTRAINT `user_ip_map_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_ip_map` +-- + +LOCK TABLES `user_ip_map` WRITE; +/*!40000 ALTER TABLE `user_ip_map` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_ip_map` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_logs` +-- + +DROP TABLE IF EXISTS `user_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_logs` ( + `user_log_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `repository_id` int(11) DEFAULT NULL, + `repository_name` varchar(255) DEFAULT NULL, + `user_ip` varchar(255) DEFAULT NULL, + `action` mediumtext, + `action_date` datetime DEFAULT NULL, + PRIMARY KEY (`user_log_id`), + UNIQUE KEY `user_log_id` (`user_log_id`), + KEY `user_id` (`user_id`), + KEY `repository_id` (`repository_id`), + CONSTRAINT `user_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_logs_ibfk_2` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_logs` +-- + +LOCK TABLES `user_logs` WRITE; +/*!40000 ALTER TABLE `user_logs` DISABLE KEYS */; +INSERT INTO `user_logs` VALUES (1,2,'marcink',1,'RC/mygr/lol','','started_following_repo','2013-05-29 14:16:09'),(2,2,'marcink',2,'RC/fakeclone','','started_following_repo','2013-05-29 14:16:09'),(3,2,'marcink',3,'RC/muay','','started_following_repo','2013-05-29 14:16:09'),(4,2,'marcink',4,'BIG/git','','started_following_repo','2013-05-29 14:16:10'),(5,2,'marcink',5,'RC/origin-fork','','started_following_repo','2013-05-29 14:16:11'),(6,2,'marcink',6,'RC/trololo','','started_following_repo','2013-05-29 14:16:11'),(7,2,'marcink',7,'csa-collins','','started_following_repo','2013-05-29 14:16:11'),(8,2,'marcink',8,'csa-harmony','','started_following_repo','2013-05-29 14:16:11'),(9,2,'marcink',9,'RC/Ä…qweqwe','','started_following_repo','2013-05-29 14:16:11'),(10,2,'marcink',10,'rhodecode','','started_following_repo','2013-05-29 14:16:11'),(11,2,'marcink',11,'csa-unity','','started_following_repo','2013-05-29 14:16:11'),(12,2,'marcink',12,'RC/Å‚Ä™cina','','started_following_repo','2013-05-29 14:16:12'),(13,2,'marcink',13,'waitress','','started_following_repo','2013-05-29 14:16:12'),(14,2,'marcink',14,'RC/rc2/test2','','started_following_repo','2013-05-29 14:16:12'),(15,2,'marcink',15,'RC/origin-fork-fork','','started_following_repo','2013-05-29 14:16:12'),(16,2,'marcink',16,'RC/rc2/test4','','started_following_repo','2013-05-29 14:16:12'),(17,2,'marcink',17,'RC/vcs-git','','started_following_repo','2013-05-29 14:16:12'),(18,2,'marcink',18,'rhodecode-extensions','','started_following_repo','2013-05-29 14:16:12'),(19,2,'marcink',19,'rhodecode-cli-gist','','started_following_repo','2013-05-29 14:16:12'),(20,2,'marcink',20,'RC/new','','started_following_repo','2013-05-29 14:16:12'),(21,2,'marcink',21,'csa-aldrin','','started_following_repo','2013-05-29 14:16:12'),(22,2,'marcink',22,'vcs','','started_following_repo','2013-05-29 14:16:13'),(23,2,'marcink',23,'csa-prometheus','','started_following_repo','2013-05-29 14:16:13'),(24,2,'marcink',24,'RC/INRC/trololo','','started_following_repo','2013-05-29 14:16:13'),(25,2,'marcink',25,'RC/empty-git','','started_following_repo','2013-05-29 14:16:13'),(26,2,'marcink',26,'RC/bin-ops','','started_following_repo','2013-05-29 14:16:13'),(27,2,'marcink',27,'csa-salt-states','','started_following_repo','2013-05-29 14:16:13'),(28,2,'marcink',28,'rhodecode-premium','','started_following_repo','2013-05-29 14:16:13'),(29,2,'marcink',29,'RC/qweqwe-fork','','started_following_repo','2013-05-29 14:16:13'),(30,2,'marcink',30,'RC/test','','started_following_repo','2013-05-29 14:16:13'),(31,2,'marcink',31,'remote-salt','','started_following_repo','2013-05-29 14:16:13'),(32,2,'marcink',32,'BIG/android','','started_following_repo','2013-05-29 14:16:13'),(33,2,'marcink',33,'DOCS','','started_following_repo','2013-05-29 14:16:24'),(34,2,'marcink',34,'rhodecode-git','','started_following_repo','2013-05-29 14:16:24'),(35,2,'marcink',35,'RC/fork-remote','','started_following_repo','2013-05-29 14:16:24'),(36,2,'marcink',36,'RC/INRC/L2_NEW/lalalal','','started_following_repo','2013-05-29 14:16:24'),(37,2,'marcink',37,'RC/INRC/L2_NEW/L3/repo_test_move','','started_following_repo','2013-05-29 14:16:25'),(38,2,'marcink',38,'RC/gogo-fork','','started_following_repo','2013-05-29 14:16:25'),(39,2,'marcink',39,'quest','','started_following_repo','2013-05-29 14:16:25'),(40,2,'marcink',40,'RC/foobar','','started_following_repo','2013-05-29 14:16:25'),(41,2,'marcink',41,'csa-hyperion','','started_following_repo','2013-05-29 14:16:25'),(42,2,'marcink',42,'RC/git-pull-test','','started_following_repo','2013-05-29 14:16:25'),(43,2,'marcink',43,'RC/qweqwe-fork2','','started_following_repo','2013-05-29 14:16:25'),(44,2,'marcink',44,'RC/jap','','started_following_repo','2013-05-29 14:16:25'),(45,2,'marcink',45,'RC/hg-repo','','started_following_repo','2013-05-29 14:16:25'),(46,2,'marcink',46,'RC/origin','','started_following_repo','2013-05-29 14:16:25'),(47,2,'marcink',47,'rhodecode-cli-api','','started_following_repo','2013-05-29 14:16:25'),(48,2,'marcink',48,'RC/rc2/test3','','started_following_repo','2013-05-29 14:16:25'),(49,2,'marcink',49,'csa-armstrong','','started_following_repo','2013-05-29 14:16:26'),(50,2,'marcink',50,'pyramidpypi','','started_following_repo','2013-05-29 14:16:26'),(51,2,'marcink',51,'RC/lol/haha','','started_following_repo','2013-05-29 14:16:26'),(52,2,'marcink',52,'csa-io','','started_following_repo','2013-05-29 14:16:26'),(53,2,'marcink',53,'enc-envelope','','started_following_repo','2013-05-29 14:16:26'),(54,2,'marcink',54,'RC/gogo2','','started_following_repo','2013-05-29 14:16:26'),(55,2,'marcink',55,'csa-libcloud','','started_following_repo','2013-05-29 14:16:27'),(56,2,'marcink',56,'RC/git-test','','started_following_repo','2013-05-29 14:16:27'),(57,2,'marcink',57,'RC/rc2/test','','started_following_repo','2013-05-29 14:16:27'),(58,2,'marcink',58,'salt','','started_following_repo','2013-05-29 14:16:27'),(59,2,'marcink',59,'RC/kiall-nova','','started_following_repo','2013-05-29 14:16:27'); +/*!40000 ALTER TABLE `user_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `user_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_repo_group_to_perm` ( + `group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`group_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`group_id`,`permission_id`), + UNIQUE KEY `group_to_perm_id` (`group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `user_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_repo_group_to_perm` +-- + +LOCK TABLES `user_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `user_repo_group_to_perm` DISABLE KEYS */; +INSERT INTO `user_repo_group_to_perm` VALUES (1,1,1,6),(2,1,2,6),(3,1,3,6),(4,1,4,6),(5,1,5,6),(6,1,6,6),(7,1,7,6),(8,1,8,6); +/*!40000 ALTER TABLE `user_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_notification` +-- + +DROP TABLE IF EXISTS `user_to_notification`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_notification` ( + `user_id` int(11) NOT NULL, + `notification_id` int(11) NOT NULL, + `read` tinyint(1) DEFAULT NULL, + `sent_on` datetime DEFAULT NULL, + PRIMARY KEY (`user_id`,`notification_id`), + UNIQUE KEY `user_id` (`user_id`,`notification_id`), + KEY `notification_id` (`notification_id`), + CONSTRAINT `user_to_notification_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_notification_ibfk_2` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`notification_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_notification` +-- + +LOCK TABLES `user_to_notification` WRITE; +/*!40000 ALTER TABLE `user_to_notification` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_to_notification` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_to_perm` +-- + +DROP TABLE IF EXISTS `user_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_to_perm` ( + `user_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`user_to_perm_id`), + UNIQUE KEY `user_id` (`user_id`,`permission_id`), + UNIQUE KEY `user_to_perm_id` (`user_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `user_to_perm_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`), + CONSTRAINT `user_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_to_perm` +-- + +LOCK TABLES `user_to_perm` WRITE; +/*!40000 ALTER TABLE `user_to_perm` DISABLE KEYS */; +INSERT INTO `user_to_perm` VALUES (4,1,2),(5,1,6),(2,1,11),(3,1,13),(1,1,15); +/*!40000 ALTER TABLE `user_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT NULL, + `admin` tinyint(1) DEFAULT NULL, + `firstname` varchar(255) DEFAULT NULL, + `lastname` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `last_login` datetime DEFAULT NULL, + `ldap_dn` varchar(255) DEFAULT NULL, + `api_key` varchar(255) DEFAULT NULL, + `inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `user_id` (`user_id`), + UNIQUE KEY `username` (`username`), + UNIQUE KEY `email` (`email`), + KEY `u_email_idx` (`email`), + KEY `u_username_idx` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'default','$2a$10$k/day.yz9z8QtPF1Mj8ZzOJ794CJS3e4bJ2OCHftGCfCCdRfGKRPm',1,0,'Anonymous','User','anonymous@rhodecode.org',NULL,NULL,'4fc339e026489778a8b80deb0ef2cce571bf02d0',1),(2,'marcink','$2a$10$piApcGV3vLj1hC6oEH6MROyDMwt5MAnu6vaN8Rwq.069FJCdgfNUC',1,1,'RhodeCode','Admin','marcin@appzonaut.com',NULL,NULL,'e69148c8899d2ae291fe0bd79be7f085bf4cb2a6',1); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_group_to_perm` ( + `users_group_repo_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_repo_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`group_id`), + UNIQUE KEY `users_group_repo_group_to_perm_id` (`users_group_repo_group_to_perm_id`), + KEY `group_id` (`group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `groups` (`group_id`), + CONSTRAINT `users_group_repo_group_to_perm_ibfk_3` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_group_to_perm` +-- + +LOCK TABLES `users_group_repo_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_repo_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_repo_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_repo_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `repository_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `repository_id` (`repository_id`,`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `users_group_id` (`users_group_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`), + CONSTRAINT `users_group_repo_to_perm_ibfk_3` FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`repo_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_repo_to_perm` +-- + +LOCK TABLES `users_group_repo_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_repo_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_repo_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_group_to_perm` +-- + +DROP TABLE IF EXISTS `users_group_to_perm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_group_to_perm` ( + `users_group_to_perm_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_to_perm_id`), + UNIQUE KEY `users_group_id` (`users_group_id`,`permission_id`), + UNIQUE KEY `users_group_to_perm_id` (`users_group_to_perm_id`), + KEY `permission_id` (`permission_id`), + CONSTRAINT `users_group_to_perm_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_group_to_perm_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_group_to_perm` +-- + +LOCK TABLES `users_group_to_perm` WRITE; +/*!40000 ALTER TABLE `users_group_to_perm` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_group_to_perm` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups` +-- + +DROP TABLE IF EXISTS `users_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups` ( + `users_group_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_name` varchar(255) NOT NULL, + `users_group_active` tinyint(1) DEFAULT NULL, + `users_group_inherit_default_permissions` tinyint(1) NOT NULL, + PRIMARY KEY (`users_group_id`), + UNIQUE KEY `users_group_id` (`users_group_id`), + UNIQUE KEY `users_group_name` (`users_group_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups` +-- + +LOCK TABLES `users_groups` WRITE; +/*!40000 ALTER TABLE `users_groups` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users_groups_members` +-- + +DROP TABLE IF EXISTS `users_groups_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_groups_members` ( + `users_group_member_id` int(11) NOT NULL AUTO_INCREMENT, + `users_group_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + PRIMARY KEY (`users_group_member_id`), + UNIQUE KEY `users_group_member_id` (`users_group_member_id`), + KEY `users_group_id` (`users_group_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `users_groups_members_ibfk_1` FOREIGN KEY (`users_group_id`) REFERENCES `users_groups` (`users_group_id`), + CONSTRAINT `users_groups_members_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users_groups_members` +-- + +LOCK TABLES `users_groups_members` WRITE; +/*!40000 ALTER TABLE `users_groups_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `users_groups_members` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2013-05-29 14:16:34 diff --git a/rhodecode/tests/database/postgres/1.4.4.sql b/rhodecode/tests/database/postgres/1.4.4.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/postgres/1.4.4.sql @@ -0,0 +1,2869 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: cache_invalidation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE cache_invalidation ( + cache_id integer NOT NULL, + cache_key character varying(255), + cache_args character varying(255), + cache_active boolean +); + + +ALTER TABLE public.cache_invalidation OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE cache_invalidation_cache_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.cache_invalidation_cache_id_seq OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE cache_invalidation_cache_id_seq OWNED BY cache_invalidation.cache_id; + + +-- +-- Name: changeset_comments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_comments ( + comment_id integer NOT NULL, + repo_id integer NOT NULL, + revision character varying(40), + pull_request_id integer, + line_no character varying(10), + hl_lines character varying(512), + f_path character varying(1000), + user_id integer NOT NULL, + text text NOT NULL, + created_on timestamp without time zone NOT NULL, + modified_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.changeset_comments OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_comments_comment_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_comments_comment_id_seq OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_comments_comment_id_seq OWNED BY changeset_comments.comment_id; + + +-- +-- Name: changeset_statuses; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_statuses ( + changeset_status_id integer NOT NULL, + repo_id integer NOT NULL, + user_id integer NOT NULL, + revision character varying(40) NOT NULL, + status character varying(128) NOT NULL, + changeset_comment_id integer, + modified_at timestamp without time zone NOT NULL, + version integer NOT NULL, + pull_request_id integer +); + + +ALTER TABLE public.changeset_statuses OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_statuses_changeset_status_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_statuses_changeset_status_id_seq OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_statuses_changeset_status_id_seq OWNED BY changeset_statuses.changeset_status_id; + + +-- +-- Name: db_migrate_version; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE db_migrate_version ( + repository_id character varying(250) NOT NULL, + repository_path text, + version integer +); + + +ALTER TABLE public.db_migrate_version OWNER TO postgres; + +-- +-- Name: groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE groups ( + group_id integer NOT NULL, + group_name character varying(255) NOT NULL, + group_parent_id integer, + group_description character varying(10000), + enable_locking boolean NOT NULL, + CONSTRAINT groups_check CHECK ((group_id <> group_parent_id)) +); + + +ALTER TABLE public.groups OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE groups_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.groups_group_id_seq OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE groups_group_id_seq OWNED BY groups.group_id; + + +-- +-- Name: notifications; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE notifications ( + notification_id integer NOT NULL, + subject character varying(512), + body text, + created_by integer, + created_on timestamp without time zone NOT NULL, + type character varying(256) +); + + +ALTER TABLE public.notifications OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE notifications_notification_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.notifications_notification_id_seq OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE notifications_notification_id_seq OWNED BY notifications.notification_id; + + +-- +-- Name: permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE permissions ( + permission_id integer NOT NULL, + permission_name character varying(255), + permission_longname character varying(255) +); + + +ALTER TABLE public.permissions OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE permissions_permission_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.permissions_permission_id_seq OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE permissions_permission_id_seq OWNED BY permissions.permission_id; + + +-- +-- Name: pull_request_reviewers; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_request_reviewers ( + pull_requests_reviewers_id integer NOT NULL, + pull_request_id integer NOT NULL, + user_id integer +); + + +ALTER TABLE public.pull_request_reviewers OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_request_reviewers_pull_requests_reviewers_id_seq OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq OWNED BY pull_request_reviewers.pull_requests_reviewers_id; + + +-- +-- Name: pull_requests; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_requests ( + pull_request_id integer NOT NULL, + title character varying(256), + description text, + status character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL, + updated_on timestamp without time zone NOT NULL, + user_id integer NOT NULL, + revisions text, + org_repo_id integer NOT NULL, + org_ref character varying(256) NOT NULL, + other_repo_id integer NOT NULL, + other_ref character varying(256) NOT NULL +); + + +ALTER TABLE public.pull_requests OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_requests_pull_request_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_requests_pull_request_id_seq OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_requests_pull_request_id_seq OWNED BY pull_requests.pull_request_id; + + +-- +-- Name: repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repo_to_perm ( + repo_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.repo_to_perm OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repo_to_perm_repo_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repo_to_perm_repo_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repo_to_perm_repo_to_perm_id_seq OWNED BY repo_to_perm.repo_to_perm_id; + + +-- +-- Name: repositories; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories ( + repo_id integer NOT NULL, + repo_name character varying(255) NOT NULL, + clone_uri character varying(255), + repo_type character varying(255) NOT NULL, + user_id integer NOT NULL, + private boolean, + statistics boolean, + downloads boolean, + description character varying(10000), + created_on timestamp without time zone, + updated_on timestamp without time zone, + landing_revision character varying(255) NOT NULL, + enable_locking boolean NOT NULL, + locked character varying(255), + fork_id integer, + group_id integer +); + + +ALTER TABLE public.repositories OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_repo_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_repo_id_seq OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_repo_id_seq OWNED BY repositories.repo_id; + + +-- +-- Name: rhodecode_settings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_settings ( + app_settings_id integer NOT NULL, + app_settings_name character varying(255), + app_settings_value character varying(255) +); + + +ALTER TABLE public.rhodecode_settings OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_settings_app_settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_settings_app_settings_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_settings_app_settings_id_seq OWNED BY rhodecode_settings.app_settings_id; + + +-- +-- Name: rhodecode_ui; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_ui ( + ui_id integer NOT NULL, + ui_section character varying(255), + ui_key character varying(255), + ui_value character varying(255), + ui_active boolean +); + + +ALTER TABLE public.rhodecode_ui OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_ui_ui_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_ui_ui_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_ui_ui_id_seq OWNED BY rhodecode_ui.ui_id; + + +-- +-- Name: statistics; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE statistics ( + stat_id integer NOT NULL, + repository_id integer NOT NULL, + stat_on_revision integer NOT NULL, + commit_activity bytea NOT NULL, + commit_activity_combined bytea NOT NULL, + languages bytea NOT NULL +); + + +ALTER TABLE public.statistics OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE statistics_stat_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.statistics_stat_id_seq OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE statistics_stat_id_seq OWNED BY statistics.stat_id; + + +-- +-- Name: user_email_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_email_map ( + email_id integer NOT NULL, + user_id integer, + email character varying(255) +); + + +ALTER TABLE public.user_email_map OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_email_map_email_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_email_map_email_id_seq OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_email_map_email_id_seq OWNED BY user_email_map.email_id; + + +-- +-- Name: user_followings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_followings ( + user_following_id integer NOT NULL, + user_id integer NOT NULL, + follows_repository_id integer, + follows_user_id integer, + follows_from timestamp without time zone +); + + +ALTER TABLE public.user_followings OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_followings_user_following_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_followings_user_following_id_seq OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_followings_user_following_id_seq OWNED BY user_followings.user_following_id; + + +-- +-- Name: user_logs; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_logs ( + user_log_id integer NOT NULL, + user_id integer NOT NULL, + repository_id integer, + repository_name character varying(255), + user_ip character varying(255), + action text, + action_date timestamp without time zone +); + + +ALTER TABLE public.user_logs OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_logs_user_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_logs_user_log_id_seq OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_logs_user_log_id_seq OWNED BY user_logs.user_log_id; + + +-- +-- Name: user_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_repo_group_to_perm ( + group_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_repo_group_to_perm_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq OWNED BY user_repo_group_to_perm.group_to_perm_id; + + +-- +-- Name: user_to_notification; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_notification ( + user_id integer NOT NULL, + notification_id integer NOT NULL, + read boolean, + sent_on timestamp without time zone +); + + +ALTER TABLE public.user_to_notification OWNER TO postgres; + +-- +-- Name: user_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_perm ( + user_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_to_perm OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_to_perm_user_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_to_perm_user_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_to_perm_user_to_perm_id_seq OWNED BY user_to_perm.user_to_perm_id; + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users ( + user_id integer NOT NULL, + username character varying(255), + password character varying(255), + active boolean, + admin boolean, + firstname character varying(255), + lastname character varying(255), + email character varying(255), + last_login timestamp without time zone, + ldap_dn character varying(255), + api_key character varying(255), + inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_group_to_perm ( + users_group_repo_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNED BY users_group_repo_group_to_perm.users_group_repo_group_to_perm_id; + + +-- +-- Name: users_group_repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq OWNED BY users_group_repo_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_to_perm_users_group_to_perm_id_seq OWNED BY users_group_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups ( + users_group_id integer NOT NULL, + users_group_name character varying(255) NOT NULL, + users_group_active boolean, + users_group_inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users_groups OWNER TO postgres; + +-- +-- Name: users_groups_members; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups_members ( + users_group_member_id integer NOT NULL, + users_group_id integer NOT NULL, + user_id integer NOT NULL +); + + +ALTER TABLE public.users_groups_members OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_members_users_group_member_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_members_users_group_member_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_members_users_group_member_id_seq OWNED BY users_groups_members.users_group_member_id; + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_users_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_users_group_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_users_group_id_seq OWNED BY users_groups.users_group_id; + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_user_id_seq OWNER TO postgres; + +-- +-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_user_id_seq OWNED BY users.user_id; + + +-- +-- Name: cache_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY cache_invalidation ALTER COLUMN cache_id SET DEFAULT nextval('cache_invalidation_cache_id_seq'::regclass); + + +-- +-- Name: comment_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments ALTER COLUMN comment_id SET DEFAULT nextval('changeset_comments_comment_id_seq'::regclass); + + +-- +-- Name: changeset_status_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses ALTER COLUMN changeset_status_id SET DEFAULT nextval('changeset_statuses_changeset_status_id_seq'::regclass); + + +-- +-- Name: group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups ALTER COLUMN group_id SET DEFAULT nextval('groups_group_id_seq'::regclass); + + +-- +-- Name: notification_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications ALTER COLUMN notification_id SET DEFAULT nextval('notifications_notification_id_seq'::regclass); + + +-- +-- Name: permission_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY permissions ALTER COLUMN permission_id SET DEFAULT nextval('permissions_permission_id_seq'::regclass); + + +-- +-- Name: pull_requests_reviewers_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers ALTER COLUMN pull_requests_reviewers_id SET DEFAULT nextval('pull_request_reviewers_pull_requests_reviewers_id_seq'::regclass); + + +-- +-- Name: pull_request_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests ALTER COLUMN pull_request_id SET DEFAULT nextval('pull_requests_pull_request_id_seq'::regclass); + + +-- +-- Name: repo_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm ALTER COLUMN repo_to_perm_id SET DEFAULT nextval('repo_to_perm_repo_to_perm_id_seq'::regclass); + + +-- +-- Name: repo_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories ALTER COLUMN repo_id SET DEFAULT nextval('repositories_repo_id_seq'::regclass); + + +-- +-- Name: app_settings_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_settings ALTER COLUMN app_settings_id SET DEFAULT nextval('rhodecode_settings_app_settings_id_seq'::regclass); + + +-- +-- Name: ui_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_ui ALTER COLUMN ui_id SET DEFAULT nextval('rhodecode_ui_ui_id_seq'::regclass); + + +-- +-- Name: stat_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics ALTER COLUMN stat_id SET DEFAULT nextval('statistics_stat_id_seq'::regclass); + + +-- +-- Name: email_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map ALTER COLUMN email_id SET DEFAULT nextval('user_email_map_email_id_seq'::regclass); + + +-- +-- Name: user_following_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings ALTER COLUMN user_following_id SET DEFAULT nextval('user_followings_user_following_id_seq'::regclass); + + +-- +-- Name: user_log_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs ALTER COLUMN user_log_id SET DEFAULT nextval('user_logs_user_log_id_seq'::regclass); + + +-- +-- Name: group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm ALTER COLUMN group_to_perm_id SET DEFAULT nextval('user_repo_group_to_perm_group_to_perm_id_seq'::regclass); + + +-- +-- Name: user_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm ALTER COLUMN user_to_perm_id SET DEFAULT nextval('user_to_perm_user_to_perm_id_seq'::regclass); + + +-- +-- Name: user_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users ALTER COLUMN user_id SET DEFAULT nextval('users_user_id_seq'::regclass); + + +-- +-- Name: users_group_repo_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm ALTER COLUMN users_group_repo_group_to_perm_id SET DEFAULT nextval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_repo_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups ALTER COLUMN users_group_id SET DEFAULT nextval('users_groups_users_group_id_seq'::regclass); + + +-- +-- Name: users_group_member_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members ALTER COLUMN users_group_member_id SET DEFAULT nextval('users_groups_members_users_group_member_id_seq'::regclass); + + +-- +-- Data for Name: cache_invalidation; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY cache_invalidation (cache_id, cache_key, cache_args, cache_active) FROM stdin; +1 1RC/fakeclone RC/fakeclone f +2 1RC/muay RC/muay f +3 1one one f +4 1RC/rc2/test2 RC/rc2/test2 f +5 1RC/rc2/test3 RC/rc2/test3 f +6 1RC/rc2/test4 RC/rc2/test4 f +7 1rhodecode-cli-gist rhodecode-cli-gist f +8 1test.onaut.com test.onaut.com f +9 1RC/new RC/new f +10 1rc_gist/32 rc_gist/32 f +11 1vcs vcs f +12 1rc_gist/36 rc_gist/36 f +13 1rc_gist/37 rc_gist/37 f +14 1rc_gist/39 rc_gist/39 f +15 1remote-salt remote-salt f +16 1RC/INRC/trololo RC/INRC/trololo f +17 1quest quest f +18 1csa-hyperion csa-hyperion f +19 1rhodecode rhodecode f +20 1RC/origin-fork-fork RC/origin-fork-fork f +21 1rc_gist/45 rc_gist/45 f +22 1rc_gist/44 rc_gist/44 f +23 1rc_gist/46 rc_gist/46 f +24 1rc_gist/41 rc_gist/41 f +25 1rc_gist/40 rc_gist/40 f +26 1RC/gogo2 RC/gogo2 f +27 1rc_gist/42 rc_gist/42 f +28 1rc_gist/49 rc_gist/49 f +29 1rc_gist/48 rc_gist/48 f +30 1csa-collins csa-collins f +31 1rc_gist/54 rc_gist/54 f +32 1rc_gist/55 rc_gist/55 f +33 1rc_gist/52 rc_gist/52 f +34 1rc_gist/53 rc_gist/53 f +35 1rc_gist/50 rc_gist/50 f +36 1rc_gist/51 rc_gist/51 f +37 1rhodecode.bak.1 rhodecode.bak.1 f +38 1BIG/android BIG/android f +39 1RC/gogo-fork RC/gogo-fork f +40 1RC/mygr/lol RC/mygr/lol f +41 1testrepo-wp testrepo-wp f +42 1RC/hg-repo RC/hg-repo f +43 1testrepo-quick testrepo-quick f +44 1RC/bin-ops RC/bin-ops f +45 1rc_gist/xFvj6dFqqVK5vfsGP8PU rc_gist/xFvj6dFqqVK5vfsGP8PU f +46 1rhodecode-git rhodecode-git f +47 1csa-io csa-io f +48 1RC/qweqwe-fork RC/qweqwe-fork f +49 1csa-libcloud csa-libcloud f +50 1waitress waitress f +51 1rc_gist/8 rc_gist/8 f +52 1rc_gist/9 rc_gist/9 f +53 1RC/foobar RC/foobar f +54 1rc_gist/1 rc_gist/1 f +55 1rc_gist/3 rc_gist/3 f +56 1rc_gist/4 rc_gist/4 f +57 1rc_gist/5 rc_gist/5 f +58 1rc_gist/6 rc_gist/6 f +59 1rc_gist/7 rc_gist/7 f +60 1csa-harmony csa-harmony f +61 1rhodecode-extensions rhodecode-extensions f +62 1csa-prometheus csa-prometheus f +63 1RC/empty-git RC/empty-git f +64 1csa-salt-states csa-salt-states f +65 1RC/łęcina RC/łęcina f +66 1rhodecode-premium rhodecode-premium f +67 1RC/qweqwe-fork2 RC/qweqwe-fork2 f +68 1RC/INRC/L2_NEW/lalalal RC/INRC/L2_NEW/lalalal f +69 1RC/INRC/L2_NEW/L3/repo_test_move RC/INRC/L2_NEW/L3/repo_test_move f +70 1rhodecode.bak rhodecode.bak f +71 1RC/jap RC/jap f +72 1RC/origin RC/origin f +73 1rhodecode-cli-api rhodecode-cli-api f +74 1csa-armstrong csa-armstrong f +75 1rc_gist/NAsB8cacjxnqdyZ8QUl3 rc_gist/NAsB8cacjxnqdyZ8QUl3 f +76 1RC/lol/haha RC/lol/haha f +77 1enc-envelope enc-envelope f +78 1rc_gist/43 rc_gist/43 f +79 1RC/test RC/test f +80 1BIG/git BIG/git f +81 1RC/origin-fork RC/origin-fork f +82 1RC/trololo RC/trololo f +83 1rc_gist/FLj8GunafFAVBnuTWDxU rc_gist/FLj8GunafFAVBnuTWDxU f +84 1csa-unity csa-unity f +85 1RC/vcs-git RC/vcs-git f +86 1rc_gist/12 rc_gist/12 f +87 1rc_gist/13 rc_gist/13 f +88 1rc_gist/10 rc_gist/10 f +89 1rc_gist/11 rc_gist/11 f +90 1RC/kiall-nova RC/kiall-nova f +91 1RC/rc2/test RC/rc2/test f +92 1DOCS DOCS f +93 1RC/fork-remote RC/fork-remote f +94 1RC/git-pull-test RC/git-pull-test f +95 1pyramidpypi pyramidpypi f +96 1rc_gist/aQpbufbhSac6FyvVHhmS rc_gist/aQpbufbhSac6FyvVHhmS f +97 1csa-aldrin csa-aldrin f +98 1RC/ąqweqwe RC/ąqweqwe f +99 1rc_gist/QL2GhrlKymNmrUJJy5js rc_gist/QL2GhrlKymNmrUJJy5js f +100 1RC/git-test RC/git-test f +101 1salt salt f +\. + + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('cache_invalidation_cache_id_seq', 101, true); + + +-- +-- Data for Name: changeset_comments; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_comments (comment_id, repo_id, revision, pull_request_id, line_no, hl_lines, f_path, user_id, text, created_on, modified_at) FROM stdin; +\. + + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_comments_comment_id_seq', 1, false); + + +-- +-- Data for Name: changeset_statuses; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_statuses (changeset_status_id, repo_id, user_id, revision, status, changeset_comment_id, modified_at, version, pull_request_id) FROM stdin; +\. + + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_statuses_changeset_status_id_seq', 1, false); + + +-- +-- Data for Name: db_migrate_version; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY db_migrate_version (repository_id, repository_path, version) FROM stdin; +rhodecode_db_migrations versions 7 +\. + + +-- +-- Data for Name: groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY groups (group_id, group_name, group_parent_id, group_description, enable_locking) FROM stdin; +1 RC \N RC group f +2 RC/rc2 1 RC/rc2 group f +3 rc_gist \N rc_gist group f +4 RC/INRC 1 RC/INRC group f +5 BIG \N BIG group f +6 RC/mygr 1 RC/mygr group f +7 RC/INRC/L2_NEW 4 RC/INRC/L2_NEW group f +8 RC/INRC/L2_NEW/L3 7 RC/INRC/L2_NEW/L3 group f +9 RC/lol 1 RC/lol group f +\. + + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('groups_group_id_seq', 9, true); + + +-- +-- Data for Name: notifications; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY notifications (notification_id, subject, body, created_by, created_on, type) FROM stdin; +\. + + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('notifications_notification_id_seq', 1, false); + + +-- +-- Data for Name: permissions; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY permissions (permission_id, permission_name, permission_longname) FROM stdin; +1 repository.none repository.none +2 repository.read repository.read +3 repository.write repository.write +4 repository.admin repository.admin +5 group.none group.none +6 group.read group.read +7 group.write group.write +8 group.admin group.admin +9 hg.admin hg.admin +10 hg.create.none hg.create.none +11 hg.create.repository hg.create.repository +12 hg.fork.none hg.fork.none +13 hg.fork.repository hg.fork.repository +14 hg.register.none hg.register.none +15 hg.register.manual_activate hg.register.manual_activate +16 hg.register.auto_activate hg.register.auto_activate +\. + + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('permissions_permission_id_seq', 16, true); + + +-- +-- Data for Name: pull_request_reviewers; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_request_reviewers (pull_requests_reviewers_id, pull_request_id, user_id) FROM stdin; +\. + + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_request_reviewers_pull_requests_reviewers_id_seq', 1, false); + + +-- +-- Data for Name: pull_requests; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_requests (pull_request_id, title, description, status, created_on, updated_on, user_id, revisions, org_repo_id, org_ref, other_repo_id, other_ref) FROM stdin; +\. + + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_requests_pull_request_id_seq', 1, false); + + +-- +-- Data for Name: repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repo_to_perm (repo_to_perm_id, user_id, permission_id, repository_id) FROM stdin; +1 1 2 1 +2 1 2 2 +3 1 2 3 +4 1 2 4 +5 1 2 5 +6 1 2 6 +7 1 2 7 +8 1 2 8 +9 1 2 9 +10 1 2 10 +11 1 2 11 +12 1 2 12 +13 1 2 13 +14 1 2 14 +15 1 2 15 +16 1 2 16 +17 1 2 17 +18 1 2 18 +19 1 2 19 +20 1 2 20 +21 1 2 21 +22 1 2 22 +23 1 2 23 +24 1 2 24 +25 1 2 25 +26 1 2 26 +27 1 2 27 +28 1 2 28 +29 1 2 29 +30 1 2 30 +31 1 2 31 +32 1 2 32 +33 1 2 33 +34 1 2 34 +35 1 2 35 +36 1 2 36 +37 1 2 37 +38 1 2 38 +39 1 2 39 +40 1 2 40 +41 1 2 41 +42 1 2 42 +43 1 2 43 +44 1 2 44 +45 1 2 45 +46 1 2 46 +47 1 2 47 +48 1 2 48 +49 1 2 49 +50 1 2 50 +51 1 2 51 +52 1 2 52 +53 1 2 53 +54 1 2 54 +55 1 2 55 +56 1 2 56 +57 1 2 57 +58 1 2 58 +59 1 2 59 +60 1 2 60 +61 1 2 61 +62 1 2 62 +63 1 2 63 +64 1 2 64 +65 1 2 65 +66 1 2 66 +67 1 2 67 +68 1 2 68 +69 1 2 69 +70 1 2 70 +71 1 2 71 +72 1 2 72 +73 1 2 73 +74 1 2 74 +75 1 2 75 +76 1 2 76 +77 1 2 77 +78 1 2 78 +79 1 2 79 +80 1 2 80 +81 1 2 81 +82 1 2 82 +83 1 2 83 +84 1 2 84 +85 1 2 85 +86 1 2 86 +87 1 2 87 +88 1 2 88 +89 1 2 89 +90 1 2 90 +91 1 2 91 +92 1 2 92 +93 1 2 93 +94 1 2 94 +95 1 2 95 +96 1 2 96 +97 1 2 97 +98 1 2 98 +99 1 2 99 +100 1 2 100 +101 1 2 101 +\. + + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repo_to_perm_repo_to_perm_id_seq', 101, true); + + +-- +-- Data for Name: repositories; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories (repo_id, repo_name, clone_uri, repo_type, user_id, private, statistics, downloads, description, created_on, updated_on, landing_revision, enable_locking, locked, fork_id, group_id) FROM stdin; +1 RC/fakeclone http://user@vm/RC/fakeclone git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.047944 2013-05-28 20:19:46.047971 tip f \N \N 1 +2 RC/muay \N hg 2 f f t RC/muay repository 2013-05-28 20:19:46.114543 2013-05-28 20:19:46.114565 tip f \N \N 1 +3 one \N hg 2 f f t one repository 2013-05-28 20:19:46.134156 2013-05-28 20:19:46.134179 tip f \N \N \N +4 RC/rc2/test2 \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.172851 2013-05-28 20:19:46.172875 tip f \N \N 2 +5 RC/rc2/test3 \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.224723 2013-05-28 20:19:46.224746 tip f \N \N 2 +6 RC/rc2/test4 \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.282256 2013-05-28 20:19:46.282281 tip f \N \N 2 +7 rhodecode-cli-gist \N hg 2 f f t rhodecode-cli-gist repository 2013-05-28 20:19:46.33147 2013-05-28 20:19:46.331495 tip f \N \N \N +8 test.onaut.com \N git 2 f f t Unnamed repository 2013-05-28 20:19:46.352391 2013-05-28 20:19:46.352413 tip f \N \N \N +9 RC/new \N hg 2 f f t RC/new repository 2013-05-28 20:19:46.406258 2013-05-28 20:19:46.406287 tip f \N \N 1 +10 rc_gist/32 \N hg 2 f f t rc_gist/32 repository 2013-05-28 20:19:46.439556 2013-05-28 20:19:46.439581 tip f \N \N 3 +11 vcs \N hg 2 f f t vcs repository 2013-05-28 20:19:46.464778 2013-05-28 20:19:46.464804 tip f \N \N \N +12 rc_gist/36 \N hg 2 f f t rc_gist/36 repository 2013-05-28 20:19:46.497987 2013-05-28 20:19:46.498012 tip f \N \N 3 +13 rc_gist/37 \N hg 2 f f t rc_gist/37 repository 2013-05-28 20:19:46.52051 2013-05-28 20:19:46.520533 tip f \N \N 3 +14 rc_gist/39 \N hg 2 f f t rc_gist/39 repository 2013-05-28 20:19:46.545352 2013-05-28 20:19:46.545375 tip f \N \N 3 +15 remote-salt \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.568093 2013-05-28 20:19:46.568116 tip f \N \N \N +16 RC/INRC/trololo \N hg 2 f f t RC/INRC/trololo repository 2013-05-28 20:19:46.630152 2013-05-28 20:19:46.630174 tip f \N \N 4 +17 quest \N hg 2 f f t quest repository 2013-05-28 20:19:46.65001 2013-05-28 20:19:46.650031 tip f \N \N \N +18 csa-hyperion \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.674955 2013-05-28 20:19:46.67498 tip f \N \N \N +19 rhodecode \N hg 2 f f t rhodecode repository 2013-05-28 20:19:46.717995 2013-05-28 20:19:46.718016 tip f \N \N \N +20 RC/origin-fork-fork \N hg 2 f f t RC/origin-fork-fork repository 2013-05-28 20:19:46.738847 2013-05-28 20:19:46.738871 tip f \N \N 1 +21 rc_gist/45 \N hg 2 f f t rc_gist/45 repository 2013-05-28 20:19:46.763345 2013-05-28 20:19:46.763368 tip f \N \N 3 +22 rc_gist/44 \N hg 2 f f t rc_gist/44 repository 2013-05-28 20:19:46.785822 2013-05-28 20:19:46.785845 tip f \N \N 3 +23 rc_gist/46 \N hg 2 f f t rc_gist/46 repository 2013-05-28 20:19:46.810502 2013-05-28 20:19:46.810526 tip f \N \N 3 +24 rc_gist/41 \N hg 2 f f t rc_gist/41 repository 2013-05-28 20:19:46.831198 2013-05-28 20:19:46.831222 tip f \N \N 3 +25 rc_gist/40 \N hg 2 f f t rc_gist/40 repository 2013-05-28 20:19:46.854003 2013-05-28 20:19:46.854027 tip f \N \N 3 +26 RC/gogo2 \N hg 2 f f t RC/gogo2 repository 2013-05-28 20:19:46.875303 2013-05-28 20:19:46.875328 tip f \N \N 1 +27 rc_gist/42 \N hg 2 f f t rc_gist/42 repository 2013-05-28 20:19:46.90018 2013-05-28 20:19:46.900204 tip f \N \N 3 +28 rc_gist/49 \N hg 2 f f t rc_gist/49 repository 2013-05-28 20:19:46.921025 2013-05-28 20:19:46.921048 tip f \N \N 3 +29 rc_gist/48 \N hg 2 f f t rc_gist/48 repository 2013-05-28 20:19:46.943213 2013-05-28 20:19:46.943239 tip f \N \N 3 +30 csa-collins \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:46.971235 2013-05-28 20:19:46.971268 tip f \N \N \N +31 rc_gist/54 \N hg 2 f f t rc_gist/54 repository 2013-05-28 20:19:47.027501 2013-05-28 20:19:47.027544 tip f \N \N 3 +32 rc_gist/55 \N hg 2 f f t rc_gist/55 repository 2013-05-28 20:19:47.050943 2013-05-28 20:19:47.050969 tip f \N \N 3 +33 rc_gist/52 \N hg 2 f f t rc_gist/52 repository 2013-05-28 20:19:47.073536 2013-05-28 20:19:47.073559 tip f \N \N 3 +34 rc_gist/53 \N hg 2 f f t rc_gist/53 repository 2013-05-28 20:19:47.094418 2013-05-28 20:19:47.094443 tip f \N \N 3 +35 rc_gist/50 \N hg 2 f f t rc_gist/50 repository 2013-05-28 20:19:47.116567 2013-05-28 20:19:47.116591 tip f \N \N 3 +36 rc_gist/51 \N hg 2 f f t rc_gist/51 repository 2013-05-28 20:19:47.136888 2013-05-28 20:19:47.136911 tip f \N \N 3 +37 rhodecode.bak.1 \N hg 2 f f t rhodecode.bak.1 repository 2013-05-28 20:19:47.16212 2013-05-28 20:19:47.162142 tip f \N \N \N +38 BIG/android \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.198231 2013-05-28 20:19:47.198266 tip f \N \N 5 +39 RC/gogo-fork \N hg 2 f f t RC/gogo-fork repository 2013-05-28 20:19:47.249438 2013-05-28 20:19:47.24946 tip f \N \N 1 +40 RC/mygr/lol \N hg 2 f f t RC/mygr/lol repository 2013-05-28 20:19:47.282234 2013-05-28 20:19:47.282267 tip f \N \N 6 +41 testrepo-wp \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.308192 2013-05-28 20:19:47.308216 tip f \N \N \N +42 RC/hg-repo \N hg 2 f f t RC/hg-repo repository 2013-05-28 20:19:47.353158 2013-05-28 20:19:47.353181 tip f \N \N 1 +43 testrepo-quick \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.375672 2013-05-28 20:19:47.375701 tip f \N \N \N +44 RC/bin-ops \N hg 2 f f t RC/bin-ops repository 2013-05-28 20:19:47.42118 2013-05-28 20:19:47.421204 tip f \N \N 1 +45 rc_gist/xFvj6dFqqVK5vfsGP8PU \N hg 2 f f t rc_gist/xFvj6dFqqVK5vfsGP8PU repository 2013-05-28 20:19:47.44612 2013-05-28 20:19:47.446142 tip f \N \N 3 +46 rhodecode-git \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.477245 2013-05-28 20:19:47.477284 tip f \N \N \N +47 csa-io \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.535352 2013-05-28 20:19:47.535377 tip f \N \N \N +48 RC/qweqwe-fork \N hg 2 f f t RC/qweqwe-fork repository 2013-05-28 20:19:47.578105 2013-05-28 20:19:47.578127 tip f \N \N 1 +49 csa-libcloud \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.600812 2013-05-28 20:19:47.600856 tip f \N \N \N +50 waitress \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.685314 2013-05-28 20:19:47.685339 tip f \N \N \N +51 rc_gist/8 \N hg 2 f f t rc_gist/8 repository 2013-05-28 20:19:47.730031 2013-05-28 20:19:47.730055 tip f \N \N 3 +52 rc_gist/9 \N hg 2 f f t rc_gist/9 repository 2013-05-28 20:19:47.751262 2013-05-28 20:19:47.751285 tip f \N \N 3 +53 RC/foobar \N hg 2 f f t RC/foobar repository 2013-05-28 20:19:47.772708 2013-05-28 20:19:47.772732 tip f \N \N 1 +54 rc_gist/1 \N hg 2 f f t rc_gist/1 repository 2013-05-28 20:19:47.7954 2013-05-28 20:19:47.795424 tip f \N \N 3 +55 rc_gist/3 \N hg 2 f f t rc_gist/3 repository 2013-05-28 20:19:47.816017 2013-05-28 20:19:47.81604 tip f \N \N 3 +56 rc_gist/4 \N hg 2 f f t rc_gist/4 repository 2013-05-28 20:19:47.840819 2013-05-28 20:19:47.840841 tip f \N \N 3 +57 rc_gist/5 \N hg 2 f f t rc_gist/5 repository 2013-05-28 20:19:47.86283 2013-05-28 20:19:47.862854 tip f \N \N 3 +58 rc_gist/6 \N hg 2 f f t rc_gist/6 repository 2013-05-28 20:19:47.885803 2013-05-28 20:19:47.885827 tip f \N \N 3 +59 rc_gist/7 \N hg 2 f f t rc_gist/7 repository 2013-05-28 20:19:47.906892 2013-05-28 20:19:47.906917 tip f \N \N 3 +60 csa-harmony \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:47.93115 2013-05-28 20:19:47.931176 tip f \N \N \N +61 rhodecode-extensions \N hg 2 f f t rhodecode-extensions repository 2013-05-28 20:19:47.98251 2013-05-28 20:19:47.982541 tip f \N \N \N +62 csa-prometheus \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.01428 2013-05-28 20:19:48.014303 tip f \N \N \N +63 RC/empty-git \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.062792 2013-05-28 20:19:48.062814 tip f \N \N 1 +64 csa-salt-states \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.108636 2013-05-28 20:19:48.108661 tip f \N \N \N +65 RC/łęcina \N hg 2 f f t RC/łęcina repository 2013-05-28 20:19:48.154998 2013-05-28 20:19:48.155023 tip f \N \N 1 +66 rhodecode-premium \N hg 2 f f t rhodecode-premium repository 2013-05-28 20:19:48.176652 2013-05-28 20:19:48.17668 tip f \N \N \N +67 RC/qweqwe-fork2 \N hg 2 f f t RC/qweqwe-fork2 repository 2013-05-28 20:19:48.198005 2013-05-28 20:19:48.198028 tip f \N \N 1 +68 RC/INRC/L2_NEW/lalalal \N hg 2 f f t RC/INRC/L2_NEW/lalalal repository 2013-05-28 20:19:48.235645 2013-05-28 20:19:48.235669 tip f \N \N 7 +69 RC/INRC/L2_NEW/L3/repo_test_move \N hg 2 f f t RC/INRC/L2_NEW/L3/repo_test_move repository 2013-05-28 20:19:48.270928 2013-05-28 20:19:48.27095 tip f \N \N 8 +70 rhodecode.bak \N hg 2 f f t rhodecode.bak repository 2013-05-28 20:19:48.289771 2013-05-28 20:19:48.289794 tip f \N \N \N +71 RC/jap \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.315557 2013-05-28 20:19:48.315581 tip f \N \N 1 +72 RC/origin \N hg 2 f f t RC/origin repository 2013-05-28 20:19:48.361233 2013-05-28 20:19:48.361257 tip f \N \N 1 +73 rhodecode-cli-api \N hg 2 f f t rhodecode-cli-api repository 2013-05-28 20:19:48.380668 2013-05-28 20:19:48.380694 tip f \N \N \N +74 csa-armstrong \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.415666 2013-05-28 20:19:48.41569 tip f \N \N \N +75 rc_gist/NAsB8cacjxnqdyZ8QUl3 \N hg 2 f f t rc_gist/NAsB8cacjxnqdyZ8QUl3 repository 2013-05-28 20:19:48.464189 2013-05-28 20:19:48.464241 tip f \N \N 3 +76 RC/lol/haha \N hg 2 f f t RC/lol/haha repository 2013-05-28 20:19:48.523514 2013-05-28 20:19:48.523544 tip f \N \N 9 +77 enc-envelope \N hg 2 f f t enc-envelope repository 2013-05-28 20:19:48.556295 2013-05-28 20:19:48.556333 tip f \N \N \N +78 rc_gist/43 \N hg 2 f f t rc_gist/43 repository 2013-05-28 20:19:48.58417 2013-05-28 20:19:48.584196 tip f \N \N 3 +79 RC/test \N hg 2 f f t RC/test repository 2013-05-28 20:19:48.609009 2013-05-28 20:19:48.609036 tip f \N \N 1 +80 BIG/git \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.634082 2013-05-28 20:19:48.634105 tip f \N \N 5 +81 RC/origin-fork \N hg 2 f f t RC/origin-fork repository 2013-05-28 20:19:48.686725 2013-05-28 20:19:48.686747 tip f \N \N 1 +82 RC/trololo \N hg 2 f f t RC/trololo repository 2013-05-28 20:19:48.715102 2013-05-28 20:19:48.715132 tip f \N \N 1 +83 rc_gist/FLj8GunafFAVBnuTWDxU \N hg 2 f f t rc_gist/FLj8GunafFAVBnuTWDxU repository 2013-05-28 20:19:48.747675 2013-05-28 20:19:48.74771 tip f \N \N 3 +84 csa-unity \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.781008 2013-05-28 20:19:48.781035 tip f \N \N \N +85 RC/vcs-git \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:48.835086 2013-05-28 20:19:48.835109 tip f \N \N 1 +86 rc_gist/12 \N hg 2 f f t rc_gist/12 repository 2013-05-28 20:19:48.893392 2013-05-28 20:19:48.893422 tip f \N \N 3 +87 rc_gist/13 \N hg 2 f f t rc_gist/13 repository 2013-05-28 20:19:48.917374 2013-05-28 20:19:48.917398 tip f \N \N 3 +88 rc_gist/10 \N hg 2 f f t rc_gist/10 repository 2013-05-28 20:19:48.940824 2013-05-28 20:19:48.94085 tip f \N \N 3 +89 rc_gist/11 \N hg 2 f f t rc_gist/11 repository 2013-05-28 20:19:48.97297 2013-05-28 20:19:48.973 tip f \N \N 3 +90 RC/kiall-nova \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.009005 2013-05-28 20:19:49.009032 tip f \N \N 1 +91 RC/rc2/test \N hg 2 f f t RC/rc2/test repository 2013-05-28 20:19:49.062753 2013-05-28 20:19:49.062777 tip f \N \N 2 +92 DOCS \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.087857 2013-05-28 20:19:49.087881 tip f \N \N \N +93 RC/fork-remote \N hg 2 f f t RC/fork-remote repository 2013-05-28 20:19:49.133406 2013-05-28 20:19:49.133432 tip f \N \N 1 +94 RC/git-pull-test \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.157471 2013-05-28 20:19:49.157508 tip f \N \N 1 +95 pyramidpypi \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.216696 2013-05-28 20:19:49.216733 tip f \N \N \N +96 rc_gist/aQpbufbhSac6FyvVHhmS \N hg 2 f f t rc_gist/aQpbufbhSac6FyvVHhmS repository 2013-05-28 20:19:49.266672 2013-05-28 20:19:49.2667 tip f \N \N 3 +97 csa-aldrin \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.291319 2013-05-28 20:19:49.291353 tip f \N \N \N +98 RC/ąqweqwe \N hg 2 f f t RC/ąqweqwe repository 2013-05-28 20:19:49.340516 2013-05-28 20:19:49.340539 tip f \N \N 1 +99 rc_gist/QL2GhrlKymNmrUJJy5js \N hg 2 f f t rc_gist/QL2GhrlKymNmrUJJy5js repository 2013-05-28 20:19:49.36452 2013-05-28 20:19:49.364547 tip f \N \N 3 +100 RC/git-test \N git 2 f f t Unnamed repository 2013-05-28 20:19:49.393521 2013-05-28 20:19:49.393548 tip f \N \N 1 +101 salt \N git 2 f f t Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:19:49.44733 2013-05-28 20:19:49.447355 tip f \N \N \N +\. + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_repo_id_seq', 101, true); + + +-- +-- Data for Name: rhodecode_settings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_settings (app_settings_id, app_settings_name, app_settings_value) FROM stdin; +1 realm RhodeCode authentication +2 title RhodeCode +3 ga_code +4 show_public_icon True +5 show_private_icon True +6 stylify_metatags False +7 ldap_active false +8 ldap_host +9 ldap_port 389 +10 ldap_tls_kind PLAIN +11 ldap_tls_reqcert +12 ldap_dn_user +13 ldap_dn_pass +14 ldap_base_dn +15 ldap_filter +16 ldap_search_scope +17 ldap_attr_login +18 ldap_attr_firstname +19 ldap_attr_lastname +20 ldap_attr_email +\. + + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_settings_app_settings_id_seq', 20, true); + + +-- +-- Data for Name: rhodecode_ui; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_ui (ui_id, ui_section, ui_key, ui_value, ui_active) FROM stdin; +1 hooks changegroup.update hg update >&2 f +2 hooks changegroup.repo_size python:rhodecode.lib.hooks.repo_size t +3 hooks changegroup.push_logger python:rhodecode.lib.hooks.log_push_action t +4 hooks prechangegroup.pre_push python:rhodecode.lib.hooks.pre_push t +5 hooks outgoing.pull_logger python:rhodecode.lib.hooks.log_pull_action t +6 hooks preoutgoing.pre_pull python:rhodecode.lib.hooks.pre_pull t +7 extensions largefiles t +8 extensions hgsubversion f +9 extensions hggit f +10 web push_ssl false t +11 web allow_archive gz zip bz2 t +12 web allow_push * t +13 web baseurl / t +14 paths / /mnt/hgfs/workspace-python t +\. + + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_ui_ui_id_seq', 14, true); + + +-- +-- Data for Name: statistics; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY statistics (stat_id, repository_id, stat_on_revision, commit_activity, commit_activity_combined, languages) FROM stdin; +\. + + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('statistics_stat_id_seq', 1, false); + + +-- +-- Data for Name: user_email_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_email_map (email_id, user_id, email) FROM stdin; +\. + + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_email_map_email_id_seq', 1, false); + + +-- +-- Data for Name: user_followings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_followings (user_following_id, user_id, follows_repository_id, follows_user_id, follows_from) FROM stdin; +1 2 1 \N 2013-05-28 20:19:46.068609 +2 2 2 \N 2013-05-28 20:19:46.126742 +3 2 3 \N 2013-05-28 20:19:46.147054 +4 2 4 \N 2013-05-28 20:19:46.213476 +5 2 5 \N 2013-05-28 20:19:46.268777 +6 2 6 \N 2013-05-28 20:19:46.322156 +7 2 7 \N 2013-05-28 20:19:46.343256 +8 2 8 \N 2013-05-28 20:19:46.395212 +9 2 9 \N 2013-05-28 20:19:46.420661 +10 2 10 \N 2013-05-28 20:19:46.451956 +11 2 11 \N 2013-05-28 20:19:46.484107 +12 2 12 \N 2013-05-28 20:19:46.510375 +13 2 13 \N 2013-05-28 20:19:46.53353 +14 2 14 \N 2013-05-28 20:19:46.557944 +15 2 15 \N 2013-05-28 20:19:46.606327 +16 2 16 \N 2013-05-28 20:19:46.642731 +17 2 17 \N 2013-05-28 20:19:46.661205 +18 2 18 \N 2013-05-28 20:19:46.710005 +19 2 19 \N 2013-05-28 20:19:46.729946 +20 2 20 \N 2013-05-28 20:19:46.752531 +21 2 21 \N 2013-05-28 20:19:46.776886 +22 2 22 \N 2013-05-28 20:19:46.801248 +23 2 23 \N 2013-05-28 20:19:46.822563 +24 2 24 \N 2013-05-28 20:19:46.845405 +25 2 25 \N 2013-05-28 20:19:46.866146 +26 2 26 \N 2013-05-28 20:19:46.891708 +27 2 27 \N 2013-05-28 20:19:46.912589 +28 2 28 \N 2013-05-28 20:19:46.934387 +29 2 29 \N 2013-05-28 20:19:46.955575 +30 2 30 \N 2013-05-28 20:19:47.0168 +31 2 31 \N 2013-05-28 20:19:47.040684 +32 2 32 \N 2013-05-28 20:19:47.063573 +33 2 33 \N 2013-05-28 20:19:47.085898 +34 2 34 \N 2013-05-28 20:19:47.10634 +35 2 35 \N 2013-05-28 20:19:47.128293 +36 2 36 \N 2013-05-28 20:19:47.151701 +37 2 37 \N 2013-05-28 20:19:47.174067 +38 2 38 \N 2013-05-28 20:19:47.235231 +39 2 39 \N 2013-05-28 20:19:47.261671 +40 2 40 \N 2013-05-28 20:19:47.297526 +41 2 41 \N 2013-05-28 20:19:47.344301 +42 2 42 \N 2013-05-28 20:19:47.364906 +43 2 43 \N 2013-05-28 20:19:47.412273 +44 2 44 \N 2013-05-28 20:19:47.437251 +45 2 45 \N 2013-05-28 20:19:47.4616 +46 2 46 \N 2013-05-28 20:19:47.525929 +47 2 47 \N 2013-05-28 20:19:47.569847 +48 2 48 \N 2013-05-28 20:19:47.591066 +49 2 49 \N 2013-05-28 20:19:47.636599 +50 2 50 \N 2013-05-28 20:19:47.721273 +51 2 51 \N 2013-05-28 20:19:47.742706 +52 2 52 \N 2013-05-28 20:19:47.763578 +53 2 53 \N 2013-05-28 20:19:47.786723 +54 2 54 \N 2013-05-28 20:19:47.806992 +55 2 55 \N 2013-05-28 20:19:47.832521 +56 2 56 \N 2013-05-28 20:19:47.854374 +57 2 57 \N 2013-05-28 20:19:47.876909 +58 2 58 \N 2013-05-28 20:19:47.897876 +59 2 59 \N 2013-05-28 20:19:47.920242 +60 2 60 \N 2013-05-28 20:19:47.971649 +61 2 61 \N 2013-05-28 20:19:48.001881 +62 2 62 \N 2013-05-28 20:19:48.052068 +63 2 63 \N 2013-05-28 20:19:48.099443 +64 2 64 \N 2013-05-28 20:19:48.145784 +65 2 65 \N 2013-05-28 20:19:48.167391 +66 2 66 \N 2013-05-28 20:19:48.189143 +67 2 67 \N 2013-05-28 20:19:48.211778 +68 2 68 \N 2013-05-28 20:19:48.24747 +69 2 69 \N 2013-05-28 20:19:48.282577 +70 2 70 \N 2013-05-28 20:19:48.303227 +71 2 71 \N 2013-05-28 20:19:48.351707 +72 2 72 \N 2013-05-28 20:19:48.373519 +73 2 73 \N 2013-05-28 20:19:48.404984 +74 2 74 \N 2013-05-28 20:19:48.450431 +75 2 75 \N 2013-05-28 20:19:48.485354 +76 2 76 \N 2013-05-28 20:19:48.543067 +77 2 77 \N 2013-05-28 20:19:48.571906 +78 2 78 \N 2013-05-28 20:19:48.599293 +79 2 79 \N 2013-05-28 20:19:48.622407 +80 2 80 \N 2013-05-28 20:19:48.67569 +81 2 81 \N 2013-05-28 20:19:48.699443 +82 2 82 \N 2013-05-28 20:19:48.734442 +83 2 83 \N 2013-05-28 20:19:48.768314 +84 2 84 \N 2013-05-28 20:19:48.821613 +85 2 85 \N 2013-05-28 20:19:48.882902 +86 2 86 \N 2013-05-28 20:19:48.906216 +87 2 87 \N 2013-05-28 20:19:48.929819 +88 2 88 \N 2013-05-28 20:19:48.956595 +89 2 89 \N 2013-05-28 20:19:48.992037 +90 2 90 \N 2013-05-28 20:19:49.052422 +91 2 91 \N 2013-05-28 20:19:49.076845 +92 2 92 \N 2013-05-28 20:19:49.123624 +93 2 93 \N 2013-05-28 20:19:49.145816 +94 2 94 \N 2013-05-28 20:19:49.201878 +95 2 95 \N 2013-05-28 20:19:49.255729 +96 2 96 \N 2013-05-28 20:19:49.279708 +97 2 97 \N 2013-05-28 20:19:49.327966 +98 2 98 \N 2013-05-28 20:19:49.355807 +99 2 99 \N 2013-05-28 20:19:49.379948 +100 2 100 \N 2013-05-28 20:19:49.437281 +101 2 101 \N 2013-05-28 20:19:49.498065 +\. + + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_followings_user_following_id_seq', 101, true); + + +-- +-- Data for Name: user_logs; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_logs (user_log_id, user_id, repository_id, repository_name, user_ip, action, action_date) FROM stdin; +1 2 1 RC/fakeclone started_following_repo 2013-05-28 20:19:46.06345 +2 2 2 RC/muay started_following_repo 2013-05-28 20:19:46.124201 +3 2 3 one started_following_repo 2013-05-28 20:19:46.144023 +4 2 4 RC/rc2/test2 started_following_repo 2013-05-28 20:19:46.183325 +5 2 5 RC/rc2/test3 started_following_repo 2013-05-28 20:19:46.238781 +6 2 6 RC/rc2/test4 started_following_repo 2013-05-28 20:19:46.292145 +7 2 7 rhodecode-cli-gist started_following_repo 2013-05-28 20:19:46.340854 +8 2 8 test.onaut.com started_following_repo 2013-05-28 20:19:46.364293 +9 2 9 RC/new started_following_repo 2013-05-28 20:19:46.418203 +10 2 10 rc_gist/32 started_following_repo 2013-05-28 20:19:46.449509 +11 2 11 vcs started_following_repo 2013-05-28 20:19:46.480962 +12 2 12 rc_gist/36 started_following_repo 2013-05-28 20:19:46.507782 +13 2 13 rc_gist/37 started_following_repo 2013-05-28 20:19:46.530376 +14 2 14 rc_gist/39 started_following_repo 2013-05-28 20:19:46.555564 +15 2 15 remote-salt started_following_repo 2013-05-28 20:19:46.581784 +16 2 16 RC/INRC/trololo started_following_repo 2013-05-28 20:19:46.640239 +17 2 17 quest started_following_repo 2013-05-28 20:19:46.658865 +18 2 18 csa-hyperion started_following_repo 2013-05-28 20:19:46.685236 +19 2 19 rhodecode started_following_repo 2013-05-28 20:19:46.727476 +20 2 20 RC/origin-fork-fork started_following_repo 2013-05-28 20:19:46.749515 +21 2 21 rc_gist/45 started_following_repo 2013-05-28 20:19:46.774465 +22 2 22 rc_gist/44 started_following_repo 2013-05-28 20:19:46.798226 +23 2 23 rc_gist/46 started_following_repo 2013-05-28 20:19:46.820131 +24 2 24 rc_gist/41 started_following_repo 2013-05-28 20:19:46.843096 +25 2 25 rc_gist/40 started_following_repo 2013-05-28 20:19:46.863481 +26 2 26 RC/gogo2 started_following_repo 2013-05-28 20:19:46.889163 +27 2 27 rc_gist/42 started_following_repo 2013-05-28 20:19:46.910218 +28 2 28 rc_gist/49 started_following_repo 2013-05-28 20:19:46.932045 +29 2 29 rc_gist/48 started_following_repo 2013-05-28 20:19:46.953051 +30 2 30 csa-collins started_following_repo 2013-05-28 20:19:46.98622 +31 2 31 rc_gist/54 started_following_repo 2013-05-28 20:19:47.038223 +32 2 32 rc_gist/55 started_following_repo 2013-05-28 20:19:47.060774 +33 2 33 rc_gist/52 started_following_repo 2013-05-28 20:19:47.083498 +34 2 34 rc_gist/53 started_following_repo 2013-05-28 20:19:47.103903 +35 2 35 rc_gist/50 started_following_repo 2013-05-28 20:19:47.125837 +36 2 36 rc_gist/51 started_following_repo 2013-05-28 20:19:47.148328 +37 2 37 rhodecode.bak.1 started_following_repo 2013-05-28 20:19:47.171696 +38 2 38 BIG/android started_following_repo 2013-05-28 20:19:47.209124 +39 2 39 RC/gogo-fork started_following_repo 2013-05-28 20:19:47.259188 +40 2 40 RC/mygr/lol started_following_repo 2013-05-28 20:19:47.295185 +41 2 41 testrepo-wp started_following_repo 2013-05-28 20:19:47.317898 +42 2 42 RC/hg-repo started_following_repo 2013-05-28 20:19:47.362609 +43 2 43 testrepo-quick started_following_repo 2013-05-28 20:19:47.387878 +44 2 44 RC/bin-ops started_following_repo 2013-05-28 20:19:47.434723 +45 2 45 rc_gist/xFvj6dFqqVK5vfsGP8PU started_following_repo 2013-05-28 20:19:47.457194 +46 2 46 rhodecode-git started_following_repo 2013-05-28 20:19:47.492079 +47 2 47 csa-io started_following_repo 2013-05-28 20:19:47.544724 +48 2 48 RC/qweqwe-fork started_following_repo 2013-05-28 20:19:47.588558 +49 2 49 csa-libcloud started_following_repo 2013-05-28 20:19:47.612633 +50 2 50 waitress started_following_repo 2013-05-28 20:19:47.695147 +51 2 51 rc_gist/8 started_following_repo 2013-05-28 20:19:47.740409 +52 2 52 rc_gist/9 started_following_repo 2013-05-28 20:19:47.760966 +53 2 53 RC/foobar started_following_repo 2013-05-28 20:19:47.784301 +54 2 54 rc_gist/1 started_following_repo 2013-05-28 20:19:47.804641 +55 2 55 rc_gist/3 started_following_repo 2013-05-28 20:19:47.830277 +56 2 56 rc_gist/4 started_following_repo 2013-05-28 20:19:47.851913 +57 2 57 rc_gist/5 started_following_repo 2013-05-28 20:19:47.874467 +58 2 58 rc_gist/6 started_following_repo 2013-05-28 20:19:47.895581 +59 2 59 rc_gist/7 started_following_repo 2013-05-28 20:19:47.917912 +60 2 60 csa-harmony started_following_repo 2013-05-28 20:19:47.941389 +61 2 61 rhodecode-extensions started_following_repo 2013-05-28 20:19:47.998531 +62 2 62 csa-prometheus started_following_repo 2013-05-28 20:19:48.024655 +63 2 63 RC/empty-git started_following_repo 2013-05-28 20:19:48.072925 +64 2 64 csa-salt-states started_following_repo 2013-05-28 20:19:48.119876 +65 2 65 RC/łęcina started_following_repo 2013-05-28 20:19:48.164852 +66 2 66 rhodecode-premium started_following_repo 2013-05-28 20:19:48.186836 +67 2 67 RC/qweqwe-fork2 started_following_repo 2013-05-28 20:19:48.208735 +68 2 68 RC/INRC/L2_NEW/lalalal started_following_repo 2013-05-28 20:19:48.245171 +69 2 69 RC/INRC/L2_NEW/L3/repo_test_move started_following_repo 2013-05-28 20:19:48.280102 +70 2 70 rhodecode.bak started_following_repo 2013-05-28 20:19:48.300852 +71 2 71 RC/jap started_following_repo 2013-05-28 20:19:48.325071 +72 2 72 RC/origin started_following_repo 2013-05-28 20:19:48.37108 +73 2 73 rhodecode-cli-api started_following_repo 2013-05-28 20:19:48.402627 +74 2 74 csa-armstrong started_following_repo 2013-05-28 20:19:48.425969 +75 2 75 rc_gist/NAsB8cacjxnqdyZ8QUl3 started_following_repo 2013-05-28 20:19:48.482094 +76 2 76 RC/lol/haha started_following_repo 2013-05-28 20:19:48.539291 +77 2 77 enc-envelope started_following_repo 2013-05-28 20:19:48.568444 +78 2 78 rc_gist/43 started_following_repo 2013-05-28 20:19:48.596804 +79 2 79 RC/test started_following_repo 2013-05-28 20:19:48.619757 +80 2 80 BIG/git started_following_repo 2013-05-28 20:19:48.647018 +81 2 81 RC/origin-fork started_following_repo 2013-05-28 20:19:48.696698 +82 2 82 RC/trololo started_following_repo 2013-05-28 20:19:48.731089 +83 2 83 rc_gist/FLj8GunafFAVBnuTWDxU started_following_repo 2013-05-28 20:19:48.765206 +84 2 84 csa-unity started_following_repo 2013-05-28 20:19:48.793189 +85 2 85 RC/vcs-git started_following_repo 2013-05-28 20:19:48.846115 +86 2 86 rc_gist/12 started_following_repo 2013-05-28 20:19:48.903713 +87 2 87 rc_gist/13 started_following_repo 2013-05-28 20:19:48.926737 +88 2 88 rc_gist/10 started_following_repo 2013-05-28 20:19:48.953085 +89 2 89 rc_gist/11 started_following_repo 2013-05-28 20:19:48.988513 +90 2 90 RC/kiall-nova started_following_repo 2013-05-28 20:19:49.022101 +91 2 91 RC/rc2/test started_following_repo 2013-05-28 20:19:49.073863 +92 2 92 DOCS started_following_repo 2013-05-28 20:19:49.097898 +93 2 93 RC/fork-remote started_following_repo 2013-05-28 20:19:49.143406 +94 2 94 RC/git-pull-test started_following_repo 2013-05-28 20:19:49.169824 +95 2 95 pyramidpypi started_following_repo 2013-05-28 20:19:49.226862 +96 2 96 rc_gist/aQpbufbhSac6FyvVHhmS started_following_repo 2013-05-28 20:19:49.2771 +97 2 97 csa-aldrin started_following_repo 2013-05-28 20:19:49.301235 +98 2 98 RC/ąqweqwe started_following_repo 2013-05-28 20:19:49.353131 +99 2 99 rc_gist/QL2GhrlKymNmrUJJy5js started_following_repo 2013-05-28 20:19:49.376769 +100 2 100 RC/git-test started_following_repo 2013-05-28 20:19:49.405255 +101 2 101 salt started_following_repo 2013-05-28 20:19:49.462231 +\. + + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_logs_user_log_id_seq', 101, true); + + +-- +-- Data for Name: user_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_repo_group_to_perm (group_to_perm_id, user_id, group_id, permission_id) FROM stdin; +1 1 1 6 +2 1 2 6 +3 1 3 6 +4 1 4 6 +5 1 5 6 +6 1 6 6 +7 1 7 6 +8 1 8 6 +9 1 9 6 +\. + + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_repo_group_to_perm_group_to_perm_id_seq', 9, true); + + +-- +-- Data for Name: user_to_notification; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_notification (user_id, notification_id, read, sent_on) FROM stdin; +\. + + +-- +-- Data for Name: user_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_perm (user_to_perm_id, user_id, permission_id) FROM stdin; +1 1 15 +2 1 11 +3 1 13 +4 1 2 +\. + + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_to_perm_user_to_perm_id_seq', 4, true); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users (user_id, username, password, active, admin, firstname, lastname, email, last_login, ldap_dn, api_key, inherit_default_permissions) FROM stdin; +1 default $2a$10$nv5rCK16FTMWwsfp7vST0.yuHJ/spZcw4VqZ9Bl5Y5fNXxdHwi6Jm t f Anonymous User anonymous@rhodecode.org \N \N 3bde4a66f98734dcc824fbfd4bfb0f0813921c34 t +2 marcink $2a$10$MNNSVrDOaAwM6FJuuPdfA.TKywm4X4prOFndPE.KamfwRTTmS42ze t t RhodeCode Admin qwe@qwe.pl \N \N 08cac6e1607032b6a712c657a70b829b91c41fbe t +\. + + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq', 1, false); + + +-- +-- Data for Name: users_group_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_group_to_perm (users_group_repo_group_to_perm_id, users_group_id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Data for Name: users_group_repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_to_perm (users_group_to_perm_id, users_group_id, permission_id, repository_id) FROM stdin; +\. + + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_to_perm (users_group_to_perm_id, users_group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups (users_group_id, users_group_name, users_group_active, users_group_inherit_default_permissions) FROM stdin; +\. + + +-- +-- Data for Name: users_groups_members; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups_members (users_group_member_id, users_group_id, user_id) FROM stdin; +\. + + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_members_users_group_member_id_seq', 1, false); + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_users_group_id_seq', 1, false); + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_user_id_seq', 2, true); + + +-- +-- Name: cache_invalidation_cache_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_cache_key_key UNIQUE (cache_key); + + +-- +-- Name: cache_invalidation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_pkey PRIMARY KEY (cache_id); + + +-- +-- Name: changeset_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pkey PRIMARY KEY (comment_id); + + +-- +-- Name: changeset_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pkey PRIMARY KEY (changeset_status_id); + + +-- +-- Name: changeset_statuses_repo_id_revision_version_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_revision_version_key UNIQUE (repo_id, revision, version); + + +-- +-- Name: db_migrate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY db_migrate_version + ADD CONSTRAINT db_migrate_version_pkey PRIMARY KEY (repository_id); + + +-- +-- Name: groups_group_name_group_parent_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_group_parent_id_key UNIQUE (group_name, group_parent_id); + + +-- +-- Name: groups_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_key UNIQUE (group_name); + + +-- +-- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_pkey PRIMARY KEY (group_id); + + +-- +-- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (notification_id); + + +-- +-- Name: permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY permissions + ADD CONSTRAINT permissions_pkey PRIMARY KEY (permission_id); + + +-- +-- Name: pull_request_reviewers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pkey PRIMARY KEY (pull_requests_reviewers_id); + + +-- +-- Name: pull_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_pkey PRIMARY KEY (pull_request_id); + + +-- +-- Name: repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_pkey PRIMARY KEY (repo_to_perm_id); + + +-- +-- Name: repo_to_perm_user_id_repository_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_repository_id_permission_id_key UNIQUE (user_id, repository_id, permission_id); + + +-- +-- Name: repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (repo_id); + + +-- +-- Name: repositories_repo_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_repo_name_key UNIQUE (repo_name); + + +-- +-- Name: rhodecode_settings_app_settings_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_app_settings_name_key UNIQUE (app_settings_name); + + +-- +-- Name: rhodecode_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_pkey PRIMARY KEY (app_settings_id); + + +-- +-- Name: rhodecode_ui_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_pkey PRIMARY KEY (ui_id); + + +-- +-- Name: rhodecode_ui_ui_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_ui_key_key UNIQUE (ui_key); + + +-- +-- Name: statistics_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_pkey PRIMARY KEY (stat_id); + + +-- +-- Name: statistics_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_key UNIQUE (repository_id); + + +-- +-- Name: user_email_map_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_email_key UNIQUE (email); + + +-- +-- Name: user_email_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_pkey PRIMARY KEY (email_id); + + +-- +-- Name: user_followings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_pkey PRIMARY KEY (user_following_id); + + +-- +-- Name: user_followings_user_id_follows_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_repository_id_key UNIQUE (user_id, follows_repository_id); + + +-- +-- Name: user_followings_user_id_follows_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_user_id_key UNIQUE (user_id, follows_user_id); + + +-- +-- Name: user_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_pkey PRIMARY KEY (user_log_id); + + +-- +-- Name: user_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_pkey PRIMARY KEY (group_to_perm_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_group_id_permission_id_key UNIQUE (user_id, group_id, permission_id); + + +-- +-- Name: user_to_notification_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_pkey PRIMARY KEY (user_id, notification_id); + + +-- +-- Name: user_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_pkey PRIMARY KEY (user_to_perm_id); + + +-- +-- Name: user_to_perm_user_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_permission_id_key UNIQUE (user_id, permission_id); + + +-- +-- Name: users_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users_group_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_pkey PRIMARY KEY (users_group_repo_group_to_perm_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_group_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_group_id_key UNIQUE (users_group_id, group_id); + + +-- +-- Name: users_group_repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_users_group_id_permi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_users_group_id_permi_key UNIQUE (repository_id, users_group_id, permission_id); + + +-- +-- Name: users_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_to_perm_users_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_permission_id_key UNIQUE (users_group_id, permission_id); + + +-- +-- Name: users_groups_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_pkey PRIMARY KEY (users_group_member_id); + + +-- +-- Name: users_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_pkey PRIMARY KEY (users_group_id); + + +-- +-- Name: users_groups_users_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_users_group_name_key UNIQUE (users_group_name); + + +-- +-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_pkey PRIMARY KEY (user_id); + + +-- +-- Name: users_username_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: cc_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cc_revision_idx ON changeset_comments USING btree (revision); + + +-- +-- Name: cs_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_revision_idx ON changeset_statuses USING btree (revision); + + +-- +-- Name: cs_version_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_version_idx ON changeset_statuses USING btree (version); + + +-- +-- Name: key_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX key_idx ON cache_invalidation USING btree (cache_key); + + +-- +-- Name: notification_type_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX notification_type_idx ON notifications USING btree (type); + + +-- +-- Name: p_perm_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX p_perm_name_idx ON permissions USING btree (permission_name); + + +-- +-- Name: r_repo_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX r_repo_name_idx ON repositories USING btree (repo_name); + + +-- +-- Name: u_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_email_idx ON users USING btree (email); + + +-- +-- Name: u_username_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_username_idx ON users USING btree (username); + + +-- +-- Name: uem_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX uem_email_idx ON user_email_map USING btree (email); + + +-- +-- Name: changeset_comments_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_comments_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: changeset_statuses_changeset_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_changeset_comment_id_fkey FOREIGN KEY (changeset_comment_id) REFERENCES changeset_comments(comment_id); + + +-- +-- Name: changeset_statuses_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_statuses_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_statuses_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: groups_group_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_parent_id_fkey FOREIGN KEY (group_parent_id) REFERENCES groups(group_id); + + +-- +-- Name: notifications_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(user_id); + + +-- +-- Name: pull_request_reviewers_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: pull_request_reviewers_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: pull_requests_org_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_org_repo_id_fkey FOREIGN KEY (org_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_other_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_other_repo_id_fkey FOREIGN KEY (other_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repo_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repositories_fork_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_fork_id_fkey FOREIGN KEY (fork_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: repositories_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: statistics_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_email_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_follows_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_repository_id_fkey FOREIGN KEY (follows_repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_followings_follows_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_user_id_fkey FOREIGN KEY (follows_user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_logs_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: user_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_notification_notification_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_notification_id_fkey FOREIGN KEY (notification_id) REFERENCES notifications(notification_id); + + +-- +-- Name: user_to_notification_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_group_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: users_group_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: users_group_repo_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_groups_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_groups_members_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/rhodecode/tests/database/postgres/1.5.0.sql b/rhodecode/tests/database/postgres/1.5.0.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/postgres/1.5.0.sql @@ -0,0 +1,2876 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: cache_invalidation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE cache_invalidation ( + cache_id integer NOT NULL, + cache_key character varying(255), + cache_args character varying(255), + cache_active boolean +); + + +ALTER TABLE public.cache_invalidation OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE cache_invalidation_cache_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.cache_invalidation_cache_id_seq OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE cache_invalidation_cache_id_seq OWNED BY cache_invalidation.cache_id; + + +-- +-- Name: changeset_comments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_comments ( + comment_id integer NOT NULL, + repo_id integer NOT NULL, + revision character varying(40), + pull_request_id integer, + line_no character varying(10), + hl_lines character varying(512), + f_path character varying(1000), + user_id integer NOT NULL, + text text NOT NULL, + created_on timestamp without time zone NOT NULL, + modified_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.changeset_comments OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_comments_comment_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_comments_comment_id_seq OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_comments_comment_id_seq OWNED BY changeset_comments.comment_id; + + +-- +-- Name: changeset_statuses; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_statuses ( + changeset_status_id integer NOT NULL, + repo_id integer NOT NULL, + user_id integer NOT NULL, + revision character varying(40) NOT NULL, + status character varying(128) NOT NULL, + changeset_comment_id integer, + modified_at timestamp without time zone NOT NULL, + version integer NOT NULL, + pull_request_id integer +); + + +ALTER TABLE public.changeset_statuses OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_statuses_changeset_status_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_statuses_changeset_status_id_seq OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_statuses_changeset_status_id_seq OWNED BY changeset_statuses.changeset_status_id; + + +-- +-- Name: db_migrate_version; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE db_migrate_version ( + repository_id character varying(250) NOT NULL, + repository_path text, + version integer +); + + +ALTER TABLE public.db_migrate_version OWNER TO postgres; + +-- +-- Name: groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE groups ( + group_id integer NOT NULL, + group_name character varying(255) NOT NULL, + group_parent_id integer, + group_description character varying(10000), + enable_locking boolean NOT NULL, + CONSTRAINT groups_check CHECK ((group_id <> group_parent_id)) +); + + +ALTER TABLE public.groups OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE groups_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.groups_group_id_seq OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE groups_group_id_seq OWNED BY groups.group_id; + + +-- +-- Name: notifications; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE notifications ( + notification_id integer NOT NULL, + subject character varying(512), + body text, + created_by integer, + created_on timestamp without time zone NOT NULL, + type character varying(256) +); + + +ALTER TABLE public.notifications OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE notifications_notification_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.notifications_notification_id_seq OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE notifications_notification_id_seq OWNED BY notifications.notification_id; + + +-- +-- Name: permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE permissions ( + permission_id integer NOT NULL, + permission_name character varying(255), + permission_longname character varying(255) +); + + +ALTER TABLE public.permissions OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE permissions_permission_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.permissions_permission_id_seq OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE permissions_permission_id_seq OWNED BY permissions.permission_id; + + +-- +-- Name: pull_request_reviewers; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_request_reviewers ( + pull_requests_reviewers_id integer NOT NULL, + pull_request_id integer NOT NULL, + user_id integer +); + + +ALTER TABLE public.pull_request_reviewers OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_request_reviewers_pull_requests_reviewers_id_seq OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq OWNED BY pull_request_reviewers.pull_requests_reviewers_id; + + +-- +-- Name: pull_requests; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_requests ( + pull_request_id integer NOT NULL, + title character varying(256), + description text, + status character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL, + updated_on timestamp without time zone NOT NULL, + user_id integer NOT NULL, + revisions text, + org_repo_id integer NOT NULL, + org_ref character varying(256) NOT NULL, + other_repo_id integer NOT NULL, + other_ref character varying(256) NOT NULL +); + + +ALTER TABLE public.pull_requests OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_requests_pull_request_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_requests_pull_request_id_seq OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_requests_pull_request_id_seq OWNED BY pull_requests.pull_request_id; + + +-- +-- Name: repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repo_to_perm ( + repo_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.repo_to_perm OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repo_to_perm_repo_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repo_to_perm_repo_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repo_to_perm_repo_to_perm_id_seq OWNED BY repo_to_perm.repo_to_perm_id; + + +-- +-- Name: repositories; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories ( + repo_id integer NOT NULL, + repo_name character varying(255) NOT NULL, + clone_uri character varying(255), + repo_type character varying(255) NOT NULL, + user_id integer NOT NULL, + private boolean, + statistics boolean, + downloads boolean, + description character varying(10000), + created_on timestamp without time zone, + updated_on timestamp without time zone, + landing_revision character varying(255) NOT NULL, + enable_locking boolean NOT NULL, + locked character varying(255), + fork_id integer, + group_id integer +); + + +ALTER TABLE public.repositories OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_repo_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_repo_id_seq OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_repo_id_seq OWNED BY repositories.repo_id; + + +-- +-- Name: rhodecode_settings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_settings ( + app_settings_id integer NOT NULL, + app_settings_name character varying(255), + app_settings_value character varying(255) +); + + +ALTER TABLE public.rhodecode_settings OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_settings_app_settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_settings_app_settings_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_settings_app_settings_id_seq OWNED BY rhodecode_settings.app_settings_id; + + +-- +-- Name: rhodecode_ui; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_ui ( + ui_id integer NOT NULL, + ui_section character varying(255), + ui_key character varying(255), + ui_value character varying(255), + ui_active boolean +); + + +ALTER TABLE public.rhodecode_ui OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_ui_ui_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_ui_ui_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_ui_ui_id_seq OWNED BY rhodecode_ui.ui_id; + + +-- +-- Name: statistics; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE statistics ( + stat_id integer NOT NULL, + repository_id integer NOT NULL, + stat_on_revision integer NOT NULL, + commit_activity bytea NOT NULL, + commit_activity_combined bytea NOT NULL, + languages bytea NOT NULL +); + + +ALTER TABLE public.statistics OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE statistics_stat_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.statistics_stat_id_seq OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE statistics_stat_id_seq OWNED BY statistics.stat_id; + + +-- +-- Name: user_email_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_email_map ( + email_id integer NOT NULL, + user_id integer, + email character varying(255) +); + + +ALTER TABLE public.user_email_map OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_email_map_email_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_email_map_email_id_seq OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_email_map_email_id_seq OWNED BY user_email_map.email_id; + + +-- +-- Name: user_followings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_followings ( + user_following_id integer NOT NULL, + user_id integer NOT NULL, + follows_repository_id integer, + follows_user_id integer, + follows_from timestamp without time zone +); + + +ALTER TABLE public.user_followings OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_followings_user_following_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_followings_user_following_id_seq OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_followings_user_following_id_seq OWNED BY user_followings.user_following_id; + + +-- +-- Name: user_logs; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_logs ( + user_log_id integer NOT NULL, + user_id integer, + username character varying(255), + repository_id integer, + repository_name character varying(255), + user_ip character varying(255), + action text, + action_date timestamp without time zone +); + + +ALTER TABLE public.user_logs OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_logs_user_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_logs_user_log_id_seq OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_logs_user_log_id_seq OWNED BY user_logs.user_log_id; + + +-- +-- Name: user_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_repo_group_to_perm ( + group_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_repo_group_to_perm_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq OWNED BY user_repo_group_to_perm.group_to_perm_id; + + +-- +-- Name: user_to_notification; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_notification ( + user_id integer NOT NULL, + notification_id integer NOT NULL, + read boolean, + sent_on timestamp without time zone +); + + +ALTER TABLE public.user_to_notification OWNER TO postgres; + +-- +-- Name: user_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_perm ( + user_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_to_perm OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_to_perm_user_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_to_perm_user_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_to_perm_user_to_perm_id_seq OWNED BY user_to_perm.user_to_perm_id; + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users ( + user_id integer NOT NULL, + username character varying(255), + password character varying(255), + active boolean, + admin boolean, + firstname character varying(255), + lastname character varying(255), + email character varying(255), + last_login timestamp without time zone, + ldap_dn character varying(255), + api_key character varying(255), + inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_group_to_perm ( + users_group_repo_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNED BY users_group_repo_group_to_perm.users_group_repo_group_to_perm_id; + + +-- +-- Name: users_group_repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq OWNED BY users_group_repo_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_to_perm_users_group_to_perm_id_seq OWNED BY users_group_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups ( + users_group_id integer NOT NULL, + users_group_name character varying(255) NOT NULL, + users_group_active boolean, + users_group_inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users_groups OWNER TO postgres; + +-- +-- Name: users_groups_members; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups_members ( + users_group_member_id integer NOT NULL, + users_group_id integer NOT NULL, + user_id integer NOT NULL +); + + +ALTER TABLE public.users_groups_members OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_members_users_group_member_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_members_users_group_member_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_members_users_group_member_id_seq OWNED BY users_groups_members.users_group_member_id; + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_users_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_users_group_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_users_group_id_seq OWNED BY users_groups.users_group_id; + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_user_id_seq OWNER TO postgres; + +-- +-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_user_id_seq OWNED BY users.user_id; + + +-- +-- Name: cache_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY cache_invalidation ALTER COLUMN cache_id SET DEFAULT nextval('cache_invalidation_cache_id_seq'::regclass); + + +-- +-- Name: comment_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments ALTER COLUMN comment_id SET DEFAULT nextval('changeset_comments_comment_id_seq'::regclass); + + +-- +-- Name: changeset_status_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses ALTER COLUMN changeset_status_id SET DEFAULT nextval('changeset_statuses_changeset_status_id_seq'::regclass); + + +-- +-- Name: group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups ALTER COLUMN group_id SET DEFAULT nextval('groups_group_id_seq'::regclass); + + +-- +-- Name: notification_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications ALTER COLUMN notification_id SET DEFAULT nextval('notifications_notification_id_seq'::regclass); + + +-- +-- Name: permission_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY permissions ALTER COLUMN permission_id SET DEFAULT nextval('permissions_permission_id_seq'::regclass); + + +-- +-- Name: pull_requests_reviewers_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers ALTER COLUMN pull_requests_reviewers_id SET DEFAULT nextval('pull_request_reviewers_pull_requests_reviewers_id_seq'::regclass); + + +-- +-- Name: pull_request_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests ALTER COLUMN pull_request_id SET DEFAULT nextval('pull_requests_pull_request_id_seq'::regclass); + + +-- +-- Name: repo_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm ALTER COLUMN repo_to_perm_id SET DEFAULT nextval('repo_to_perm_repo_to_perm_id_seq'::regclass); + + +-- +-- Name: repo_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories ALTER COLUMN repo_id SET DEFAULT nextval('repositories_repo_id_seq'::regclass); + + +-- +-- Name: app_settings_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_settings ALTER COLUMN app_settings_id SET DEFAULT nextval('rhodecode_settings_app_settings_id_seq'::regclass); + + +-- +-- Name: ui_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_ui ALTER COLUMN ui_id SET DEFAULT nextval('rhodecode_ui_ui_id_seq'::regclass); + + +-- +-- Name: stat_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics ALTER COLUMN stat_id SET DEFAULT nextval('statistics_stat_id_seq'::regclass); + + +-- +-- Name: email_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map ALTER COLUMN email_id SET DEFAULT nextval('user_email_map_email_id_seq'::regclass); + + +-- +-- Name: user_following_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings ALTER COLUMN user_following_id SET DEFAULT nextval('user_followings_user_following_id_seq'::regclass); + + +-- +-- Name: user_log_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs ALTER COLUMN user_log_id SET DEFAULT nextval('user_logs_user_log_id_seq'::regclass); + + +-- +-- Name: group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm ALTER COLUMN group_to_perm_id SET DEFAULT nextval('user_repo_group_to_perm_group_to_perm_id_seq'::regclass); + + +-- +-- Name: user_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm ALTER COLUMN user_to_perm_id SET DEFAULT nextval('user_to_perm_user_to_perm_id_seq'::regclass); + + +-- +-- Name: user_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users ALTER COLUMN user_id SET DEFAULT nextval('users_user_id_seq'::regclass); + + +-- +-- Name: users_group_repo_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm ALTER COLUMN users_group_repo_group_to_perm_id SET DEFAULT nextval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_repo_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups ALTER COLUMN users_group_id SET DEFAULT nextval('users_groups_users_group_id_seq'::regclass); + + +-- +-- Name: users_group_member_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members ALTER COLUMN users_group_member_id SET DEFAULT nextval('users_groups_members_users_group_member_id_seq'::regclass); + + +-- +-- Data for Name: cache_invalidation; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY cache_invalidation (cache_id, cache_key, cache_args, cache_active) FROM stdin; +1 1RC/fakeclone RC/fakeclone t +2 1RC/muay RC/muay f +3 1one one f +4 1RC/rc2/test2 RC/rc2/test2 t +5 1RC/rc2/test3 RC/rc2/test3 t +6 1RC/rc2/test4 RC/rc2/test4 t +7 1rhodecode-cli-gist rhodecode-cli-gist f +8 1test.onaut.com test.onaut.com t +9 1RC/new RC/new f +10 1.rc_gist_store/32 .rc_gist_store/32 f +11 1vcs vcs f +12 1.rc_gist_store/36 .rc_gist_store/36 f +13 1.rc_gist_store/37 .rc_gist_store/37 f +14 1.rc_gist_store/39 .rc_gist_store/39 f +15 1remote-salt remote-salt t +16 1RC/INRC/trololo RC/INRC/trololo f +17 1quest quest f +18 1csa-hyperion csa-hyperion t +19 1rhodecode rhodecode f +20 1RC/origin-fork-fork RC/origin-fork-fork f +21 1.rc_gist_store/45 .rc_gist_store/45 f +22 1.rc_gist_store/44 .rc_gist_store/44 f +23 1.rc_gist_store/46 .rc_gist_store/46 f +24 1.rc_gist_store/41 .rc_gist_store/41 f +25 1.rc_gist_store/40 .rc_gist_store/40 f +26 1RC/gogo2 RC/gogo2 f +27 1.rc_gist_store/42 .rc_gist_store/42 f +28 1.rc_gist_store/49 .rc_gist_store/49 f +29 1.rc_gist_store/48 .rc_gist_store/48 f +30 1csa-collins csa-collins t +31 1.rc_gist_store/54 .rc_gist_store/54 f +32 1.rc_gist_store/55 .rc_gist_store/55 f +33 1.rc_gist_store/52 .rc_gist_store/52 f +34 1.rc_gist_store/53 .rc_gist_store/53 f +35 1.rc_gist_store/50 .rc_gist_store/50 f +36 1.rc_gist_store/51 .rc_gist_store/51 f +37 1rhodecode.bak.1 rhodecode.bak.1 f +38 1BIG/android BIG/android t +39 1RC/gogo-fork RC/gogo-fork f +40 1RC/mygr/lol RC/mygr/lol f +41 1testrepo-wp testrepo-wp t +42 1RC/hg-repo RC/hg-repo f +43 1testrepo-quick testrepo-quick t +44 1RC/bin-ops RC/bin-ops f +45 1.rc_gist_store/xFvj6dFqqVK5vfsGP8PU .rc_gist_store/xFvj6dFqqVK5vfsGP8PU f +46 1rhodecode-git rhodecode-git t +47 1csa-io csa-io t +48 1RC/qweqwe-fork RC/qweqwe-fork f +49 1csa-libcloud csa-libcloud t +50 1waitress waitress t +51 1.rc_gist_store/8 .rc_gist_store/8 f +52 1.rc_gist_store/9 .rc_gist_store/9 f +53 1RC/foobar RC/foobar f +54 1.rc_gist_store/1 .rc_gist_store/1 f +55 1.rc_gist_store/3 .rc_gist_store/3 f +56 1.rc_gist_store/4 .rc_gist_store/4 f +57 1.rc_gist_store/5 .rc_gist_store/5 f +58 1.rc_gist_store/6 .rc_gist_store/6 f +59 1.rc_gist_store/7 .rc_gist_store/7 f +60 1csa-harmony csa-harmony t +61 1RC/łęcina RC/łęcina f +62 1rhodecode-extensions rhodecode-extensions f +63 1csa-prometheus csa-prometheus t +64 1RC/empty-git RC/empty-git t +65 1csa-salt-states csa-salt-states t +66 1rhodecode-premium rhodecode-premium f +67 1RC/qweqwe-fork2 RC/qweqwe-fork2 f +68 1RC/INRC/L2_NEW/lalalal RC/INRC/L2_NEW/lalalal f +69 1RC/INRC/L2_NEW/L3/repo_test_move RC/INRC/L2_NEW/L3/repo_test_move f +70 1rhodecode.bak rhodecode.bak f +71 1RC/jap RC/jap t +72 1RC/origin RC/origin f +73 1rhodecode-cli-api rhodecode-cli-api f +74 1csa-armstrong csa-armstrong t +75 1.rc_gist_store/NAsB8cacjxnqdyZ8QUl3 .rc_gist_store/NAsB8cacjxnqdyZ8QUl3 f +76 1RC/lol/haha RC/lol/haha f +77 1enc-envelope enc-envelope f +78 1.rc_gist_store/43 .rc_gist_store/43 f +79 1RC/test RC/test f +80 1BIG/git BIG/git t +81 1RC/origin-fork RC/origin-fork f +82 1RC/trololo RC/trololo f +83 1.rc_gist_store/FLj8GunafFAVBnuTWDxU .rc_gist_store/FLj8GunafFAVBnuTWDxU f +84 1RC/ąqweqwe RC/ąqweqwe f +85 1csa-unity csa-unity t +86 1RC/vcs-git RC/vcs-git t +87 1.rc_gist_store/12 .rc_gist_store/12 f +88 1.rc_gist_store/13 .rc_gist_store/13 f +89 1.rc_gist_store/10 .rc_gist_store/10 f +90 1.rc_gist_store/11 .rc_gist_store/11 f +91 1RC/kiall-nova RC/kiall-nova t +92 1RC/rc2/test RC/rc2/test f +93 1DOCS DOCS t +94 1RC/fork-remote RC/fork-remote f +95 1RC/git-pull-test RC/git-pull-test t +96 1pyramidpypi pyramidpypi t +97 1.rc_gist_store/aQpbufbhSac6FyvVHhmS .rc_gist_store/aQpbufbhSac6FyvVHhmS f +98 1csa-aldrin csa-aldrin t +99 1.rc_gist_store/QL2GhrlKymNmrUJJy5js .rc_gist_store/QL2GhrlKymNmrUJJy5js f +100 1RC/git-test RC/git-test t +101 1salt salt t +\. + + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('cache_invalidation_cache_id_seq', 101, true); + + +-- +-- Data for Name: changeset_comments; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_comments (comment_id, repo_id, revision, pull_request_id, line_no, hl_lines, f_path, user_id, text, created_on, modified_at) FROM stdin; +\. + + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_comments_comment_id_seq', 1, false); + + +-- +-- Data for Name: changeset_statuses; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_statuses (changeset_status_id, repo_id, user_id, revision, status, changeset_comment_id, modified_at, version, pull_request_id) FROM stdin; +\. + + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_statuses_changeset_status_id_seq', 1, false); + + +-- +-- Data for Name: db_migrate_version; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY db_migrate_version (repository_id, repository_path, version) FROM stdin; +rhodecode_db_migrations versions 8 +\. + + +-- +-- Data for Name: groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY groups (group_id, group_name, group_parent_id, group_description, enable_locking) FROM stdin; +1 RC \N RC group f +2 RC/rc2 1 RC/rc2 group f +3 .rc_gist_store \N .rc_gist_store group f +4 RC/INRC 1 RC/INRC group f +5 BIG \N BIG group f +6 RC/mygr 1 RC/mygr group f +7 RC/INRC/L2_NEW 4 RC/INRC/L2_NEW group f +8 RC/INRC/L2_NEW/L3 7 RC/INRC/L2_NEW/L3 group f +9 RC/lol 1 RC/lol group f +\. + + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('groups_group_id_seq', 9, true); + + +-- +-- Data for Name: notifications; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY notifications (notification_id, subject, body, created_by, created_on, type) FROM stdin; +\. + + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('notifications_notification_id_seq', 1, false); + + +-- +-- Data for Name: permissions; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY permissions (permission_id, permission_name, permission_longname) FROM stdin; +1 repository.none repository.none +2 repository.read repository.read +3 repository.write repository.write +4 repository.admin repository.admin +5 group.none group.none +6 group.read group.read +7 group.write group.write +8 group.admin group.admin +9 hg.admin hg.admin +10 hg.create.none hg.create.none +11 hg.create.repository hg.create.repository +12 hg.fork.none hg.fork.none +13 hg.fork.repository hg.fork.repository +14 hg.register.none hg.register.none +15 hg.register.manual_activate hg.register.manual_activate +16 hg.register.auto_activate hg.register.auto_activate +\. + + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('permissions_permission_id_seq', 16, true); + + +-- +-- Data for Name: pull_request_reviewers; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_request_reviewers (pull_requests_reviewers_id, pull_request_id, user_id) FROM stdin; +\. + + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_request_reviewers_pull_requests_reviewers_id_seq', 1, false); + + +-- +-- Data for Name: pull_requests; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_requests (pull_request_id, title, description, status, created_on, updated_on, user_id, revisions, org_repo_id, org_ref, other_repo_id, other_ref) FROM stdin; +\. + + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_requests_pull_request_id_seq', 1, false); + + +-- +-- Data for Name: repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repo_to_perm (repo_to_perm_id, user_id, permission_id, repository_id) FROM stdin; +1 1 2 1 +2 1 2 2 +3 1 2 3 +4 1 2 4 +5 1 2 5 +6 1 2 6 +7 1 2 7 +8 1 2 8 +9 1 2 9 +10 1 2 10 +11 1 2 11 +12 1 2 12 +13 1 2 13 +14 1 2 14 +15 1 2 15 +16 1 2 16 +17 1 2 17 +18 1 2 18 +19 1 2 19 +20 1 2 20 +21 1 2 21 +22 1 2 22 +23 1 2 23 +24 1 2 24 +25 1 2 25 +26 1 2 26 +27 1 2 27 +28 1 2 28 +29 1 2 29 +30 1 2 30 +31 1 2 31 +32 1 2 32 +33 1 2 33 +34 1 2 34 +35 1 2 35 +36 1 2 36 +37 1 2 37 +38 1 2 38 +39 1 2 39 +40 1 2 40 +41 1 2 41 +42 1 2 42 +43 1 2 43 +44 1 2 44 +45 1 2 45 +46 1 2 46 +47 1 2 47 +48 1 2 48 +49 1 2 49 +50 1 2 50 +51 1 2 51 +52 1 2 52 +53 1 2 53 +54 1 2 54 +55 1 2 55 +56 1 2 56 +57 1 2 57 +58 1 2 58 +59 1 2 59 +60 1 2 60 +61 1 2 61 +62 1 2 62 +63 1 2 63 +64 1 2 64 +65 1 2 65 +66 1 2 66 +67 1 2 67 +68 1 2 68 +69 1 2 69 +70 1 2 70 +71 1 2 71 +72 1 2 72 +73 1 2 73 +74 1 2 74 +75 1 2 75 +76 1 2 76 +77 1 2 77 +78 1 2 78 +79 1 2 79 +80 1 2 80 +81 1 2 81 +82 1 2 82 +83 1 2 83 +84 1 2 84 +85 1 2 85 +86 1 2 86 +87 1 2 87 +88 1 2 88 +89 1 2 89 +90 1 2 90 +91 1 2 91 +92 1 2 92 +93 1 2 93 +94 1 2 94 +95 1 2 95 +96 1 2 96 +97 1 2 97 +98 1 2 98 +99 1 2 99 +100 1 2 100 +101 1 2 101 +\. + + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repo_to_perm_repo_to_perm_id_seq', 101, true); + + +-- +-- Data for Name: repositories; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories (repo_id, repo_name, clone_uri, repo_type, user_id, private, statistics, downloads, description, created_on, updated_on, landing_revision, enable_locking, locked, fork_id, group_id) FROM stdin; +1 RC/fakeclone http://user@vm/RC/fakeclone git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:07.392436 2013-05-28 20:25:07.39247 tip f \N \N 1 +2 RC/muay \N hg 2 f f f RC/muay repository 2013-05-28 20:25:07.504925 2013-05-28 20:25:07.504979 tip f \N \N 1 +3 one \N hg 2 f f f one repository 2013-05-28 20:25:07.536707 2013-05-28 20:25:07.536736 tip f \N \N \N +4 RC/rc2/test2 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:07.579176 2013-05-28 20:25:07.579209 tip f \N \N 2 +5 RC/rc2/test3 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:07.638818 2013-05-28 20:25:07.63884 tip f \N \N 2 +6 RC/rc2/test4 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:07.704695 2013-05-28 20:25:07.704732 tip f \N \N 2 +7 rhodecode-cli-gist \N hg 2 f f f rhodecode-cli-gist repository 2013-05-28 20:25:07.760722 2013-05-28 20:25:07.760749 tip f \N \N \N +8 test.onaut.com \N git 2 f f f Unnamed repository 2013-05-28 20:25:07.788683 2013-05-28 20:25:07.788705 tip f \N \N \N +9 RC/new \N hg 2 f f f RC/new repository 2013-05-28 20:25:07.845443 2013-05-28 20:25:07.845467 tip f \N \N 1 +10 .rc_gist_store/32 \N hg 2 f f f .rc_gist_store/32 repository 2013-05-28 20:25:07.887214 2013-05-28 20:25:07.887238 tip f \N \N 3 +11 vcs \N hg 2 f f f vcs repository 2013-05-28 20:25:07.913342 2013-05-28 20:25:07.913367 tip f \N \N \N +12 .rc_gist_store/36 \N hg 2 f f f .rc_gist_store/36 repository 2013-05-28 20:25:07.943324 2013-05-28 20:25:07.943361 tip f \N \N 3 +13 .rc_gist_store/37 \N hg 2 f f f .rc_gist_store/37 repository 2013-05-28 20:25:07.979896 2013-05-28 20:25:07.979929 tip f \N \N 3 +14 .rc_gist_store/39 \N hg 2 f f f .rc_gist_store/39 repository 2013-05-28 20:25:08.018938 2013-05-28 20:25:08.018965 tip f \N \N 3 +15 remote-salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:08.047164 2013-05-28 20:25:08.047189 tip f \N \N \N +16 RC/INRC/trololo \N hg 2 f f f RC/INRC/trololo repository 2013-05-28 20:25:08.117849 2013-05-28 20:25:08.117873 tip f \N \N 4 +17 quest \N hg 2 f f f quest repository 2013-05-28 20:25:08.149575 2013-05-28 20:25:08.149599 tip f \N \N \N +18 csa-hyperion \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:08.175969 2013-05-28 20:25:08.176001 tip f \N \N \N +19 rhodecode \N hg 2 f f f rhodecode repository 2013-05-28 20:25:08.228453 2013-05-28 20:25:08.228475 tip f \N \N \N +20 RC/origin-fork-fork \N hg 2 f f f RC/origin-fork-fork repository 2013-05-28 20:25:08.25984 2013-05-28 20:25:08.259873 tip f \N \N 1 +21 .rc_gist_store/45 \N hg 2 f f f .rc_gist_store/45 repository 2013-05-28 20:25:08.290796 2013-05-28 20:25:08.290821 tip f \N \N 3 +22 .rc_gist_store/44 \N hg 2 f f f .rc_gist_store/44 repository 2013-05-28 20:25:08.318312 2013-05-28 20:25:08.318334 tip f \N \N 3 +23 .rc_gist_store/46 \N hg 2 f f f .rc_gist_store/46 repository 2013-05-28 20:25:08.349026 2013-05-28 20:25:08.349054 tip f \N \N 3 +24 .rc_gist_store/41 \N hg 2 f f f .rc_gist_store/41 repository 2013-05-28 20:25:08.37987 2013-05-28 20:25:08.379921 tip f \N \N 3 +25 .rc_gist_store/40 \N hg 2 f f f .rc_gist_store/40 repository 2013-05-28 20:25:08.413778 2013-05-28 20:25:08.413809 tip f \N \N 3 +26 RC/gogo2 \N hg 2 f f f RC/gogo2 repository 2013-05-28 20:25:08.455781 2013-05-28 20:25:08.455813 tip f \N \N 1 +27 .rc_gist_store/42 \N hg 2 f f f .rc_gist_store/42 repository 2013-05-28 20:25:08.502679 2013-05-28 20:25:08.502707 tip f \N \N 3 +28 .rc_gist_store/49 \N hg 2 f f f .rc_gist_store/49 repository 2013-05-28 20:25:08.539391 2013-05-28 20:25:08.539419 tip f \N \N 3 +29 .rc_gist_store/48 \N hg 2 f f f .rc_gist_store/48 repository 2013-05-28 20:25:08.568634 2013-05-28 20:25:08.568661 tip f \N \N 3 +30 csa-collins \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:08.598715 2013-05-28 20:25:08.59874 tip f \N \N \N +31 .rc_gist_store/54 \N hg 2 f f f .rc_gist_store/54 repository 2013-05-28 20:25:08.661033 2013-05-28 20:25:08.66106 tip f \N \N 3 +32 .rc_gist_store/55 \N hg 2 f f f .rc_gist_store/55 repository 2013-05-28 20:25:08.689489 2013-05-28 20:25:08.689512 tip f \N \N 3 +33 .rc_gist_store/52 \N hg 2 f f f .rc_gist_store/52 repository 2013-05-28 20:25:08.716507 2013-05-28 20:25:08.716536 tip f \N \N 3 +34 .rc_gist_store/53 \N hg 2 f f f .rc_gist_store/53 repository 2013-05-28 20:25:08.74462 2013-05-28 20:25:08.744643 tip f \N \N 3 +35 .rc_gist_store/50 \N hg 2 f f f .rc_gist_store/50 repository 2013-05-28 20:25:08.771475 2013-05-28 20:25:08.771498 tip f \N \N 3 +36 .rc_gist_store/51 \N hg 2 f f f .rc_gist_store/51 repository 2013-05-28 20:25:08.804204 2013-05-28 20:25:08.804234 tip f \N \N 3 +37 rhodecode.bak.1 \N hg 2 f f f rhodecode.bak.1 repository 2013-05-28 20:25:08.830393 2013-05-28 20:25:08.830416 tip f \N \N \N +38 BIG/android \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:08.874702 2013-05-28 20:25:08.874725 tip f \N \N 5 +39 RC/gogo-fork \N hg 2 f f f RC/gogo-fork repository 2013-05-28 20:25:08.932526 2013-05-28 20:25:08.932559 tip f \N \N 1 +40 RC/mygr/lol \N hg 2 f f f RC/mygr/lol repository 2013-05-28 20:25:08.97967 2013-05-28 20:25:08.979709 tip f \N \N 6 +41 testrepo-wp \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.017161 2013-05-28 20:25:09.017199 tip f \N \N \N +42 RC/hg-repo \N hg 2 f f f RC/hg-repo repository 2013-05-28 20:25:09.080153 2013-05-28 20:25:09.080178 tip f \N \N 1 +43 testrepo-quick \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.107095 2013-05-28 20:25:09.107118 tip f \N \N \N +44 RC/bin-ops \N hg 2 f f f RC/bin-ops repository 2013-05-28 20:25:09.165752 2013-05-28 20:25:09.165788 tip f \N \N 1 +45 .rc_gist_store/xFvj6dFqqVK5vfsGP8PU \N hg 2 f f f .rc_gist_store/xFvj6dFqqVK5vfsGP8PU repository 2013-05-28 20:25:09.195335 2013-05-28 20:25:09.19536 tip f \N \N 3 +46 rhodecode-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.225975 2013-05-28 20:25:09.225996 tip f \N \N \N +47 csa-io \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.281133 2013-05-28 20:25:09.281156 tip f \N \N \N +48 RC/qweqwe-fork \N hg 2 f f f RC/qweqwe-fork repository 2013-05-28 20:25:09.342971 2013-05-28 20:25:09.342996 tip f \N \N 1 +49 csa-libcloud \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.370819 2013-05-28 20:25:09.370844 tip f \N \N \N +50 waitress \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.433003 2013-05-28 20:25:09.433038 tip f \N \N \N +51 .rc_gist_store/8 \N hg 2 f f f .rc_gist_store/8 repository 2013-05-28 20:25:09.49346 2013-05-28 20:25:09.493492 tip f \N \N 3 +52 .rc_gist_store/9 \N hg 2 f f f .rc_gist_store/9 repository 2013-05-28 20:25:09.533111 2013-05-28 20:25:09.53314 tip f \N \N 3 +53 RC/foobar \N hg 2 f f f RC/foobar repository 2013-05-28 20:25:09.56286 2013-05-28 20:25:09.562895 tip f \N \N 1 +54 .rc_gist_store/1 \N hg 2 f f f .rc_gist_store/1 repository 2013-05-28 20:25:09.594992 2013-05-28 20:25:09.595017 tip f \N \N 3 +55 .rc_gist_store/3 \N hg 2 f f f .rc_gist_store/3 repository 2013-05-28 20:25:09.625902 2013-05-28 20:25:09.62593 tip f \N \N 3 +56 .rc_gist_store/4 \N hg 2 f f f .rc_gist_store/4 repository 2013-05-28 20:25:09.656929 2013-05-28 20:25:09.656963 tip f \N \N 3 +57 .rc_gist_store/5 \N hg 2 f f f .rc_gist_store/5 repository 2013-05-28 20:25:09.691164 2013-05-28 20:25:09.69119 tip f \N \N 3 +58 .rc_gist_store/6 \N hg 2 f f f .rc_gist_store/6 repository 2013-05-28 20:25:09.722296 2013-05-28 20:25:09.722321 tip f \N \N 3 +59 .rc_gist_store/7 \N hg 2 f f f .rc_gist_store/7 repository 2013-05-28 20:25:09.752556 2013-05-28 20:25:09.752584 tip f \N \N 3 +60 csa-harmony \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.781956 2013-05-28 20:25:09.781978 tip f \N \N \N +61 RC/łęcina \N hg 2 f f f RC/łęcina repository 2013-05-28 20:25:09.838047 2013-05-28 20:25:09.83807 tip f \N \N 1 +62 rhodecode-extensions \N hg 2 f f f rhodecode-extensions repository 2013-05-28 20:25:09.862369 2013-05-28 20:25:09.862395 tip f \N \N \N +63 csa-prometheus \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.887883 2013-05-28 20:25:09.887905 tip f \N \N \N +64 RC/empty-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:09.947252 2013-05-28 20:25:09.94728 tip f \N \N 1 +65 csa-salt-states \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.014164 2013-05-28 20:25:10.014188 tip f \N \N \N +66 rhodecode-premium \N hg 2 f f f rhodecode-premium repository 2013-05-28 20:25:10.069134 2013-05-28 20:25:10.069157 tip f \N \N \N +67 RC/qweqwe-fork2 \N hg 2 f f f RC/qweqwe-fork2 repository 2013-05-28 20:25:10.101186 2013-05-28 20:25:10.101237 tip f \N \N 1 +68 RC/INRC/L2_NEW/lalalal \N hg 2 f f f RC/INRC/L2_NEW/lalalal repository 2013-05-28 20:25:10.142571 2013-05-28 20:25:10.142593 tip f \N \N 7 +69 RC/INRC/L2_NEW/L3/repo_test_move \N hg 2 f f f RC/INRC/L2_NEW/L3/repo_test_move repository 2013-05-28 20:25:10.190116 2013-05-28 20:25:10.190144 tip f \N \N 8 +70 rhodecode.bak \N hg 2 f f f rhodecode.bak repository 2013-05-28 20:25:10.219036 2013-05-28 20:25:10.219062 tip f \N \N \N +71 RC/jap \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.253039 2013-05-28 20:25:10.253074 tip f \N \N 1 +72 RC/origin \N hg 2 f f f RC/origin repository 2013-05-28 20:25:10.314832 2013-05-28 20:25:10.314858 tip f \N \N 1 +73 rhodecode-cli-api \N hg 2 f f f rhodecode-cli-api repository 2013-05-28 20:25:10.340679 2013-05-28 20:25:10.340705 tip f \N \N \N +74 csa-armstrong \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.373473 2013-05-28 20:25:10.373498 tip f \N \N \N +75 .rc_gist_store/NAsB8cacjxnqdyZ8QUl3 \N hg 2 f f f .rc_gist_store/NAsB8cacjxnqdyZ8QUl3 repository 2013-05-28 20:25:10.433134 2013-05-28 20:25:10.433157 tip f \N \N 3 +76 RC/lol/haha \N hg 2 f f f RC/lol/haha repository 2013-05-28 20:25:10.485738 2013-05-28 20:25:10.485774 tip f \N \N 9 +77 enc-envelope \N hg 2 f f f enc-envelope repository 2013-05-28 20:25:10.522396 2013-05-28 20:25:10.52242 tip f \N \N \N +78 .rc_gist_store/43 \N hg 2 f f f .rc_gist_store/43 repository 2013-05-28 20:25:10.55549 2013-05-28 20:25:10.555518 tip f \N \N 3 +79 RC/test \N hg 2 f f f RC/test repository 2013-05-28 20:25:10.58186 2013-05-28 20:25:10.581884 tip f \N \N 1 +80 BIG/git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.613169 2013-05-28 20:25:10.613192 tip f \N \N 5 +81 RC/origin-fork \N hg 2 f f f RC/origin-fork repository 2013-05-28 20:25:10.66528 2013-05-28 20:25:10.665303 tip f \N \N 1 +82 RC/trololo \N hg 2 f f f RC/trololo repository 2013-05-28 20:25:10.692546 2013-05-28 20:25:10.692571 tip f \N \N 1 +83 .rc_gist_store/FLj8GunafFAVBnuTWDxU \N hg 2 f f f .rc_gist_store/FLj8GunafFAVBnuTWDxU repository 2013-05-28 20:25:10.719549 2013-05-28 20:25:10.719575 tip f \N \N 3 +84 RC/ąqweqwe \N hg 2 f f f RC/ąqweqwe repository 2013-05-28 20:25:10.74739 2013-05-28 20:25:10.747414 tip f \N \N 1 +85 csa-unity \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.779116 2013-05-28 20:25:10.779141 tip f \N \N \N +86 RC/vcs-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:10.835779 2013-05-28 20:25:10.835804 tip f \N \N 1 +87 .rc_gist_store/12 \N hg 2 f f f .rc_gist_store/12 repository 2013-05-28 20:25:10.893085 2013-05-28 20:25:10.893109 tip f \N \N 3 +88 .rc_gist_store/13 \N hg 2 f f f .rc_gist_store/13 repository 2013-05-28 20:25:10.92266 2013-05-28 20:25:10.922688 tip f \N \N 3 +89 .rc_gist_store/10 \N hg 2 f f f .rc_gist_store/10 repository 2013-05-28 20:25:10.952412 2013-05-28 20:25:10.952444 tip f \N \N 3 +90 .rc_gist_store/11 \N hg 2 f f f .rc_gist_store/11 repository 2013-05-28 20:25:10.991803 2013-05-28 20:25:10.991851 tip f \N \N 3 +91 RC/kiall-nova \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.027916 2013-05-28 20:25:11.02794 tip f \N \N 1 +92 RC/rc2/test \N hg 2 f f f RC/rc2/test repository 2013-05-28 20:25:11.082308 2013-05-28 20:25:11.082331 tip f \N \N 2 +93 DOCS \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.109114 2013-05-28 20:25:11.109139 tip f \N \N \N +94 RC/fork-remote \N hg 2 f f f RC/fork-remote repository 2013-05-28 20:25:11.16158 2013-05-28 20:25:11.161605 tip f \N \N 1 +95 RC/git-pull-test \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.195729 2013-05-28 20:25:11.195753 tip f \N \N 1 +96 pyramidpypi \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.247897 2013-05-28 20:25:11.247919 tip f \N \N \N +97 .rc_gist_store/aQpbufbhSac6FyvVHhmS \N hg 2 f f f .rc_gist_store/aQpbufbhSac6FyvVHhmS repository 2013-05-28 20:25:11.304386 2013-05-28 20:25:11.304416 tip f \N \N 3 +98 csa-aldrin \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.334081 2013-05-28 20:25:11.334104 tip f \N \N \N +99 .rc_gist_store/QL2GhrlKymNmrUJJy5js \N hg 2 f f f .rc_gist_store/QL2GhrlKymNmrUJJy5js repository 2013-05-28 20:25:11.392571 2013-05-28 20:25:11.392603 tip f \N \N 3 +100 RC/git-test \N git 2 f f f Unnamed repository 2013-05-28 20:25:11.422773 2013-05-28 20:25:11.422798 tip f \N \N 1 +101 salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:25:11.491206 2013-05-28 20:25:11.491244 tip f \N \N \N +\. + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_repo_id_seq', 101, true); + + +-- +-- Data for Name: rhodecode_settings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_settings (app_settings_id, app_settings_name, app_settings_value) FROM stdin; +1 realm RhodeCode authentication +2 title RhodeCode +3 ga_code +4 show_public_icon True +5 show_private_icon True +6 stylify_metatags False +7 ldap_active false +8 ldap_host +9 ldap_port 389 +10 ldap_tls_kind PLAIN +11 ldap_tls_reqcert +12 ldap_dn_user +13 ldap_dn_pass +14 ldap_base_dn +15 ldap_filter +16 ldap_search_scope +17 ldap_attr_login +18 ldap_attr_firstname +19 ldap_attr_lastname +20 ldap_attr_email +21 default_repo_enable_locking False +22 default_repo_enable_downloads False +23 default_repo_enable_statistics False +24 default_repo_private False +25 default_repo_type hg +\. + + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_settings_app_settings_id_seq', 25, true); + + +-- +-- Data for Name: rhodecode_ui; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_ui (ui_id, ui_section, ui_key, ui_value, ui_active) FROM stdin; +1 hooks changegroup.update hg update >&2 f +2 hooks changegroup.repo_size python:rhodecode.lib.hooks.repo_size t +3 hooks changegroup.push_logger python:rhodecode.lib.hooks.log_push_action t +4 hooks prechangegroup.pre_push python:rhodecode.lib.hooks.pre_push t +5 hooks outgoing.pull_logger python:rhodecode.lib.hooks.log_pull_action t +6 hooks preoutgoing.pre_pull python:rhodecode.lib.hooks.pre_pull t +7 extensions largefiles t +8 extensions hgsubversion f +9 extensions hggit f +10 web push_ssl false t +11 web allow_archive gz zip bz2 t +12 web allow_push * t +13 web baseurl / t +14 paths / /mnt/hgfs/workspace-python t +\. + + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_ui_ui_id_seq', 14, true); + + +-- +-- Data for Name: statistics; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY statistics (stat_id, repository_id, stat_on_revision, commit_activity, commit_activity_combined, languages) FROM stdin; +\. + + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('statistics_stat_id_seq', 1, false); + + +-- +-- Data for Name: user_email_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_email_map (email_id, user_id, email) FROM stdin; +\. + + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_email_map_email_id_seq', 1, false); + + +-- +-- Data for Name: user_followings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_followings (user_following_id, user_id, follows_repository_id, follows_user_id, follows_from) FROM stdin; +1 2 1 \N 2013-05-28 20:25:07.419366 +2 2 2 \N 2013-05-28 20:25:07.523213 +3 2 3 \N 2013-05-28 20:25:07.551071 +4 2 4 \N 2013-05-28 20:25:07.593417 +5 2 5 \N 2013-05-28 20:25:07.652097 +6 2 6 \N 2013-05-28 20:25:07.718865 +7 2 7 \N 2013-05-28 20:25:07.775955 +8 2 8 \N 2013-05-28 20:25:07.802067 +9 2 9 \N 2013-05-28 20:25:07.85919 +10 2 10 \N 2013-05-28 20:25:07.898708 +11 2 11 \N 2013-05-28 20:25:07.928087 +12 2 12 \N 2013-05-28 20:25:07.958332 +13 2 13 \N 2013-05-28 20:25:07.999131 +14 2 14 \N 2013-05-28 20:25:08.03233 +15 2 15 \N 2013-05-28 20:25:08.062772 +16 2 16 \N 2013-05-28 20:25:08.133488 +17 2 17 \N 2013-05-28 20:25:08.16114 +18 2 18 \N 2013-05-28 20:25:08.190194 +19 2 19 \N 2013-05-28 20:25:08.243763 +20 2 20 \N 2013-05-28 20:25:08.276008 +21 2 21 \N 2013-05-28 20:25:08.302919 +22 2 22 \N 2013-05-28 20:25:08.333401 +23 2 23 \N 2013-05-28 20:25:08.364937 +24 2 24 \N 2013-05-28 20:25:08.396443 +25 2 25 \N 2013-05-28 20:25:08.432066 +26 2 26 \N 2013-05-28 20:25:08.475434 +27 2 27 \N 2013-05-28 20:25:08.519422 +28 2 28 \N 2013-05-28 20:25:08.554142 +29 2 29 \N 2013-05-28 20:25:08.582317 +30 2 30 \N 2013-05-28 20:25:08.614023 +31 2 31 \N 2013-05-28 20:25:08.674443 +32 2 32 \N 2013-05-28 20:25:08.702086 +33 2 33 \N 2013-05-28 20:25:08.730009 +34 2 34 \N 2013-05-28 20:25:08.75688 +35 2 35 \N 2013-05-28 20:25:08.785569 +36 2 36 \N 2013-05-28 20:25:08.81867 +37 2 37 \N 2013-05-28 20:25:08.845372 +38 2 38 \N 2013-05-28 20:25:08.887009 +39 2 39 \N 2013-05-28 20:25:08.94708 +40 2 40 \N 2013-05-28 20:25:08.997848 +41 2 41 \N 2013-05-28 20:25:09.03424 +42 2 42 \N 2013-05-28 20:25:09.091839 +43 2 43 \N 2013-05-28 20:25:09.121068 +44 2 44 \N 2013-05-28 20:25:09.177967 +45 2 45 \N 2013-05-28 20:25:09.210977 +46 2 46 \N 2013-05-28 20:25:09.237728 +47 2 47 \N 2013-05-28 20:25:09.297594 +48 2 48 \N 2013-05-28 20:25:09.354276 +49 2 49 \N 2013-05-28 20:25:09.387242 +50 2 50 \N 2013-05-28 20:25:09.447636 +51 2 51 \N 2013-05-28 20:25:09.513617 +52 2 52 \N 2013-05-28 20:25:09.545837 +53 2 53 \N 2013-05-28 20:25:09.577221 +54 2 54 \N 2013-05-28 20:25:09.606831 +55 2 55 \N 2013-05-28 20:25:09.641289 +56 2 56 \N 2013-05-28 20:25:09.673187 +57 2 57 \N 2013-05-28 20:25:09.703041 +58 2 58 \N 2013-05-28 20:25:09.737676 +59 2 59 \N 2013-05-28 20:25:09.767992 +60 2 60 \N 2013-05-28 20:25:09.795625 +61 2 61 \N 2013-05-28 20:25:09.849362 +62 2 62 \N 2013-05-28 20:25:09.875072 +63 2 63 \N 2013-05-28 20:25:09.899962 +64 2 64 \N 2013-05-28 20:25:09.959371 +65 2 65 \N 2013-05-28 20:25:10.027104 +66 2 66 \N 2013-05-28 20:25:10.085728 +67 2 67 \N 2013-05-28 20:25:10.113237 +68 2 68 \N 2013-05-28 20:25:10.153369 +69 2 69 \N 2013-05-28 20:25:10.202414 +70 2 70 \N 2013-05-28 20:25:10.231925 +71 2 71 \N 2013-05-28 20:25:10.272999 +72 2 72 \N 2013-05-28 20:25:10.325972 +73 2 73 \N 2013-05-28 20:25:10.357303 +74 2 74 \N 2013-05-28 20:25:10.386804 +75 2 75 \N 2013-05-28 20:25:10.445843 +76 2 76 \N 2013-05-28 20:25:10.505361 +77 2 77 \N 2013-05-28 20:25:10.534813 +78 2 78 \N 2013-05-28 20:25:10.567787 +79 2 79 \N 2013-05-28 20:25:10.594885 +80 2 80 \N 2013-05-28 20:25:10.625153 +81 2 81 \N 2013-05-28 20:25:10.676514 +82 2 82 \N 2013-05-28 20:25:10.704862 +83 2 83 \N 2013-05-28 20:25:10.732891 +84 2 84 \N 2013-05-28 20:25:10.761585 +85 2 85 \N 2013-05-28 20:25:10.794418 +86 2 86 \N 2013-05-28 20:25:10.849868 +87 2 87 \N 2013-05-28 20:25:10.905233 +88 2 88 \N 2013-05-28 20:25:10.935564 +89 2 89 \N 2013-05-28 20:25:10.965226 +90 2 90 \N 2013-05-28 20:25:11.011674 +91 2 91 \N 2013-05-28 20:25:11.039829 +92 2 92 \N 2013-05-28 20:25:11.094952 +93 2 93 \N 2013-05-28 20:25:11.121706 +94 2 94 \N 2013-05-28 20:25:11.176407 +95 2 95 \N 2013-05-28 20:25:11.20814 +96 2 96 \N 2013-05-28 20:25:11.260602 +97 2 97 \N 2013-05-28 20:25:11.316663 +98 2 98 \N 2013-05-28 20:25:11.34702 +99 2 99 \N 2013-05-28 20:25:11.405701 +100 2 100 \N 2013-05-28 20:25:11.437031 +101 2 101 \N 2013-05-28 20:25:11.508609 +\. + + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_followings_user_following_id_seq', 101, true); + + +-- +-- Data for Name: user_logs; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_logs (user_log_id, user_id, username, repository_id, repository_name, user_ip, action, action_date) FROM stdin; +1 2 marcink 1 RC/fakeclone started_following_repo 2013-05-28 20:25:07.413172 +2 2 marcink 2 RC/muay started_following_repo 2013-05-28 20:25:07.520161 +3 2 marcink 3 one started_following_repo 2013-05-28 20:25:07.548707 +4 2 marcink 4 RC/rc2/test2 started_following_repo 2013-05-28 20:25:07.591048 +5 2 marcink 5 RC/rc2/test3 started_following_repo 2013-05-28 20:25:07.648472 +6 2 marcink 6 RC/rc2/test4 started_following_repo 2013-05-28 20:25:07.715291 +7 2 marcink 7 rhodecode-cli-gist started_following_repo 2013-05-28 20:25:07.773926 +8 2 marcink 8 test.onaut.com started_following_repo 2013-05-28 20:25:07.798491 +9 2 marcink 9 RC/new started_following_repo 2013-05-28 20:25:07.856745 +10 2 marcink 10 .rc_gist_store/32 started_following_repo 2013-05-28 20:25:07.896778 +11 2 marcink 11 vcs started_following_repo 2013-05-28 20:25:07.925912 +12 2 marcink 12 .rc_gist_store/36 started_following_repo 2013-05-28 20:25:07.956523 +13 2 marcink 13 .rc_gist_store/37 started_following_repo 2013-05-28 20:25:07.996439 +14 2 marcink 14 .rc_gist_store/39 started_following_repo 2013-05-28 20:25:08.030537 +15 2 marcink 15 remote-salt started_following_repo 2013-05-28 20:25:08.059837 +16 2 marcink 16 RC/INRC/trololo started_following_repo 2013-05-28 20:25:08.130912 +17 2 marcink 17 quest started_following_repo 2013-05-28 20:25:08.159419 +18 2 marcink 18 csa-hyperion started_following_repo 2013-05-28 20:25:08.187182 +19 2 marcink 19 rhodecode started_following_repo 2013-05-28 20:25:08.241777 +20 2 marcink 20 RC/origin-fork-fork started_following_repo 2013-05-28 20:25:08.272993 +21 2 marcink 21 .rc_gist_store/45 started_following_repo 2013-05-28 20:25:08.300966 +22 2 marcink 22 .rc_gist_store/44 started_following_repo 2013-05-28 20:25:08.33152 +23 2 marcink 23 .rc_gist_store/46 started_following_repo 2013-05-28 20:25:08.36291 +24 2 marcink 24 .rc_gist_store/41 started_following_repo 2013-05-28 20:25:08.394552 +25 2 marcink 25 .rc_gist_store/40 started_following_repo 2013-05-28 20:25:08.42548 +26 2 marcink 26 RC/gogo2 started_following_repo 2013-05-28 20:25:08.471727 +27 2 marcink 27 .rc_gist_store/42 started_following_repo 2013-05-28 20:25:08.517494 +28 2 marcink 28 .rc_gist_store/49 started_following_repo 2013-05-28 20:25:08.552265 +29 2 marcink 29 .rc_gist_store/48 started_following_repo 2013-05-28 20:25:08.580457 +30 2 marcink 30 csa-collins started_following_repo 2013-05-28 20:25:08.610418 +31 2 marcink 31 .rc_gist_store/54 started_following_repo 2013-05-28 20:25:08.672441 +32 2 marcink 32 .rc_gist_store/55 started_following_repo 2013-05-28 20:25:08.700234 +33 2 marcink 33 .rc_gist_store/52 started_following_repo 2013-05-28 20:25:08.727752 +34 2 marcink 34 .rc_gist_store/53 started_following_repo 2013-05-28 20:25:08.75499 +35 2 marcink 35 .rc_gist_store/50 started_following_repo 2013-05-28 20:25:08.783835 +36 2 marcink 36 .rc_gist_store/51 started_following_repo 2013-05-28 20:25:08.816881 +37 2 marcink 37 rhodecode.bak.1 started_following_repo 2013-05-28 20:25:08.842944 +38 2 marcink 38 BIG/android started_following_repo 2013-05-28 20:25:08.884294 +39 2 marcink 39 RC/gogo-fork started_following_repo 2013-05-28 20:25:08.944917 +40 2 marcink 40 RC/mygr/lol started_following_repo 2013-05-28 20:25:08.99476 +41 2 marcink 41 testrepo-wp started_following_repo 2013-05-28 20:25:09.030696 +42 2 marcink 42 RC/hg-repo started_following_repo 2013-05-28 20:25:09.089719 +43 2 marcink 43 testrepo-quick started_following_repo 2013-05-28 20:25:09.118511 +44 2 marcink 44 RC/bin-ops started_following_repo 2013-05-28 20:25:09.17613 +45 2 marcink 45 .rc_gist_store/xFvj6dFqqVK5vfsGP8PU started_following_repo 2013-05-28 20:25:09.208613 +46 2 marcink 46 rhodecode-git started_following_repo 2013-05-28 20:25:09.235248 +47 2 marcink 47 csa-io started_following_repo 2013-05-28 20:25:09.294126 +48 2 marcink 48 RC/qweqwe-fork started_following_repo 2013-05-28 20:25:09.352407 +49 2 marcink 49 csa-libcloud started_following_repo 2013-05-28 20:25:09.384157 +50 2 marcink 50 waitress started_following_repo 2013-05-28 20:25:09.443826 +51 2 marcink 51 .rc_gist_store/8 started_following_repo 2013-05-28 20:25:09.511525 +52 2 marcink 52 .rc_gist_store/9 started_following_repo 2013-05-28 20:25:09.543993 +53 2 marcink 53 RC/foobar started_following_repo 2013-05-28 20:25:09.574874 +54 2 marcink 54 .rc_gist_store/1 started_following_repo 2013-05-28 20:25:09.605025 +55 2 marcink 55 .rc_gist_store/3 started_following_repo 2013-05-28 20:25:09.639417 +56 2 marcink 56 .rc_gist_store/4 started_following_repo 2013-05-28 20:25:09.671288 +57 2 marcink 57 .rc_gist_store/5 started_following_repo 2013-05-28 20:25:09.70115 +58 2 marcink 58 .rc_gist_store/6 started_following_repo 2013-05-28 20:25:09.735455 +59 2 marcink 59 .rc_gist_store/7 started_following_repo 2013-05-28 20:25:09.765397 +60 2 marcink 60 csa-harmony started_following_repo 2013-05-28 20:25:09.792266 +61 2 marcink 61 RC/łęcina started_following_repo 2013-05-28 20:25:09.847716 +62 2 marcink 62 rhodecode-extensions started_following_repo 2013-05-28 20:25:09.873349 +63 2 marcink 63 csa-prometheus started_following_repo 2013-05-28 20:25:09.897434 +64 2 marcink 64 RC/empty-git started_following_repo 2013-05-28 20:25:09.956588 +65 2 marcink 65 csa-salt-states started_following_repo 2013-05-28 20:25:10.023676 +66 2 marcink 66 rhodecode-premium started_following_repo 2013-05-28 20:25:10.083925 +67 2 marcink 67 RC/qweqwe-fork2 started_following_repo 2013-05-28 20:25:10.11151 +68 2 marcink 68 RC/INRC/L2_NEW/lalalal started_following_repo 2013-05-28 20:25:10.151677 +69 2 marcink 69 RC/INRC/L2_NEW/L3/repo_test_move started_following_repo 2013-05-28 20:25:10.200478 +70 2 marcink 70 rhodecode.bak started_following_repo 2013-05-28 20:25:10.229049 +71 2 marcink 71 RC/jap started_following_repo 2013-05-28 20:25:10.269933 +72 2 marcink 72 RC/origin started_following_repo 2013-05-28 20:25:10.324135 +73 2 marcink 73 rhodecode-cli-api started_following_repo 2013-05-28 20:25:10.354684 +74 2 marcink 74 csa-armstrong started_following_repo 2013-05-28 20:25:10.384192 +75 2 marcink 75 .rc_gist_store/NAsB8cacjxnqdyZ8QUl3 started_following_repo 2013-05-28 20:25:10.444031 +76 2 marcink 76 RC/lol/haha started_following_repo 2013-05-28 20:25:10.501665 +77 2 marcink 77 enc-envelope started_following_repo 2013-05-28 20:25:10.532521 +78 2 marcink 78 .rc_gist_store/43 started_following_repo 2013-05-28 20:25:10.565719 +79 2 marcink 79 RC/test started_following_repo 2013-05-28 20:25:10.592427 +80 2 marcink 80 BIG/git started_following_repo 2013-05-28 20:25:10.622609 +81 2 marcink 81 RC/origin-fork started_following_repo 2013-05-28 20:25:10.674818 +82 2 marcink 82 RC/trololo started_following_repo 2013-05-28 20:25:10.70267 +83 2 marcink 83 .rc_gist_store/FLj8GunafFAVBnuTWDxU started_following_repo 2013-05-28 20:25:10.730417 +84 2 marcink 84 RC/ąqweqwe started_following_repo 2013-05-28 20:25:10.759771 +85 2 marcink 85 csa-unity started_following_repo 2013-05-28 20:25:10.791604 +86 2 marcink 86 RC/vcs-git started_following_repo 2013-05-28 20:25:10.847105 +87 2 marcink 87 .rc_gist_store/12 started_following_repo 2013-05-28 20:25:10.903299 +88 2 marcink 88 .rc_gist_store/13 started_following_repo 2013-05-28 20:25:10.93383 +89 2 marcink 89 .rc_gist_store/10 started_following_repo 2013-05-28 20:25:10.963388 +90 2 marcink 90 .rc_gist_store/11 started_following_repo 2013-05-28 20:25:11.009722 +91 2 marcink 91 RC/kiall-nova started_following_repo 2013-05-28 20:25:11.037156 +92 2 marcink 92 RC/rc2/test started_following_repo 2013-05-28 20:25:11.092773 +93 2 marcink 93 DOCS started_following_repo 2013-05-28 20:25:11.119232 +94 2 marcink 94 RC/fork-remote started_following_repo 2013-05-28 20:25:11.173979 +95 2 marcink 95 RC/git-pull-test started_following_repo 2013-05-28 20:25:11.205569 +96 2 marcink 96 pyramidpypi started_following_repo 2013-05-28 20:25:11.257363 +97 2 marcink 97 .rc_gist_store/aQpbufbhSac6FyvVHhmS started_following_repo 2013-05-28 20:25:11.315047 +98 2 marcink 98 csa-aldrin started_following_repo 2013-05-28 20:25:11.344453 +99 2 marcink 99 .rc_gist_store/QL2GhrlKymNmrUJJy5js started_following_repo 2013-05-28 20:25:11.403828 +100 2 marcink 100 RC/git-test started_following_repo 2013-05-28 20:25:11.433792 +101 2 marcink 101 salt started_following_repo 2013-05-28 20:25:11.505324 +\. + + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_logs_user_log_id_seq', 101, true); + + +-- +-- Data for Name: user_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_repo_group_to_perm (group_to_perm_id, user_id, group_id, permission_id) FROM stdin; +1 1 1 6 +2 1 2 6 +3 1 3 6 +4 1 4 6 +5 1 5 6 +6 1 6 6 +7 1 7 6 +8 1 8 6 +9 1 9 6 +\. + + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_repo_group_to_perm_group_to_perm_id_seq', 9, true); + + +-- +-- Data for Name: user_to_notification; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_notification (user_id, notification_id, read, sent_on) FROM stdin; +\. + + +-- +-- Data for Name: user_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_perm (user_to_perm_id, user_id, permission_id) FROM stdin; +1 1 15 +2 1 11 +3 1 13 +4 1 2 +5 1 6 +\. + + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_to_perm_user_to_perm_id_seq', 5, true); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users (user_id, username, password, active, admin, firstname, lastname, email, last_login, ldap_dn, api_key, inherit_default_permissions) FROM stdin; +1 default $2a$10$g6.8mU0wOOc7Srb76XAueumBDyxC0UdrFxW2RJSqR4B7kM616HRm. t f Anonymous User anonymous@rhodecode.org \N \N 0b73aec3eb88ec4b25dbb00f8126468b5f984022 t +2 marcink $2a$10$hNQ1Nk0duJbBG8HBqni7Q.HEaH5SWDW.H5fvEv2K4Ikk6wJFMkDeq t t RhodeCode Admin marcin@rhodoecode.com \N \N 868d314f51262eb43c3c44569e8fa674299ad5a5 t +\. + + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq', 1, false); + + +-- +-- Data for Name: users_group_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_group_to_perm (users_group_repo_group_to_perm_id, users_group_id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Data for Name: users_group_repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_to_perm (users_group_to_perm_id, users_group_id, permission_id, repository_id) FROM stdin; +\. + + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_to_perm (users_group_to_perm_id, users_group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups (users_group_id, users_group_name, users_group_active, users_group_inherit_default_permissions) FROM stdin; +\. + + +-- +-- Data for Name: users_groups_members; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups_members (users_group_member_id, users_group_id, user_id) FROM stdin; +\. + + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_members_users_group_member_id_seq', 1, false); + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_users_group_id_seq', 1, false); + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_user_id_seq', 2, true); + + +-- +-- Name: cache_invalidation_cache_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_cache_key_key UNIQUE (cache_key); + + +-- +-- Name: cache_invalidation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_pkey PRIMARY KEY (cache_id); + + +-- +-- Name: changeset_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pkey PRIMARY KEY (comment_id); + + +-- +-- Name: changeset_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pkey PRIMARY KEY (changeset_status_id); + + +-- +-- Name: changeset_statuses_repo_id_revision_version_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_revision_version_key UNIQUE (repo_id, revision, version); + + +-- +-- Name: db_migrate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY db_migrate_version + ADD CONSTRAINT db_migrate_version_pkey PRIMARY KEY (repository_id); + + +-- +-- Name: groups_group_name_group_parent_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_group_parent_id_key UNIQUE (group_name, group_parent_id); + + +-- +-- Name: groups_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_key UNIQUE (group_name); + + +-- +-- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_pkey PRIMARY KEY (group_id); + + +-- +-- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (notification_id); + + +-- +-- Name: permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY permissions + ADD CONSTRAINT permissions_pkey PRIMARY KEY (permission_id); + + +-- +-- Name: pull_request_reviewers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pkey PRIMARY KEY (pull_requests_reviewers_id); + + +-- +-- Name: pull_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_pkey PRIMARY KEY (pull_request_id); + + +-- +-- Name: repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_pkey PRIMARY KEY (repo_to_perm_id); + + +-- +-- Name: repo_to_perm_user_id_repository_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_repository_id_permission_id_key UNIQUE (user_id, repository_id, permission_id); + + +-- +-- Name: repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (repo_id); + + +-- +-- Name: repositories_repo_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_repo_name_key UNIQUE (repo_name); + + +-- +-- Name: rhodecode_settings_app_settings_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_app_settings_name_key UNIQUE (app_settings_name); + + +-- +-- Name: rhodecode_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_pkey PRIMARY KEY (app_settings_id); + + +-- +-- Name: rhodecode_ui_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_pkey PRIMARY KEY (ui_id); + + +-- +-- Name: rhodecode_ui_ui_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_ui_key_key UNIQUE (ui_key); + + +-- +-- Name: statistics_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_pkey PRIMARY KEY (stat_id); + + +-- +-- Name: statistics_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_key UNIQUE (repository_id); + + +-- +-- Name: user_email_map_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_email_key UNIQUE (email); + + +-- +-- Name: user_email_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_pkey PRIMARY KEY (email_id); + + +-- +-- Name: user_followings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_pkey PRIMARY KEY (user_following_id); + + +-- +-- Name: user_followings_user_id_follows_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_repository_id_key UNIQUE (user_id, follows_repository_id); + + +-- +-- Name: user_followings_user_id_follows_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_user_id_key UNIQUE (user_id, follows_user_id); + + +-- +-- Name: user_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_pkey PRIMARY KEY (user_log_id); + + +-- +-- Name: user_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_pkey PRIMARY KEY (group_to_perm_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_group_id_permission_id_key UNIQUE (user_id, group_id, permission_id); + + +-- +-- Name: user_to_notification_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_pkey PRIMARY KEY (user_id, notification_id); + + +-- +-- Name: user_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_pkey PRIMARY KEY (user_to_perm_id); + + +-- +-- Name: user_to_perm_user_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_permission_id_key UNIQUE (user_id, permission_id); + + +-- +-- Name: users_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users_group_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_pkey PRIMARY KEY (users_group_repo_group_to_perm_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_group_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_group_id_key UNIQUE (users_group_id, group_id); + + +-- +-- Name: users_group_repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_users_group_id_permi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_users_group_id_permi_key UNIQUE (repository_id, users_group_id, permission_id); + + +-- +-- Name: users_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_to_perm_users_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_permission_id_key UNIQUE (users_group_id, permission_id); + + +-- +-- Name: users_groups_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_pkey PRIMARY KEY (users_group_member_id); + + +-- +-- Name: users_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_pkey PRIMARY KEY (users_group_id); + + +-- +-- Name: users_groups_users_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_users_group_name_key UNIQUE (users_group_name); + + +-- +-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_pkey PRIMARY KEY (user_id); + + +-- +-- Name: users_username_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: cc_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cc_revision_idx ON changeset_comments USING btree (revision); + + +-- +-- Name: cs_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_revision_idx ON changeset_statuses USING btree (revision); + + +-- +-- Name: cs_version_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_version_idx ON changeset_statuses USING btree (version); + + +-- +-- Name: key_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX key_idx ON cache_invalidation USING btree (cache_key); + + +-- +-- Name: notification_type_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX notification_type_idx ON notifications USING btree (type); + + +-- +-- Name: p_perm_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX p_perm_name_idx ON permissions USING btree (permission_name); + + +-- +-- Name: r_repo_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX r_repo_name_idx ON repositories USING btree (repo_name); + + +-- +-- Name: u_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_email_idx ON users USING btree (email); + + +-- +-- Name: u_username_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_username_idx ON users USING btree (username); + + +-- +-- Name: uem_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX uem_email_idx ON user_email_map USING btree (email); + + +-- +-- Name: changeset_comments_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_comments_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: changeset_statuses_changeset_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_changeset_comment_id_fkey FOREIGN KEY (changeset_comment_id) REFERENCES changeset_comments(comment_id); + + +-- +-- Name: changeset_statuses_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_statuses_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_statuses_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: groups_group_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_parent_id_fkey FOREIGN KEY (group_parent_id) REFERENCES groups(group_id); + + +-- +-- Name: notifications_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(user_id); + + +-- +-- Name: pull_request_reviewers_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: pull_request_reviewers_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: pull_requests_org_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_org_repo_id_fkey FOREIGN KEY (org_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_other_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_other_repo_id_fkey FOREIGN KEY (other_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repo_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repositories_fork_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_fork_id_fkey FOREIGN KEY (fork_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: repositories_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: statistics_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_email_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_follows_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_repository_id_fkey FOREIGN KEY (follows_repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_followings_follows_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_user_id_fkey FOREIGN KEY (follows_user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_logs_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: user_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_notification_notification_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_notification_id_fkey FOREIGN KEY (notification_id) REFERENCES notifications(notification_id); + + +-- +-- Name: user_to_notification_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_group_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: users_group_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: users_group_repo_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_groups_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_groups_members_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/rhodecode/tests/database/postgres/1.6.0.sql b/rhodecode/tests/database/postgres/1.6.0.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/postgres/1.6.0.sql @@ -0,0 +1,2861 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: cache_invalidation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE cache_invalidation ( + cache_id integer NOT NULL, + cache_key character varying(255), + cache_args character varying(255), + cache_active boolean +); + + +ALTER TABLE public.cache_invalidation OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE cache_invalidation_cache_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.cache_invalidation_cache_id_seq OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE cache_invalidation_cache_id_seq OWNED BY cache_invalidation.cache_id; + + +-- +-- Name: changeset_comments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_comments ( + comment_id integer NOT NULL, + repo_id integer NOT NULL, + revision character varying(40), + pull_request_id integer, + line_no character varying(10), + hl_lines character varying(512), + f_path character varying(1000), + user_id integer NOT NULL, + text text NOT NULL, + created_on timestamp without time zone NOT NULL, + modified_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.changeset_comments OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_comments_comment_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_comments_comment_id_seq OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_comments_comment_id_seq OWNED BY changeset_comments.comment_id; + + +-- +-- Name: changeset_statuses; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_statuses ( + changeset_status_id integer NOT NULL, + repo_id integer NOT NULL, + user_id integer NOT NULL, + revision character varying(40) NOT NULL, + status character varying(128) NOT NULL, + changeset_comment_id integer, + modified_at timestamp without time zone NOT NULL, + version integer NOT NULL, + pull_request_id integer +); + + +ALTER TABLE public.changeset_statuses OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_statuses_changeset_status_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_statuses_changeset_status_id_seq OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_statuses_changeset_status_id_seq OWNED BY changeset_statuses.changeset_status_id; + + +-- +-- Name: db_migrate_version; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE db_migrate_version ( + repository_id character varying(250) NOT NULL, + repository_path text, + version integer +); + + +ALTER TABLE public.db_migrate_version OWNER TO postgres; + +-- +-- Name: groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE groups ( + group_id integer NOT NULL, + group_name character varying(255) NOT NULL, + group_parent_id integer, + group_description character varying(10000), + enable_locking boolean NOT NULL, + CONSTRAINT groups_check CHECK ((group_id <> group_parent_id)) +); + + +ALTER TABLE public.groups OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE groups_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.groups_group_id_seq OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE groups_group_id_seq OWNED BY groups.group_id; + + +-- +-- Name: notifications; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE notifications ( + notification_id integer NOT NULL, + subject character varying(512), + body text, + created_by integer, + created_on timestamp without time zone NOT NULL, + type character varying(256) +); + + +ALTER TABLE public.notifications OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE notifications_notification_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.notifications_notification_id_seq OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE notifications_notification_id_seq OWNED BY notifications.notification_id; + + +-- +-- Name: permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE permissions ( + permission_id integer NOT NULL, + permission_name character varying(255), + permission_longname character varying(255) +); + + +ALTER TABLE public.permissions OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE permissions_permission_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.permissions_permission_id_seq OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE permissions_permission_id_seq OWNED BY permissions.permission_id; + + +-- +-- Name: pull_request_reviewers; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_request_reviewers ( + pull_requests_reviewers_id integer NOT NULL, + pull_request_id integer NOT NULL, + user_id integer +); + + +ALTER TABLE public.pull_request_reviewers OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_request_reviewers_pull_requests_reviewers_id_seq OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq OWNED BY pull_request_reviewers.pull_requests_reviewers_id; + + +-- +-- Name: pull_requests; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_requests ( + pull_request_id integer NOT NULL, + title character varying(256), + description text, + status character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL, + updated_on timestamp without time zone NOT NULL, + user_id integer NOT NULL, + revisions text, + org_repo_id integer NOT NULL, + org_ref character varying(256) NOT NULL, + other_repo_id integer NOT NULL, + other_ref character varying(256) NOT NULL +); + + +ALTER TABLE public.pull_requests OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_requests_pull_request_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_requests_pull_request_id_seq OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_requests_pull_request_id_seq OWNED BY pull_requests.pull_request_id; + + +-- +-- Name: repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repo_to_perm ( + repo_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.repo_to_perm OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repo_to_perm_repo_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repo_to_perm_repo_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repo_to_perm_repo_to_perm_id_seq OWNED BY repo_to_perm.repo_to_perm_id; + + +-- +-- Name: repositories; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories ( + repo_id integer NOT NULL, + repo_name character varying(255) NOT NULL, + clone_uri character varying(255), + repo_type character varying(255) NOT NULL, + user_id integer NOT NULL, + private boolean, + statistics boolean, + downloads boolean, + description character varying(10000), + created_on timestamp without time zone, + updated_on timestamp without time zone, + landing_revision character varying(255) NOT NULL, + enable_locking boolean NOT NULL, + locked character varying(255), + changeset_cache bytea, + fork_id integer, + group_id integer +); + + +ALTER TABLE public.repositories OWNER TO postgres; + +-- +-- Name: repositories_fields; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories_fields ( + repo_field_id integer NOT NULL, + repository_id integer NOT NULL, + field_key character varying(250), + field_label character varying(1024) NOT NULL, + field_value character varying(10000) NOT NULL, + field_desc character varying(1024) NOT NULL, + field_type character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL +); + + +ALTER TABLE public.repositories_fields OWNER TO postgres; + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_fields_repo_field_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_fields_repo_field_id_seq OWNER TO postgres; + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_fields_repo_field_id_seq OWNED BY repositories_fields.repo_field_id; + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_repo_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_repo_id_seq OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_repo_id_seq OWNED BY repositories.repo_id; + + +-- +-- Name: rhodecode_settings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_settings ( + app_settings_id integer NOT NULL, + app_settings_name character varying(255), + app_settings_value character varying(255) +); + + +ALTER TABLE public.rhodecode_settings OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_settings_app_settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_settings_app_settings_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_settings_app_settings_id_seq OWNED BY rhodecode_settings.app_settings_id; + + +-- +-- Name: rhodecode_ui; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_ui ( + ui_id integer NOT NULL, + ui_section character varying(255), + ui_key character varying(255), + ui_value character varying(255), + ui_active boolean +); + + +ALTER TABLE public.rhodecode_ui OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_ui_ui_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_ui_ui_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_ui_ui_id_seq OWNED BY rhodecode_ui.ui_id; + + +-- +-- Name: statistics; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE statistics ( + stat_id integer NOT NULL, + repository_id integer NOT NULL, + stat_on_revision integer NOT NULL, + commit_activity bytea NOT NULL, + commit_activity_combined bytea NOT NULL, + languages bytea NOT NULL +); + + +ALTER TABLE public.statistics OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE statistics_stat_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.statistics_stat_id_seq OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE statistics_stat_id_seq OWNED BY statistics.stat_id; + + +-- +-- Name: user_email_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_email_map ( + email_id integer NOT NULL, + user_id integer, + email character varying(255) +); + + +ALTER TABLE public.user_email_map OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_email_map_email_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_email_map_email_id_seq OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_email_map_email_id_seq OWNED BY user_email_map.email_id; + + +-- +-- Name: user_followings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_followings ( + user_following_id integer NOT NULL, + user_id integer NOT NULL, + follows_repository_id integer, + follows_user_id integer, + follows_from timestamp without time zone +); + + +ALTER TABLE public.user_followings OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_followings_user_following_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_followings_user_following_id_seq OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_followings_user_following_id_seq OWNED BY user_followings.user_following_id; + + +-- +-- Name: user_ip_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_ip_map ( + ip_id integer NOT NULL, + user_id integer, + ip_addr character varying(255), + active boolean +); + + +ALTER TABLE public.user_ip_map OWNER TO postgres; + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_ip_map_ip_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_ip_map_ip_id_seq OWNER TO postgres; + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_ip_map_ip_id_seq OWNED BY user_ip_map.ip_id; + + +-- +-- Name: user_logs; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_logs ( + user_log_id integer NOT NULL, + user_id integer, + username character varying(255), + repository_id integer, + repository_name character varying(255), + user_ip character varying(255), + action text, + action_date timestamp without time zone +); + + +ALTER TABLE public.user_logs OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_logs_user_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_logs_user_log_id_seq OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_logs_user_log_id_seq OWNED BY user_logs.user_log_id; + + +-- +-- Name: user_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_repo_group_to_perm ( + group_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_repo_group_to_perm_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq OWNED BY user_repo_group_to_perm.group_to_perm_id; + + +-- +-- Name: user_to_notification; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_notification ( + user_id integer NOT NULL, + notification_id integer NOT NULL, + read boolean, + sent_on timestamp without time zone +); + + +ALTER TABLE public.user_to_notification OWNER TO postgres; + +-- +-- Name: user_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_perm ( + user_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_to_perm OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_to_perm_user_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_to_perm_user_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_to_perm_user_to_perm_id_seq OWNED BY user_to_perm.user_to_perm_id; + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users ( + user_id integer NOT NULL, + username character varying(255), + password character varying(255), + active boolean, + admin boolean, + firstname character varying(255), + lastname character varying(255), + email character varying(255), + last_login timestamp without time zone, + ldap_dn character varying(255), + api_key character varying(255), + inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_group_to_perm ( + users_group_repo_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNED BY users_group_repo_group_to_perm.users_group_repo_group_to_perm_id; + + +-- +-- Name: users_group_repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq OWNED BY users_group_repo_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_to_perm_users_group_to_perm_id_seq OWNED BY users_group_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups ( + users_group_id integer NOT NULL, + users_group_name character varying(255) NOT NULL, + users_group_active boolean, + users_group_inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users_groups OWNER TO postgres; + +-- +-- Name: users_groups_members; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups_members ( + users_group_member_id integer NOT NULL, + users_group_id integer NOT NULL, + user_id integer NOT NULL +); + + +ALTER TABLE public.users_groups_members OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_members_users_group_member_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_members_users_group_member_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_members_users_group_member_id_seq OWNED BY users_groups_members.users_group_member_id; + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_users_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_users_group_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_users_group_id_seq OWNED BY users_groups.users_group_id; + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_user_id_seq OWNER TO postgres; + +-- +-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_user_id_seq OWNED BY users.user_id; + + +-- +-- Name: cache_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY cache_invalidation ALTER COLUMN cache_id SET DEFAULT nextval('cache_invalidation_cache_id_seq'::regclass); + + +-- +-- Name: comment_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments ALTER COLUMN comment_id SET DEFAULT nextval('changeset_comments_comment_id_seq'::regclass); + + +-- +-- Name: changeset_status_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses ALTER COLUMN changeset_status_id SET DEFAULT nextval('changeset_statuses_changeset_status_id_seq'::regclass); + + +-- +-- Name: group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups ALTER COLUMN group_id SET DEFAULT nextval('groups_group_id_seq'::regclass); + + +-- +-- Name: notification_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications ALTER COLUMN notification_id SET DEFAULT nextval('notifications_notification_id_seq'::regclass); + + +-- +-- Name: permission_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY permissions ALTER COLUMN permission_id SET DEFAULT nextval('permissions_permission_id_seq'::regclass); + + +-- +-- Name: pull_requests_reviewers_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers ALTER COLUMN pull_requests_reviewers_id SET DEFAULT nextval('pull_request_reviewers_pull_requests_reviewers_id_seq'::regclass); + + +-- +-- Name: pull_request_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests ALTER COLUMN pull_request_id SET DEFAULT nextval('pull_requests_pull_request_id_seq'::regclass); + + +-- +-- Name: repo_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm ALTER COLUMN repo_to_perm_id SET DEFAULT nextval('repo_to_perm_repo_to_perm_id_seq'::regclass); + + +-- +-- Name: repo_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories ALTER COLUMN repo_id SET DEFAULT nextval('repositories_repo_id_seq'::regclass); + + +-- +-- Name: repo_field_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories_fields ALTER COLUMN repo_field_id SET DEFAULT nextval('repositories_fields_repo_field_id_seq'::regclass); + + +-- +-- Name: app_settings_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_settings ALTER COLUMN app_settings_id SET DEFAULT nextval('rhodecode_settings_app_settings_id_seq'::regclass); + + +-- +-- Name: ui_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_ui ALTER COLUMN ui_id SET DEFAULT nextval('rhodecode_ui_ui_id_seq'::regclass); + + +-- +-- Name: stat_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics ALTER COLUMN stat_id SET DEFAULT nextval('statistics_stat_id_seq'::regclass); + + +-- +-- Name: email_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map ALTER COLUMN email_id SET DEFAULT nextval('user_email_map_email_id_seq'::regclass); + + +-- +-- Name: user_following_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings ALTER COLUMN user_following_id SET DEFAULT nextval('user_followings_user_following_id_seq'::regclass); + + +-- +-- Name: ip_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_ip_map ALTER COLUMN ip_id SET DEFAULT nextval('user_ip_map_ip_id_seq'::regclass); + + +-- +-- Name: user_log_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs ALTER COLUMN user_log_id SET DEFAULT nextval('user_logs_user_log_id_seq'::regclass); + + +-- +-- Name: group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm ALTER COLUMN group_to_perm_id SET DEFAULT nextval('user_repo_group_to_perm_group_to_perm_id_seq'::regclass); + + +-- +-- Name: user_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm ALTER COLUMN user_to_perm_id SET DEFAULT nextval('user_to_perm_user_to_perm_id_seq'::regclass); + + +-- +-- Name: user_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users ALTER COLUMN user_id SET DEFAULT nextval('users_user_id_seq'::regclass); + + +-- +-- Name: users_group_repo_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm ALTER COLUMN users_group_repo_group_to_perm_id SET DEFAULT nextval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_repo_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups ALTER COLUMN users_group_id SET DEFAULT nextval('users_groups_users_group_id_seq'::regclass); + + +-- +-- Name: users_group_member_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members ALTER COLUMN users_group_member_id SET DEFAULT nextval('users_groups_members_users_group_member_id_seq'::regclass); + + +-- +-- Data for Name: cache_invalidation; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY cache_invalidation (cache_id, cache_key, cache_args, cache_active) FROM stdin; +1 1RC/mygr/lol RC/mygr/lol f +2 1RC/fakeclone RC/fakeclone t +3 1RC/muay RC/muay f +4 1BIG/git BIG/git t +5 1RC/origin-fork RC/origin-fork f +6 1one one f +7 1rhodecode.bak.1 rhodecode.bak.1 f +8 1csa-collins csa-collins t +9 1csa-harmony csa-harmony t +10 1RC/ąqweqwe RC/ąqweqwe f +11 1rhodecode rhodecode f +12 1csa-unity csa-unity t +13 1RC/łęcina RC/łęcina f +14 1waitress waitress t +15 1RC/rc2/test2 RC/rc2/test2 t +16 1RC/origin-fork-fork RC/origin-fork-fork f +17 1RC/rc2/test4 RC/rc2/test4 t +18 1RC/vcs-git RC/vcs-git t +19 1rhodecode-extensions rhodecode-extensions f +20 1rhodecode-cli-gist rhodecode-cli-gist f +21 1test.onaut.com test.onaut.com t +22 1RC/new RC/new f +23 1csa-aldrin csa-aldrin t +24 1vcs vcs f +25 1csa-prometheus csa-prometheus t +26 1RC/INRC/trololo RC/INRC/trololo f +27 1RC/empty-git RC/empty-git t +28 1csa-salt-states csa-salt-states t +29 1rhodecode-premium rhodecode-premium f +30 1RC/qweqwe-fork RC/qweqwe-fork f +31 1testrepo-quick testrepo-quick t +32 1RC/test RC/test f +33 1remote-salt remote-salt t +34 1BIG/android BIG/android t +35 1DOCS DOCS t +36 1rhodecode-git rhodecode-git t +37 1RC/bin-ops RC/bin-ops f +38 1RC/INRC/L2_NEW/lalalal RC/INRC/L2_NEW/lalalal f +39 1RC/fork-remote RC/fork-remote f +40 1RC/INRC/L2_NEW/L3/repo_test_move RC/INRC/L2_NEW/L3/repo_test_move f +41 1RC/gogo-fork RC/gogo-fork f +42 1quest quest f +43 1RC/foobar RC/foobar f +44 1csa-hyperion csa-hyperion t +45 1RC/git-pull-test RC/git-pull-test t +46 1RC/qweqwe-fork2 RC/qweqwe-fork2 f +47 1RC/jap RC/jap t +48 1RC/hg-repo RC/hg-repo f +49 1RC/origin RC/origin f +50 1rhodecode-cli-api rhodecode-cli-api f +51 1RC/rc2/test3 RC/rc2/test3 t +52 1csa-armstrong csa-armstrong t +53 1RC/trololo RC/trololo f +54 1testrepo-wp testrepo-wp t +55 1pyramidpypi pyramidpypi t +56 1salt salt t +57 1RC/lol/haha RC/lol/haha f +58 1csa-io csa-io t +59 1enc-envelope enc-envelope f +60 1RC/gogo2 RC/gogo2 f +61 1csa-libcloud csa-libcloud t +62 1RC/git-test RC/git-test t +63 1RC/rc2/test RC/rc2/test f +64 1rhodecode.bak rhodecode.bak f +65 1RC/kiall-nova RC/kiall-nova t +\. + + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('cache_invalidation_cache_id_seq', 65, true); + + +-- +-- Data for Name: changeset_comments; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_comments (comment_id, repo_id, revision, pull_request_id, line_no, hl_lines, f_path, user_id, text, created_on, modified_at) FROM stdin; +\. + + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_comments_comment_id_seq', 1, false); + + +-- +-- Data for Name: changeset_statuses; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_statuses (changeset_status_id, repo_id, user_id, revision, status, changeset_comment_id, modified_at, version, pull_request_id) FROM stdin; +\. + + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_statuses_changeset_status_id_seq', 1, false); + + +-- +-- Data for Name: db_migrate_version; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY db_migrate_version (repository_id, repository_path, version) FROM stdin; +rhodecode_db_migrations versions 11 +\. + + +-- +-- Data for Name: groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY groups (group_id, group_name, group_parent_id, group_description, enable_locking) FROM stdin; +1 RC \N RC group f +2 RC/mygr 1 RC/mygr group f +3 BIG \N BIG group f +4 RC/rc2 1 RC/rc2 group f +5 RC/INRC 1 RC/INRC group f +6 RC/INRC/L2_NEW 5 RC/INRC/L2_NEW group f +7 RC/INRC/L2_NEW/L3 6 RC/INRC/L2_NEW/L3 group f +8 RC/lol 1 RC/lol group f +\. + + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('groups_group_id_seq', 8, true); + + +-- +-- Data for Name: notifications; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY notifications (notification_id, subject, body, created_by, created_on, type) FROM stdin; +\. + + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('notifications_notification_id_seq', 1, false); + + +-- +-- Data for Name: permissions; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY permissions (permission_id, permission_name, permission_longname) FROM stdin; +1 repository.none repository.none +2 repository.read repository.read +3 repository.write repository.write +4 repository.admin repository.admin +5 group.none group.none +6 group.read group.read +7 group.write group.write +8 group.admin group.admin +9 hg.admin hg.admin +10 hg.create.none hg.create.none +11 hg.create.repository hg.create.repository +12 hg.fork.none hg.fork.none +13 hg.fork.repository hg.fork.repository +14 hg.register.none hg.register.none +15 hg.register.manual_activate hg.register.manual_activate +16 hg.register.auto_activate hg.register.auto_activate +\. + + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('permissions_permission_id_seq', 16, true); + + +-- +-- Data for Name: pull_request_reviewers; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_request_reviewers (pull_requests_reviewers_id, pull_request_id, user_id) FROM stdin; +\. + + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_request_reviewers_pull_requests_reviewers_id_seq', 1, false); + + +-- +-- Data for Name: pull_requests; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_requests (pull_request_id, title, description, status, created_on, updated_on, user_id, revisions, org_repo_id, org_ref, other_repo_id, other_ref) FROM stdin; +\. + + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_requests_pull_request_id_seq', 1, false); + + +-- +-- Data for Name: repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repo_to_perm (repo_to_perm_id, user_id, permission_id, repository_id) FROM stdin; +1 1 2 1 +2 1 2 2 +3 1 2 3 +4 1 2 4 +5 1 2 5 +6 1 2 6 +7 1 2 7 +8 1 2 8 +9 1 2 9 +10 1 2 10 +11 1 2 11 +12 1 2 12 +13 1 2 13 +14 1 2 14 +15 1 2 15 +16 1 2 16 +17 1 2 17 +18 1 2 18 +19 1 2 19 +20 1 2 20 +21 1 2 21 +22 1 2 22 +23 1 2 23 +24 1 2 24 +25 1 2 25 +26 1 2 26 +27 1 2 27 +28 1 2 28 +29 1 2 29 +30 1 2 30 +31 1 2 31 +32 1 2 32 +33 1 2 33 +34 1 2 34 +35 1 2 35 +36 1 2 36 +37 1 2 37 +38 1 2 38 +39 1 2 39 +40 1 2 40 +41 1 2 41 +42 1 2 42 +43 1 2 43 +44 1 2 44 +45 1 2 45 +46 1 2 46 +47 1 2 47 +48 1 2 48 +49 1 2 49 +50 1 2 50 +51 1 2 51 +52 1 2 52 +53 1 2 53 +54 1 2 54 +55 1 2 55 +56 1 2 56 +57 1 2 57 +58 1 2 58 +59 1 2 59 +60 1 2 60 +61 1 2 61 +62 1 2 62 +63 1 2 63 +64 1 2 64 +65 1 2 65 +\. + + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repo_to_perm_repo_to_perm_id_seq', 65, true); + + +-- +-- Data for Name: repositories; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories (repo_id, repo_name, clone_uri, repo_type, user_id, private, statistics, downloads, description, created_on, updated_on, landing_revision, enable_locking, locked, changeset_cache, fork_id, group_id) FROM stdin; +1 RC/mygr/lol http://user@vm/RC/mygr/lol hg 2 f f f RC/mygr/lol repository 2013-05-28 20:26:59.886314 2013-05-28 20:26:59.886502 tip f \N \N \N 2 +2 RC/fakeclone \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:26:59.94415 2013-05-09 01:48:00 tip f \N \\x7b227261775f6964223a202264666137643337363737386436383164313831386634316231373730366566613630333362343037222c202273686f72745f6964223a2022646661376433373637373864222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30395430313a34383a3030222c20226d657373616765223a202266697865645c6e222c20227265766973696f6e223a203239337d \N 1 +3 RC/muay \N hg 2 f f f RC/muay repository 2013-05-28 20:27:00.114841 2013-05-28 20:27:00.114864 tip f \N \N \N 1 +4 BIG/git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:00.171891 2012-10-21 23:47:54 tip f \N \\x7b227261775f6964223a202233306634633636653633343736306138316162323761323336666531663234383266366637383536222c202273686f72745f6964223a2022333066346336366536333437222c2022617574686f72223a20224a756e696f20432048616d616e6f203c6769747374657240706f626f782e636f6d3e222c202264617465223a2022323031322d31302d32315432333a34373a3534222c20226d657373616765223a202257686174277320636f6f6b696e672028323031322f313020233037295c6e222c20227265766973696f6e223a2033323136307d \N 3 +5 RC/origin-fork \N hg 2 f f f RC/origin-fork repository 2013-05-28 20:27:01.457264 2013-03-06 20:16:20 tip f \N \\x7b227261775f6964223a202266306365333961366639656466633633393264346436313337663035626233383731653431373830222c202273686f72745f6964223a2022663063653339613666396564222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d30365432303a31363a3230222c20226d657373616765223a20224564697465642066696c6520766961206f7074696f6e735c6e2d20666978656420315c6e2d66207869656420325c6e616e6420736f206f6e20736f206f6e207472616c6c616c616c61222c20227265766973696f6e223a2032317d \N 1 +6 one \N hg 2 f f f one repository 2013-05-28 20:27:01.525404 2013-05-23 12:11:57 tip f \N \\x7b227261775f6964223a202233393435643961623264396533323262623666643561613763333461316530313132326265343662222c202273686f72745f6964223a2022333934356439616232643965222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d32335431323a31313a3537222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N \N +7 rhodecode.bak.1 \N hg 2 f f f rhodecode.bak.1 repository 2013-05-28 20:27:01.578685 2013-05-28 14:44:56 tip f \N \\x7b227261775f6964223a202232336637333938396439323230343636666239646237633635316431336162663637393666373663222c202273686f72745f6964223a2022323366373339383964393232222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385431343a34343a3536222c20226d657373616765223a20226d657267652064657620696e746f2072686f6465636f64652d70616d222c20227265766973696f6e223a20343034307d \N \N +8 csa-collins \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:01.645073 2013-02-25 17:31:39 tip f \N \\x7b227261775f6964223a202238626536613130643634356338646461356631663333313439363232383131386165383732636538222c202273686f72745f6964223a2022386265366131306436343563222c2022617574686f72223a20224261737469616e20416c62657273203c696e666f406261737469616e616c626572732e64653e222c202264617465223a2022323031332d30322d32355431373a33313a3339222c20226d657373616765223a20224d65726765206272616e6368202773746167652720696e746f207374616765325c6e222c20227265766973696f6e223a20323733317d \N \N +9 csa-harmony \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:01.870853 2013-05-22 14:49:45 tip f \N \\x7b227261775f6964223a202232376235393630333631386230373235396361306462366230303939306665656261393639333066222c202273686f72745f6964223a2022323762353936303336313862222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32325431343a34393a3435222c20226d657373616765223a20224164646564206b776172677320746f2073657475702066756e6374696f6e7320666f72206c61746572206f7074696f6e616c20706172616d735c6e222c20227265766973696f6e223a203333397d \N \N +10 RC/ąqweqwe \N hg 2 f f f RC/ąqweqwe repository 2013-05-28 20:27:02.376512 2013-05-28 20:27:02.376535 tip f \N \N \N 1 +11 rhodecode \N hg 2 f f f rhodecode repository 2013-05-28 20:27:02.424079 2013-05-28 20:16:08 tip f \N \\x7b227261775f6964223a202237613161333935356434343661343664353235663034326265373339343161303231323266633332222c202273686f72745f6964223a2022376131613339353564343436222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385432303a31363a3038222c20226d657373616765223a20226d6967726174696f6e20746f20312e372e30222c20227265766973696f6e223a20343034357d \N \N +12 csa-unity \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.495342 2013-04-29 14:38:23 tip f \N \\x7b227261775f6964223a202230393337303837353965626634666432626231626463616436316662363131626333323933336433222c202273686f72745f6964223a2022303933373038373539656266222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32395431343a33383a3233222c20226d657373616765223a202272657665727420746f206c6f67626f6f6b20302e332e30222c20227265766973696f6e223a2032387d \N \N +13 RC/łęcina \N hg 2 f f f RC/łęcina repository 2013-05-28 20:27:02.664128 2013-03-06 16:17:49 tip f \N \\x7b227261775f6964223a202231656535383962636661393231326335313130656135633166653263633866663665616631333033222c202273686f72745f6964223a2022316565353839626366613932222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d30365431363a31373a3439222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N 1 +14 waitress \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.721063 2013-05-28 13:21:35 tip f \N \\x7b227261775f6964223a202265356431333863653366373534653630333165376162643736653566353237333633666461663432222c202273686f72745f6964223a2022653564313338636533663735222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385431333a32313a3335222c20226d657373616765223a2022416464656420646f637320616e64206e657720666c616720696e746f2072756e6e65725c6e222c20227265766973696f6e223a203237327d \N \N +15 RC/rc2/test2 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.896717 2013-03-03 00:29:35 tip f \N \\x7b227261775f6964223a202230656233333034666333336430356433323866383632376239616434346461653833663331336132222c202273686f72745f6964223a2022306562333330346663333364222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30335430303a32393a3335222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e202066697820726571756573747320312e31206a736f6e206d6574686f645c6e202066697865642074657374735c6e20206d6f76656420746573747320696e746f207061636b6167655c6e20202d62756d7020646973747269627574655c6e2020757064617465202e67697469676e6f72655c6e202076657273696f6e20667265657a65206f66206c6962735c6e202072656d6f766520676576656e742066726f6d20494f20617320646570656e64656e63795c6e202061646420756e69747920617320646570735c6e202066756c6c792064656c65676174652041555448206261636b20746f2061726d7374726f6e675c6e222c20227265766973696f6e223a2035307d \N 4 +16 RC/origin-fork-fork \N hg 2 f f f RC/origin-fork-fork repository 2013-05-28 20:27:03.013741 2013-05-06 23:44:50 tip f \N \\x7b227261775f6964223a202236643939653064346466636334613561666135633133386665613230393834373036333466373733222c202273686f72745f6964223a2022366439396530643464666363222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d30365432333a34343a3530222c20226d657373616765223a20224973737565202331373039343a20436c656172207374616c65207468726561642073746174657320616674657220666f726b28292e5c6e5c6e4e6f746520746861742074686973206973206120706f74656e7469616c6c792064697372757074697665206368616e67652073696e6365206974206d61795c6e72656c6561736520736f6d652073797374656d207265736f757263657320776869636820776f756c64206f74686572776973652072656d61696e5c6e70657270657475616c6c7920616c6976652028652e672e20646174616261736520636f6e6e656374696f6e73206b65707420696e207468726561642d6c6f63616c5c6e73746f72616765292e222c20227265766973696f6e223a2032357d \N 1 +17 RC/rc2/test4 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.077195 2013-03-21 22:55:29 tip f \N \\x7b227261775f6964223a202233623661633766356539333264346464313338373161306232336436636139383531306438386332222c202273686f72745f6964223a2022336236616337663565393332222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d32315432323a35353a3239222c20226d657373616765223a2022647361646173222c20227265766973696f6e223a2035317d \N 4 +18 RC/vcs-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.207037 2013-04-26 23:34:15 tip f \N \\x7b227261775f6964223a202239306461316636396136633630663764346435363436656533396163356636313038626330373763222c202273686f72745f6964223a2022393064613166363961366336222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32365432333a33343a3135222c20226d657373616765223a20226d65726765207769746820474954207663735c6e222c20227265766973696f6e223a203634387d \N 1 +19 rhodecode-extensions \N hg 2 f f f rhodecode-extensions repository 2013-05-28 20:27:03.363473 2013-02-13 16:50:33 tip f \N \\x7b227261775f6964223a202264613765356637613339643332303366663062346166353031386163346138306439346564316434222c202273686f72745f6964223a2022646137653566376133396433222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30322d31335431363a35303a3333222c20226d657373616765223a20224c696e6b6966792068697063686174206d65737361676573222c20227265766973696f6e223a20327d \N \N +20 rhodecode-cli-gist \N hg 2 f f f rhodecode-cli-gist repository 2013-05-28 20:27:03.415835 2013-05-28 20:27:03.415858 tip f \N \N \N \N +21 test.onaut.com \N git 2 f f f Unnamed repository 2013-05-28 20:27:03.46164 2013-04-29 11:08:31 tip f \N \\x7b227261775f6964223a202236666465656664323034633461656637636263623966656563646564313436373364383563663230222c202273686f72745f6964223a2022366664656566643230346334222c2022617574686f72223a2022596f7572204e616d65203c796f75406578616d706c652e636f6d3e222c202264617465223a2022323031332d30342d32395431313a30383a3331222c20226d657373616765223a2022666f6f6261725c6e222c20227265766973696f6e223a20307d \N \N +22 RC/new \N hg 2 f f f RC/new repository 2013-05-28 20:27:03.580255 2013-04-17 13:02:59 tip f \N \\x7b227261775f6964223a202239333139326530336133353532623864613466656534306530303163363033303437323362623432222c202273686f72745f6964223a2022393331393265303361333535222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d31375431333a30323a3539222c20226d657373616765223a202272656e616d65222c20227265766973696f6e223a20317d \N 1 +46 RC/qweqwe-fork2 \N hg 2 f f f RC/qweqwe-fork2 repository 2013-05-28 20:27:17.359662 2013-05-28 20:27:17.359684 tip f \N \N \N 1 +23 csa-aldrin \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.639793 2013-05-02 23:47:52 tip f \N \\x7b227261775f6964223a202236376565396538333063323235393231656331353937346163316466646531376139333065326662222c202273686f72745f6964223a2022363765653965383330633232222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30325432333a34373a3532222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e20206d6f76656420676576656e7420696e746f206f757420696e7465726e616c207365727665725c6e202073747570696420617373686f6c657320696e20676576656e742073686f756c64206c6561726e20686f7720746f207061636b6167652e2e2e5c6e2020666978656420676576656e7420646570656e64656e6379206c696e6b5c6e202061646465642073657061726174652063616c6c20666f722073657373696f6e2076616c69646174696f6e5c6e222c20227265766973696f6e223a203239337d \N \N +24 vcs \N hg 2 f f f vcs repository 2013-05-28 20:27:03.856575 2013-05-09 00:28:54 tip f \N \\x7b227261775f6964223a202236666261353966396637383036613534356130653565626163393336393931383238343336323630222c202273686f72745f6964223a2022366662613539663966373830222c2022617574686f72223a20224c756b61737a2042616c6365727a616b203c6c756b61737a62616c6365727a616b40676d61696c2e636f6d3e222c202264617465223a2022323031332d30352d30395430303a32383a3534222c20226d657373616765223a20224d657267652070756c6c207265717565737420233131372066726f6d206e69656462616c736b692f6d61737465725c6e5c6e4b65794572726f723a2027616c6c27222c20227265766973696f6e223a203730377d \N \N +25 csa-prometheus \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.916977 2013-04-29 14:37:43 tip f \N \\x7b227261775f6964223a202261373139626438326432356537343131666462373937396331326330383366353961323036613663222c202273686f72745f6964223a2022613731396264383264323565222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32395431343a33373a3433222c20226d657373616765223a2022726576657274206c6f67626f6f6b20746f20302e332e30222c20227265766973696f6e223a2037397d \N \N +26 RC/INRC/trololo \N hg 2 f f f RC/INRC/trololo repository 2013-05-28 20:27:04.096413 2013-05-28 20:27:04.096437 tip f \N \N \N 5 +27 RC/empty-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.148472 2013-05-28 20:27:04.148509 tip f \N \N \N 1 +28 csa-salt-states \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.212846 2013-05-06 14:48:48 tip f \N \\x7b227261775f6964223a202230633230646337326261656564633363653834306336313131373463376531636433623034393139222c202273686f72745f6964223a2022306332306463373262616565222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30365431343a34383a3438222c20226d657373616765223a2022696e6372656173652073616d706c696e67206f66204350552074696d6520746f20302e357320666f72206d6f7265207265616c697374696320646174612e222c20227265766973696f6e223a2037317d \N \N +29 rhodecode-premium \N hg 2 f f f rhodecode-premium repository 2013-05-28 20:27:04.419538 2013-03-21 22:58:11 tip f \N \\x7b227261775f6964223a202264656433356266303137663136626361643636313163376666653362316231633130393432663530222c202273686f72745f6964223a2022646564333562663031376631222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d32315432323a35383a3131222c20226d657373616765223a202276657273696f6e2062756d7020746f20312e352e347032222c20227265766973696f6e223a20333637347d \N \N +30 RC/qweqwe-fork \N hg 2 f f f RC/qweqwe-fork repository 2013-05-28 20:27:04.494164 2013-05-28 20:27:04.494188 tip f \N \N \N 1 +31 testrepo-quick \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.547757 2012-08-31 11:34:33 tip f \N \\x7b227261775f6964223a202236303763396632336633373731626633353731346639626166353539666433313138366432353930222c202273686f72745f6964223a2022363037633966323366333737222c2022617574686f72223a202253656261737469616e204b726575747a626572676572203c73656261737469616e406170707a6f6e6175742e636f6d3e222c202264617465223a2022323031322d30382d33315431313a33343a3333222c20226d657373616765223a20226164646564207465737420666f72202e617a2d7368617265642066696c655c6e222c20227265766973696f6e223a2031327d \N \N +32 RC/test \N hg 2 f f f RC/test repository 2013-05-28 20:27:04.697514 2013-01-30 22:56:03 tip f \N \\x7b227261775f6964223a202265353032356533313664396163623339653566383631633439343234306265346635643536646536222c202273686f72745f6964223a2022653530323565333136643961222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e406d61712e696f3e222c202264617465223a2022323031332d30312d33305432323a35363a3033222c20226d657373616765223a20223c7363726970743e616c65727428277873733227293b3c2f7363726970743e202066697865732023373030222c20227265766973696f6e223a20327d \N 1 +33 remote-salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.750525 2012-10-14 22:04:05 tip f \N \\x7b227261775f6964223a202264363631646337323439326536366361623761363437646362353635323030393036376161386364222c202273686f72745f6964223a2022643636316463373234393265222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031322d31302d31345432323a30343a3035222c20226d657373616765223a20224c6f6767696e675c6e4f6e2d7468652d666c79206d736720656e6372797074696f6e207573696e6720676f6f676c6573206b6579437a6172206c6962222c20227265766973696f6e223a20337d \N \N +34 BIG/android \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.869224 2012-06-17 00:44:46 tip f \N \\x7b227261775f6964223a202265383662313437653462363930386137633561623039363364373766623038363736373962316565222c202273686f72745f6964223a2022653836623134376534623639222c2022617574686f72223a20224265726e6861726420526f73656e6b7261656e7a6572203c4265726e686172642e526f73656e6b72616e7a6572406c696e61726f2e6f72673e222c202264617465223a2022323031322d30362d31375430303a34343a3436222c20226d657373616765223a202270616e64613a204261636b706f72742048444d492076732e204456492070617463682066726f6d206b65726e656c2f70616e64612e6769745c6e5c6e5468697320706174636820616c6c6f777320737769746368696e6720746865207072696d61727920646973706c6179206f7574707574206465766963652e5c6e5c6e4368616e67652d49643a2049366533306538376262633761613732623561636336653663346564333430313938333565363532345c6e5369676e65642d6f66662d62793a204265726e6861726420526f73656e6b7261656e7a6572203c4265726e686172642e526f73656e6b72616e7a6572406c696e61726f2e6f72673e5c6e222c20227265766973696f6e223a203239343839367d \N 3 +35 DOCS \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:16.065483 2013-04-25 16:45:59 tip f \N \\x7b227261775f6964223a202231653461373238656537613661613838626531313236306436343739613434366562383635646533222c202273686f72745f6964223a2022316534613732386565376136222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32355431363a34353a3539222c20226d657373616765223a202273796e6320646f637320776974682061726d7374726f6e67222c20227265766973696f6e223a2031357d \N \N +36 rhodecode-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:16.225335 2013-01-04 00:24:22 tip f \N \\x7b227261775f6964223a202236323966313533386164343830306666303531313335313666366139333365326232343366323035222c202273686f72745f6964223a2022363239663135333861643438222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30312d30345430303a32343a3232222c20226d657373616765223a20226e6963657220726570726573656e746174696f6e206f66206c697374206f662072657363616e6e6564207265706f7369746f726965735c6e5c6e2d2d48472d2d5c6e6272616e6368203a20626574615c6e222c20227265766973696f6e223a20333134327d \N \N +37 RC/bin-ops \N hg 2 f f f RC/bin-ops repository 2013-05-28 20:27:16.463774 2013-05-12 12:39:34 tip f \N \\x7b227261775f6964223a202234323331373632643863316161636135626533646231353939313037313233366333326537363534222c202273686f72745f6964223a2022343233313736326438633161222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d31325431323a33393a3334222c20226d657373616765223a20224564697465642066696c652066696c6531207669612052686f6465436f6465222c20227265766973696f6e223a2032337d \N 1 +38 RC/INRC/L2_NEW/lalalal \N hg 2 f f f RC/INRC/L2_NEW/lalalal repository 2013-05-28 20:27:16.555625 2013-05-28 20:27:16.55565 tip f \N \N \N 6 +39 RC/fork-remote \N hg 2 f f f RC/fork-remote repository 2013-05-28 20:27:16.622524 2013-03-10 22:47:24 tip f \N \\x7b227261775f6964223a202236303535353438346130613064366535323565396437616231623164636535616239656239343837222c202273686f72745f6964223a2022363035353534383461306130222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d31305432323a34373a3234222c20226d657373616765223a2022616161222c20227265766973696f6e223a2032367d \N 1 +40 RC/INRC/L2_NEW/L3/repo_test_move \N hg 2 f f f RC/INRC/L2_NEW/L3/repo_test_move repository 2013-05-28 20:27:16.717095 2013-05-28 20:27:16.717133 tip f \N \N \N 7 +41 RC/gogo-fork \N hg 2 f f f RC/gogo-fork repository 2013-05-28 20:27:16.790103 2013-05-28 20:27:16.790129 tip f \N \N \N 1 +42 quest \N hg 2 f f f quest repository 2013-05-28 20:27:16.858741 2013-03-04 23:01:40 tip f \N \\x7b227261775f6964223a202235346230316366646561323562663431636438653961313834633538353263356434386438363463222c202273686f72745f6964223a2022353462303163666465613235222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30345432333a30313a3430222c20226d657373616765223a202274656d706c61746520616e642076657273696f6e20302e302e31222c20227265766973696f6e223a2034317d \N \N +43 RC/foobar \N hg 2 f f f RC/foobar repository 2013-05-28 20:27:16.930525 2013-04-15 21:34:57 tip f \N \\x7b227261775f6964223a202263313764633363353636393532383133653834303337646664363261343735356564336339313263222c202273686f72745f6964223a2022633137646333633536363935222c2022617574686f72223a20224d6972656b204b6f7474203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30342d31355432313a33343a3537222c20226d657373616765223a20224564697465642066696c65206c6f6c2e727374207669612052686f6465436f6465222c20227265766973696f6e223a20317d \N 1 +44 csa-hyperion \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.021283 2013-05-20 21:58:28 tip f \N \\x7b227261775f6964223a202232353263393236643130373032653665663763323435366632666332333839323830386535336130222c202273686f72745f6964223a2022323532633932366431303730222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32305432313a35383a3238222c20226d657373616765223a2022666978657320666f72206e657720636f64655c6e222c20227265766973696f6e223a2035377d \N \N +45 RC/git-pull-test \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.231975 2013-05-20 13:03:02 tip f \N \\x7b227261775f6964223a202262326366313133366630396661363164663930343639623433333130363135393834626337643535222c202273686f72745f6964223a2022623263663131333666303966222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32305431333a30333a3032222c20226d657373616765223a202261646465645c6e222c20227265766973696f6e223a2031337d \N 1 +47 RC/jap \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.427862 2013-04-24 11:15:30 tip f \N \\x7b227261775f6964223a202232663632636532323435336136376565666436666162316434653035333532306538646562646636222c202273686f72745f6964223a2022326636326365323234353361222c2022617574686f72223a202244656d6f2055736572203c64656d6f4072686f6465636f64652e6f72673e222c202264617465223a2022323031332d30342d32345431313a31353a3330222c20226d657373616765223a20225c75333064355c75333061315c75333061345c75333065625c75386666645c7535326130222c20227265766973696f6e223a20357d \N 1 +48 RC/hg-repo \N hg 2 f f f RC/hg-repo repository 2013-05-28 20:27:17.558936 2013-05-08 22:54:45 tip f \N \\x7b227261775f6964223a202264363364343065386230363835616636646235663263663737303065383032313661663563373339222c202273686f72745f6964223a2022643633643430653862303638222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d30385432323a35343a3435222c20226d657373616765223a20224564697465642066696c652068616861207669612052686f6465436f6465222c20227265766973696f6e223a2032357d \N 1 +49 RC/origin \N hg 2 f f f RC/origin repository 2013-05-28 20:27:17.634344 2013-04-05 13:05:02 tip f \N \\x7b227261775f6964223a202235666266326630656164613433626333336139346534383335303333333564386636373537303933222c202273686f72745f6964223a2022356662663266306561646134222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d30355431333a30353a3032222c20226d657373616765223a20226669786564222c20227265766973696f6e223a2032397d \N 1 +50 rhodecode-cli-api \N hg 2 f f f rhodecode-cli-api repository 2013-05-28 20:27:17.708944 2013-05-28 20:27:17.708995 tip f \N \N \N \N +51 RC/rc2/test3 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.781161 2013-03-03 00:29:35 tip f \N \\x7b227261775f6964223a202230656233333034666333336430356433323866383632376239616434346461653833663331336132222c202273686f72745f6964223a2022306562333330346663333364222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30335430303a32393a3335222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e202066697820726571756573747320312e31206a736f6e206d6574686f645c6e202066697865642074657374735c6e20206d6f76656420746573747320696e746f207061636b6167655c6e20202d62756d7020646973747269627574655c6e2020757064617465202e67697469676e6f72655c6e202076657273696f6e20667265657a65206f66206c6962735c6e202072656d6f766520676576656e742066726f6d20494f20617320646570656e64656e63795c6e202061646420756e69747920617320646570735c6e202066756c6c792064656c65676174652041555448206261636b20746f2061726d7374726f6e675c6e222c20227265766973696f6e223a2035307d \N 4 +52 csa-armstrong \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.898234 2013-05-22 18:10:20 tip f \N \\x7b227261775f6964223a202236306666613230313866613132306339376330633566636162393365636438326532633361363931222c202273686f72745f6964223a2022363066666132303138666131222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32325431383a31303a3230222c20226d657373616765223a20226669782061637475616c2070726f677265737320696e63726561736520696e2073616c742063616c6c735c6e222c20227265766973696f6e223a20313134307d \N \N +53 RC/trololo \N hg 2 f f f RC/trololo repository 2013-05-28 20:27:18.620592 2013-03-28 02:35:50 tip f \N \\x7b227261775f6964223a202238393064373436396162616333363036333763386366373966313538623137303431356531363533222c202273686f72745f6964223a2022383930643734363961626163222c2022617574686f72223a202264656d6f2075736572203c6d617263696e406d61712e696f3e222c202264617465223a2022323031332d30332d32385430323a33353a3530222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N 1 +54 testrepo-wp \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:18.695645 2012-08-27 11:05:37 tip f \N \\x7b227261775f6964223a202264393461663531633130313032303433306132386463616561313135336464643932326332396563222c202273686f72745f6964223a2022643934616635316331303130222c2022617574686f72223a202253656261737469616e204b726575747a626572676572203c73656261737469616e406170707a6f6e6175742e636f6d3e222c202264617465223a2022323031322d30382d32375431313a30353a3337222c20226d657373616765223a2022757064617465642063726564735c6e222c20227265766973696f6e223a20377d \N \N +55 pyramidpypi \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:18.824235 2013-04-25 16:34:48 tip f \N \\x7b227261775f6964223a202265643961636566666164613365663338353039633564373031306230313662613435653832393434222c202273686f72745f6964223a2022656439616365666661646133222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32355431363a33343a3438222c20226d657373616765223a202276657273696f6e2062756d70222c20227265766973696f6e223a2032387d \N \N +56 salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.036099 2012-10-15 05:20:58 tip f \N \\x7b227261775f6964223a202262643434383332323330666331396562383066653439656630316261646234373765663863613663222c202273686f72745f6964223a2022626434343833323233306663222c2022617574686f72223a202254686f6d61732053204861746368203c746861746368343540676d61696c2e636f6d3e222c202264617465223a2022323031322d31302d31355430353a32303a3538222c20226d657373616765223a20224d657267652070756c6c20726571756573742023323234342066726f6d2046697265486f73742f746f706c6576656c5f776d695f696d706f72745c6e5c6e546f706c6576656c20776d6920696d706f7274222c20227265766973696f6e223a20363935377d \N \N +57 RC/lol/haha \N hg 2 f f f RC/lol/haha repository 2013-05-28 20:27:19.44935 2013-05-28 20:27:19.449372 tip f \N \N \N 8 +58 csa-io \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.531664 2013-05-02 22:52:54 tip f \N \\x7b227261775f6964223a202262643065663731666366643038386138326238363237653630616161316632303230656433336261222c202273686f72745f6964223a2022626430656637316663666430222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30325432323a35323a3534222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e2020557365206578745f6a736f6e20696e7374656164206f6620706c61696e2073696d706c656a736f6e2073657269616c697a65725c6e20206c6f67206572726f7273206f6e207265737466756c6c206a736f6e20706172736572732f6465636f646572735c6e2020666978656420736f6d652073657269616c697a6174696f6e2070726f626c656d735c6e202076657273696f6e2062756d705c6e20205265706f7369746f7279207265766973696f6e73204150495c6e20206d657263757269616c2076657273696f6e2062756d705c6e202042756d70205643532076657273696f6e20746f20302e342e3020616e64206d6f766520697420746f20636f64652e6170707a6f6e6175742e636f6d5c6e2020666978206c6f6767696e67206f6e206368616e676573206a736f6e206d6f64756c6520696e20726571756573747320312e585c6e222c20227265766973696f6e223a2035397d \N \N +59 enc-envelope \N hg 2 f f f enc-envelope repository 2013-05-28 20:27:19.74793 2013-03-07 15:37:40 tip f \N \\x7b227261775f6964223a202238313030363666383335643663303832393530666337383238646564353062396238643963323239222c202273686f72745f6964223a2022383130303636663833356436222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30375431353a33373a3430222c20226d657373616765223a202273686f77206d6f72652064657461696c656420696e666f2061626f75742077726f6e672073747265616d222c20227265766973696f6e223a20357d \N \N +60 RC/gogo2 \N hg 2 f f f RC/gogo2 repository 2013-05-28 20:27:19.827312 2013-05-28 20:27:19.827334 tip f \N \N \N 1 +61 csa-libcloud \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.892075 2013-04-17 16:42:42 tip f \N \\x7b227261775f6964223a202261326661353531363333636533363937616336336139333561613731663165376238303232326165222c202273686f72745f6964223a2022613266613535313633336365222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d31375431363a34323a3432222c20226d657373616765223a202266696c746572206f6e6c79206c697374656e65727320427269676874626f782063616e2070726f63657373222c20227265766973696f6e223a20313839357d \N \N +62 RC/git-test \N git 2 f f f Unnamed repository 2013-05-28 20:27:20.231554 2013-03-25 22:50:04 tip f \N \\x7b227261775f6964223a202235643561646464666339323963643839653931313131366436306231323064316361613866333964222c202273686f72745f6964223a2022356435616464646663393239222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d32355432323a35303a3034222c20226d657373616765223a202266785c6e222c20227265766973696f6e223a20397d \N 1 +63 RC/rc2/test \N hg 2 f f f RC/rc2/test repository 2013-05-28 20:27:20.356786 2013-05-28 20:27:20.35683 tip f \N \N \N 4 +64 rhodecode.bak \N hg 2 f f f rhodecode.bak repository 2013-05-28 20:27:20.423238 2013-05-28 02:41:49 tip f \N \\x7b227261775f6964223a202262633862616365663164303663306330643132616337386638326565353330666363393661663561222c202273686f72745f6964223a2022626338626163656631643036222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385430323a34313a3439222c20226d657373616765223a20224164646564206e657720617069206d6574686f64735c6e2d206765745f7365727665725f696e666f5c6e2d206765745f69705c6e2d207570646174655f7265706f5c6e2d206765745f7265706f5f67726f75705c6e2d206765745f7265706f5f67726f7570735c6e2d206372656174655f7265706f5f67726f75705c6e2d207570646174655f7265706f5f67726f75705c6e2d2064656c6574655f7265706f5f67726f75705c6e2d207570646174655f757365725f67726f75705c6e2d206765745f676973745c6e2d206765745f67697374735c6e2d2064656c6574655f676973745c6e5c6e2b207265666163746f72696e67206f66206e616d657320616e642067656e6572616c2041504920636c65616e75702e5c6e41504920646f63732077696c6c206e6f772062652067656e657261746564206261736564206f6e2066756e6374696f6e20646f63737472696e67735c6e546869732077696c6c206d616b652069742065617369657220746f20646f2070726f70657220646f63756d656e746174696f6e20666f72204150492e222c20227265766973696f6e223a20343033397d \N \N +65 RC/kiall-nova \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:20.524084 2012-10-23 10:22:06 tip f \N \\x7b227261775f6964223a202261306663643132343830373161643636623631306561633439303361646633366233313433393062222c202273686f72745f6964223a2022613066636431323438303731222c2022617574686f72223a20224a656e6b696e73203c6a656e6b696e73407265766965772e6f70656e737461636b2e6f72673e222c202264617465223a2022323031322d31302d32335431303a32323a3036222c20226d657373616765223a20224d65726765205c22466978206e6f76612d766f6c756d652d75736167652d61756469745c22222c20227265766973696f6e223a2031373235337d \N 1 +\. + + +-- +-- Data for Name: repositories_fields; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories_fields (repo_field_id, repository_id, field_key, field_label, field_value, field_desc, field_type, created_on) FROM stdin; +\. + + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_fields_repo_field_id_seq', 1, false); + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_repo_id_seq', 65, true); + + +-- +-- Data for Name: rhodecode_settings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_settings (app_settings_id, app_settings_name, app_settings_value) FROM stdin; +1 realm RhodeCode authentication +2 title RhodeCode +3 ga_code 123456 +4 show_public_icon True +5 show_private_icon True +6 stylify_metatags False +7 ldap_active false +8 ldap_host +9 ldap_port 389 +10 ldap_tls_kind PLAIN +11 ldap_tls_reqcert +12 ldap_dn_user +13 ldap_dn_pass +14 ldap_base_dn +15 ldap_filter +16 ldap_search_scope +17 ldap_attr_login +18 ldap_attr_firstname +19 ldap_attr_lastname +20 ldap_attr_email +21 default_repo_enable_locking False +22 default_repo_enable_downloads False +23 default_repo_enable_statistics False +24 default_repo_private False +25 default_repo_type hg +\. + + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_settings_app_settings_id_seq', 25, true); + + +-- +-- Data for Name: rhodecode_ui; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_ui (ui_id, ui_section, ui_key, ui_value, ui_active) FROM stdin; +1 hooks changegroup.update hg update >&2 f +2 hooks changegroup.repo_size python:rhodecode.lib.hooks.repo_size t +3 hooks changegroup.push_logger python:rhodecode.lib.hooks.log_push_action t +4 hooks prechangegroup.pre_push python:rhodecode.lib.hooks.pre_push t +5 hooks outgoing.pull_logger python:rhodecode.lib.hooks.log_pull_action t +6 hooks preoutgoing.pre_pull python:rhodecode.lib.hooks.pre_pull t +7 extensions largefiles t +8 extensions hgsubversion f +9 extensions hggit f +10 web push_ssl false t +11 web allow_archive gz zip bz2 t +12 web allow_push * t +13 web baseurl / t +14 paths / /mnt/hgfs/workspace-python t +\. + + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_ui_ui_id_seq', 14, true); + + +-- +-- Data for Name: statistics; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY statistics (stat_id, repository_id, stat_on_revision, commit_activity, commit_activity_combined, languages) FROM stdin; +\. + + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('statistics_stat_id_seq', 1, false); + + +-- +-- Data for Name: user_email_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_email_map (email_id, user_id, email) FROM stdin; +\. + + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_email_map_email_id_seq', 1, false); + + +-- +-- Data for Name: user_followings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_followings (user_following_id, user_id, follows_repository_id, follows_user_id, follows_from) FROM stdin; +1 2 1 \N 2013-05-28 20:26:59.905946 +2 2 2 \N 2013-05-28 20:26:59.958581 +3 2 3 \N 2013-05-28 20:27:00.145566 +4 2 4 \N 2013-05-28 20:27:00.184438 +5 2 5 \N 2013-05-28 20:27:01.507836 +6 2 6 \N 2013-05-28 20:27:01.562696 +7 2 7 \N 2013-05-28 20:27:01.630538 +8 2 8 \N 2013-05-28 20:27:01.658765 +9 2 9 \N 2013-05-28 20:27:01.883077 +10 2 10 \N 2013-05-28 20:27:02.410512 +11 2 11 \N 2013-05-28 20:27:02.47039 +12 2 12 \N 2013-05-28 20:27:02.512861 +13 2 13 \N 2013-05-28 20:27:02.705559 +14 2 14 \N 2013-05-28 20:27:02.736051 +15 2 15 \N 2013-05-28 20:27:02.909458 +16 2 16 \N 2013-05-28 20:27:03.058143 +17 2 17 \N 2013-05-28 20:27:03.092663 +18 2 18 \N 2013-05-28 20:27:03.220556 +19 2 19 \N 2013-05-28 20:27:03.401209 +20 2 20 \N 2013-05-28 20:27:03.446846 +21 2 21 \N 2013-05-28 20:27:03.478718 +22 2 22 \N 2013-05-28 20:27:03.625506 +23 2 23 \N 2013-05-28 20:27:03.654446 +24 2 24 \N 2013-05-28 20:27:03.90204 +25 2 25 \N 2013-05-28 20:27:03.935584 +26 2 26 \N 2013-05-28 20:27:04.133528 +27 2 27 \N 2013-05-28 20:27:04.165426 +28 2 28 \N 2013-05-28 20:27:04.227192 +29 2 29 \N 2013-05-28 20:27:04.470074 +30 2 30 \N 2013-05-28 20:27:04.535036 +31 2 31 \N 2013-05-28 20:27:04.56081 +32 2 32 \N 2013-05-28 20:27:04.73511 +33 2 33 \N 2013-05-28 20:27:04.762367 +34 2 34 \N 2013-05-28 20:27:04.882269 +35 2 35 \N 2013-05-28 20:27:16.081624 +36 2 36 \N 2013-05-28 20:27:16.238074 +37 2 37 \N 2013-05-28 20:27:16.490921 +38 2 38 \N 2013-05-28 20:27:16.606332 +39 2 39 \N 2013-05-28 20:27:16.683877 +40 2 40 \N 2013-05-28 20:27:16.772204 +41 2 41 \N 2013-05-28 20:27:16.846091 +42 2 42 \N 2013-05-28 20:27:16.915625 +43 2 43 \N 2013-05-28 20:27:17.000652 +44 2 44 \N 2013-05-28 20:27:17.035001 +45 2 45 \N 2013-05-28 20:27:17.245544 +46 2 46 \N 2013-05-28 20:27:17.412282 +47 2 47 \N 2013-05-28 20:27:17.442703 +48 2 48 \N 2013-05-28 20:27:17.616299 +49 2 49 \N 2013-05-28 20:27:17.694907 +50 2 50 \N 2013-05-28 20:27:17.76193 +51 2 51 \N 2013-05-28 20:27:17.796316 +52 2 52 \N 2013-05-28 20:27:17.911214 +53 2 53 \N 2013-05-28 20:27:18.67818 +54 2 54 \N 2013-05-28 20:27:18.712023 +55 2 55 \N 2013-05-28 20:27:18.837132 +56 2 56 \N 2013-05-28 20:27:19.053951 +57 2 57 \N 2013-05-28 20:27:19.51609 +58 2 58 \N 2013-05-28 20:27:19.543354 +59 2 59 \N 2013-05-28 20:27:19.809302 +60 2 60 \N 2013-05-28 20:27:19.877469 +61 2 61 \N 2013-05-28 20:27:19.908981 +62 2 62 \N 2013-05-28 20:27:20.247031 +63 2 63 \N 2013-05-28 20:27:20.410876 +64 2 64 \N 2013-05-28 20:27:20.506094 +65 2 65 \N 2013-05-28 20:27:20.536866 +\. + + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_followings_user_following_id_seq', 65, true); + + +-- +-- Data for Name: user_ip_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_ip_map (ip_id, user_id, ip_addr, active) FROM stdin; +\. + + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_ip_map_ip_id_seq', 1, false); + + +-- +-- Data for Name: user_logs; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_logs (user_log_id, user_id, username, repository_id, repository_name, user_ip, action, action_date) FROM stdin; +1 2 marcink 1 RC/mygr/lol started_following_repo 2013-05-28 20:26:59.900931 +2 2 marcink 2 RC/fakeclone started_following_repo 2013-05-28 20:26:59.955428 +3 2 marcink 3 RC/muay started_following_repo 2013-05-28 20:27:00.125953 +4 2 marcink 4 BIG/git started_following_repo 2013-05-28 20:27:00.181617 +5 2 marcink 5 RC/origin-fork started_following_repo 2013-05-28 20:27:01.466724 +6 2 marcink 6 one started_following_repo 2013-05-28 20:27:01.536732 +7 2 marcink 7 rhodecode.bak.1 started_following_repo 2013-05-28 20:27:01.589472 +8 2 marcink 8 csa-collins started_following_repo 2013-05-28 20:27:01.655365 +9 2 marcink 9 csa-harmony started_following_repo 2013-05-28 20:27:01.88057 +10 2 marcink 10 RC/ąqweqwe started_following_repo 2013-05-28 20:27:02.387499 +11 2 marcink 11 rhodecode started_following_repo 2013-05-28 20:27:02.433418 +12 2 marcink 12 csa-unity started_following_repo 2013-05-28 20:27:02.508796 +13 2 marcink 13 RC/łęcina started_following_repo 2013-05-28 20:27:02.674658 +14 2 marcink 14 waitress started_following_repo 2013-05-28 20:27:02.73244 +15 2 marcink 15 RC/rc2/test2 started_following_repo 2013-05-28 20:27:02.906659 +16 2 marcink 16 RC/origin-fork-fork started_following_repo 2013-05-28 20:27:03.02717 +17 2 marcink 17 RC/rc2/test4 started_following_repo 2013-05-28 20:27:03.090085 +18 2 marcink 18 RC/vcs-git started_following_repo 2013-05-28 20:27:03.218033 +19 2 marcink 19 rhodecode-extensions started_following_repo 2013-05-28 20:27:03.374166 +20 2 marcink 20 rhodecode-cli-gist started_following_repo 2013-05-28 20:27:03.425087 +21 2 marcink 21 test.onaut.com started_following_repo 2013-05-28 20:27:03.473193 +22 2 marcink 22 RC/new started_following_repo 2013-05-28 20:27:03.593153 +23 2 marcink 23 csa-aldrin started_following_repo 2013-05-28 20:27:03.651182 +24 2 marcink 24 vcs started_following_repo 2013-05-28 20:27:03.866907 +25 2 marcink 25 csa-prometheus started_following_repo 2013-05-28 20:27:03.931789 +26 2 marcink 26 RC/INRC/trololo started_following_repo 2013-05-28 20:27:04.108947 +27 2 marcink 27 RC/empty-git started_following_repo 2013-05-28 20:27:04.162816 +28 2 marcink 28 csa-salt-states started_following_repo 2013-05-28 20:27:04.224517 +29 2 marcink 29 rhodecode-premium started_following_repo 2013-05-28 20:27:04.429318 +30 2 marcink 30 RC/qweqwe-fork started_following_repo 2013-05-28 20:27:04.508625 +31 2 marcink 31 testrepo-quick started_following_repo 2013-05-28 20:27:04.558071 +32 2 marcink 32 RC/test started_following_repo 2013-05-28 20:27:04.707963 +33 2 marcink 33 remote-salt started_following_repo 2013-05-28 20:27:04.759601 +34 2 marcink 34 BIG/android started_following_repo 2013-05-28 20:27:04.879601 +35 2 marcink 35 DOCS started_following_repo 2013-05-28 20:27:16.077043 +36 2 marcink 36 rhodecode-git started_following_repo 2013-05-28 20:27:16.235309 +37 2 marcink 37 RC/bin-ops started_following_repo 2013-05-28 20:27:16.474785 +38 2 marcink 38 RC/INRC/L2_NEW/lalalal started_following_repo 2013-05-28 20:27:16.566047 +39 2 marcink 39 RC/fork-remote started_following_repo 2013-05-28 20:27:16.636895 +40 2 marcink 40 RC/INRC/L2_NEW/L3/repo_test_move started_following_repo 2013-05-28 20:27:16.73064 +41 2 marcink 41 RC/gogo-fork started_following_repo 2013-05-28 20:27:16.801352 +42 2 marcink 42 quest started_following_repo 2013-05-28 20:27:16.870218 +43 2 marcink 43 RC/foobar started_following_repo 2013-05-28 20:27:16.94344 +44 2 marcink 44 csa-hyperion started_following_repo 2013-05-28 20:27:17.032368 +45 2 marcink 45 RC/git-pull-test started_following_repo 2013-05-28 20:27:17.242321 +46 2 marcink 46 RC/qweqwe-fork2 started_following_repo 2013-05-28 20:27:17.369718 +47 2 marcink 47 RC/jap started_following_repo 2013-05-28 20:27:17.438737 +48 2 marcink 48 RC/hg-repo started_following_repo 2013-05-28 20:27:17.568968 +49 2 marcink 49 RC/origin started_following_repo 2013-05-28 20:27:17.647722 +50 2 marcink 50 rhodecode-cli-api started_following_repo 2013-05-28 20:27:17.720735 +51 2 marcink 51 RC/rc2/test3 started_following_repo 2013-05-28 20:27:17.793213 +52 2 marcink 52 csa-armstrong started_following_repo 2013-05-28 20:27:17.908068 +53 2 marcink 53 RC/trololo started_following_repo 2013-05-28 20:27:18.630661 +54 2 marcink 54 testrepo-wp started_following_repo 2013-05-28 20:27:18.707708 +55 2 marcink 55 pyramidpypi started_following_repo 2013-05-28 20:27:18.834547 +56 2 marcink 56 salt started_following_repo 2013-05-28 20:27:19.050625 +57 2 marcink 57 RC/lol/haha started_following_repo 2013-05-28 20:27:19.462058 +58 2 marcink 58 csa-io started_following_repo 2013-05-28 20:27:19.540782 +59 2 marcink 59 enc-envelope started_following_repo 2013-05-28 20:27:19.758453 +60 2 marcink 60 RC/gogo2 started_following_repo 2013-05-28 20:27:19.838573 +61 2 marcink 61 csa-libcloud started_following_repo 2013-05-28 20:27:19.904526 +62 2 marcink 62 RC/git-test started_following_repo 2013-05-28 20:27:20.243692 +63 2 marcink 63 RC/rc2/test started_following_repo 2013-05-28 20:27:20.36788 +64 2 marcink 64 rhodecode.bak started_following_repo 2013-05-28 20:27:20.435328 +65 2 marcink 65 RC/kiall-nova started_following_repo 2013-05-28 20:27:20.533474 +\. + + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_logs_user_log_id_seq', 65, true); + + +-- +-- Data for Name: user_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_repo_group_to_perm (group_to_perm_id, user_id, group_id, permission_id) FROM stdin; +1 1 1 6 +2 1 2 6 +3 1 3 6 +4 1 4 6 +5 1 5 6 +6 1 6 6 +7 1 7 6 +8 1 8 6 +\. + + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_repo_group_to_perm_group_to_perm_id_seq', 8, true); + + +-- +-- Data for Name: user_to_notification; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_notification (user_id, notification_id, read, sent_on) FROM stdin; +\. + + +-- +-- Data for Name: user_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_perm (user_to_perm_id, user_id, permission_id) FROM stdin; +1 1 15 +2 1 11 +3 1 13 +4 1 2 +5 1 6 +\. + + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_to_perm_user_to_perm_id_seq', 5, true); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users (user_id, username, password, active, admin, firstname, lastname, email, last_login, ldap_dn, api_key, inherit_default_permissions) FROM stdin; +1 default $2a$10$pgqzrZyjE0YBlVErXftPnu4bMmbkO4BSIPtgPsrEoxM6xBdu.pFyi t f Anonymous User anonymous@rhodecode.org \N \N b7e62414df8fe4328b567603d6a409946af4a8f7 t +2 marcink $2a$10$htEvNjGrB1xEWaXJGrlWee.LB/ZT4.RON.VOfQ9caBSGSLnbHnvz2 t t RhodeCode Admin marcin@rhodecode.com \N \N 1d6f72e5dc6de70d9623f006edb28b8b56b3ebce t +\. + + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq', 1, false); + + +-- +-- Data for Name: users_group_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_group_to_perm (users_group_repo_group_to_perm_id, users_group_id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Data for Name: users_group_repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_to_perm (users_group_to_perm_id, users_group_id, permission_id, repository_id) FROM stdin; +\. + + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_to_perm (users_group_to_perm_id, users_group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups (users_group_id, users_group_name, users_group_active, users_group_inherit_default_permissions) FROM stdin; +\. + + +-- +-- Data for Name: users_groups_members; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups_members (users_group_member_id, users_group_id, user_id) FROM stdin; +\. + + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_members_users_group_member_id_seq', 1, false); + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_users_group_id_seq', 1, false); + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_user_id_seq', 2, true); + + +-- +-- Name: cache_invalidation_cache_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_cache_key_key UNIQUE (cache_key); + + +-- +-- Name: cache_invalidation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_pkey PRIMARY KEY (cache_id); + + +-- +-- Name: changeset_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pkey PRIMARY KEY (comment_id); + + +-- +-- Name: changeset_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pkey PRIMARY KEY (changeset_status_id); + + +-- +-- Name: changeset_statuses_repo_id_revision_version_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_revision_version_key UNIQUE (repo_id, revision, version); + + +-- +-- Name: db_migrate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY db_migrate_version + ADD CONSTRAINT db_migrate_version_pkey PRIMARY KEY (repository_id); + + +-- +-- Name: groups_group_name_group_parent_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_group_parent_id_key UNIQUE (group_name, group_parent_id); + + +-- +-- Name: groups_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_key UNIQUE (group_name); + + +-- +-- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_pkey PRIMARY KEY (group_id); + + +-- +-- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (notification_id); + + +-- +-- Name: permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY permissions + ADD CONSTRAINT permissions_pkey PRIMARY KEY (permission_id); + + +-- +-- Name: pull_request_reviewers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pkey PRIMARY KEY (pull_requests_reviewers_id); + + +-- +-- Name: pull_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_pkey PRIMARY KEY (pull_request_id); + + +-- +-- Name: repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_pkey PRIMARY KEY (repo_to_perm_id); + + +-- +-- Name: repo_to_perm_user_id_repository_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_repository_id_permission_id_key UNIQUE (user_id, repository_id, permission_id); + + +-- +-- Name: repositories_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_pkey PRIMARY KEY (repo_field_id); + + +-- +-- Name: repositories_fields_repository_id_field_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_repository_id_field_key_key UNIQUE (repository_id, field_key); + + +-- +-- Name: repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (repo_id); + + +-- +-- Name: repositories_repo_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_repo_name_key UNIQUE (repo_name); + + +-- +-- Name: rhodecode_settings_app_settings_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_app_settings_name_key UNIQUE (app_settings_name); + + +-- +-- Name: rhodecode_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_pkey PRIMARY KEY (app_settings_id); + + +-- +-- Name: rhodecode_ui_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_pkey PRIMARY KEY (ui_id); + + +-- +-- Name: rhodecode_ui_ui_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_ui_key_key UNIQUE (ui_key); + + +-- +-- Name: statistics_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_pkey PRIMARY KEY (stat_id); + + +-- +-- Name: statistics_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_key UNIQUE (repository_id); + + +-- +-- Name: user_email_map_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_email_key UNIQUE (email); + + +-- +-- Name: user_email_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_pkey PRIMARY KEY (email_id); + + +-- +-- Name: user_followings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_pkey PRIMARY KEY (user_following_id); + + +-- +-- Name: user_followings_user_id_follows_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_repository_id_key UNIQUE (user_id, follows_repository_id); + + +-- +-- Name: user_followings_user_id_follows_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_user_id_key UNIQUE (user_id, follows_user_id); + + +-- +-- Name: user_ip_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_pkey PRIMARY KEY (ip_id); + + +-- +-- Name: user_ip_map_user_id_ip_addr_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_user_id_ip_addr_key UNIQUE (user_id, ip_addr); + + +-- +-- Name: user_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_pkey PRIMARY KEY (user_log_id); + + +-- +-- Name: user_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_pkey PRIMARY KEY (group_to_perm_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_group_id_permission_id_key UNIQUE (user_id, group_id, permission_id); + + +-- +-- Name: user_to_notification_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_pkey PRIMARY KEY (user_id, notification_id); + + +-- +-- Name: user_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_pkey PRIMARY KEY (user_to_perm_id); + + +-- +-- Name: user_to_perm_user_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_permission_id_key UNIQUE (user_id, permission_id); + + +-- +-- Name: users_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users_group_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_pkey PRIMARY KEY (users_group_repo_group_to_perm_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_group_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_group_id_key UNIQUE (users_group_id, group_id); + + +-- +-- Name: users_group_repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_users_group_id_permi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_users_group_id_permi_key UNIQUE (repository_id, users_group_id, permission_id); + + +-- +-- Name: users_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_to_perm_users_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_permission_id_key UNIQUE (users_group_id, permission_id); + + +-- +-- Name: users_groups_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_pkey PRIMARY KEY (users_group_member_id); + + +-- +-- Name: users_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_pkey PRIMARY KEY (users_group_id); + + +-- +-- Name: users_groups_users_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_users_group_name_key UNIQUE (users_group_name); + + +-- +-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_pkey PRIMARY KEY (user_id); + + +-- +-- Name: users_username_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: cc_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cc_revision_idx ON changeset_comments USING btree (revision); + + +-- +-- Name: cs_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_revision_idx ON changeset_statuses USING btree (revision); + + +-- +-- Name: cs_version_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_version_idx ON changeset_statuses USING btree (version); + + +-- +-- Name: key_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX key_idx ON cache_invalidation USING btree (cache_key); + + +-- +-- Name: notification_type_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX notification_type_idx ON notifications USING btree (type); + + +-- +-- Name: p_perm_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX p_perm_name_idx ON permissions USING btree (permission_name); + + +-- +-- Name: r_repo_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX r_repo_name_idx ON repositories USING btree (repo_name); + + +-- +-- Name: u_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_email_idx ON users USING btree (email); + + +-- +-- Name: u_username_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_username_idx ON users USING btree (username); + + +-- +-- Name: uem_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX uem_email_idx ON user_email_map USING btree (email); + + +-- +-- Name: changeset_comments_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_comments_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: changeset_statuses_changeset_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_changeset_comment_id_fkey FOREIGN KEY (changeset_comment_id) REFERENCES changeset_comments(comment_id); + + +-- +-- Name: changeset_statuses_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_statuses_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_statuses_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: groups_group_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_parent_id_fkey FOREIGN KEY (group_parent_id) REFERENCES groups(group_id); + + +-- +-- Name: notifications_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(user_id); + + +-- +-- Name: pull_request_reviewers_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: pull_request_reviewers_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: pull_requests_org_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_org_repo_id_fkey FOREIGN KEY (org_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_other_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_other_repo_id_fkey FOREIGN KEY (other_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repo_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repositories_fields_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_fork_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_fork_id_fkey FOREIGN KEY (fork_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: repositories_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: statistics_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_email_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_follows_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_repository_id_fkey FOREIGN KEY (follows_repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_followings_follows_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_user_id_fkey FOREIGN KEY (follows_user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_ip_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_logs_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: user_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_notification_notification_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_notification_id_fkey FOREIGN KEY (notification_id) REFERENCES notifications(notification_id); + + +-- +-- Name: user_to_notification_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_group_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: users_group_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: users_group_repo_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_groups_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_groups_members_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/rhodecode/tests/database/postgres/1.6.0_no_repo_name_index.sql b/rhodecode/tests/database/postgres/1.6.0_no_repo_name_index.sql new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/postgres/1.6.0_no_repo_name_index.sql @@ -0,0 +1,2854 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: cache_invalidation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE cache_invalidation ( + cache_id integer NOT NULL, + cache_key character varying(255), + cache_args character varying(255), + cache_active boolean +); + + +ALTER TABLE public.cache_invalidation OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE cache_invalidation_cache_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.cache_invalidation_cache_id_seq OWNER TO postgres; + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE cache_invalidation_cache_id_seq OWNED BY cache_invalidation.cache_id; + + +-- +-- Name: changeset_comments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_comments ( + comment_id integer NOT NULL, + repo_id integer NOT NULL, + revision character varying(40), + pull_request_id integer, + line_no character varying(10), + hl_lines character varying(512), + f_path character varying(1000), + user_id integer NOT NULL, + text text NOT NULL, + created_on timestamp without time zone NOT NULL, + modified_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.changeset_comments OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_comments_comment_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_comments_comment_id_seq OWNER TO postgres; + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_comments_comment_id_seq OWNED BY changeset_comments.comment_id; + + +-- +-- Name: changeset_statuses; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE changeset_statuses ( + changeset_status_id integer NOT NULL, + repo_id integer NOT NULL, + user_id integer NOT NULL, + revision character varying(40) NOT NULL, + status character varying(128) NOT NULL, + changeset_comment_id integer, + modified_at timestamp without time zone NOT NULL, + version integer NOT NULL, + pull_request_id integer +); + + +ALTER TABLE public.changeset_statuses OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE changeset_statuses_changeset_status_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.changeset_statuses_changeset_status_id_seq OWNER TO postgres; + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE changeset_statuses_changeset_status_id_seq OWNED BY changeset_statuses.changeset_status_id; + + +-- +-- Name: db_migrate_version; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE db_migrate_version ( + repository_id character varying(250) NOT NULL, + repository_path text, + version integer +); + + +ALTER TABLE public.db_migrate_version OWNER TO postgres; + +-- +-- Name: groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE groups ( + group_id integer NOT NULL, + group_name character varying(255) NOT NULL, + group_parent_id integer, + group_description character varying(10000), + enable_locking boolean NOT NULL, + CONSTRAINT groups_check CHECK ((group_id <> group_parent_id)) +); + + +ALTER TABLE public.groups OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE groups_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.groups_group_id_seq OWNER TO postgres; + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE groups_group_id_seq OWNED BY groups.group_id; + + +-- +-- Name: notifications; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE notifications ( + notification_id integer NOT NULL, + subject character varying(512), + body text, + created_by integer, + created_on timestamp without time zone NOT NULL, + type character varying(256) +); + + +ALTER TABLE public.notifications OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE notifications_notification_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.notifications_notification_id_seq OWNER TO postgres; + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE notifications_notification_id_seq OWNED BY notifications.notification_id; + + +-- +-- Name: permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE permissions ( + permission_id integer NOT NULL, + permission_name character varying(255), + permission_longname character varying(255) +); + + +ALTER TABLE public.permissions OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE permissions_permission_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.permissions_permission_id_seq OWNER TO postgres; + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE permissions_permission_id_seq OWNED BY permissions.permission_id; + + +-- +-- Name: pull_request_reviewers; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_request_reviewers ( + pull_requests_reviewers_id integer NOT NULL, + pull_request_id integer NOT NULL, + user_id integer +); + + +ALTER TABLE public.pull_request_reviewers OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_request_reviewers_pull_requests_reviewers_id_seq OWNER TO postgres; + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_request_reviewers_pull_requests_reviewers_id_seq OWNED BY pull_request_reviewers.pull_requests_reviewers_id; + + +-- +-- Name: pull_requests; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE pull_requests ( + pull_request_id integer NOT NULL, + title character varying(256), + description text, + status character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL, + updated_on timestamp without time zone NOT NULL, + user_id integer NOT NULL, + revisions text, + org_repo_id integer NOT NULL, + org_ref character varying(256) NOT NULL, + other_repo_id integer NOT NULL, + other_ref character varying(256) NOT NULL +); + + +ALTER TABLE public.pull_requests OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE pull_requests_pull_request_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.pull_requests_pull_request_id_seq OWNER TO postgres; + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE pull_requests_pull_request_id_seq OWNED BY pull_requests.pull_request_id; + + +-- +-- Name: repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repo_to_perm ( + repo_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.repo_to_perm OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repo_to_perm_repo_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repo_to_perm_repo_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repo_to_perm_repo_to_perm_id_seq OWNED BY repo_to_perm.repo_to_perm_id; + + +-- +-- Name: repositories; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories ( + repo_id integer NOT NULL, + repo_name character varying(255) NOT NULL, + clone_uri character varying(255), + repo_type character varying(255) NOT NULL, + user_id integer NOT NULL, + private boolean, + statistics boolean, + downloads boolean, + description character varying(10000), + created_on timestamp without time zone, + updated_on timestamp without time zone, + landing_revision character varying(255) NOT NULL, + enable_locking boolean NOT NULL, + locked character varying(255), + changeset_cache bytea, + fork_id integer, + group_id integer +); + + +ALTER TABLE public.repositories OWNER TO postgres; + +-- +-- Name: repositories_fields; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE repositories_fields ( + repo_field_id integer NOT NULL, + repository_id integer NOT NULL, + field_key character varying(250), + field_label character varying(1024) NOT NULL, + field_value character varying(10000) NOT NULL, + field_desc character varying(1024) NOT NULL, + field_type character varying(256) NOT NULL, + created_on timestamp without time zone NOT NULL +); + + +ALTER TABLE public.repositories_fields OWNER TO postgres; + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_fields_repo_field_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_fields_repo_field_id_seq OWNER TO postgres; + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_fields_repo_field_id_seq OWNED BY repositories_fields.repo_field_id; + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE repositories_repo_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_repo_id_seq OWNER TO postgres; + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE repositories_repo_id_seq OWNED BY repositories.repo_id; + + +-- +-- Name: rhodecode_settings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_settings ( + app_settings_id integer NOT NULL, + app_settings_name character varying(255), + app_settings_value character varying(255) +); + + +ALTER TABLE public.rhodecode_settings OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_settings_app_settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_settings_app_settings_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_settings_app_settings_id_seq OWNED BY rhodecode_settings.app_settings_id; + + +-- +-- Name: rhodecode_ui; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE rhodecode_ui ( + ui_id integer NOT NULL, + ui_section character varying(255), + ui_key character varying(255), + ui_value character varying(255), + ui_active boolean +); + + +ALTER TABLE public.rhodecode_ui OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE rhodecode_ui_ui_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.rhodecode_ui_ui_id_seq OWNER TO postgres; + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE rhodecode_ui_ui_id_seq OWNED BY rhodecode_ui.ui_id; + + +-- +-- Name: statistics; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE statistics ( + stat_id integer NOT NULL, + repository_id integer NOT NULL, + stat_on_revision integer NOT NULL, + commit_activity bytea NOT NULL, + commit_activity_combined bytea NOT NULL, + languages bytea NOT NULL +); + + +ALTER TABLE public.statistics OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE statistics_stat_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.statistics_stat_id_seq OWNER TO postgres; + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE statistics_stat_id_seq OWNED BY statistics.stat_id; + + +-- +-- Name: user_email_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_email_map ( + email_id integer NOT NULL, + user_id integer, + email character varying(255) +); + + +ALTER TABLE public.user_email_map OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_email_map_email_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_email_map_email_id_seq OWNER TO postgres; + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_email_map_email_id_seq OWNED BY user_email_map.email_id; + + +-- +-- Name: user_followings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_followings ( + user_following_id integer NOT NULL, + user_id integer NOT NULL, + follows_repository_id integer, + follows_user_id integer, + follows_from timestamp without time zone +); + + +ALTER TABLE public.user_followings OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_followings_user_following_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_followings_user_following_id_seq OWNER TO postgres; + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_followings_user_following_id_seq OWNED BY user_followings.user_following_id; + + +-- +-- Name: user_ip_map; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_ip_map ( + ip_id integer NOT NULL, + user_id integer, + ip_addr character varying(255), + active boolean +); + + +ALTER TABLE public.user_ip_map OWNER TO postgres; + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_ip_map_ip_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_ip_map_ip_id_seq OWNER TO postgres; + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_ip_map_ip_id_seq OWNED BY user_ip_map.ip_id; + + +-- +-- Name: user_logs; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_logs ( + user_log_id integer NOT NULL, + user_id integer, + username character varying(255), + repository_id integer, + repository_name character varying(255), + user_ip character varying(255), + action text, + action_date timestamp without time zone +); + + +ALTER TABLE public.user_logs OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_logs_user_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_logs_user_log_id_seq OWNER TO postgres; + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_logs_user_log_id_seq OWNED BY user_logs.user_log_id; + + +-- +-- Name: user_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_repo_group_to_perm ( + group_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_repo_group_to_perm_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_repo_group_to_perm_group_to_perm_id_seq OWNED BY user_repo_group_to_perm.group_to_perm_id; + + +-- +-- Name: user_to_notification; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_notification ( + user_id integer NOT NULL, + notification_id integer NOT NULL, + read boolean, + sent_on timestamp without time zone +); + + +ALTER TABLE public.user_to_notification OWNER TO postgres; + +-- +-- Name: user_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE user_to_perm ( + user_to_perm_id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.user_to_perm OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE user_to_perm_user_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.user_to_perm_user_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE user_to_perm_user_to_perm_id_seq OWNED BY user_to_perm.user_to_perm_id; + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users ( + user_id integer NOT NULL, + username character varying(255), + password character varying(255), + active boolean, + admin boolean, + firstname character varying(255), + lastname character varying(255), + email character varying(255), + last_login timestamp without time zone, + ldap_dn character varying(255), + api_key character varying(255), + inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_group_to_perm ( + users_group_repo_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_group_to_per_users_group_repo_group_to_per_seq OWNED BY users_group_repo_group_to_perm.users_group_repo_group_to_perm_id; + + +-- +-- Name: users_group_repo_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_repo_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL, + repository_id integer NOT NULL +); + + +ALTER TABLE public.users_group_repo_to_perm OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_repo_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_repo_to_perm_users_group_to_perm_id_seq OWNED BY users_group_repo_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_group_to_perm; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_group_to_perm ( + users_group_to_perm_id integer NOT NULL, + users_group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.users_group_to_perm OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_group_to_perm_users_group_to_perm_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_group_to_perm_users_group_to_perm_id_seq OWNER TO postgres; + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_group_to_perm_users_group_to_perm_id_seq OWNED BY users_group_to_perm.users_group_to_perm_id; + + +-- +-- Name: users_groups; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups ( + users_group_id integer NOT NULL, + users_group_name character varying(255) NOT NULL, + users_group_active boolean, + users_group_inherit_default_permissions boolean NOT NULL +); + + +ALTER TABLE public.users_groups OWNER TO postgres; + +-- +-- Name: users_groups_members; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE users_groups_members ( + users_group_member_id integer NOT NULL, + users_group_id integer NOT NULL, + user_id integer NOT NULL +); + + +ALTER TABLE public.users_groups_members OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_members_users_group_member_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_members_users_group_member_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_members_users_group_member_id_seq OWNED BY users_groups_members.users_group_member_id; + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_groups_users_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_groups_users_group_id_seq OWNER TO postgres; + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_groups_users_group_id_seq OWNED BY users_groups.users_group_id; + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE users_user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.users_user_id_seq OWNER TO postgres; + +-- +-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE users_user_id_seq OWNED BY users.user_id; + + +-- +-- Name: cache_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY cache_invalidation ALTER COLUMN cache_id SET DEFAULT nextval('cache_invalidation_cache_id_seq'::regclass); + + +-- +-- Name: comment_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments ALTER COLUMN comment_id SET DEFAULT nextval('changeset_comments_comment_id_seq'::regclass); + + +-- +-- Name: changeset_status_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses ALTER COLUMN changeset_status_id SET DEFAULT nextval('changeset_statuses_changeset_status_id_seq'::regclass); + + +-- +-- Name: group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups ALTER COLUMN group_id SET DEFAULT nextval('groups_group_id_seq'::regclass); + + +-- +-- Name: notification_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications ALTER COLUMN notification_id SET DEFAULT nextval('notifications_notification_id_seq'::regclass); + + +-- +-- Name: permission_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY permissions ALTER COLUMN permission_id SET DEFAULT nextval('permissions_permission_id_seq'::regclass); + + +-- +-- Name: pull_requests_reviewers_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers ALTER COLUMN pull_requests_reviewers_id SET DEFAULT nextval('pull_request_reviewers_pull_requests_reviewers_id_seq'::regclass); + + +-- +-- Name: pull_request_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests ALTER COLUMN pull_request_id SET DEFAULT nextval('pull_requests_pull_request_id_seq'::regclass); + + +-- +-- Name: repo_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm ALTER COLUMN repo_to_perm_id SET DEFAULT nextval('repo_to_perm_repo_to_perm_id_seq'::regclass); + + +-- +-- Name: repo_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories ALTER COLUMN repo_id SET DEFAULT nextval('repositories_repo_id_seq'::regclass); + + +-- +-- Name: repo_field_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories_fields ALTER COLUMN repo_field_id SET DEFAULT nextval('repositories_fields_repo_field_id_seq'::regclass); + + +-- +-- Name: app_settings_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_settings ALTER COLUMN app_settings_id SET DEFAULT nextval('rhodecode_settings_app_settings_id_seq'::regclass); + + +-- +-- Name: ui_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY rhodecode_ui ALTER COLUMN ui_id SET DEFAULT nextval('rhodecode_ui_ui_id_seq'::regclass); + + +-- +-- Name: stat_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics ALTER COLUMN stat_id SET DEFAULT nextval('statistics_stat_id_seq'::regclass); + + +-- +-- Name: email_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map ALTER COLUMN email_id SET DEFAULT nextval('user_email_map_email_id_seq'::regclass); + + +-- +-- Name: user_following_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings ALTER COLUMN user_following_id SET DEFAULT nextval('user_followings_user_following_id_seq'::regclass); + + +-- +-- Name: ip_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_ip_map ALTER COLUMN ip_id SET DEFAULT nextval('user_ip_map_ip_id_seq'::regclass); + + +-- +-- Name: user_log_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs ALTER COLUMN user_log_id SET DEFAULT nextval('user_logs_user_log_id_seq'::regclass); + + +-- +-- Name: group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm ALTER COLUMN group_to_perm_id SET DEFAULT nextval('user_repo_group_to_perm_group_to_perm_id_seq'::regclass); + + +-- +-- Name: user_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm ALTER COLUMN user_to_perm_id SET DEFAULT nextval('user_to_perm_user_to_perm_id_seq'::regclass); + + +-- +-- Name: user_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users ALTER COLUMN user_id SET DEFAULT nextval('users_user_id_seq'::regclass); + + +-- +-- Name: users_group_repo_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm ALTER COLUMN users_group_repo_group_to_perm_id SET DEFAULT nextval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_repo_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_to_perm_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm ALTER COLUMN users_group_to_perm_id SET DEFAULT nextval('users_group_to_perm_users_group_to_perm_id_seq'::regclass); + + +-- +-- Name: users_group_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups ALTER COLUMN users_group_id SET DEFAULT nextval('users_groups_users_group_id_seq'::regclass); + + +-- +-- Name: users_group_member_id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members ALTER COLUMN users_group_member_id SET DEFAULT nextval('users_groups_members_users_group_member_id_seq'::regclass); + + +-- +-- Data for Name: cache_invalidation; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY cache_invalidation (cache_id, cache_key, cache_args, cache_active) FROM stdin; +1 1RC/mygr/lol RC/mygr/lol f +2 1RC/fakeclone RC/fakeclone t +3 1RC/muay RC/muay f +4 1BIG/git BIG/git t +5 1RC/origin-fork RC/origin-fork f +6 1one one f +7 1rhodecode.bak.1 rhodecode.bak.1 f +8 1csa-collins csa-collins t +9 1csa-harmony csa-harmony t +10 1RC/ąqweqwe RC/ąqweqwe f +11 1rhodecode rhodecode f +12 1csa-unity csa-unity t +13 1RC/łęcina RC/łęcina f +14 1waitress waitress t +15 1RC/rc2/test2 RC/rc2/test2 t +16 1RC/origin-fork-fork RC/origin-fork-fork f +17 1RC/rc2/test4 RC/rc2/test4 t +18 1RC/vcs-git RC/vcs-git t +19 1rhodecode-extensions rhodecode-extensions f +20 1rhodecode-cli-gist rhodecode-cli-gist f +21 1test.onaut.com test.onaut.com t +22 1RC/new RC/new f +23 1csa-aldrin csa-aldrin t +24 1vcs vcs f +25 1csa-prometheus csa-prometheus t +26 1RC/INRC/trololo RC/INRC/trololo f +27 1RC/empty-git RC/empty-git t +28 1csa-salt-states csa-salt-states t +29 1rhodecode-premium rhodecode-premium f +30 1RC/qweqwe-fork RC/qweqwe-fork f +31 1testrepo-quick testrepo-quick t +32 1RC/test RC/test f +33 1remote-salt remote-salt t +34 1BIG/android BIG/android t +35 1DOCS DOCS t +36 1rhodecode-git rhodecode-git t +37 1RC/bin-ops RC/bin-ops f +38 1RC/INRC/L2_NEW/lalalal RC/INRC/L2_NEW/lalalal f +39 1RC/fork-remote RC/fork-remote f +40 1RC/INRC/L2_NEW/L3/repo_test_move RC/INRC/L2_NEW/L3/repo_test_move f +41 1RC/gogo-fork RC/gogo-fork f +42 1quest quest f +43 1RC/foobar RC/foobar f +44 1csa-hyperion csa-hyperion t +45 1RC/git-pull-test RC/git-pull-test t +46 1RC/qweqwe-fork2 RC/qweqwe-fork2 f +47 1RC/jap RC/jap t +48 1RC/hg-repo RC/hg-repo f +49 1RC/origin RC/origin f +50 1rhodecode-cli-api rhodecode-cli-api f +51 1RC/rc2/test3 RC/rc2/test3 t +52 1csa-armstrong csa-armstrong t +53 1RC/trololo RC/trololo f +54 1testrepo-wp testrepo-wp t +55 1pyramidpypi pyramidpypi t +56 1salt salt t +57 1RC/lol/haha RC/lol/haha f +58 1csa-io csa-io t +59 1enc-envelope enc-envelope f +60 1RC/gogo2 RC/gogo2 f +61 1csa-libcloud csa-libcloud t +62 1RC/git-test RC/git-test t +63 1RC/rc2/test RC/rc2/test f +64 1rhodecode.bak rhodecode.bak f +65 1RC/kiall-nova RC/kiall-nova t +\. + + +-- +-- Name: cache_invalidation_cache_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('cache_invalidation_cache_id_seq', 65, true); + + +-- +-- Data for Name: changeset_comments; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_comments (comment_id, repo_id, revision, pull_request_id, line_no, hl_lines, f_path, user_id, text, created_on, modified_at) FROM stdin; +\. + + +-- +-- Name: changeset_comments_comment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_comments_comment_id_seq', 1, false); + + +-- +-- Data for Name: changeset_statuses; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY changeset_statuses (changeset_status_id, repo_id, user_id, revision, status, changeset_comment_id, modified_at, version, pull_request_id) FROM stdin; +\. + + +-- +-- Name: changeset_statuses_changeset_status_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('changeset_statuses_changeset_status_id_seq', 1, false); + + +-- +-- Data for Name: db_migrate_version; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY db_migrate_version (repository_id, repository_path, version) FROM stdin; +rhodecode_db_migrations versions 11 +\. + + +-- +-- Data for Name: groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY groups (group_id, group_name, group_parent_id, group_description, enable_locking) FROM stdin; +1 RC \N RC group f +2 RC/mygr 1 RC/mygr group f +3 BIG \N BIG group f +4 RC/rc2 1 RC/rc2 group f +5 RC/INRC 1 RC/INRC group f +6 RC/INRC/L2_NEW 5 RC/INRC/L2_NEW group f +7 RC/INRC/L2_NEW/L3 6 RC/INRC/L2_NEW/L3 group f +8 RC/lol 1 RC/lol group f +\. + + +-- +-- Name: groups_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('groups_group_id_seq', 8, true); + + +-- +-- Data for Name: notifications; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY notifications (notification_id, subject, body, created_by, created_on, type) FROM stdin; +\. + + +-- +-- Name: notifications_notification_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('notifications_notification_id_seq', 1, false); + + +-- +-- Data for Name: permissions; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY permissions (permission_id, permission_name, permission_longname) FROM stdin; +1 repository.none repository.none +2 repository.read repository.read +3 repository.write repository.write +4 repository.admin repository.admin +5 group.none group.none +6 group.read group.read +7 group.write group.write +8 group.admin group.admin +9 hg.admin hg.admin +10 hg.create.none hg.create.none +11 hg.create.repository hg.create.repository +12 hg.fork.none hg.fork.none +13 hg.fork.repository hg.fork.repository +14 hg.register.none hg.register.none +15 hg.register.manual_activate hg.register.manual_activate +16 hg.register.auto_activate hg.register.auto_activate +\. + + +-- +-- Name: permissions_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('permissions_permission_id_seq', 16, true); + + +-- +-- Data for Name: pull_request_reviewers; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_request_reviewers (pull_requests_reviewers_id, pull_request_id, user_id) FROM stdin; +\. + + +-- +-- Name: pull_request_reviewers_pull_requests_reviewers_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_request_reviewers_pull_requests_reviewers_id_seq', 1, false); + + +-- +-- Data for Name: pull_requests; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY pull_requests (pull_request_id, title, description, status, created_on, updated_on, user_id, revisions, org_repo_id, org_ref, other_repo_id, other_ref) FROM stdin; +\. + + +-- +-- Name: pull_requests_pull_request_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('pull_requests_pull_request_id_seq', 1, false); + + +-- +-- Data for Name: repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repo_to_perm (repo_to_perm_id, user_id, permission_id, repository_id) FROM stdin; +1 1 2 1 +2 1 2 2 +3 1 2 3 +4 1 2 4 +5 1 2 5 +6 1 2 6 +7 1 2 7 +8 1 2 8 +9 1 2 9 +10 1 2 10 +11 1 2 11 +12 1 2 12 +13 1 2 13 +14 1 2 14 +15 1 2 15 +16 1 2 16 +17 1 2 17 +18 1 2 18 +19 1 2 19 +20 1 2 20 +21 1 2 21 +22 1 2 22 +23 1 2 23 +24 1 2 24 +25 1 2 25 +26 1 2 26 +27 1 2 27 +28 1 2 28 +29 1 2 29 +30 1 2 30 +31 1 2 31 +32 1 2 32 +33 1 2 33 +34 1 2 34 +35 1 2 35 +36 1 2 36 +37 1 2 37 +38 1 2 38 +39 1 2 39 +40 1 2 40 +41 1 2 41 +42 1 2 42 +43 1 2 43 +44 1 2 44 +45 1 2 45 +46 1 2 46 +47 1 2 47 +48 1 2 48 +49 1 2 49 +50 1 2 50 +51 1 2 51 +52 1 2 52 +53 1 2 53 +54 1 2 54 +55 1 2 55 +56 1 2 56 +57 1 2 57 +58 1 2 58 +59 1 2 59 +60 1 2 60 +61 1 2 61 +62 1 2 62 +63 1 2 63 +64 1 2 64 +65 1 2 65 +\. + + +-- +-- Name: repo_to_perm_repo_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repo_to_perm_repo_to_perm_id_seq', 65, true); + + +-- +-- Data for Name: repositories; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories (repo_id, repo_name, clone_uri, repo_type, user_id, private, statistics, downloads, description, created_on, updated_on, landing_revision, enable_locking, locked, changeset_cache, fork_id, group_id) FROM stdin; +1 RC/mygr/lol http://user@vm/RC/mygr/lol hg 2 f f f RC/mygr/lol repository 2013-05-28 20:26:59.886314 2013-05-28 20:26:59.886502 tip f \N \N \N 2 +2 RC/fakeclone \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:26:59.94415 2013-05-09 01:48:00 tip f \N \\x7b227261775f6964223a202264666137643337363737386436383164313831386634316231373730366566613630333362343037222c202273686f72745f6964223a2022646661376433373637373864222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30395430313a34383a3030222c20226d657373616765223a202266697865645c6e222c20227265766973696f6e223a203239337d \N 1 +3 RC/muay \N hg 2 f f f RC/muay repository 2013-05-28 20:27:00.114841 2013-05-28 20:27:00.114864 tip f \N \N \N 1 +4 BIG/git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:00.171891 2012-10-21 23:47:54 tip f \N \\x7b227261775f6964223a202233306634633636653633343736306138316162323761323336666531663234383266366637383536222c202273686f72745f6964223a2022333066346336366536333437222c2022617574686f72223a20224a756e696f20432048616d616e6f203c6769747374657240706f626f782e636f6d3e222c202264617465223a2022323031322d31302d32315432333a34373a3534222c20226d657373616765223a202257686174277320636f6f6b696e672028323031322f313020233037295c6e222c20227265766973696f6e223a2033323136307d \N 3 +5 RC/origin-fork \N hg 2 f f f RC/origin-fork repository 2013-05-28 20:27:01.457264 2013-03-06 20:16:20 tip f \N \\x7b227261775f6964223a202266306365333961366639656466633633393264346436313337663035626233383731653431373830222c202273686f72745f6964223a2022663063653339613666396564222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d30365432303a31363a3230222c20226d657373616765223a20224564697465642066696c6520766961206f7074696f6e735c6e2d20666978656420315c6e2d66207869656420325c6e616e6420736f206f6e20736f206f6e207472616c6c616c616c61222c20227265766973696f6e223a2032317d \N 1 +6 one \N hg 2 f f f one repository 2013-05-28 20:27:01.525404 2013-05-23 12:11:57 tip f \N \\x7b227261775f6964223a202233393435643961623264396533323262623666643561613763333461316530313132326265343662222c202273686f72745f6964223a2022333934356439616232643965222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d32335431323a31313a3537222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N \N +7 rhodecode.bak.1 \N hg 2 f f f rhodecode.bak.1 repository 2013-05-28 20:27:01.578685 2013-05-28 14:44:56 tip f \N \\x7b227261775f6964223a202232336637333938396439323230343636666239646237633635316431336162663637393666373663222c202273686f72745f6964223a2022323366373339383964393232222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385431343a34343a3536222c20226d657373616765223a20226d657267652064657620696e746f2072686f6465636f64652d70616d222c20227265766973696f6e223a20343034307d \N \N +8 csa-collins \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:01.645073 2013-02-25 17:31:39 tip f \N \\x7b227261775f6964223a202238626536613130643634356338646461356631663333313439363232383131386165383732636538222c202273686f72745f6964223a2022386265366131306436343563222c2022617574686f72223a20224261737469616e20416c62657273203c696e666f406261737469616e616c626572732e64653e222c202264617465223a2022323031332d30322d32355431373a33313a3339222c20226d657373616765223a20224d65726765206272616e6368202773746167652720696e746f207374616765325c6e222c20227265766973696f6e223a20323733317d \N \N +9 csa-harmony \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:01.870853 2013-05-22 14:49:45 tip f \N \\x7b227261775f6964223a202232376235393630333631386230373235396361306462366230303939306665656261393639333066222c202273686f72745f6964223a2022323762353936303336313862222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32325431343a34393a3435222c20226d657373616765223a20224164646564206b776172677320746f2073657475702066756e6374696f6e7320666f72206c61746572206f7074696f6e616c20706172616d735c6e222c20227265766973696f6e223a203333397d \N \N +10 RC/ąqweqwe \N hg 2 f f f RC/ąqweqwe repository 2013-05-28 20:27:02.376512 2013-05-28 20:27:02.376535 tip f \N \N \N 1 +11 rhodecode \N hg 2 f f f rhodecode repository 2013-05-28 20:27:02.424079 2013-05-28 20:16:08 tip f \N \\x7b227261775f6964223a202237613161333935356434343661343664353235663034326265373339343161303231323266633332222c202273686f72745f6964223a2022376131613339353564343436222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385432303a31363a3038222c20226d657373616765223a20226d6967726174696f6e20746f20312e372e30222c20227265766973696f6e223a20343034357d \N \N +12 csa-unity \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.495342 2013-04-29 14:38:23 tip f \N \\x7b227261775f6964223a202230393337303837353965626634666432626231626463616436316662363131626333323933336433222c202273686f72745f6964223a2022303933373038373539656266222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32395431343a33383a3233222c20226d657373616765223a202272657665727420746f206c6f67626f6f6b20302e332e30222c20227265766973696f6e223a2032387d \N \N +13 RC/łęcina \N hg 2 f f f RC/łęcina repository 2013-05-28 20:27:02.664128 2013-03-06 16:17:49 tip f \N \\x7b227261775f6964223a202231656535383962636661393231326335313130656135633166653263633866663665616631333033222c202273686f72745f6964223a2022316565353839626366613932222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d30365431363a31373a3439222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N 1 +14 waitress \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.721063 2013-05-28 13:21:35 tip f \N \\x7b227261775f6964223a202265356431333863653366373534653630333165376162643736653566353237333633666461663432222c202273686f72745f6964223a2022653564313338636533663735222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385431333a32313a3335222c20226d657373616765223a2022416464656420646f637320616e64206e657720666c616720696e746f2072756e6e65725c6e222c20227265766973696f6e223a203237327d \N \N +15 RC/rc2/test2 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:02.896717 2013-03-03 00:29:35 tip f \N \\x7b227261775f6964223a202230656233333034666333336430356433323866383632376239616434346461653833663331336132222c202273686f72745f6964223a2022306562333330346663333364222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30335430303a32393a3335222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e202066697820726571756573747320312e31206a736f6e206d6574686f645c6e202066697865642074657374735c6e20206d6f76656420746573747320696e746f207061636b6167655c6e20202d62756d7020646973747269627574655c6e2020757064617465202e67697469676e6f72655c6e202076657273696f6e20667265657a65206f66206c6962735c6e202072656d6f766520676576656e742066726f6d20494f20617320646570656e64656e63795c6e202061646420756e69747920617320646570735c6e202066756c6c792064656c65676174652041555448206261636b20746f2061726d7374726f6e675c6e222c20227265766973696f6e223a2035307d \N 4 +16 RC/origin-fork-fork \N hg 2 f f f RC/origin-fork-fork repository 2013-05-28 20:27:03.013741 2013-05-06 23:44:50 tip f \N \\x7b227261775f6964223a202236643939653064346466636334613561666135633133386665613230393834373036333466373733222c202273686f72745f6964223a2022366439396530643464666363222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d30365432333a34343a3530222c20226d657373616765223a20224973737565202331373039343a20436c656172207374616c65207468726561642073746174657320616674657220666f726b28292e5c6e5c6e4e6f746520746861742074686973206973206120706f74656e7469616c6c792064697372757074697665206368616e67652073696e6365206974206d61795c6e72656c6561736520736f6d652073797374656d207265736f757263657320776869636820776f756c64206f74686572776973652072656d61696e5c6e70657270657475616c6c7920616c6976652028652e672e20646174616261736520636f6e6e656374696f6e73206b65707420696e207468726561642d6c6f63616c5c6e73746f72616765292e222c20227265766973696f6e223a2032357d \N 1 +17 RC/rc2/test4 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.077195 2013-03-21 22:55:29 tip f \N \\x7b227261775f6964223a202233623661633766356539333264346464313338373161306232336436636139383531306438386332222c202273686f72745f6964223a2022336236616337663565393332222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30332d32315432323a35353a3239222c20226d657373616765223a2022647361646173222c20227265766973696f6e223a2035317d \N 4 +18 RC/vcs-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.207037 2013-04-26 23:34:15 tip f \N \\x7b227261775f6964223a202239306461316636396136633630663764346435363436656533396163356636313038626330373763222c202273686f72745f6964223a2022393064613166363961366336222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32365432333a33343a3135222c20226d657373616765223a20226d65726765207769746820474954207663735c6e222c20227265766973696f6e223a203634387d \N 1 +19 rhodecode-extensions \N hg 2 f f f rhodecode-extensions repository 2013-05-28 20:27:03.363473 2013-02-13 16:50:33 tip f \N \\x7b227261775f6964223a202264613765356637613339643332303366663062346166353031386163346138306439346564316434222c202273686f72745f6964223a2022646137653566376133396433222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30322d31335431363a35303a3333222c20226d657373616765223a20224c696e6b6966792068697063686174206d65737361676573222c20227265766973696f6e223a20327d \N \N +20 rhodecode-cli-gist \N hg 2 f f f rhodecode-cli-gist repository 2013-05-28 20:27:03.415835 2013-05-28 20:27:03.415858 tip f \N \N \N \N +21 test.onaut.com \N git 2 f f f Unnamed repository 2013-05-28 20:27:03.46164 2013-04-29 11:08:31 tip f \N \\x7b227261775f6964223a202236666465656664323034633461656637636263623966656563646564313436373364383563663230222c202273686f72745f6964223a2022366664656566643230346334222c2022617574686f72223a2022596f7572204e616d65203c796f75406578616d706c652e636f6d3e222c202264617465223a2022323031332d30342d32395431313a30383a3331222c20226d657373616765223a2022666f6f6261725c6e222c20227265766973696f6e223a20307d \N \N +22 RC/new \N hg 2 f f f RC/new repository 2013-05-28 20:27:03.580255 2013-04-17 13:02:59 tip f \N \\x7b227261775f6964223a202239333139326530336133353532623864613466656534306530303163363033303437323362623432222c202273686f72745f6964223a2022393331393265303361333535222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d31375431333a30323a3539222c20226d657373616765223a202272656e616d65222c20227265766973696f6e223a20317d \N 1 +46 RC/qweqwe-fork2 \N hg 2 f f f RC/qweqwe-fork2 repository 2013-05-28 20:27:17.359662 2013-05-28 20:27:17.359684 tip f \N \N \N 1 +23 csa-aldrin \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.639793 2013-05-02 23:47:52 tip f \N \\x7b227261775f6964223a202236376565396538333063323235393231656331353937346163316466646531376139333065326662222c202273686f72745f6964223a2022363765653965383330633232222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30325432333a34373a3532222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e20206d6f76656420676576656e7420696e746f206f757420696e7465726e616c207365727665725c6e202073747570696420617373686f6c657320696e20676576656e742073686f756c64206c6561726e20686f7720746f207061636b6167652e2e2e5c6e2020666978656420676576656e7420646570656e64656e6379206c696e6b5c6e202061646465642073657061726174652063616c6c20666f722073657373696f6e2076616c69646174696f6e5c6e222c20227265766973696f6e223a203239337d \N \N +24 vcs \N hg 2 f f f vcs repository 2013-05-28 20:27:03.856575 2013-05-09 00:28:54 tip f \N \\x7b227261775f6964223a202236666261353966396637383036613534356130653565626163393336393931383238343336323630222c202273686f72745f6964223a2022366662613539663966373830222c2022617574686f72223a20224c756b61737a2042616c6365727a616b203c6c756b61737a62616c6365727a616b40676d61696c2e636f6d3e222c202264617465223a2022323031332d30352d30395430303a32383a3534222c20226d657373616765223a20224d657267652070756c6c207265717565737420233131372066726f6d206e69656462616c736b692f6d61737465725c6e5c6e4b65794572726f723a2027616c6c27222c20227265766973696f6e223a203730377d \N \N +25 csa-prometheus \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:03.916977 2013-04-29 14:37:43 tip f \N \\x7b227261775f6964223a202261373139626438326432356537343131666462373937396331326330383366353961323036613663222c202273686f72745f6964223a2022613731396264383264323565222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32395431343a33373a3433222c20226d657373616765223a2022726576657274206c6f67626f6f6b20746f20302e332e30222c20227265766973696f6e223a2037397d \N \N +26 RC/INRC/trololo \N hg 2 f f f RC/INRC/trololo repository 2013-05-28 20:27:04.096413 2013-05-28 20:27:04.096437 tip f \N \N \N 5 +27 RC/empty-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.148472 2013-05-28 20:27:04.148509 tip f \N \N \N 1 +28 csa-salt-states \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.212846 2013-05-06 14:48:48 tip f \N \\x7b227261775f6964223a202230633230646337326261656564633363653834306336313131373463376531636433623034393139222c202273686f72745f6964223a2022306332306463373262616565222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30365431343a34383a3438222c20226d657373616765223a2022696e6372656173652073616d706c696e67206f66204350552074696d6520746f20302e357320666f72206d6f7265207265616c697374696320646174612e222c20227265766973696f6e223a2037317d \N \N +29 rhodecode-premium \N hg 2 f f f rhodecode-premium repository 2013-05-28 20:27:04.419538 2013-03-21 22:58:11 tip f \N \\x7b227261775f6964223a202264656433356266303137663136626361643636313163376666653362316231633130393432663530222c202273686f72745f6964223a2022646564333562663031376631222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d32315432323a35383a3131222c20226d657373616765223a202276657273696f6e2062756d7020746f20312e352e347032222c20227265766973696f6e223a20333637347d \N \N +30 RC/qweqwe-fork \N hg 2 f f f RC/qweqwe-fork repository 2013-05-28 20:27:04.494164 2013-05-28 20:27:04.494188 tip f \N \N \N 1 +31 testrepo-quick \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.547757 2012-08-31 11:34:33 tip f \N \\x7b227261775f6964223a202236303763396632336633373731626633353731346639626166353539666433313138366432353930222c202273686f72745f6964223a2022363037633966323366333737222c2022617574686f72223a202253656261737469616e204b726575747a626572676572203c73656261737469616e406170707a6f6e6175742e636f6d3e222c202264617465223a2022323031322d30382d33315431313a33343a3333222c20226d657373616765223a20226164646564207465737420666f72202e617a2d7368617265642066696c655c6e222c20227265766973696f6e223a2031327d \N \N +32 RC/test \N hg 2 f f f RC/test repository 2013-05-28 20:27:04.697514 2013-01-30 22:56:03 tip f \N \\x7b227261775f6964223a202265353032356533313664396163623339653566383631633439343234306265346635643536646536222c202273686f72745f6964223a2022653530323565333136643961222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e406d61712e696f3e222c202264617465223a2022323031332d30312d33305432323a35363a3033222c20226d657373616765223a20223c7363726970743e616c65727428277873733227293b3c2f7363726970743e202066697865732023373030222c20227265766973696f6e223a20327d \N 1 +33 remote-salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.750525 2012-10-14 22:04:05 tip f \N \\x7b227261775f6964223a202264363631646337323439326536366361623761363437646362353635323030393036376161386364222c202273686f72745f6964223a2022643636316463373234393265222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031322d31302d31345432323a30343a3035222c20226d657373616765223a20224c6f6767696e675c6e4f6e2d7468652d666c79206d736720656e6372797074696f6e207573696e6720676f6f676c6573206b6579437a6172206c6962222c20227265766973696f6e223a20337d \N \N +34 BIG/android \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:04.869224 2012-06-17 00:44:46 tip f \N \\x7b227261775f6964223a202265383662313437653462363930386137633561623039363364373766623038363736373962316565222c202273686f72745f6964223a2022653836623134376534623639222c2022617574686f72223a20224265726e6861726420526f73656e6b7261656e7a6572203c4265726e686172642e526f73656e6b72616e7a6572406c696e61726f2e6f72673e222c202264617465223a2022323031322d30362d31375430303a34343a3436222c20226d657373616765223a202270616e64613a204261636b706f72742048444d492076732e204456492070617463682066726f6d206b65726e656c2f70616e64612e6769745c6e5c6e5468697320706174636820616c6c6f777320737769746368696e6720746865207072696d61727920646973706c6179206f7574707574206465766963652e5c6e5c6e4368616e67652d49643a2049366533306538376262633761613732623561636336653663346564333430313938333565363532345c6e5369676e65642d6f66662d62793a204265726e6861726420526f73656e6b7261656e7a6572203c4265726e686172642e526f73656e6b72616e7a6572406c696e61726f2e6f72673e5c6e222c20227265766973696f6e223a203239343839367d \N 3 +35 DOCS \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:16.065483 2013-04-25 16:45:59 tip f \N \\x7b227261775f6964223a202231653461373238656537613661613838626531313236306436343739613434366562383635646533222c202273686f72745f6964223a2022316534613732386565376136222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32355431363a34353a3539222c20226d657373616765223a202273796e6320646f637320776974682061726d7374726f6e67222c20227265766973696f6e223a2031357d \N \N +36 rhodecode-git \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:16.225335 2013-01-04 00:24:22 tip f \N \\x7b227261775f6964223a202236323966313533386164343830306666303531313335313666366139333365326232343366323035222c202273686f72745f6964223a2022363239663135333861643438222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30312d30345430303a32343a3232222c20226d657373616765223a20226e6963657220726570726573656e746174696f6e206f66206c697374206f662072657363616e6e6564207265706f7369746f726965735c6e5c6e2d2d48472d2d5c6e6272616e6368203a20626574615c6e222c20227265766973696f6e223a20333134327d \N \N +37 RC/bin-ops \N hg 2 f f f RC/bin-ops repository 2013-05-28 20:27:16.463774 2013-05-12 12:39:34 tip f \N \\x7b227261775f6964223a202234323331373632643863316161636135626533646231353939313037313233366333326537363534222c202273686f72745f6964223a2022343233313736326438633161222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d31325431323a33393a3334222c20226d657373616765223a20224564697465642066696c652066696c6531207669612052686f6465436f6465222c20227265766973696f6e223a2032337d \N 1 +38 RC/INRC/L2_NEW/lalalal \N hg 2 f f f RC/INRC/L2_NEW/lalalal repository 2013-05-28 20:27:16.555625 2013-05-28 20:27:16.55565 tip f \N \N \N 6 +39 RC/fork-remote \N hg 2 f f f RC/fork-remote repository 2013-05-28 20:27:16.622524 2013-03-10 22:47:24 tip f \N \\x7b227261775f6964223a202236303535353438346130613064366535323565396437616231623164636535616239656239343837222c202273686f72745f6964223a2022363035353534383461306130222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d31305432323a34373a3234222c20226d657373616765223a2022616161222c20227265766973696f6e223a2032367d \N 1 +40 RC/INRC/L2_NEW/L3/repo_test_move \N hg 2 f f f RC/INRC/L2_NEW/L3/repo_test_move repository 2013-05-28 20:27:16.717095 2013-05-28 20:27:16.717133 tip f \N \N \N 7 +41 RC/gogo-fork \N hg 2 f f f RC/gogo-fork repository 2013-05-28 20:27:16.790103 2013-05-28 20:27:16.790129 tip f \N \N \N 1 +42 quest \N hg 2 f f f quest repository 2013-05-28 20:27:16.858741 2013-03-04 23:01:40 tip f \N \\x7b227261775f6964223a202235346230316366646561323562663431636438653961313834633538353263356434386438363463222c202273686f72745f6964223a2022353462303163666465613235222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30345432333a30313a3430222c20226d657373616765223a202274656d706c61746520616e642076657273696f6e20302e302e31222c20227265766973696f6e223a2034317d \N \N +43 RC/foobar \N hg 2 f f f RC/foobar repository 2013-05-28 20:27:16.930525 2013-04-15 21:34:57 tip f \N \\x7b227261775f6964223a202263313764633363353636393532383133653834303337646664363261343735356564336339313263222c202273686f72745f6964223a2022633137646333633536363935222c2022617574686f72223a20224d6972656b204b6f7474203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30342d31355432313a33343a3537222c20226d657373616765223a20224564697465642066696c65206c6f6c2e727374207669612052686f6465436f6465222c20227265766973696f6e223a20317d \N 1 +44 csa-hyperion \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.021283 2013-05-20 21:58:28 tip f \N \\x7b227261775f6964223a202232353263393236643130373032653665663763323435366632666332333839323830386535336130222c202273686f72745f6964223a2022323532633932366431303730222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32305432313a35383a3238222c20226d657373616765223a2022666978657320666f72206e657720636f64655c6e222c20227265766973696f6e223a2035377d \N \N +45 RC/git-pull-test \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.231975 2013-05-20 13:03:02 tip f \N \\x7b227261775f6964223a202262326366313133366630396661363164663930343639623433333130363135393834626337643535222c202273686f72745f6964223a2022623263663131333666303966222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32305431333a30333a3032222c20226d657373616765223a202261646465645c6e222c20227265766973696f6e223a2031337d \N 1 +47 RC/jap \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.427862 2013-04-24 11:15:30 tip f \N \\x7b227261775f6964223a202232663632636532323435336136376565666436666162316434653035333532306538646562646636222c202273686f72745f6964223a2022326636326365323234353361222c2022617574686f72223a202244656d6f2055736572203c64656d6f4072686f6465636f64652e6f72673e222c202264617465223a2022323031332d30342d32345431313a31353a3330222c20226d657373616765223a20225c75333064355c75333061315c75333061345c75333065625c75386666645c7535326130222c20227265766973696f6e223a20357d \N 1 +48 RC/hg-repo \N hg 2 f f f RC/hg-repo repository 2013-05-28 20:27:17.558936 2013-05-08 22:54:45 tip f \N \\x7b227261775f6964223a202264363364343065386230363835616636646235663263663737303065383032313661663563373339222c202273686f72745f6964223a2022643633643430653862303638222c2022617574686f72223a202252686f6465436f64652041646d696e203c6d617263696e40707974686f6e2d626c6f672e636f6d3e222c202264617465223a2022323031332d30352d30385432323a35343a3435222c20226d657373616765223a20224564697465642066696c652068616861207669612052686f6465436f6465222c20227265766973696f6e223a2032357d \N 1 +49 RC/origin \N hg 2 f f f RC/origin repository 2013-05-28 20:27:17.634344 2013-04-05 13:05:02 tip f \N \\x7b227261775f6964223a202235666266326630656164613433626333336139346534383335303333333564386636373537303933222c202273686f72745f6964223a2022356662663266306561646134222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d30355431333a30353a3032222c20226d657373616765223a20226669786564222c20227265766973696f6e223a2032397d \N 1 +50 rhodecode-cli-api \N hg 2 f f f rhodecode-cli-api repository 2013-05-28 20:27:17.708944 2013-05-28 20:27:17.708995 tip f \N \N \N \N +51 RC/rc2/test3 \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.781161 2013-03-03 00:29:35 tip f \N \\x7b227261775f6964223a202230656233333034666333336430356433323866383632376239616434346461653833663331336132222c202273686f72745f6964223a2022306562333330346663333364222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30335430303a32393a3335222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e202066697820726571756573747320312e31206a736f6e206d6574686f645c6e202066697865642074657374735c6e20206d6f76656420746573747320696e746f207061636b6167655c6e20202d62756d7020646973747269627574655c6e2020757064617465202e67697469676e6f72655c6e202076657273696f6e20667265657a65206f66206c6962735c6e202072656d6f766520676576656e742066726f6d20494f20617320646570656e64656e63795c6e202061646420756e69747920617320646570735c6e202066756c6c792064656c65676174652041555448206261636b20746f2061726d7374726f6e675c6e222c20227265766973696f6e223a2035307d \N 4 +52 csa-armstrong \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:17.898234 2013-05-22 18:10:20 tip f \N \\x7b227261775f6964223a202236306666613230313866613132306339376330633566636162393365636438326532633361363931222c202273686f72745f6964223a2022363066666132303138666131222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32325431383a31303a3230222c20226d657373616765223a20226669782061637475616c2070726f677265737320696e63726561736520696e2073616c742063616c6c735c6e222c20227265766973696f6e223a20313134307d \N \N +53 RC/trololo \N hg 2 f f f RC/trololo repository 2013-05-28 20:27:18.620592 2013-03-28 02:35:50 tip f \N \\x7b227261775f6964223a202238393064373436396162616333363036333763386366373966313538623137303431356531363533222c202273686f72745f6964223a2022383930643734363961626163222c2022617574686f72223a202264656d6f2075736572203c6d617263696e406d61712e696f3e222c202264617465223a2022323031332d30332d32385430323a33353a3530222c20226d657373616765223a202241646465642066696c65207669612052686f6465436f6465222c20227265766973696f6e223a20307d \N 1 +54 testrepo-wp \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:18.695645 2012-08-27 11:05:37 tip f \N \\x7b227261775f6964223a202264393461663531633130313032303433306132386463616561313135336464643932326332396563222c202273686f72745f6964223a2022643934616635316331303130222c2022617574686f72223a202253656261737469616e204b726575747a626572676572203c73656261737469616e406170707a6f6e6175742e636f6d3e222c202264617465223a2022323031322d30382d32375431313a30353a3337222c20226d657373616765223a2022757064617465642063726564735c6e222c20227265766973696f6e223a20377d \N \N +55 pyramidpypi \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:18.824235 2013-04-25 16:34:48 tip f \N \\x7b227261775f6964223a202265643961636566666164613365663338353039633564373031306230313662613435653832393434222c202273686f72745f6964223a2022656439616365666661646133222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d32355431363a33343a3438222c20226d657373616765223a202276657273696f6e2062756d70222c20227265766973696f6e223a2032387d \N \N +56 salt \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.036099 2012-10-15 05:20:58 tip f \N \\x7b227261775f6964223a202262643434383332323330666331396562383066653439656630316261646234373765663863613663222c202273686f72745f6964223a2022626434343833323233306663222c2022617574686f72223a202254686f6d61732053204861746368203c746861746368343540676d61696c2e636f6d3e222c202264617465223a2022323031322d31302d31355430353a32303a3538222c20226d657373616765223a20224d657267652070756c6c20726571756573742023323234342066726f6d2046697265486f73742f746f706c6576656c5f776d695f696d706f72745c6e5c6e546f706c6576656c20776d6920696d706f7274222c20227265766973696f6e223a20363935377d \N \N +57 RC/lol/haha \N hg 2 f f f RC/lol/haha repository 2013-05-28 20:27:19.44935 2013-05-28 20:27:19.449372 tip f \N \N \N 8 +58 csa-io \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.531664 2013-05-02 22:52:54 tip f \N \\x7b227261775f6964223a202262643065663731666366643038386138326238363237653630616161316632303230656433336261222c202273686f72745f6964223a2022626430656637316663666430222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d30325432323a35323a3534222c20226d657373616765223a20224d65726765206272616e636820277374616765275c6e5c6e2a2073746167653a5c6e2020557365206578745f6a736f6e20696e7374656164206f6620706c61696e2073696d706c656a736f6e2073657269616c697a65725c6e20206c6f67206572726f7273206f6e207265737466756c6c206a736f6e20706172736572732f6465636f646572735c6e2020666978656420736f6d652073657269616c697a6174696f6e2070726f626c656d735c6e202076657273696f6e2062756d705c6e20205265706f7369746f7279207265766973696f6e73204150495c6e20206d657263757269616c2076657273696f6e2062756d705c6e202042756d70205643532076657273696f6e20746f20302e342e3020616e64206d6f766520697420746f20636f64652e6170707a6f6e6175742e636f6d5c6e2020666978206c6f6767696e67206f6e206368616e676573206a736f6e206d6f64756c6520696e20726571756573747320312e585c6e222c20227265766973696f6e223a2035397d \N \N +59 enc-envelope \N hg 2 f f f enc-envelope repository 2013-05-28 20:27:19.74793 2013-03-07 15:37:40 tip f \N \\x7b227261775f6964223a202238313030363666383335643663303832393530666337383238646564353062396238643963323239222c202273686f72745f6964223a2022383130303636663833356436222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d30375431353a33373a3430222c20226d657373616765223a202273686f77206d6f72652064657461696c656420696e666f2061626f75742077726f6e672073747265616d222c20227265766973696f6e223a20357d \N \N +60 RC/gogo2 \N hg 2 f f f RC/gogo2 repository 2013-05-28 20:27:19.827312 2013-05-28 20:27:19.827334 tip f \N \N \N 1 +61 csa-libcloud \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:19.892075 2013-04-17 16:42:42 tip f \N \\x7b227261775f6964223a202261326661353531363333636533363937616336336139333561613731663165376238303232326165222c202273686f72745f6964223a2022613266613535313633336365222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30342d31375431363a34323a3432222c20226d657373616765223a202266696c746572206f6e6c79206c697374656e65727320427269676874626f782063616e2070726f63657373222c20227265766973696f6e223a20313839357d \N \N +62 RC/git-test \N git 2 f f f Unnamed repository 2013-05-28 20:27:20.231554 2013-03-25 22:50:04 tip f \N \\x7b227261775f6964223a202235643561646464666339323963643839653931313131366436306231323064316361613866333964222c202273686f72745f6964223a2022356435616464646663393239222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30332d32355432323a35303a3034222c20226d657373616765223a202266785c6e222c20227265766973696f6e223a20397d \N 1 +63 RC/rc2/test \N hg 2 f f f RC/rc2/test repository 2013-05-28 20:27:20.356786 2013-05-28 20:27:20.35683 tip f \N \N \N 4 +64 rhodecode.bak \N hg 2 f f f rhodecode.bak repository 2013-05-28 20:27:20.423238 2013-05-28 02:41:49 tip f \N \\x7b227261775f6964223a202262633862616365663164303663306330643132616337386638326565353330666363393661663561222c202273686f72745f6964223a2022626338626163656631643036222c2022617574686f72223a20224d617263696e204b757a6d696e736b69203c6d617263696e40707974686f6e2d776f726b732e636f6d3e222c202264617465223a2022323031332d30352d32385430323a34313a3439222c20226d657373616765223a20224164646564206e657720617069206d6574686f64735c6e2d206765745f7365727665725f696e666f5c6e2d206765745f69705c6e2d207570646174655f7265706f5c6e2d206765745f7265706f5f67726f75705c6e2d206765745f7265706f5f67726f7570735c6e2d206372656174655f7265706f5f67726f75705c6e2d207570646174655f7265706f5f67726f75705c6e2d2064656c6574655f7265706f5f67726f75705c6e2d207570646174655f757365725f67726f75705c6e2d206765745f676973745c6e2d206765745f67697374735c6e2d2064656c6574655f676973745c6e5c6e2b207265666163746f72696e67206f66206e616d657320616e642067656e6572616c2041504920636c65616e75702e5c6e41504920646f63732077696c6c206e6f772062652067656e657261746564206261736564206f6e2066756e6374696f6e20646f63737472696e67735c6e546869732077696c6c206d616b652069742065617369657220746f20646f2070726f70657220646f63756d656e746174696f6e20666f72204150492e222c20227265766973696f6e223a20343033397d \N \N +65 RC/kiall-nova \N git 2 f f f Unnamed repository; edit this file 'description' to name the repository.\n 2013-05-28 20:27:20.524084 2012-10-23 10:22:06 tip f \N \\x7b227261775f6964223a202261306663643132343830373161643636623631306561633439303361646633366233313433393062222c202273686f72745f6964223a2022613066636431323438303731222c2022617574686f72223a20224a656e6b696e73203c6a656e6b696e73407265766965772e6f70656e737461636b2e6f72673e222c202264617465223a2022323031322d31302d32335431303a32323a3036222c20226d657373616765223a20224d65726765205c22466978206e6f76612d766f6c756d652d75736167652d61756469745c22222c20227265766973696f6e223a2031373235337d \N 1 +\. + + +-- +-- Data for Name: repositories_fields; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY repositories_fields (repo_field_id, repository_id, field_key, field_label, field_value, field_desc, field_type, created_on) FROM stdin; +\. + + +-- +-- Name: repositories_fields_repo_field_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_fields_repo_field_id_seq', 1, false); + + +-- +-- Name: repositories_repo_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('repositories_repo_id_seq', 65, true); + + +-- +-- Data for Name: rhodecode_settings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_settings (app_settings_id, app_settings_name, app_settings_value) FROM stdin; +1 realm RhodeCode authentication +2 title RhodeCode +3 ga_code 123456 +4 show_public_icon True +5 show_private_icon True +6 stylify_metatags False +7 ldap_active false +8 ldap_host +9 ldap_port 389 +10 ldap_tls_kind PLAIN +11 ldap_tls_reqcert +12 ldap_dn_user +13 ldap_dn_pass +14 ldap_base_dn +15 ldap_filter +16 ldap_search_scope +17 ldap_attr_login +18 ldap_attr_firstname +19 ldap_attr_lastname +20 ldap_attr_email +21 default_repo_enable_locking False +22 default_repo_enable_downloads False +23 default_repo_enable_statistics False +24 default_repo_private False +25 default_repo_type hg +\. + + +-- +-- Name: rhodecode_settings_app_settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_settings_app_settings_id_seq', 25, true); + + +-- +-- Data for Name: rhodecode_ui; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY rhodecode_ui (ui_id, ui_section, ui_key, ui_value, ui_active) FROM stdin; +1 hooks changegroup.update hg update >&2 f +2 hooks changegroup.repo_size python:rhodecode.lib.hooks.repo_size t +3 hooks changegroup.push_logger python:rhodecode.lib.hooks.log_push_action t +4 hooks prechangegroup.pre_push python:rhodecode.lib.hooks.pre_push t +5 hooks outgoing.pull_logger python:rhodecode.lib.hooks.log_pull_action t +6 hooks preoutgoing.pre_pull python:rhodecode.lib.hooks.pre_pull t +7 extensions largefiles t +8 extensions hgsubversion f +9 extensions hggit f +10 web push_ssl false t +11 web allow_archive gz zip bz2 t +12 web allow_push * t +13 web baseurl / t +14 paths / /mnt/hgfs/workspace-python t +\. + + +-- +-- Name: rhodecode_ui_ui_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('rhodecode_ui_ui_id_seq', 14, true); + + +-- +-- Data for Name: statistics; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY statistics (stat_id, repository_id, stat_on_revision, commit_activity, commit_activity_combined, languages) FROM stdin; +\. + + +-- +-- Name: statistics_stat_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('statistics_stat_id_seq', 1, false); + + +-- +-- Data for Name: user_email_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_email_map (email_id, user_id, email) FROM stdin; +\. + + +-- +-- Name: user_email_map_email_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_email_map_email_id_seq', 1, false); + + +-- +-- Data for Name: user_followings; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_followings (user_following_id, user_id, follows_repository_id, follows_user_id, follows_from) FROM stdin; +1 2 1 \N 2013-05-28 20:26:59.905946 +2 2 2 \N 2013-05-28 20:26:59.958581 +3 2 3 \N 2013-05-28 20:27:00.145566 +4 2 4 \N 2013-05-28 20:27:00.184438 +5 2 5 \N 2013-05-28 20:27:01.507836 +6 2 6 \N 2013-05-28 20:27:01.562696 +7 2 7 \N 2013-05-28 20:27:01.630538 +8 2 8 \N 2013-05-28 20:27:01.658765 +9 2 9 \N 2013-05-28 20:27:01.883077 +10 2 10 \N 2013-05-28 20:27:02.410512 +11 2 11 \N 2013-05-28 20:27:02.47039 +12 2 12 \N 2013-05-28 20:27:02.512861 +13 2 13 \N 2013-05-28 20:27:02.705559 +14 2 14 \N 2013-05-28 20:27:02.736051 +15 2 15 \N 2013-05-28 20:27:02.909458 +16 2 16 \N 2013-05-28 20:27:03.058143 +17 2 17 \N 2013-05-28 20:27:03.092663 +18 2 18 \N 2013-05-28 20:27:03.220556 +19 2 19 \N 2013-05-28 20:27:03.401209 +20 2 20 \N 2013-05-28 20:27:03.446846 +21 2 21 \N 2013-05-28 20:27:03.478718 +22 2 22 \N 2013-05-28 20:27:03.625506 +23 2 23 \N 2013-05-28 20:27:03.654446 +24 2 24 \N 2013-05-28 20:27:03.90204 +25 2 25 \N 2013-05-28 20:27:03.935584 +26 2 26 \N 2013-05-28 20:27:04.133528 +27 2 27 \N 2013-05-28 20:27:04.165426 +28 2 28 \N 2013-05-28 20:27:04.227192 +29 2 29 \N 2013-05-28 20:27:04.470074 +30 2 30 \N 2013-05-28 20:27:04.535036 +31 2 31 \N 2013-05-28 20:27:04.56081 +32 2 32 \N 2013-05-28 20:27:04.73511 +33 2 33 \N 2013-05-28 20:27:04.762367 +34 2 34 \N 2013-05-28 20:27:04.882269 +35 2 35 \N 2013-05-28 20:27:16.081624 +36 2 36 \N 2013-05-28 20:27:16.238074 +37 2 37 \N 2013-05-28 20:27:16.490921 +38 2 38 \N 2013-05-28 20:27:16.606332 +39 2 39 \N 2013-05-28 20:27:16.683877 +40 2 40 \N 2013-05-28 20:27:16.772204 +41 2 41 \N 2013-05-28 20:27:16.846091 +42 2 42 \N 2013-05-28 20:27:16.915625 +43 2 43 \N 2013-05-28 20:27:17.000652 +44 2 44 \N 2013-05-28 20:27:17.035001 +45 2 45 \N 2013-05-28 20:27:17.245544 +46 2 46 \N 2013-05-28 20:27:17.412282 +47 2 47 \N 2013-05-28 20:27:17.442703 +48 2 48 \N 2013-05-28 20:27:17.616299 +49 2 49 \N 2013-05-28 20:27:17.694907 +50 2 50 \N 2013-05-28 20:27:17.76193 +51 2 51 \N 2013-05-28 20:27:17.796316 +52 2 52 \N 2013-05-28 20:27:17.911214 +53 2 53 \N 2013-05-28 20:27:18.67818 +54 2 54 \N 2013-05-28 20:27:18.712023 +55 2 55 \N 2013-05-28 20:27:18.837132 +56 2 56 \N 2013-05-28 20:27:19.053951 +57 2 57 \N 2013-05-28 20:27:19.51609 +58 2 58 \N 2013-05-28 20:27:19.543354 +59 2 59 \N 2013-05-28 20:27:19.809302 +60 2 60 \N 2013-05-28 20:27:19.877469 +61 2 61 \N 2013-05-28 20:27:19.908981 +62 2 62 \N 2013-05-28 20:27:20.247031 +63 2 63 \N 2013-05-28 20:27:20.410876 +64 2 64 \N 2013-05-28 20:27:20.506094 +65 2 65 \N 2013-05-28 20:27:20.536866 +\. + + +-- +-- Name: user_followings_user_following_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_followings_user_following_id_seq', 65, true); + + +-- +-- Data for Name: user_ip_map; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_ip_map (ip_id, user_id, ip_addr, active) FROM stdin; +\. + + +-- +-- Name: user_ip_map_ip_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_ip_map_ip_id_seq', 1, false); + + +-- +-- Data for Name: user_logs; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_logs (user_log_id, user_id, username, repository_id, repository_name, user_ip, action, action_date) FROM stdin; +1 2 marcink 1 RC/mygr/lol started_following_repo 2013-05-28 20:26:59.900931 +2 2 marcink 2 RC/fakeclone started_following_repo 2013-05-28 20:26:59.955428 +3 2 marcink 3 RC/muay started_following_repo 2013-05-28 20:27:00.125953 +4 2 marcink 4 BIG/git started_following_repo 2013-05-28 20:27:00.181617 +5 2 marcink 5 RC/origin-fork started_following_repo 2013-05-28 20:27:01.466724 +6 2 marcink 6 one started_following_repo 2013-05-28 20:27:01.536732 +7 2 marcink 7 rhodecode.bak.1 started_following_repo 2013-05-28 20:27:01.589472 +8 2 marcink 8 csa-collins started_following_repo 2013-05-28 20:27:01.655365 +9 2 marcink 9 csa-harmony started_following_repo 2013-05-28 20:27:01.88057 +10 2 marcink 10 RC/ąqweqwe started_following_repo 2013-05-28 20:27:02.387499 +11 2 marcink 11 rhodecode started_following_repo 2013-05-28 20:27:02.433418 +12 2 marcink 12 csa-unity started_following_repo 2013-05-28 20:27:02.508796 +13 2 marcink 13 RC/łęcina started_following_repo 2013-05-28 20:27:02.674658 +14 2 marcink 14 waitress started_following_repo 2013-05-28 20:27:02.73244 +15 2 marcink 15 RC/rc2/test2 started_following_repo 2013-05-28 20:27:02.906659 +16 2 marcink 16 RC/origin-fork-fork started_following_repo 2013-05-28 20:27:03.02717 +17 2 marcink 17 RC/rc2/test4 started_following_repo 2013-05-28 20:27:03.090085 +18 2 marcink 18 RC/vcs-git started_following_repo 2013-05-28 20:27:03.218033 +19 2 marcink 19 rhodecode-extensions started_following_repo 2013-05-28 20:27:03.374166 +20 2 marcink 20 rhodecode-cli-gist started_following_repo 2013-05-28 20:27:03.425087 +21 2 marcink 21 test.onaut.com started_following_repo 2013-05-28 20:27:03.473193 +22 2 marcink 22 RC/new started_following_repo 2013-05-28 20:27:03.593153 +23 2 marcink 23 csa-aldrin started_following_repo 2013-05-28 20:27:03.651182 +24 2 marcink 24 vcs started_following_repo 2013-05-28 20:27:03.866907 +25 2 marcink 25 csa-prometheus started_following_repo 2013-05-28 20:27:03.931789 +26 2 marcink 26 RC/INRC/trololo started_following_repo 2013-05-28 20:27:04.108947 +27 2 marcink 27 RC/empty-git started_following_repo 2013-05-28 20:27:04.162816 +28 2 marcink 28 csa-salt-states started_following_repo 2013-05-28 20:27:04.224517 +29 2 marcink 29 rhodecode-premium started_following_repo 2013-05-28 20:27:04.429318 +30 2 marcink 30 RC/qweqwe-fork started_following_repo 2013-05-28 20:27:04.508625 +31 2 marcink 31 testrepo-quick started_following_repo 2013-05-28 20:27:04.558071 +32 2 marcink 32 RC/test started_following_repo 2013-05-28 20:27:04.707963 +33 2 marcink 33 remote-salt started_following_repo 2013-05-28 20:27:04.759601 +34 2 marcink 34 BIG/android started_following_repo 2013-05-28 20:27:04.879601 +35 2 marcink 35 DOCS started_following_repo 2013-05-28 20:27:16.077043 +36 2 marcink 36 rhodecode-git started_following_repo 2013-05-28 20:27:16.235309 +37 2 marcink 37 RC/bin-ops started_following_repo 2013-05-28 20:27:16.474785 +38 2 marcink 38 RC/INRC/L2_NEW/lalalal started_following_repo 2013-05-28 20:27:16.566047 +39 2 marcink 39 RC/fork-remote started_following_repo 2013-05-28 20:27:16.636895 +40 2 marcink 40 RC/INRC/L2_NEW/L3/repo_test_move started_following_repo 2013-05-28 20:27:16.73064 +41 2 marcink 41 RC/gogo-fork started_following_repo 2013-05-28 20:27:16.801352 +42 2 marcink 42 quest started_following_repo 2013-05-28 20:27:16.870218 +43 2 marcink 43 RC/foobar started_following_repo 2013-05-28 20:27:16.94344 +44 2 marcink 44 csa-hyperion started_following_repo 2013-05-28 20:27:17.032368 +45 2 marcink 45 RC/git-pull-test started_following_repo 2013-05-28 20:27:17.242321 +46 2 marcink 46 RC/qweqwe-fork2 started_following_repo 2013-05-28 20:27:17.369718 +47 2 marcink 47 RC/jap started_following_repo 2013-05-28 20:27:17.438737 +48 2 marcink 48 RC/hg-repo started_following_repo 2013-05-28 20:27:17.568968 +49 2 marcink 49 RC/origin started_following_repo 2013-05-28 20:27:17.647722 +50 2 marcink 50 rhodecode-cli-api started_following_repo 2013-05-28 20:27:17.720735 +51 2 marcink 51 RC/rc2/test3 started_following_repo 2013-05-28 20:27:17.793213 +52 2 marcink 52 csa-armstrong started_following_repo 2013-05-28 20:27:17.908068 +53 2 marcink 53 RC/trololo started_following_repo 2013-05-28 20:27:18.630661 +54 2 marcink 54 testrepo-wp started_following_repo 2013-05-28 20:27:18.707708 +55 2 marcink 55 pyramidpypi started_following_repo 2013-05-28 20:27:18.834547 +56 2 marcink 56 salt started_following_repo 2013-05-28 20:27:19.050625 +57 2 marcink 57 RC/lol/haha started_following_repo 2013-05-28 20:27:19.462058 +58 2 marcink 58 csa-io started_following_repo 2013-05-28 20:27:19.540782 +59 2 marcink 59 enc-envelope started_following_repo 2013-05-28 20:27:19.758453 +60 2 marcink 60 RC/gogo2 started_following_repo 2013-05-28 20:27:19.838573 +61 2 marcink 61 csa-libcloud started_following_repo 2013-05-28 20:27:19.904526 +62 2 marcink 62 RC/git-test started_following_repo 2013-05-28 20:27:20.243692 +63 2 marcink 63 RC/rc2/test started_following_repo 2013-05-28 20:27:20.36788 +64 2 marcink 64 rhodecode.bak started_following_repo 2013-05-28 20:27:20.435328 +65 2 marcink 65 RC/kiall-nova started_following_repo 2013-05-28 20:27:20.533474 +\. + + +-- +-- Name: user_logs_user_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_logs_user_log_id_seq', 65, true); + + +-- +-- Data for Name: user_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_repo_group_to_perm (group_to_perm_id, user_id, group_id, permission_id) FROM stdin; +1 1 1 6 +2 1 2 6 +3 1 3 6 +4 1 4 6 +5 1 5 6 +6 1 6 6 +7 1 7 6 +8 1 8 6 +\. + + +-- +-- Name: user_repo_group_to_perm_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_repo_group_to_perm_group_to_perm_id_seq', 8, true); + + +-- +-- Data for Name: user_to_notification; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_notification (user_id, notification_id, read, sent_on) FROM stdin; +\. + + +-- +-- Data for Name: user_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY user_to_perm (user_to_perm_id, user_id, permission_id) FROM stdin; +1 1 15 +2 1 11 +3 1 13 +4 1 2 +5 1 6 +\. + + +-- +-- Name: user_to_perm_user_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('user_to_perm_user_to_perm_id_seq', 5, true); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users (user_id, username, password, active, admin, firstname, lastname, email, last_login, ldap_dn, api_key, inherit_default_permissions) FROM stdin; +1 default $2a$10$pgqzrZyjE0YBlVErXftPnu4bMmbkO4BSIPtgPsrEoxM6xBdu.pFyi t f Anonymous User anonymous@rhodecode.org \N \N b7e62414df8fe4328b567603d6a409946af4a8f7 t +2 marcink $2a$10$htEvNjGrB1xEWaXJGrlWee.LB/ZT4.RON.VOfQ9caBSGSLnbHnvz2 t t RhodeCode Admin marcin@rhodecode.com \N \N 1d6f72e5dc6de70d9623f006edb28b8b56b3ebce t +\. + + +-- +-- Name: users_group_repo_group_to_per_users_group_repo_group_to_per_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_group_to_per_users_group_repo_group_to_per_seq', 1, false); + + +-- +-- Data for Name: users_group_repo_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_group_to_perm (users_group_repo_group_to_perm_id, users_group_id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Data for Name: users_group_repo_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_repo_to_perm (users_group_to_perm_id, users_group_id, permission_id, repository_id) FROM stdin; +\. + + +-- +-- Name: users_group_repo_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_repo_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_group_to_perm; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_group_to_perm (users_group_to_perm_id, users_group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: users_group_to_perm_users_group_to_perm_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_group_to_perm_users_group_to_perm_id_seq', 1, false); + + +-- +-- Data for Name: users_groups; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups (users_group_id, users_group_name, users_group_active, users_group_inherit_default_permissions) FROM stdin; +\. + + +-- +-- Data for Name: users_groups_members; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY users_groups_members (users_group_member_id, users_group_id, user_id) FROM stdin; +\. + + +-- +-- Name: users_groups_members_users_group_member_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_members_users_group_member_id_seq', 1, false); + + +-- +-- Name: users_groups_users_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_groups_users_group_id_seq', 1, false); + + +-- +-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('users_user_id_seq', 2, true); + + +-- +-- Name: cache_invalidation_cache_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_cache_key_key UNIQUE (cache_key); + + +-- +-- Name: cache_invalidation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY cache_invalidation + ADD CONSTRAINT cache_invalidation_pkey PRIMARY KEY (cache_id); + + +-- +-- Name: changeset_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pkey PRIMARY KEY (comment_id); + + +-- +-- Name: changeset_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pkey PRIMARY KEY (changeset_status_id); + + +-- +-- Name: changeset_statuses_repo_id_revision_version_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_revision_version_key UNIQUE (repo_id, revision, version); + + +-- +-- Name: db_migrate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY db_migrate_version + ADD CONSTRAINT db_migrate_version_pkey PRIMARY KEY (repository_id); + + +-- +-- Name: groups_group_name_group_parent_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_group_parent_id_key UNIQUE (group_name, group_parent_id); + + +-- +-- Name: groups_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_name_key UNIQUE (group_name); + + +-- +-- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_pkey PRIMARY KEY (group_id); + + +-- +-- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (notification_id); + + +-- +-- Name: permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY permissions + ADD CONSTRAINT permissions_pkey PRIMARY KEY (permission_id); + + +-- +-- Name: pull_request_reviewers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pkey PRIMARY KEY (pull_requests_reviewers_id); + + +-- +-- Name: pull_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_pkey PRIMARY KEY (pull_request_id); + + +-- +-- Name: repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_pkey PRIMARY KEY (repo_to_perm_id); + + +-- +-- Name: repo_to_perm_user_id_repository_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_repository_id_permission_id_key UNIQUE (user_id, repository_id, permission_id); + + +-- +-- Name: repositories_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_pkey PRIMARY KEY (repo_field_id); + + +-- +-- Name: repositories_fields_repository_id_field_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_repository_id_field_key_key UNIQUE (repository_id, field_key); + + +-- +-- Name: repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (repo_id); + + +-- +-- Name: repositories_repo_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_repo_name_key UNIQUE (repo_name); + + +-- +-- Name: rhodecode_settings_app_settings_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_app_settings_name_key UNIQUE (app_settings_name); + + +-- +-- Name: rhodecode_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_settings + ADD CONSTRAINT rhodecode_settings_pkey PRIMARY KEY (app_settings_id); + + +-- +-- Name: rhodecode_ui_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_pkey PRIMARY KEY (ui_id); + + +-- +-- Name: rhodecode_ui_ui_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY rhodecode_ui + ADD CONSTRAINT rhodecode_ui_ui_key_key UNIQUE (ui_key); + + +-- +-- Name: statistics_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_pkey PRIMARY KEY (stat_id); + + +-- +-- Name: statistics_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_key UNIQUE (repository_id); + + +-- +-- Name: user_email_map_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_email_key UNIQUE (email); + + +-- +-- Name: user_email_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_pkey PRIMARY KEY (email_id); + + +-- +-- Name: user_followings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_pkey PRIMARY KEY (user_following_id); + + +-- +-- Name: user_followings_user_id_follows_repository_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_repository_id_key UNIQUE (user_id, follows_repository_id); + + +-- +-- Name: user_followings_user_id_follows_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_follows_user_id_key UNIQUE (user_id, follows_user_id); + + +-- +-- Name: user_ip_map_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_pkey PRIMARY KEY (ip_id); + + +-- +-- Name: user_ip_map_user_id_ip_addr_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_user_id_ip_addr_key UNIQUE (user_id, ip_addr); + + +-- +-- Name: user_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_pkey PRIMARY KEY (user_log_id); + + +-- +-- Name: user_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_pkey PRIMARY KEY (group_to_perm_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_group_id_permission_id_key UNIQUE (user_id, group_id, permission_id); + + +-- +-- Name: user_to_notification_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_pkey PRIMARY KEY (user_id, notification_id); + + +-- +-- Name: user_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_pkey PRIMARY KEY (user_to_perm_id); + + +-- +-- Name: user_to_perm_user_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_permission_id_key UNIQUE (user_id, permission_id); + + +-- +-- Name: users_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users_group_repo_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_pkey PRIMARY KEY (users_group_repo_group_to_perm_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_group_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_group_id_key UNIQUE (users_group_id, group_id); + + +-- +-- Name: users_group_repo_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_users_group_id_permi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_users_group_id_permi_key UNIQUE (repository_id, users_group_id, permission_id); + + +-- +-- Name: users_group_to_perm_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_pkey PRIMARY KEY (users_group_to_perm_id); + + +-- +-- Name: users_group_to_perm_users_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_permission_id_key UNIQUE (users_group_id, permission_id); + + +-- +-- Name: users_groups_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_pkey PRIMARY KEY (users_group_member_id); + + +-- +-- Name: users_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_pkey PRIMARY KEY (users_group_id); + + +-- +-- Name: users_groups_users_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users_groups + ADD CONSTRAINT users_groups_users_group_name_key UNIQUE (users_group_name); + + +-- +-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_pkey PRIMARY KEY (user_id); + + +-- +-- Name: users_username_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: cc_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cc_revision_idx ON changeset_comments USING btree (revision); + + +-- +-- Name: cs_revision_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_revision_idx ON changeset_statuses USING btree (revision); + + +-- +-- Name: cs_version_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX cs_version_idx ON changeset_statuses USING btree (version); + + +-- +-- Name: key_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX key_idx ON cache_invalidation USING btree (cache_key); + + +-- +-- Name: notification_type_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX notification_type_idx ON notifications USING btree (type); + + +-- +-- Name: p_perm_name_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX p_perm_name_idx ON permissions USING btree (permission_name); + + +-- +-- Name: u_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_email_idx ON users USING btree (email); + + +-- +-- Name: u_username_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX u_username_idx ON users USING btree (username); + + +-- +-- Name: uem_email_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE INDEX uem_email_idx ON user_email_map USING btree (email); + + +-- +-- Name: changeset_comments_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_comments_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_comments + ADD CONSTRAINT changeset_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: changeset_statuses_changeset_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_changeset_comment_id_fkey FOREIGN KEY (changeset_comment_id) REFERENCES changeset_comments(comment_id); + + +-- +-- Name: changeset_statuses_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: changeset_statuses_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_repo_id_fkey FOREIGN KEY (repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: changeset_statuses_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY changeset_statuses + ADD CONSTRAINT changeset_statuses_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: groups_group_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY groups + ADD CONSTRAINT groups_group_parent_id_fkey FOREIGN KEY (group_parent_id) REFERENCES groups(group_id); + + +-- +-- Name: notifications_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY notifications + ADD CONSTRAINT notifications_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(user_id); + + +-- +-- Name: pull_request_reviewers_pull_request_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_pull_request_id_fkey FOREIGN KEY (pull_request_id) REFERENCES pull_requests(pull_request_id); + + +-- +-- Name: pull_request_reviewers_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_request_reviewers + ADD CONSTRAINT pull_request_reviewers_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: pull_requests_org_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_org_repo_id_fkey FOREIGN KEY (org_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_other_repo_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_other_repo_id_fkey FOREIGN KEY (other_repo_id) REFERENCES repositories(repo_id); + + +-- +-- Name: pull_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY pull_requests + ADD CONSTRAINT pull_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repo_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repo_to_perm + ADD CONSTRAINT repo_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: repositories_fields_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories_fields + ADD CONSTRAINT repositories_fields_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_fork_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_fork_id_fkey FOREIGN KEY (fork_id) REFERENCES repositories(repo_id); + + +-- +-- Name: repositories_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: repositories_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY repositories + ADD CONSTRAINT repositories_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: statistics_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY statistics + ADD CONSTRAINT statistics_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_email_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_email_map + ADD CONSTRAINT user_email_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_follows_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_repository_id_fkey FOREIGN KEY (follows_repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_followings_follows_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_follows_user_id_fkey FOREIGN KEY (follows_user_id) REFERENCES users(user_id); + + +-- +-- Name: user_followings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_followings + ADD CONSTRAINT user_followings_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_ip_map_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_ip_map + ADD CONSTRAINT user_ip_map_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_logs_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: user_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_logs + ADD CONSTRAINT user_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: user_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_repo_group_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_repo_group_to_perm + ADD CONSTRAINT user_repo_group_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_notification_notification_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_notification_id_fkey FOREIGN KEY (notification_id) REFERENCES notifications(notification_id); + + +-- +-- Name: user_to_notification_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_notification + ADD CONSTRAINT user_to_notification_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: user_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: user_to_perm_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY user_to_perm + ADD CONSTRAINT user_to_perm_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_group_repo_group_to_perm_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(group_id); + + +-- +-- Name: users_group_repo_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_group_to_perm + ADD CONSTRAINT users_group_repo_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_repo_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_repo_to_perm_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES repositories(repo_id); + + +-- +-- Name: users_group_repo_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_repo_to_perm + ADD CONSTRAINT users_group_repo_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_group_to_perm_permission_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(permission_id); + + +-- +-- Name: users_group_to_perm_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_group_to_perm + ADD CONSTRAINT users_group_to_perm_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: users_groups_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(user_id); + + +-- +-- Name: users_groups_members_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY users_groups_members + ADD CONSTRAINT users_groups_members_users_group_id_fkey FOREIGN KEY (users_group_id) REFERENCES users_groups(users_group_id); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.1.8.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.1.8.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..0b622a0ae821b48f0dc276b77afaabb3c25d9fbb GIT binary patch literal 52224 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 diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.2.5.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.2.5.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..f0ad11bddf1474da7954830ce6eb4be4a74a6eb1 GIT binary patch literal 90112 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 TB-9WIJtey!6|#U(Riyt9+^TlT diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.3.6.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.3.6.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..21d4ca90fcddbf9d2e1c16c6827b5b7ab0469ba9 GIT binary patch literal 80896 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 O3w@=C70U^-@c#j^F8W&l diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.4.4.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.4.4.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..cce74f5851dafba73127da26fbf3c3f125efc8b3 GIT binary patch literal 126976 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 RN<<1-oi{{N!ql_*{{!W^olO7$ diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.4.4_with_groups.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.4.4_with_groups.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..4e7803333bb57353f3e002ccb4a192132c02de7c GIT binary patch literal 126976 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 T*)PdqF=%$)5Df`Y%jW+NB%kWs diff --git a/rhodecode/tests/database/sqlite/rhodecode.1.4.4_with_ldap_active.sqlite b/rhodecode/tests/database/sqlite/rhodecode.1.4.4_with_ldap_active.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..f7adb439398ed3fc1eaaa22a9f8c8b94847f2ca0 GIT binary patch literal 126976 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 diff --git a/rhodecode/tests/database/test_creation.py b/rhodecode/tests/database/test_creation.py new file mode 100755 --- /dev/null +++ b/rhodecode/tests/database/test_creation.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +def test_create_db(db_backend): + db_backend.teardown_db() + db_backend.setup_db() + db_backend.assert_returncode_success() + + db_backend.setup_rhodecode_db() + db_backend.assert_returncode_success() diff --git a/rhodecode/tests/database/test_migration.py b/rhodecode/tests/database/test_migration.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/database/test_migration.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import pytest + + +@pytest.mark.dbs("postgres") +@pytest.mark.parametrize("dumpname", [ + '1.4.4.sql', + '1.5.0.sql', + '1.6.0.sql', + '1.6.0_no_repo_name_index.sql', +]) +def test_migrate_postgres_db(db_backend, dumpname): + _run_migration_test(db_backend, dumpname) + + +@pytest.mark.dbs("sqlite") +@pytest.mark.parametrize("dumpname", [ + 'rhodecode.1.4.4.sqlite', + 'rhodecode.1.4.4_with_groups.sqlite', + 'rhodecode.1.4.4_with_ldap_active.sqlite', +]) +def test_migrate_sqlite_db(db_backend, dumpname): + _run_migration_test(db_backend, dumpname) + + +@pytest.mark.dbs("mysql") +@pytest.mark.parametrize("dumpname", [ + '1.4.4.sql', + '1.5.0.sql', + '1.6.0.sql', + '1.6.0_no_repo_name_index.sql', +]) +def test_migrate_mysql_db(db_backend, dumpname): + _run_migration_test(db_backend, dumpname) + + +def _run_migration_test(db_backend, dumpname): + db_backend.teardown_db() + db_backend.setup_db() + db_backend.assert_returncode_success() + + db_backend.import_dump(dumpname) + db_backend.upgrade_database() + db_backend.assert_returncode_success() diff --git a/rhodecode/tests/fixture.py b/rhodecode/tests/fixture.py new file mode 100644 --- /dev/null +++ b/rhodecode/tests/fixture.py @@ -0,0 +1,331 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2016 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +""" +Helpers for fixture generation +""" + +import os +import time +import tempfile +import shutil + +import configobj + +from rhodecode.tests import * +from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.user import UserModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.user_group import UserGroupModel +from rhodecode.model.gist import GistModel + +dn = os.path.dirname +FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures') + + +def error_function(*args, **kwargs): + raise Exception('Total Crash !') + + +class TestINI(object): + """ + Allows to create a new test.ini file as a copy of existing one with edited + data. Example usage:: + + with TestINI('test.ini', [{'section':{'key':val'}]) as new_test_ini_path: + print 'paster server %s' % new_test_ini + """ + + def __init__(self, ini_file_path, ini_params, new_file_prefix='DEFAULT', + destroy=True, dir=None): + self.ini_file_path = ini_file_path + self.ini_params = ini_params + self.new_path = None + self.new_path_prefix = new_file_prefix + self._destroy = destroy + self._dir = dir + + def __enter__(self): + return self.create() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.destroy() + + def create(self): + config = configobj.ConfigObj( + self.ini_file_path, file_error=True, write_empty_values=True) + + for data in self.ini_params: + section, ini_params = data.items()[0] + key, val = ini_params.items()[0] + config[section][key] = val + with tempfile.NamedTemporaryFile( + prefix=self.new_path_prefix, suffix='.ini', dir=self._dir, + delete=False) as new_ini_file: + config.write(new_ini_file) + self.new_path = new_ini_file.name + + return self.new_path + + def destroy(self): + if self._destroy: + os.remove(self.new_path) + + +class Fixture(object): + + def anon_access(self, status): + """ + Context process for disabling anonymous access. use like: + fixture = Fixture() + with fixture.anon_access(False): + #tests + + after this block anon access will be set to `not status` + """ + + class context(object): + def __enter__(self): + anon = User.get_default_user() + anon.active = status + Session().add(anon) + Session().commit() + time.sleep(1.5) # must sleep for cache (1s to expire) + + def __exit__(self, exc_type, exc_val, exc_tb): + anon = User.get_default_user() + anon.active = not status + Session().add(anon) + Session().commit() + + return context() + + def _get_repo_create_params(self, **custom): + defs = { + 'repo_name': None, + 'repo_type': 'hg', + 'clone_uri': '', + 'repo_group': '-1', + 'repo_description': 'DESC', + 'repo_private': False, + 'repo_landing_rev': 'rev:tip', + 'repo_copy_permissions': False, + 'repo_state': Repository.STATE_CREATED, + } + defs.update(custom) + if 'repo_name_full' not in custom: + defs.update({'repo_name_full': defs['repo_name']}) + + # fix the repo name if passed as repo_name_full + if defs['repo_name']: + defs['repo_name'] = defs['repo_name'].split('/')[-1] + + return defs + + def _get_group_create_params(self, **custom): + defs = { + 'group_name': None, + 'group_description': 'DESC', + 'perm_updates': [], + 'perm_additions': [], + 'perm_deletions': [], + 'group_parent_id': -1, + 'enable_locking': False, + 'recursive': False, + } + defs.update(custom) + + return defs + + def _get_user_create_params(self, name, **custom): + defs = { + 'username': name, + 'password': 'qweqwe', + 'email': '%s+test@rhodecode.org' % name, + 'firstname': 'TestUser', + 'lastname': 'Test', + 'active': True, + 'admin': False, + 'extern_type': 'rhodecode', + 'extern_name': None, + } + defs.update(custom) + + return defs + + def _get_user_group_create_params(self, name, **custom): + defs = { + 'users_group_name': name, + 'user_group_description': 'DESC', + 'users_group_active': True, + 'user_group_data': {}, + } + defs.update(custom) + + return defs + + def create_repo(self, name, **kwargs): + repo_group = kwargs.get('repo_group') + if isinstance(repo_group, RepoGroup): + kwargs['repo_group'] = repo_group.group_id + name = name.split(Repository.NAME_SEP)[-1] + name = Repository.NAME_SEP.join((repo_group.group_name, name)) + + if 'skip_if_exists' in kwargs: + del kwargs['skip_if_exists'] + r = Repository.get_by_repo_name(name) + if r: + return r + + form_data = self._get_repo_create_params(repo_name=name, **kwargs) + cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN) + RepoModel().create(form_data, cur_user) + Session().commit() + repo = Repository.get_by_repo_name(name) + assert repo + return repo + + def create_fork(self, repo_to_fork, fork_name, **kwargs): + repo_to_fork = Repository.get_by_repo_name(repo_to_fork) + + form_data = self._get_repo_create_params(repo_name=fork_name, + fork_parent_id=repo_to_fork.repo_id, + repo_type=repo_to_fork.repo_type, + **kwargs) + #TODO: fix it !! + form_data['description'] = form_data['repo_description'] + form_data['private'] = form_data['repo_private'] + form_data['landing_rev'] = form_data['repo_landing_rev'] + + owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN) + RepoModel().create_fork(form_data, cur_user=owner) + Session().commit() + r = Repository.get_by_repo_name(fork_name) + assert r + return r + + def destroy_repo(self, repo_name, **kwargs): + RepoModel().delete(repo_name, **kwargs) + Session().commit() + + def destroy_repo_on_filesystem(self, repo_name): + rm_path = os.path.join(RepoModel().repos_path, repo_name) + if os.path.isdir(rm_path): + shutil.rmtree(rm_path) + + def create_repo_group(self, name, **kwargs): + if 'skip_if_exists' in kwargs: + del kwargs['skip_if_exists'] + gr = RepoGroup.get_by_group_name(group_name=name) + if gr: + return gr + form_data = self._get_group_create_params(group_name=name, **kwargs) + owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN) + gr = RepoGroupModel().create( + group_name=form_data['group_name'], + group_description=form_data['group_name'], + owner=owner) + Session().commit() + gr = RepoGroup.get_by_group_name(gr.group_name) + return gr + + def destroy_repo_group(self, repogroupid): + RepoGroupModel().delete(repogroupid) + Session().commit() + + def create_user(self, name, **kwargs): + if 'skip_if_exists' in kwargs: + del kwargs['skip_if_exists'] + user = User.get_by_username(name) + if user: + return user + form_data = self._get_user_create_params(name, **kwargs) + user = UserModel().create(form_data) + Session().commit() + user = User.get_by_username(user.username) + return user + + def destroy_user(self, userid): + UserModel().delete(userid) + Session().commit() + + def destroy_users(self, userid_iter): + for user_id in userid_iter: + if User.get_by_username(user_id): + UserModel().delete(user_id) + Session().commit() + + def create_user_group(self, name, **kwargs): + if 'skip_if_exists' in kwargs: + del kwargs['skip_if_exists'] + gr = UserGroup.get_by_group_name(group_name=name) + if gr: + return gr + form_data = self._get_user_group_create_params(name, **kwargs) + owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN) + user_group = UserGroupModel().create( + name=form_data['users_group_name'], + description=form_data['user_group_description'], + owner=owner, active=form_data['users_group_active'], + group_data=form_data['user_group_data']) + Session().commit() + user_group = UserGroup.get_by_group_name(user_group.users_group_name) + return user_group + + def destroy_user_group(self, usergroupid): + UserGroupModel().delete(user_group=usergroupid, force=True) + Session().commit() + + def create_gist(self, **kwargs): + form_data = { + 'description': 'new-gist', + 'owner': TEST_USER_ADMIN_LOGIN, + 'gist_type': GistModel.cls.GIST_PUBLIC, + 'lifetime': -1, + 'acl_level': Gist.ACL_LEVEL_PUBLIC, + 'gist_mapping': {'filename1.txt': {'content': 'hello world'},} + } + form_data.update(kwargs) + gist = GistModel().create( + description=form_data['description'], owner=form_data['owner'], + gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'], + lifetime=form_data['lifetime'], gist_acl_level=form_data['acl_level'] + ) + Session().commit() + return gist + + def destroy_gists(self, gistid=None): + for g in GistModel.cls.get_all(): + if gistid: + if gistid == g.gist_access_id: + GistModel().delete(g) + else: + GistModel().delete(g) + Session().commit() + + def load_resource(self, resource_name, strip=False): + with open(os.path.join(FIXTURES, resource_name)) as f: + source = f.read() + if strip: + source = source.strip() + + return source diff --git a/rhodecode/tests/fixtures/diff_with_diff_data.diff b/rhodecode/tests/fixtures/diff_with_diff_data.diff new file mode 100644 --- /dev/null +++ b/rhodecode/tests/fixtures/diff_with_diff_data.diff @@ -0,0 +1,416 @@ +diff --git a/vcs/backends/base.py b/vcs/backends/base.py +index 212267ca23949807b8d89fa8ca495827dcfab3b1..ad17f16634da602503ed4ddd7cdd2e1ccdf4bed4 100644 +--- a/vcs/backends/base.py ++++ b/vcs/backends/base.py +@@ -54,6 +54,7 @@ class BaseRepository(object): + """ + scm = None + DEFAULT_BRANCH_NAME = None ++ EMPTY_CHANGESET = '0' * 40 + + def __init__(self, repo_path, create=False, **kwargs): + """ +@@ -204,6 +205,23 @@ class BaseRepository(object): + """ + raise NotImplementedError + ++ def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, ++ context=3): ++ """ ++ Returns (git like) *diff*, as plain text. Shows changes introduced by ++ ``rev2`` since ``rev1``. ++ ++ :param rev1: Entry point from which diff is shown. Can be ++ ``self.EMPTY_CHANGESET`` - in this case, patch showing all ++ the changes since empty state of the repository until ``rev2`` ++ :param rev2: Until which revision changes should be shown. ++ :param ignore_whitespace: If set to ``True``, would not show whitespace ++ changes. Defaults to ``False``. ++ :param context: How many lines before/after changed lines should be ++ shown. Defaults to ``3``. ++ """ ++ raise NotImplementedError ++ + # ========== # + # COMMIT API # + # ========== # +@@ -341,7 +359,6 @@ class BaseChangeset(object): + otherwise; trying to access this attribute while there is no + changesets would raise ``EmptyRepositoryError`` + """ +- + def __str__(self): + return '<%s at %s:%s>' % (self.__class__.__name__, self.revision, + self.short_id) +@@ -591,7 +608,6 @@ class BaseChangeset(object): + return data + + +- + class BaseWorkdir(object): + """ + Working directory representation of single repository. +diff --git a/vcs/backends/git/repository.py b/vcs/backends/git/repository.py +index 8b9d1247fdee44e7a021b80e4965d8609cfd5720..e9f04e74dedd2f57417eb91dd2f4f7c61ec7e097 100644 +--- a/vcs/backends/git/repository.py ++++ b/vcs/backends/git/repository.py +@@ -12,6 +12,7 @@ + import os + import re + import time ++import inspect + import posixpath + from dulwich.repo import Repo, NotGitRepository + #from dulwich.config import ConfigFile +@@ -101,21 +102,6 @@ class GitRepository(BaseRepository): + "stderr:\n%s" % (cmd, se)) + return so, se + +- def _get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, +- context=3): +- rev1 = self._get_revision(rev1) +- rev2 = self._get_revision(rev2) +- +- if ignore_whitespace: +- cmd = 'diff -U%s -w %s %s' % (context, rev1, rev2) +- else: +- cmd = 'diff -U%s %s %s' % (context, rev1, rev2) +- if path: +- cmd += ' -- "%s"' % path +- so, se = self.run_git_command(cmd) +- +- return so +- + def _check_url(self, url): + """ + Functon will check given url and try to verify if it's a valid +@@ -322,6 +308,8 @@ class GitRepository(BaseRepository): + Returns ``GitChangeset`` object representing commit from git repository + at the given revision or head (most recent commit) if None given. + """ ++ if isinstance(revision, GitChangeset): ++ return revision + revision = self._get_revision(revision) + changeset = GitChangeset(repository=self, revision=revision) + return changeset +@@ -398,6 +386,49 @@ class GitRepository(BaseRepository): + for rev in revs: + yield self.get_changeset(rev) + ++ def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, ++ context=3): ++ """ ++ Returns (git like) *diff*, as plain text. Shows changes introduced by ++ ``rev2`` since ``rev1``. ++ ++ :param rev1: Entry point from which diff is shown. Can be ++ ``self.EMPTY_CHANGESET`` - in this case, patch showing all ++ the changes since empty state of the repository until ``rev2`` ++ :param rev2: Until which revision changes should be shown. ++ :param ignore_whitespace: If set to ``True``, would not show whitespace ++ changes. Defaults to ``False``. ++ :param context: How many lines before/after changed lines should be ++ shown. Defaults to ``3``. ++ """ ++ flags = ['-U%s' % context] ++ if ignore_whitespace: ++ flags.append('-w') ++ ++ if rev1 == self.EMPTY_CHANGESET: ++ rev2 = self.get_changeset(rev2).raw_id ++ cmd = ' '.join(['show'] + flags + [rev2]) ++ else: ++ rev1 = self.get_changeset(rev1).raw_id ++ rev2 = self.get_changeset(rev2).raw_id ++ cmd = ' '.join(['diff'] + flags + [rev1, rev2]) ++ ++ if path: ++ cmd += ' -- "%s"' % path ++ stdout, stderr = self.run_git_command(cmd) ++ # If we used 'show' command, strip first few lines (until actual diff ++ # starts) ++ if rev1 == self.EMPTY_CHANGESET: ++ lines = stdout.splitlines() ++ x = 0 ++ for line in lines: ++ if line.startswith('diff'): ++ break ++ x += 1 ++ # Append new line just like 'diff' command do ++ stdout = '\n'.join(lines[x:]) + '\n' ++ return stdout ++ + @LazyProperty + def in_memory_changeset(self): + """ +diff --git a/vcs/backends/hg.py b/vcs/backends/hg.py +index f1f9f95e4d476ab01d8e7b02a8b59034c0740a3b..b7d63c552c39b2f8aaec17ef46551369c8b8e793 100644 +--- a/vcs/backends/hg.py ++++ b/vcs/backends/hg.py +@@ -256,13 +256,32 @@ class MercurialRepository(BaseRepository): + + return map(lambda x: hex(x[7]), self._repo.changelog.index)[:-1] + +- def _get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, ++ def get_diff(self, rev1, rev2, path='', ignore_whitespace=False, + context=3): ++ """ ++ Returns (git like) *diff*, as plain text. Shows changes introduced by ++ ``rev2`` since ``rev1``. ++ ++ :param rev1: Entry point from which diff is shown. Can be ++ ``self.EMPTY_CHANGESET`` - in this case, patch showing all ++ the changes since empty state of the repository until ``rev2`` ++ :param rev2: Until which revision changes should be shown. ++ :param ignore_whitespace: If set to ``True``, would not show whitespace ++ changes. Defaults to ``False``. ++ :param context: How many lines before/after changed lines should be ++ shown. Defaults to ``3``. ++ """ ++ # Check if given revisions are present at repository (may raise ++ # ChangesetDoesNotExistError) ++ if rev1 != self.EMPTY_CHANGESET: ++ self.get_changeset(rev1) ++ self.get_changeset(rev2) ++ + file_filter = match(self.path, '', [path]) +- return patch.diff(self._repo, rev1, rev2, match=file_filter, ++ return ''.join(patch.diff(self._repo, rev1, rev2, match=file_filter, + opts=diffopts(git=True, + ignorews=ignore_whitespace, +- context=context)) ++ context=context))) + + def _check_url(self, url): + """ +diff --git a/vcs/tests/test_git.py b/vcs/tests/test_git.py +index 30da035a2a35c3dca14064778e97188b6d4ce5d6..d4b82b9e612af8bb5bf490a827377c7c2567735a 100644 +--- a/vcs/tests/test_git.py ++++ b/vcs/tests/test_git.py +@@ -639,19 +639,19 @@ class GitSpecificWithRepoTest(BackendTestMixin, unittest.TestCase): + + def test_get_diff_runs_git_command_with_hashes(self): + self.repo.run_git_command = mock.Mock(return_value=['', '']) +- self.repo._get_diff(0, 1) ++ self.repo.get_diff(0, 1) + self.repo.run_git_command.assert_called_once_with('diff -U%s %s %s' % + (3, self.repo._get_revision(0), self.repo._get_revision(1))) + + def test_get_diff_runs_git_command_with_str_hashes(self): + self.repo.run_git_command = mock.Mock(return_value=['', '']) +- self.repo._get_diff('0' * 40, 1) +- self.repo.run_git_command.assert_called_once_with('diff -U%s %s %s' % +- (3, self.repo._get_revision(0), self.repo._get_revision(1))) ++ self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1) ++ self.repo.run_git_command.assert_called_once_with('show -U%s %s' % ++ (3, self.repo._get_revision(1))) + + def test_get_diff_runs_git_command_with_path_if_its_given(self): + self.repo.run_git_command = mock.Mock(return_value=['', '']) +- self.repo._get_diff(0, 1, 'foo') ++ self.repo.get_diff(0, 1, 'foo') + self.repo.run_git_command.assert_called_once_with('diff -U%s %s %s -- "foo"' + % (3, self.repo._get_revision(0), self.repo._get_revision(1))) + +diff --git a/vcs/tests/test_repository.py b/vcs/tests/test_repository.py +index e34033e29fa9b3d3366b723beab129cee73869b9..b6e3f419778d6009229e9108824acaf83eea1784 100644 +--- a/vcs/tests/test_repository.py ++++ b/vcs/tests/test_repository.py +@@ -1,9 +1,12 @@ + from __future__ import with_statement ++import datetime + from base import BackendTestMixin + from conf import SCM_TESTS ++from conf import TEST_USER_CONFIG_FILE ++from vcs.nodes import FileNode + from vcs.utils.compat import unittest ++from vcs.exceptions import ChangesetDoesNotExistError + +-from conf import TEST_USER_CONFIG_FILE + + class RepositoryBaseTest(BackendTestMixin): + recreate_repo_per_test = False +@@ -29,6 +32,176 @@ class RepositoryBaseTest(BackendTestMixin): + 'foo.bar@example.com') + + ++ ++class RepositoryGetDiffTest(BackendTestMixin): ++ ++ @classmethod ++ def _get_commits(cls): ++ commits = [ ++ { ++ 'message': 'Initial commit', ++ 'author': 'Joe Doe ', ++ 'date': datetime.datetime(2010, 1, 1, 20), ++ 'added': [ ++ FileNode('foobar', content='foobar'), ++ FileNode('foobar2', content='foobar2'), ++ ], ++ }, ++ { ++ 'message': 'Changed foobar, added foobar3', ++ 'author': 'Jane Doe ', ++ 'date': datetime.datetime(2010, 1, 1, 21), ++ 'added': [ ++ FileNode('foobar3', content='foobar3'), ++ ], ++ 'changed': [ ++ FileNode('foobar', 'FOOBAR'), ++ ], ++ }, ++ { ++ 'message': 'Removed foobar, changed foobar3', ++ 'author': 'Jane Doe ', ++ 'date': datetime.datetime(2010, 1, 1, 22), ++ 'changed': [ ++ FileNode('foobar3', content='FOOBAR\nFOOBAR\nFOOBAR\n'), ++ ], ++ 'removed': [FileNode('foobar')], ++ }, ++ ] ++ return commits ++ ++ def test_raise_for_wrong(self): ++ with self.assertRaises(ChangesetDoesNotExistError): ++ self.repo.get_diff('a' * 40, 'b' * 40) ++ ++class GitRepositoryGetDiffTest(RepositoryGetDiffTest, unittest.TestCase): ++ backend_alias = 'git' ++ ++ def test_initial_commit_diff(self): ++ initial_rev = self.repo.revisions[0] ++ self.assertEqual(self.repo.get_diff(self.repo.EMPTY_CHANGESET, initial_rev), '''diff --git a/foobar b/foobar ++new file mode 100644 ++index 0000000..f6ea049 ++--- /dev/null +++++ b/foobar ++@@ -0,0 +1 @@ +++foobar ++\ No newline at end of file ++diff --git a/foobar2 b/foobar2 ++new file mode 100644 ++index 0000000..e8c9d6b ++--- /dev/null +++++ b/foobar2 ++@@ -0,0 +1 @@ +++foobar2 ++\ No newline at end of file ++''') ++ ++ def test_second_changeset_diff(self): ++ revs = self.repo.revisions ++ self.assertEqual(self.repo.get_diff(revs[0], revs[1]), '''diff --git a/foobar b/foobar ++index f6ea049..389865b 100644 ++--- a/foobar +++++ b/foobar ++@@ -1 +1 @@ ++-foobar ++\ No newline at end of file +++FOOBAR ++\ No newline at end of file ++diff --git a/foobar3 b/foobar3 ++new file mode 100644 ++index 0000000..c11c37d ++--- /dev/null +++++ b/foobar3 ++@@ -0,0 +1 @@ +++foobar3 ++\ No newline at end of file ++''') ++ ++ def test_third_changeset_diff(self): ++ revs = self.repo.revisions ++ self.assertEqual(self.repo.get_diff(revs[1], revs[2]), '''diff --git a/foobar b/foobar ++deleted file mode 100644 ++index 389865b..0000000 ++--- a/foobar +++++ /dev/null ++@@ -1 +0,0 @@ ++-FOOBAR ++\ No newline at end of file ++diff --git a/foobar3 b/foobar3 ++index c11c37d..f932447 100644 ++--- a/foobar3 +++++ b/foobar3 ++@@ -1 +1,3 @@ ++-foobar3 ++\ No newline at end of file +++FOOBAR +++FOOBAR +++FOOBAR ++''') ++ ++ ++class HgRepositoryGetDiffTest(RepositoryGetDiffTest, unittest.TestCase): ++ backend_alias = 'hg' ++ ++ def test_initial_commit_diff(self): ++ initial_rev = self.repo.revisions[0] ++ self.assertEqual(self.repo.get_diff(self.repo.EMPTY_CHANGESET, initial_rev), '''diff --git a/foobar b/foobar ++new file mode 100755 ++--- /dev/null +++++ b/foobar ++@@ -0,0 +1,1 @@ +++foobar ++\ No newline at end of file ++diff --git a/foobar2 b/foobar2 ++new file mode 100755 ++--- /dev/null +++++ b/foobar2 ++@@ -0,0 +1,1 @@ +++foobar2 ++\ No newline at end of file ++''') ++ ++ def test_second_changeset_diff(self): ++ revs = self.repo.revisions ++ self.assertEqual(self.repo.get_diff(revs[0], revs[1]), '''diff --git a/foobar b/foobar ++--- a/foobar +++++ b/foobar ++@@ -1,1 +1,1 @@ ++-foobar ++\ No newline at end of file +++FOOBAR ++\ No newline at end of file ++diff --git a/foobar3 b/foobar3 ++new file mode 100755 ++--- /dev/null +++++ b/foobar3 ++@@ -0,0 +1,1 @@ +++foobar3 ++\ No newline at end of file ++''') ++ ++ def test_third_changeset_diff(self): ++ revs = self.repo.revisions ++ self.assertEqual(self.repo.get_diff(revs[1], revs[2]), '''diff --git a/foobar b/foobar ++deleted file mode 100755 ++--- a/foobar +++++ /dev/null ++@@ -1,1 +0,0 @@ ++-FOOBAR ++\ No newline at end of file ++diff --git a/foobar3 b/foobar3 ++--- a/foobar3 +++++ b/foobar3 ++@@ -1,1 +1,3 @@ ++-foobar3 ++\ No newline at end of file +++FOOBAR +++FOOBAR +++FOOBAR ++''') ++ ++ + # For each backend create test case class + for alias in SCM_TESTS: + attrs = { +@@ -38,7 +211,6 @@ for alias in SCM_TESTS: + bases = (RepositoryBaseTest, unittest.TestCase) + globals()[cls_name] = type(cls_name, bases, attrs) + +- + if __name__ == '__main__': + unittest.main() diff --git a/rhodecode/tests/fixtures/git_diff_binary_and_normal.diff b/rhodecode/tests/fixtures/git_diff_binary_and_normal.diff new file mode 100644 --- /dev/null +++ b/rhodecode/tests/fixtures/git_diff_binary_and_normal.diff @@ -0,0 +1,570 @@ +diff --git a/img/baseline-10px.png b/img/baseline-10px.png +new file mode 100644 +index 0000000000000000000000000000000000000000..16095dcbf5c9ea41caeb1e3e41d647d425222ed1 +GIT binary patch +literal 152 +zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0lw^r(L`iUdT1k0gQ7VIDN`6wR +zf@f}GdTLN=VoGJ<$y6JlA}dc9$B>F!Nx%O8w`Ue+77%bXFxq5j_~-xsZV_1~1zCBH +y)y@U((_~Lrb!=|_@`K?vV_&A58+!u-Gs6x+MGjBnI|qTLFnGH9xvXF!Nk9Jow`XSN + + +- Baseline ++ Twitter Baseline + + + +@@ -11,6 +11,7 @@ + + + ++ + + ++ + ++ ++ ++ ++ ++ ++ ++
    ++ ++
    ++ ${next.body()} ++ ++ ++ ++
    ++ ++
    ++ ++ ++ +\ No newline at end of file +diff --git a/pylons_app/templates/errors/error_document.html b/pylons_app/templates/errors/error_document.html +new file mode 100755 +--- /dev/null ++++ b/pylons_app/templates/errors/error_document.html +@@ -0,0 +1,39 @@ ++## -*- coding: utf-8 -*- ++ ++ ++ ++ ++ Error - ${c.error_message} ++ ++ ++ ++ ++ ++ ++
    ++

    ${c.error_message}

    ++ ++

    ${c.error_explanation}

    ++

    ${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}

    ++
    ++ ++ ++ ++ +diff --git a/pylons_app/templates/index.html b/pylons_app/templates/index.html +new file mode 100644 +--- /dev/null ++++ b/pylons_app/templates/index.html +@@ -0,0 +1,161 @@ ++ ## -*- coding: utf-8 -*- ++<%inherit file = "base/base.html"/> ++ ++<%def name="page_title()"> ++ ${_('Wire transfer')} ++ ++ ++<%def name="body()"> ++
    ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++
    ++ ++

    Hello we are Luminous

    ++

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ++eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad ++minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ++ex ea commodo consequat.


    ++ ++

    What we do

    ++ ++
    ++ ++ ++ ++
    ++

    Design

    ++

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ++eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad ++minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ++ex ea. More »

    ++
    ++ ++
    ++ ++
    ++ ++ ++ ++
    ++

    Development

    ++

    ${h.secure_form('/home/make_payment',method='post',id="secure_form")} ++ ##Secure Form Tag for prevention of Cross-site request forgery (CSRF) attacks. ++ ##Generates form tags that include client-specific authorization tokens to be verified by the destined web app. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ${h.get_error('_authentication_token',c.form_errors)}
    ${_('Account number')}${h.text('account_number',size=44,maxlength=38)}${h.get_error('account_number',c.form_errors)}
    ${_('Title')}${h.textarea("title", "", cols=43, rows=5,maxlength=20)}${h.get_error('title',c.form_errors)}
    ${_('Recipient')}${h.select('recipient',1,c.recipients_list)}${h.get_error('recipient',c.form_errors)}
    ${_('Recipient address')}${h.text('recipient_address',size=44)}${h.get_error('recipient_address',c.form_errors)}
    ${_('Amount')}${h.text('amount',size='7')}zł${h.get_error('amount',c.form_errors)}
    ${h.submit('send',_('send'))}
    ++ ${h.end_form()}More »

    ++
    ++ ++
    ++ ++
    ++ ++ ++ ++
    ++

    Marketing

    ++

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ++eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad ++minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ++ex ea. More »

    ++
    ++ ++
    ++ ++
    ++ ++
    ++ ++ ++ ++<%def name="footer()"> ++ ++ ++ ++ +diff --git a/pylons_app/templates/index2.html b/pylons_app/templates/index2.html +new file mode 100644 +--- /dev/null ++++ b/pylons_app/templates/index2.html +@@ -0,0 +1,110 @@ ++ ## -*- coding: utf-8 -*- ++<%inherit file = "base/base.html"/> ++ ++<%def name="page_title()"> ++ ${_('Wire transfer')} ++ ++ ++<%def name="body()"> ++

    ${h.link('Home','/')} / ${_('Wire transfer')}

    ++ ${h.secure_form('/home/make_payment',method='post',id="secure_form")} ++ ##Secure Form Tag for prevention of Cross-site request forgery (CSRF) attacks. ++ ##Generates form tags that include client-specific authorization tokens to be verified by the destined web app. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ${h.get_error('_authentication_token',c.form_errors)}
    ${_('Account number')}${h.text('account_number',size=44,maxlength=38)}${h.get_error('account_number',c.form_errors)}
    ${_('Title')}${h.textarea("title", "", cols=43, rows=5,maxlength=20)}${h.get_error('title',c.form_errors)}
    ${_('Recipient')}${h.select('recipient',1,c.recipients_list)}${h.get_error('recipient',c.form_errors)}
    ${_('Recipient address')}${h.text('recipient_address',size=44)}${h.get_error('recipient_address',c.form_errors)}
    ${_('Amount')}${h.text('amount',size='7')}zł${h.get_error('amount',c.form_errors)}
    ${h.submit('send',_('send'))}
    ++ ${h.end_form()} ++ ++ ${c.name} ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/pylons_app/templates/payment_confirmation.html b/pylons_app/templates/payment_confirmation.html +new file mode 100644 +--- /dev/null ++++ b/pylons_app/templates/payment_confirmation.html +@@ -0,0 +1,19 @@ ++## -*- coding: utf-8 -*- ++<%inherit file="base/base.html"/> ++<%def name="page_title()"> ++ ${_('Wire transfer confirmation')} ++ ++ ++<%def name="body()"> ++

    ${h.link('Home','/')} / ${_('Wire transfer confirmation')}

    ++ ++ % for k,v in c.form_result.items(): ++ %if k not in ['_authentication_token','recipient','send']: ++ ++ ++ ++ ++ %endif ++ % endfor ++
    ${k}${v}
    ++ +\ No newline at end of file +diff --git a/pylons_app/tests/__init__.py b/pylons_app/tests/__init__.py +new file mode 100644 +--- /dev/null ++++ b/pylons_app/tests/__init__.py +@@ -0,0 +1,36 @@ ++"""Pylons application test package ++ ++This package assumes the Pylons environment is already loaded, such as ++when this script is imported from the `nosetests --with-pylons=test.ini` ++command. ++ ++This module initializes the application via ``websetup`` (`paster ++setup-app`) and provides the base testing objects. ++""" ++from unittest import TestCase ++ ++from paste.deploy import loadapp ++from paste.script.appinstall import SetupCommand ++from pylons import config, url ++from routes.util import URLGenerator ++from webtest import TestApp ++ ++import pylons.test ++ ++__all__ = ['environ', 'url', 'TestController'] ++ ++# Invoke websetup with the current config file ++SetupCommand('setup-app').run([config['__file__']]) ++ ++environ = {} ++ ++class TestController(TestCase): ++ ++ def __init__(self, *args, **kwargs): ++ if pylons.test.pylonsapp: ++ wsgiapp = pylons.test.pylonsapp ++ else: ++ wsgiapp = loadapp('config:%s' % config['__file__']) ++ self.app = TestApp(wsgiapp) ++ url._push_object(URLGenerator(config['routes.map'], environ)) ++ TestCase.__init__(self, *args, **kwargs) +diff --git a/pylons_app/tests/functional/__init__.py b/pylons_app/tests/functional/__init__.py +new file mode 100644 +diff --git a/pylons_app/tests/test_models.py b/pylons_app/tests/test_models.py +new file mode 100644 +diff --git a/pylons_app/websetup.py b/pylons_app/websetup.py +new file mode 100644 +--- /dev/null ++++ b/pylons_app/websetup.py +@@ -0,0 +1,9 @@ ++"""Setup the pylons_app application""" ++import logging ++from pylons_app.config.environment import load_environment ++log = logging.getLogger(__name__) ++ ++ ++def setup_app(command, conf, vars): ++ """Place any commands to setup pylons_app here""" ++ load_environment(conf.global_conf, conf.local_conf) +diff --git a/setup.cfg b/setup.cfg +new file mode 100644 +--- /dev/null ++++ b/setup.cfg +@@ -0,0 +1,31 @@ ++[egg_info] ++tag_build = dev ++tag_svn_revision = true ++ ++[easy_install] ++find_links = http://www.pylonshq.com/download/ ++ ++[nosetests] ++with-pylons = development.ini ++ ++# Babel configuration ++[compile_catalog] ++domain = pylons_app ++directory = pylons_app/i18n ++statistics = true ++ ++[extract_messages] ++add_comments = TRANSLATORS: ++output_file = pylons_app/i18n/pylons_app.pot ++width = 80 ++ ++[init_catalog] ++domain = pylons_app ++input_file = pylons_app/i18n/pylons_app.pot ++output_dir = pylons_app/i18n ++ ++[update_catalog] ++domain = pylons_app ++input_file = pylons_app/i18n/pylons_app.pot ++output_dir = pylons_app/i18n ++previous = true +diff --git a/setup.py b/setup.py +new file mode 100644 +--- /dev/null ++++ b/setup.py +@@ -0,0 +1,38 @@ ++try: ++ from setuptools import setup, find_packages ++except ImportError: ++ from ez_setup import use_setuptools ++ use_setuptools() ++ from setuptools import setup, find_packages ++ ++setup( ++ name = 'pylons_app', ++ version = '1.0', ++ description = '', ++ author = 'marcin kuzminski', ++ author_email = 'marcin@python-blog.com', ++ url = '', ++ install_requires = [ ++ "Pylons>=0.9.7,<=0.9.7.99", ++ "SQLAlchemy>=0.5,<=0.5.99", ++ "Mako>=0.2.2,<=0.2.99", ++ ], ++ setup_requires = ["PasteScript>=1.6.3"], ++ packages = find_packages(exclude = ['ez_setup']), ++ include_package_data = True, ++ test_suite = 'nose.collector', ++ package_data = {'pylons_app': ['i18n/*/LC_MESSAGES/*.mo']}, ++ message_extractors = {'pylons_app': [ ++ ('**.py', 'python', None), ++ ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}), ++ ('public/**', 'ignore', None)]}, ++ zip_safe = False, ++ paster_plugins = ['PasteScript', 'Pylons'], ++ entry_points = """ ++ [paste.app_factory] ++ main = pylons_app.config.middleware:make_app ++ ++ [paste.app_install] ++ main = pylons.util:PylonsInstaller ++ """, ++) diff --git a/rhodecode/tests/fixtures/svn_node_history_branches.json b/rhodecode/tests/fixtures/svn_node_history_branches.json new file mode 100644 --- /dev/null +++ b/rhodecode/tests/fixtures/svn_node_history_branches.json @@ -0,0 +1,1 @@ +{"more": false, "results": [{"text": "Changesets", "children": [{"text": "r15:16", "id": "16"}, {"text": "r12:13", "id": "13"}, {"text": "r7:8", "id": "8"}, {"text": "r3:4", "id": "4"}, {"text": "r2:3", "id": "3"}]}, {"text": "Branches", "children": [{"text": "branches/add-docs", "id": "branches/add-docs/example.py@26"}, {"text": "branches/argparse", "id": "branches/argparse/example.py@26"}, {"text": "trunk", "id": "trunk/example.py@26"}]}, {"text": "Tags", "children": [{"text": "tags/v0.1", "id": "tags/v0.1/example.py@26"}, {"text": "tags/v0.2", "id": "tags/v0.2/example.py@26"}, {"text": "tags/v0.3", "id": "tags/v0.3/example.py@26"}, {"text": "tags/v0.5", "id": "tags/v0.5/example.py@26"}]}]} \ No newline at end of file diff --git a/rhodecode/tests/fixtures/svn_node_history_response.json b/rhodecode/tests/fixtures/svn_node_history_response.json new file mode 100644 --- /dev/null +++ b/rhodecode/tests/fixtures/svn_node_history_response.json @@ -0,0 +1,1 @@ +{"results": [{"text": "Changesets", "children": [{"text": "r382:383", "id": "383"}, {"text": "r323:324", "id": "324"}, {"text": "r322:323", "id": "323"}, {"text": "r299:300", "id": "300"}, {"text": "r277:278", "id": "278"}, {"text": "r273:274", "id": "274"}, {"text": "r270:271", "id": "271"}, {"text": "r269:270", "id": "270"}, {"text": "r263:264", "id": "264"}, {"text": "r261:262", "id": "262"}, {"text": "r251:252", "id": "252"}, {"text": "r208:209", "id": "209"}, {"text": "r202:203", "id": "203"}, {"text": "r173:174", "id": "174"}, {"text": "r172:173", "id": "173"}, {"text": "r171:172", "id": "172"}, {"text": "r145:146", "id": "146"}, {"text": "r144:145", "id": "145"}, {"text": "r140:141", "id": "141"}, {"text": "r134:135", "id": "135"}, {"text": "r107:108", "id": "108"}, {"text": "r106:107", "id": "107"}, {"text": "r100:101", "id": "101"}, {"text": "r94:95", "id": "95"}, {"text": "r85:86", "id": "86"}, {"text": "r73:74", "id": "74"}, {"text": "r72:73", "id": "73"}, {"text": "r71:72", "id": "72"}, {"text": "r69:70", "id": "70"}, {"text": "r67:68", "id": "68"}, {"text": "r63:64", "id": "64"}, {"text": "r62:63", "id": "63"}, {"text": "r61:62", "id": "62"}, {"text": "r50:51", "id": "51"}, {"text": "r49:50", "id": "50"}, {"text": "r48:49", "id": "49"}, {"text": "r47:48", "id": "48"}, {"text": "r46:47", "id": "47"}, {"text": "r45:46", "id": "46"}, {"text": "r41:42", "id": "42"}, {"text": "r39:40", "id": "40"}, {"text": "r37:38", "id": "38"}, {"text": "r25:26", "id": "26"}, {"text": "r23:24", "id": "24"}, {"text": "r8:9", "id": "9"}, {"text": "r7:8", "id": "8"}]}, {"text": "Branches", "children": []}, {"text": "Tags", "children": []}], "more": false} \ No newline at end of file diff --git a/rhodecode/tests/fixtures/vcs_search_index.tar.gz b/rhodecode/tests/fixtures/vcs_search_index.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..8608697cfaee888c2a9275f9365e31e8956dab31 GIT binary patch literal 4184019 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
    NVtXq>~ccvoD)Q+YF#mA*r-tIAQx|fHzy6Vw$~m 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Γ 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�|4fMu(DzEqP$a2~2aXD0^;0>x50gv&Sd2c>01A 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�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

    jE$B1nqEOylZ;f8QJCBp6jD`rj*A?^ z;LTX2dqm~|yhT0-iz~X>)uaw~O+&Ps{t>NWTVarvhk7iM!GDU3_Eg19!=NOnRrDvH z?M(9+wib`%z~GSW8B>Vp%3;<2jes|zJ~zu2cu$o$j*cZLxv?7UsS;E8nl zf0PAeSVL>xcy_++yd|$Ds-(*PDsN_xpYyic^ha-;=}N}INo~LR7dsi+m>w84amimb zkZC;#Ij?5I$>2p+*FU`WQhJe$c*BFPIVvSx)9Qy^(2qMPFtnTQ>xMh;?x5U1g@jYNR_iMLg$Jv{=BP37N2&}I)4wuNgOZgcue7JR{!A1F8}deokpiC`%GHfqkpx zlTEyUzl!fd^o8}ymumidStOpZ)3#NN1o7I3zh0J)urIvGYwwE33E*w|^}-F&Pg@{Y zMk)p=nLb;uhT}Oyhw5OvcP@0v*%hnO;R{Q)m{d|CuhReyJ^j5e&=_Z|s~-k8%KE$T zFTA&Y5(byH)bGtxUYK+BnC@EDoI}nK10Iinhqe~`Hn&GpD!w)@zpqJ4SL9(D@j*FG z0KD8WM#4rngYi%NByVV@ZR=3hP6muGiC(~gV5&@0R4tY+&1TJLro)cbyuvmp1lNn zBNoi1?5)^aB5L`de$V_%XA&N>tI&SqAWfaZTcNGI;kSdZT_-HKU5#O;L&W7SSpmC1 z+SampWue>RzW1JxZ@;5t&#O?7brsPm$FCpcXOCaW_N{_$h21woo(gaQH$6E^Us6R# zmAGZrg8sfFpr}k;|7PG?DXAeK8JkGM3$ z!uLfAm`O}n%6+u4N|rfq+h%O5sW+RB9$ypJhhm$w%;aiJw)0)W6?NdTSxB|p7uKRp zymQI-X${XdfNDEB%Rq!T4P*$LmPH{4C71V$1rokl-|?0qbW3MCL<9UWE}5;-o0g3# zX!fwog_~J{f2b;ijZ>O8CWA+vQEem8Ubo#tjkzvFh7)r8k>zL$gF@=jLzp8iEZzKp zp>IXr^Xs*fm~F+9?w!QlAxLPOdC{?q=&Y?CnG5|9O=Ly9`!yCvw}D|pti2XTZc)!+ zP5t(?r~y)MLG#r4!4+uPQ#KO^*M)-)v4KEcUtZ^~jTlh_27 zai-!{ESA6~7|4Bz3iC;4X7S5(rMr3QY#Zo9fFPif0A!7YIAnc?C==WrAZOs|VZ+rA zW8n#G%)=Ur1k5?FN&@I?novcy>@ru2; zAJL4q^!NMf;g+gD{yFJ81Mux6C6Djl%P~x`HMl%$qkt#h+ zo&q015m=8pKXes{By#(t*|AurI)DvVVs?;m` zX8>66y06B>DfwWonG8Gvf(74BV^l9vHh9PaqMSG=uhyfiV}S(iY2Yrg&~E!J$( zehpUNQopx{d>p7S<1$yK?ns~x##L$)1-24Xogewv2TSuuu&pX(<3W_8Q$Y=C&RfG3 zru8qyEcQX@nY^ud`mA0s`SX+10a6Z;o?5>@I7<111MZGzM(^v%c*+25$t=xpLOHGG z@6)kG+i3JXIo|4juvRNp-IJN zcd7B#^s48Qj$6Yu9X@JyZ6tZo_*I?NR%2nQ`X628EJ3}i^}a)`cQws`Uhii36M@4A zU8;;2m*n=YVscSKk2gi`uk}6O+q$p;dh^O>w$(}y51FiXoD8iJ-DHuE7JdPi%Rsqy z!|C_+WGHif8SxRzK7U6Sz)vRVohK(_Z1My*bI`5EQwsBPmUesPw zcFx~^snigx$~|P${LsKMX1Hu71gbh6y(z7XCn4-v0kl($Q^xY8R!6D7M_01api?_M&RzFl+7n!8Jd+e! zHWpNcfE~U=$ns;glFJgcn}hV|KtD#*Wl93@QGmFHcvJ7pAXMYwbz_+*HrGT=4$&zV zPcRbDDhE850iGMZ5-Pl!QV&)#(1uB85|Sx`lr2T%60&sHKU7s`2G-8FQuaHuN>P;{ACYpaLH|9AG^c(DfX?`&l@>GNrxHYO6wiv zp)s?5nY>Oj0OIpMpe2o5qgMt|V`ZjkTe_QPq3R~$Tm;}6w~kD`+@N=QOl-*1&~3$q zVAAWH(X1quAR=>k;i#_|>P2u0MT@&n{<8vW97Fe~sYxc=l5~B8Ki`%oD%bpQRnE1@Z9I10k|`$xEbI8{e*A)#AzPkop>R~6&3 z^_qsvBTELHP_y))T6hJ~Z>xfbgnu%9JKpEOrtO^}8rq94TkTUN>g;%qO&26P>#`{i z-Ei(@fJnFJZpTwOw9=qblwvAz{2msy?uNT8`x5Vmh?0#86A__ z_^~?`j)uJW?luMl3SYN}Uf5mQWg|?}DHP3v`syI>Lg;eiMB39>)-{iq?FJPWGP>v|UI_r%L(WvcHE00wruZ3IcuKRJ|!P*>i-M^fh5XyiOpq6Y09^wl^9u6?^ zwkR-Z&x>Eo#=DWW_WG;S@BQs`4_h>dXQW$6`Sgo+1~~uyvlp;~{Ox1}9~|@@y(0B= zW4ExgogKzT+Kpr*Pih4cp4S0o6&T37{R0&K9@Uhf4|Vf@|L z_3QZLk5LZ^NrqU=i9Zu}_)7Uu`@|xL_6jd0QW+EFPbq;WJ~a@^?H93R`_cnj5L|&u z@!t)IUQjf@HgfYW-Q*KojsIMe@9by30|WLVQ^$LL|CKc=rl z;WHbt^t~QOO8D$O3Z^{PrR7D$%W|9jA0=d{=Swvp;;zrKo5eqcGUY)EmSIAWaFP8j zSw1K^tOXL9)pNN%0VKV?F0in;q!@FUxulL)5v>oarOSO{fGlC)W626MTvYeqNKzV&niq--E|zV@?m;TJlqzY%YC4nE88IrLi& z7)yp2(6douz5u(s(ZjI+__^|;o2LYg>JKpwli)+8l4qXe&JQ{$cQ zDYoRJh8|n10-oxPu50c|ddf`6U%j;q(B0P);NMh+j6_xBtj~GAj^WQiE&Q_tffOZ3 zwKW8o52z0U;8Z&u3wEerlr+h0Ure~Ocn!k@IhUKFTwfyVVsoX7b<_8tEy7RQ?7|Tv zs^_mS0jMHcAktsN%L)~ZVp&SJX52BvJhX@9ZxMqH1K{I`WGQ-zH|qOX)EdUpVYSNi z+C)&27-?PIn00D%yctcK0G-$1RtRH_jLA?|s$E}U{p-3k&$Lc4Yq)1Oh7-#DjRS#! z640c0cft_Q%dg2%DWfTcj>l{Dzg=tzqDn+jXq{SLeYh~O{rIT6b}P7aD~B?uxP&AM zCn9*I#+5*}2mDXey0sUgrnE#Pm_63wNZk+=!#kV^3`?IA9p*S}4LcvI@FFpJHN5Mq zYk|dM*^!S154Nd0h-fY&xF$3EwEY|J#-sFA!C(Xw2g@#eldQ1PkwZBUH`PtEag2KL zeEkIP!%c6P8Fn3qz+e@cXoi6iyHX>ywigsChgL$~1%O90!vZIPo|cy)vL9OLCae4E5jm>yYlKczBbYPqu7JPKbJ-%TWbvWs| z4Iy&s81nD5WR|_>MI%XKLZ}JW--gj?TGankHVk;CuE;Q!Np9;-_==DLQ+?W#?dzix zZlpK0wPT}^G53c+DAD<3K{JfUquYk#AalYy{BkQ4x!MOra-v@iDkgL1YtsswbI|^J znjj-{3Bg_Y_RnTHt{f0dUO%1*M0RNX1=M*Z(0jUYM?%ZM zc5Y=lbMJ?{D~hJqT}gk!*P4xRa&x$e<6AGAE*h-j9n&CXk&~NUa(-PYdo6LmzI9LC zX>KOE`j!$~Ynwh7E=sgl{hbO zS8W^}qccQl4T786m{!Pfb@~%(7;{pfZ$&gv&HSA^*(Wmnb5g&%OvE)z*XK^rbNCkk?TUNnbme%(rt4+*7?>794z_G!v{XTP z^k=JVQb^0nRNOL1Vgp)z;f^ivF$jxPKKj!hqo7tXL;+<-a>_2{GNTy%@$MAZnwt9E z5J8W4=D?aD5B(-Nzx@EK#DSw4DrO-1XweFK(Z*LkhKo>aw)tQXrb z6L)g!zCaQAPzDXxNwk>fXN90NN?uj_WNDh|7pgea33}g~)&&=ypJjJ1MkZ|{XE#C+ zPlJfo~TzJD-`>|;VXZdBMF5iu!7CFOr1^pysqR#w;uyd4-M8bkkc znce-e7d`h8Q{aM(iIizjT`vZi4lYqV-?dZKfqGJt;}JDy-fc^Md0OH82h<1tOReI? zkcAe6I-y_WvrWrK8AC;uOb;FuS`1U5vAVq|!O_;}0x`y6@V`Wpk5YG79l@TW*?&SJ zlYMS65=`cy^~O{if0=Q+u5!IsnPg-s%W`{kn`;dj#6M-|bcV-ox-^{~`UdOz^=TUD zyN7s5?0Aw)qJ_+jT}UY<(*kHj0@x9!f*&n7l%`wnsm{XtR7DSX(dO2%Kp=vzTjFZM zEo(N?G-53b`{ZAwX`6b-S1$^-5J>t5k44&kVkC68z5I=kBo*-E4I=Yf z*$dKV;TeX{ucy7JuL}6+;P-Ln)i|y4e9CeBBox$)r=6=86jU%NC4+Q&#G6r|jDca= z2)C4cd|QYOW1^S$F4+7`8&t9TjwwZ_6JeHNg53iub{GzT9+-0CLOv_dmS7UUQ=x(l z=8{>8c_P0;OUT5G*8kh9T0Q86X$~}JGny&&jxDdHgf-z|BJgs?zjfcq$zHSkci)D) zlQG%Zmj>?kI@AJ;^~l4hr&l$!6PghsS~9uXYo9MLqpo!J6R$WzhTd(MPe;a|^m^cm z{8Uk&!BC;(tn(G{h*e`eZ9ykY-N>77Om674T1#N-%D%xGTGNmZ0IKYJc4K{c^13tD z8Jh!qmgEr`c}FmHNKTWNnEikE{baPK-0fm>m~4yr`itqPZTNx5?39B=}`0?QT6e3uVR){dfl0 zoi2tyY0$|8ee8IIn`IdZ7Clwnd@MN`)drKp?rO2ducFICT4{r6!8sg>|zrT3H$j3OXFN+04A3l&paRfUNU-2x% z#3#Yh9KKGO(0pbGC+cP8Zqgw5?Q>@6j6J`v|C6&*Z>N?a%XyCR{F>-KGyJn~CwYg^ zo*=jOoGUqHKlKW>r;9l>V(LKOdwHbhte0=y(d~ixg1q0F6(c&+g@|Ng1srI814I8Q zw4AFUYM=*5nDZv|NS1aanD9KM{jCSno9GthRDRNDIvI@y%h)BS4~4(}6he+&el3^K zcw@AoK)yT3TzqaS-mbNvsa3QTg_znc z&Kop+JEYc&qMQCUkP`k%``jNuqqJ9Rf1pV}(I+rarP2_c4Jg}tZr|d8t+o5UWI{65w&zfwvB*+XlchMVTj%3y?o%`{iw%kDr^L&CjRll-d zfMPRle|v4C5DlK;BI&JhJa>-VIH0}Y27AaDZ&}CQUe5!)QWV`sfnNT-sxuRJN#B#1 z+Q#4qEO@}F)jo}{qO%{vs6m;qVYu)@nG6>ZYE$9sGJq_>%&SdpAvx+&ClrBNi#7O&BPGz*0no6E`sn@v;c7}}hgWjFtOhv;NW`U5Q* zg9sSmPY9v5{<7xs18T}_1JC0A;Pn_5VO7{5qCSxuJ-Z~?HdV#j*Zx7~)HZw&>vPYsIJ{qZy zkFOgi4;dq#u(PSkQ5yvE+4E8y>MBhzfR|S)c&e&@=3&*vte+Oz5GAN&*R>4*trulz z%x&#OYfADrx*M9GNYLpylz zJZ-}<42c(;5tuTx?+Wp}>sKww&B8Uz1_zISu4041BK6`3;tr4J*Xw36TgUxX2h|8e zCNE2&{dDwIcMHV8Fw{)+yzah{ZW_2*_9%?Iv}9>9>_75TX~`@)Fq!-qEoh`!BOA*N zIz_htyLGs6-R%a|bO(C=+TQ)iMW_%q1OKJ~M6$?NJvHCn26E3OSd~8fg};*Kb&J z>zmTiRUh{-5&+ZU5~9pV?^Q-~Rp@UaS)sE!K%^5&#x=^C_r&n;EOmDx{@cz_74BXfeC!puX&hAC`kH#fgs1wn2ufeOw) z`0p0fTPRE@Q$=1r+3VR)hrwjD+Dcurl;+zFIIQz_D>Vb`^@#L}s*|u<$Tv@{wB3m0 z`tLZh`+5(T837+&$F#y)onMnK<;D9}nKvg6VHy$2S7oPJw609Aq6Mewo> zL-yD7){i)sm2}GBi`3}E)fqQmM}3}kt(6yqDR^6&?-sRh{u_if)Rx0DzMHj+tsn)} z08jjKFYLEplMl(oXD14RYUQfv2v)FQq934BadY6(J^chArT^?#G_%pMGzVd~5bd<24miwQ2la@x)>=436oW@yZCc?dxy^|SMj0FY#%~25ozF=adg08`9lLGwz!4~5uRy6 z#W`nwLtVnE+zKxi7H%-Wv+$*uZz@*TgFQ!Y?zNEPPI{Qm zvu>q)S!oSRUlOZ`S`apI`XJ^Bla;G?aIa3mS7Xt}6_<;4rdin40KLUK_aaZ*+*s7% zSmvt7708#2TGSFQ`KO=y1P`c+tV;;RanI(UINJ+zqU?<<-^! zYqbHj>-hMKvZ1fVMy<$QwioUJDJBXcKqq+Az*cDQ^zSMY?war2FV--NC;l_0jo>66 znOdx6XAYP9tGlbs=0FPP)wBVc_#f2HxE82d;$04tj*4R9FQ(dQUx|qEDpi_V(YuYOu18{TR{&- z!V|+o>juG3u1Fw`15nsW{>SBAUW%fD&Hq>fEd2uE1& zO6^`$WDC1x5rWL;6Lutfp1R_f4!EW65`h_Za4dQZQ^^NWLrPjb*z9q%JDY@O64*RY ze6J%=IU+ZO6~?UyD0Al)a?8?kNrFkRh?E}_V_l(p$v&TU%8=wBR} z15q}A5}1_&TYl1(bSXd19iLL#3dqs)SIwO;H&+J^Yq*;WU>O(fJu?Jp!TcOjgWc$G z{!q9s=lKR%vS9zMrK-^77&X3wmI0dPs$gNL2up*{T+MQCoWL=EJB=2vi2YmZR)v<< z1g!tqCTmy+0v8CShV^M`p*0(lv%c;U6xLH!p&O}@C!Fum8_9$0LMp?mG%iXn%2gFU zz0Q8mdu(%me+?`7S%FbUOkptg>4OBjrW0!iufB#Su=Ntl(BIPH-FY`o+qJ|Sve zhj5q=nTyJ#O}Mk?uhsRViQSecS#)kD^W%}L*@m{gT6T|DY*MckZ-*gnAB5({V|+JddB zxArmu&H-k;k8SLorYgKuM07UWg%27(<2q%nK} zt;1Dr`8Xli+#Z?uL+oz0!)Uh$lGy0+P2oy!NW@ocbym`pAxSq4)HAP$%*wKFVZvN9 zo3(lI*$dEmu;>G>P7&=HwIEu|7&`@kPmPE zO9dS8PAF6VXNl@L3-rz^!)~YnFG&+)B994r*xNovWL?Iud2jzz zeE960QcGTpp7i1dtm5F^k#{=`53G$;eF>$~8%tiD6r;?SRu`=)C54qxoIdTsB z-UkA#CNE#E^^x6`KXU#e_o7sn>WVsTl(ZsAZ`flIX9sc&gn}k!D}{xwwrTBw9ja+p z^lM!DgVUH)0Jtg|N+43w4Th`n?>PktQMJ_?)2u0gGeM+E-*r}%3vpYqlXt&<%Xw)9 zxKT~MT*$wgGYf29;EFbcivPCkF}XLO2(nPpCZ@JFtzfzg{nSO@!^&+7hVlASRu171OaZkN z_v$%Aoqb-__FDG*K&SUzv?2pXo|gSip$OVSczDqvUb6l``#=)VMgq5md{Q`2dMkNA3t9EFTcdDLvVZ)Jv$TLS#8D{qfRfm+*BTsb0oJA9= zNxV*VfKYxbawvtFPQkEolA;E52Q??R(x`Hsqow;KeD*%7e?40ag}y;tC)N(0ErFg$4~DEc>99xi1U(gM9^z5HNvF!NlhA*!!*dc1K=b!idk&T zLL77km30QREnP~js7$q{VRS@T4V#a$GZjd?Edj|fN`#Xgj%~n759!=D5Q@N&{KR&W z7xxw)rd^@obk`SHt=cgtCNz#YH(?HT)1_(+3ifa=^Rg3_`MNNnI!XRI-|Aoh=gD>z_#Qqg-a(tp72Be82{DnBaW41Zi45f*FP$4Ho!q44%kgGvVH z%NlP#)Gcrr;V?>s;KC5#7mr2?j~#T61E6b9_)<(1hini5%sSHRJ zpA^Y1E|MA1Qws$Ng4Hu!$qdGJjj)u3!*34N5`5=Wx9Kd|YynIjet233eZ=Xux-8OD z2%Q~zBH5P@ItJ9DbEN+XsLv9fQ684~YQ&mXVuewg6X}}wz=nt%quvJ%4^_89ryu8A z9JiW&822ztfcit3O}H-UYqN-_Mnm|7sW>&0qzSB{aOa)CSN7kWEDd2zaX|X*N1G_I z&~^HL#VaNwFJ!eMa6dn0oKZ5l(#LHw4lt9GyKl!Lc0PoW*jZPF1#_gB5md5r*&4Y2 z77OvM)=5(syQ>jdhL9 zq&3IyR=pJ2C#_xAUXPEIc{|jlSh#-buRKH!@V@b*2>qI3yyXRJHBcFKH2`eyO;+SL z8tYrH(pbLl%ZTbcvW3O%vl5o#{6Q%rSV_>H70KC-H-$J;K1CFCN#Mn=H!PxBKdE#~ z;hu#Dm!JZQ0K8^JhMBX6qPL~7;bbO@hLl@tN5LV!$ryYqEWRt&_50sN>yS1AYuY+q zdJug4i7Q8RIQx*A{09rsg2a*T`E`%2Rk9EHai*I5PlnqUwN>T3>|RxlK|HpX146&i zxg_5-?DQ%D8nyeSm_`0l2*1_`R*3}u8sruMOSfZ^s?*1$4TW=R2rj%m?Xfl1j(0#z z5~S1LCKQQ`NN0g@F?D0E7dun9_x*Q38G*fAj1aH4{bsj!!*3CV!~9%jHqfxtsSH~3 zGV$-4f{k?sR~DOX13a2Ntg!~p8t+8fVr9ZmOIDFUrzKML`X#ei*`O{o6R(+5dkyj> zjOWB4COo`FQD2ogyK!0Q^@Q>igg;LF@GMD2QfhxzhUejD;wrV=e{JITf^rxKqzv#b zVF>1|x-z|;h+Y%#-5}+pNMaW+z8FWDC)WXEK+0riz+CpI$3gNGc!sC*vQ@>ECvX!w zCXg*^!`|3iEubH4*t-iygFeV8aJ12=)W9lzS|Cu@M?qQr;oAE(J>(}t&W}KQ3Ad-` zjQeD3l--eyHD!tTjbZJggV4RluV0s8JZPU*$Y|NbZ1r?naYk$(FR;9eIdG|UhR6|> zPqb8jfOqozZeOR|#2BDKr4_m0;a>LJ%9^IyTOVw%=hY%)n-BSg&H(6n(6=}4p()wu zvP(5f&JeROMSY;P(2;QnBqNiX?E!?YXS;)%L6KA=9u|jHtTz_5t`5;ayoGjc5Q-i+ z?O;yH;kAa?r)3e-OEuJY33}PRk15Yjgqlq2$ z4%wn{Jcm@4gZR-dO_^EP?nsTm@Ly2>GFO3%RZLGH6h%P_c;(NR3Fw8oFsAQe5NogNH<$7@T*)Q* z8TljOJ*?f3iuOfebkqrkV8Gni2_=)S+p(p_H1ba_ZAW9Un$Tiq^iJ)dL4h_uQu;#X z(-KBPK>bT`9~~~Qk|1pd5A{Y0t4$!axd}$l744tOkiT^R*s(7ig3w5=S=04fD{J;I zQn9>{`)GqAUb=V0vhPaN)?R;u6a`lr<1`%R$2@&?0k_@2GOTX3(Rey4DikMdn;|xdvCBqW*wr@ zIllfv+ZA{k0@S&zyg^EmEVvb2wa$e>^ng|L4CcCwIY_?D>kmWVARFL=d(J_)nev04 zC)r1SBk%KSZwSJ)HKc9N=EeY2X6gxCI$O+=9jKW($!*?R$~fA(td5w_3wxUwQo-zI zEr;`XN;C6?vaq zS|}Of@*m@dhWpX1Zhj;S?(;p!Fc6I6lK>khNm5oD;hI=yvHj;6=>vOgW%fL7cVQLs z`H@r4uh%^t&Z91*(^)|cWd1P*KB8pR%f0G-_IRUm5*4Ce_ZUVGGwj9=Nf%^jC%%D- zCZx$#7zR7rl@M0LS+o2X0d>Y#fqlLZ&-|9AX=f;eDTpR=S%3(mVD~F`N$QEimaeMm zqjlODFdl_6K&snF#8^6TYX%*PoJR&qvVN5jtA9qi1|l zsBw_%4Nj3@!^h6}-Jms7;k?zynJEGBe9G&1uo1)I%w6rX>-66S&S*r-2Qjw24Ftg<#DXt^8v zEGY=?M=AB`l`5?b~Ld4EA$f%T}?fB`!z3W2J>bH^y6-KIEm+F_Xp?E6_4ZzgB5u1ZHMF&YBXZP z&JIyomJwwiO7d<$X&SK#1~z5X(1J}n6*74oIyTyFK@m7FMEj3fS(nDGK;Ir(c#$s} z4yx+V?+QtTMSe%wNK-Lbvcu9<+Nb~Vv1VCv_V!Oxzi`o}ciwGlk_cyrTPXh(=?MdK|mqNTW z29ZQBhhZ0MrrWqs&Km}=aXJS5tj%U%+gcg+BVjyu>`fBPg6qDnSYW~M1}To&qC!|0 z!qonW6cfjaP5TZp5G(0`{)hj#=cYbd_^J=iSmR`hS^QHXI&<4s*}GvaV5Ob z$DO~72o8#jS>?Pypy-cpeQ{5R`k$Nm@vSdWZ?wMD7C@#?`!}jcRUED1B+fcsPf=F~ zXoj9xVeP+CL!k3-HKDC(K! z>nS|2Y4#-Tg=EnlZ$v4a%@0s{n@w^HXe!RUAc8B&9c#cx`m=cz2lK7L;M}kL^_z7l zV07{*c!3~mu1OrO01s)JCj~Ww{K$yBl}D=I<8blfoqygF2$rjIqHLy&=;cFM01dn* zJ7d2i!vWt~%go#x8Wt&cQ7b2-tJmU1lCWhodHJgc^6$9AJYaiACwBk6gFp86AuVRX zu%96<(@nCN@BkjP13DN(O?_=+3agEH>Wh zVbfOX(7j{m=5nC@zK@u#LFyD*jm(de#cAS#UbB72LEHVic~PP>-=h-XE4*J7D+fO_ zEM$_!&MJv!qevm$Oxt`S<;w85ngT4rNi5z5>=}6wj|>*Vw*jg3I)VWFwK^QwbB>?| zP)Xp@zw3hQ^!tsM5Yi0mwrD);3x(ERW$KTO%>8O7&)Z@ocP?EHYDe3`G^Dtlk#clD z%^97F*)rX}73)p=*(L-$pabG#F1ki@O^$VDoZFus{X@@SC##UW%)TDXB5_7%>fTLe z`y{Y;)6t(a#WS?!5BwqJ2T5V}30r@JLlV87u+fUC0puTP^7wk4^dwM~X{o~!_x-J) zivD_h%9iOCYkt=OU3Iq zJ;4*=$#5)kSh^}07?>|@K;ITIfYq673>8JG^kJo&%(`|Xbc*wcSF2W<*P;Q~Clf2v zZyJz5!(&R+lBFFoL*M4z$xhejfvXZ05_;GsqkWRPz1IGjir2>@^p=L^k_`J1UN<%5 zyZ9B1EbeJ9&APPbrj{#wRUo;!AyRhY*Z#t2XE+X#nkyjY~btUsNlEB5TSj{|ChiP&3HzGmS z;<%2bWSzWa6qD>-@5cpbGB`Z$p9ZdGWydLJWBf@Y89a#0vHD@`&tO+T>lu`2EnMyO zu>QKxdtcw%EWNe-B(B%$3v!Pl#Go7#M-rSpSbV!SE#6(mF!aDww@l+!Ru?bNS@cJG zAW8coGx#qfRPgBZ^>_5_h;UPppjqipiQiF_IUl0gB35#X?Dnp|Q`&UT=bQr0wI@LB zNNKv-5pPS$`t1=ou=rMo1Erh!ZJLCb_j@&VOT+8Xa{hR8|a}J6<8P^(&};y;8pJ%rdrx#r4hv zbtwL4By{5n)>F7&z3J{j(9)9jDGI&Qqo(@7aX)ohryD&hCHJ9qDNF1Tmz56l2Wrl6 z(g=zB?Zi5Fv%cmB0E0Q*9^ zX%~;0O@T=zbcaR$2PYxBDB6D=BjNXdmwKRv#^r77Gm|iEuHzx-Cognj&1)1!~KHc za(X}e@r-P-Ye7^~wiTV!f>x!~8lClNsQYRmh{P_XwzLOd%2X9)E@wYov z#zzRj_x z-m$y9wOptIUK*2-*1<4217D40QE2E_`$JEG51Ewur_g+zJP?NM1hA zF8VIZf#RhfG2pSR+F1=8DQ54~Idp5jF+IxFgTqD9aVqon-H1oVZgBfIz;gKe+J$!X zL=>hnP?(iB8C@RKiTlU&le~2ZM&PVd@2L+i?24?OCPABcLbb6$IsGnwfAmHa_Qq(3 zs9*SS19F!REOkN5790hXSOvS6@Gedm9ac?mdF?HhO5mttllQjBFtS{2z1k}Z-V z+H6w@SyGWD*=nXRiXvH4AxbJsA<;yOLe^xd@n+v9+hm*XK1cO#|M$DT@4C9Ko_Wr_ z{O;eqJkN1l+Gc`Ml}rvh#ud{9Ob)A>96lLW{D*)^pnn|m5j1n064^{4%E+| zpN+=ZX_>5<^gsK8-;lCC8fSR3UywN_&rr^wwLrGHZN1})KgxT@rA@y$6p6EzkbO`Z zhNHrNTTKoh;$@!)am%J`HEFj8_jP`)pA9IZqO#F) zm$Zg_GH8UV182Upy^ObT#JS)LZU*~_%gW8p847O|4E`Xm_{Ms_hCE}z!tttV4qWhM zAho7bY0)MX65ibwjwjh%0B=YJ?Y3%<3;BhNtvWm%d!ArmPPuGAc{Ak>_c3beTY2x7 z7WAwlmW-#CNno!$BYAD+Y^C;h?+h9+v3fX-HfTs01wz~)4mFc@Kd24nc$OO#r?N`c z<53vSca`jiHL@Stbt#!ZC)k*N(;u2;SVoE~?w9wr{5F@xl8}Aw9H;8ansEUG?s3JR z1Wej};+UNl^Z-EkG=uiukaBZ0jg|@qR7?W91P%w(95bXqc@(wkQnrDAylnK0KC!1F zgSHX&Q<6ry#}fDrD2JkOMQyqiYBa7$Le`^xmq?_Vb_O+MtMdUWY1ujl()^K{al=?N#wbq4g-otB+eHkGox_6YhU^cVcP6lPaL5}P?W+a7Z_BLrw3zIOrb+vcKTh>NtxhJI%)ORp z$Ut5~Ea;muXh$G_=629WgYw=j;wUFYVBz*$CSKiSu1}tk0iu^I=pz}l4uDF^pi!f6 z#6k$=>5RO0GyHqgU)tm2p<-fsW}GfylB8i`x?Q*dYVvqof_pq(mXR{K&4|rJ#7(@lC+M|$Xk^!X}rq5bi z2c$(+1HinZiRPI&zagMh%S6)y>T}}^t%Zssf|BeeZN|O~ni~9Do4J}p>$oHFoKu{t z!j_nXx}8^Gq0~S%X!vwa^x;Wj|=B zX?1;hBQ(pP!L~aSS>3jv8*9ib=HtyJWK&AnTT)I|$ur`hoaW}%!DDFrTHpn2o{sZ_ zNoYD$T?@d<*<0G|nv6A1fTNOm9}wivplu#P1%u*L?={RlrOf+*rAQ#kCC;x$o>3Fq zuw!|udOp5f)ntt@fq2@Hm;&@bFUw7J$3uG0lFZA1(c!X1L{045@(n>Mhsq%XS7?;pQ6ZXSIeeAmQ%Lp<9n&N-cba_+<-hIXKkjTEpd3r zg8n0eHtxH}(UEAo#iZ08_1I!SvHKk2R=x!QX~RHHWkx(Upom1{HpBP;?Dg`DTPO?> zIGNN&%~M;c@sYUApU@!?4`Lmt*e7{!rL^IGp;_+=dG87o;yZW_hmv!WqDd(nU-#^S zssK+F3?Q?KNKp9(1&vzng7R~kQ99OUTZLtjvD(Ac*6cv*-*Hq@|v~#8B;8kx?8?a^vm-~H{XI!wLFGtz&TqE0A4D2Yw zQcSkLB6D+4J=)-8cGoqoqO6ZT*PIV_|&@{|5|PGhOnG=coozLUzHA`+>4=eykr0&Y{K4RkG3QvGZ?%{eF2yCdx+ec3_Qj z{w*{*%wfT#q?9k;+riPe1-%wUp{;5X=!Lr3Y(Oc8IRRG(WaP?(rfPt?n#tTZI1@T) z=K|sQ5!*Ra3d%Va^gLi_&H_1-4bPy#_(SHms0Ra=VzQf1v`jb*Ja_M&-mA?5E;B%K zG3+yO%+DxZn6`KgwIfHybAU|W3|bd79`tw@6&GBNW=$}IMnrpT4#prASpNZ=ECULw zC=3UK6OWhGK6lc;b$T3#Pc@(fFS@14GbpJ2U{?M|U4ZuO&}D;J#vN8izxhRRGsh?Ri}?%e@nVUzPZ=~DR>-d9Kli%5 zEX5{o)t_5aHAC(8nA$8cTJ+e4e6#M|PfM4pZMUP(y*0m#9Ltzjjhw_+$A;LRsYhUb*~<>Y>gV(K!=Y$E zf`?sQa6cuJk8Xw&2n=~;ryEE9bk0tE9{8`=h91YK5={`DFkd_E-;kJ>DD$eMI91Y) zSg4JEk?BZ82y`8`hTQ*DSS>V*5GaWG5e1|2rv~jDST1g?BgjpWa#^Y)JLlh0=8^br z`aS<%W8wIdiF`aj@y>Z|z5A!RUmiL`%Fk9UM*I^hPY7*o4Nwcc`XZL5nLYZhVYU|M0do9Duj8uY9T_K)1;aV}{@*>ON&YVTDD>qIi(^ z910?~s={GM>>_c|tCNB>?<4DDVno+*1BzG0VIb zooE$(Hw8Ka56RU-Zg5K1KV?*>hKkf6%pZum23CM&Xx+s~@$`$GALPrXTXy1M%L_M?1K z;c4=({D;d9H~v9T3o$ZsyAhy-kIEt~4(Z^eY9eat0uVmNmW&6hi0D{~t4Jr~HD zKHFnE(i7NvVput+re-};u!hAWcszsnT!u;QH!@YZ%Ucm_zhLNRbW`rGbjT0t)WKi;MA5w@_x21{zNh?v*6TWX=K7jx9HnC&y& zhkqNp@Hb<123~J_f@_5TVfdp#a8e65Zw>1UZud9`>wmhhP@X*HH{$v2kKgtq$8bvAB^Q z_|w?xdBzcB$=!1Kto3hm{YHQF1kfg`r#V=P?37h+cR${t_ggOeZ*qsF=e7Pc8?{bu|qS*}B5LDAzz^)bHENw&$LRra&gymN; z8}au*D|fW@QPqQ_b^j5~EfDx($E3UbYiS=GAG#|Hhs{ zJlBra*)uyl|KA>dVbl1%6E`S{)~qgLl+igq81-#A!Ut( z7V>-Rw}$$Z+6-0cCpP(C*e3ADfrFF&sTseW)dk;HM9@V=2i0@`OaKR}>eV!|`PWl3 zp+4fr#U8Gnz{vk9vwu9Uuv%HJ{~Pm$9gFb#TCIO6|3vVokH1s*>tP1zUH!it|D{3y z#C#t!XNV`vi2jA-eg7o+&$1w`|D8CLyJE3vlYb@r)R5bMH0S@U6v#*u_x~td%*3r( zvEMsU(f!7@p_mnKE=T?EVv{l&6WFpi(zvZ3%tej;AcUm3ji*PcEn?!VBS8VdOTWb5<)V(XuMkziY8g85Gd z{_MI{xStF(^Ztv0KkaXe`KSHX|1tT{QTA8GsOWhDlgdX>_>Wm8#Up3E>aWrpn1Z^! zCHAI5!bUvL#+0l6jRl0He`jdVKQr{dO16AT_dinf*VGy$n_vCUN&ct&yPrg;PnG;P z`AUlH|0d#p82k4$YfTMhC0wFelKzq*h5t+GZ2rBc@XrkWg@NGT#jUvF|DkkRi9!Eq z?63WJ|24sa}-s;sN5)@{3Q$E0<>c;L?3mH#>56-5a*Aux2X ztNh&+o|v?hhTLw%6P}bmt-yXkk=k$?3D!gy; z@cQ4nD`GZy$vvQ&a>l4G*!(fA!sv-%Xj|j(_2MNI0V7lE-2syKWz2;14GDd_la$3q!03h%mjUm#Xszf?UtCH-yFJ0s^p zLq{1x<><@(7$fIbUAj#BWUDV%oGXkw|JVOi^FhI|xlztNsG=jXLAU69OI#s$TFUT-3j z975Y}RA+kyc2f);4-qaX6s06=n&G4j$D~c_&jvjiq|&C0Eag>tO^e+09k~f&85Vxe zI$jzLk!g)Chp&1}FUM(Qr|+2T;>!1?tlD<_^JtpmxrfPT3}*+rEX-e5Ei1hCB(o`r z;w{Y?KC)9>H~qXbjq;?eg=T+P+|7FGo_ZbGJ#?-5IdaGcDIiehcg9S$T{vXz3c$uPx^|@##Y|If0FKA#`M~h?~A9C#@&c z)y4Xo(}sSDt|j$`b(JGd8wuM7*lGJipS|U3CaX%2w|>>${=|TGM`vhV7VT7#0nJTk zO|*vhy^G4y=h*2yy8Hn$Zc_C=zLMAZ?(u8g$66#4Y=s9d-;27B^%lbP@{3uO}ddV%U8leVh7pJ&r|@ontUc?S+K~ zG*?2n0_(F4KgFz&%Mmk@dhw+?Nk55)_BC{C|CwfT@ftFTqwLo3eJq0ulgG2s8%UcA z2~V>t$tZ|ved2l5Z~k!l#m{fVu*$~tsGXtD$APk9PO>?N)>oXHeyJd>JXB(S6JYW! zAuxKB`6x&3WAn|g`nd_}Qje*)=|5SLpP5!!RH7^`VT5};^1|hC*_mU#__Fw=jLjp( zgOlrpa;|sgI$!lGk<7X?`PhJ#u9I{jpz>a;7}i-vs&sszne4a8xMpE>_vfZ1Zu)`o zgwB51EWv9B`6=&7;^lU2j+Pt zZBNIqi=X%7?4Fox8{D&N8KU4rijLl z{TD0c=e(eZPV-{${QkCvSuU9lgAM1ImUTzeKZ;=+VrkCF5t#vT%F-*@>-QzBUUOn2 zp|GEW)-1XsFFN0V<|TOsvx1*mU_kSejILa>;dBzjWQ<#XZwqUOxMvhO?|gz>pKgjh zXmzY0r)~)|Om>MP%Ur=I37A74{V=BA%-IrcI^QCO-7HHfSWAEYxU)dafpS{M((%+y z^-l+l+>2x|%Ap=z>!5vv$yY>Q-r5b`l#O^4zI;TAyZLIZuxw|a1Wk%zh#e{?37@jt$0fmYAl%(FCMJGUrufljGx?tv6&>ND+%#&Z@jeHW-; zj1%L@>+?Y!2FDWpn`z-{RbtptwtSw)$E?br39`j8@4TqC$sSSUbe%vcmq**PT)NI? zGK_dKA`M__aMAJ-Zl)(fSD(JhbmMo>ZgmIyBe9Y_cb$2(c3f7L-p%1C*X*(HK6H+> z@gKI>8CpKz(lCDV&Vi#)%-QS{?Vf1;^Sucts6__)2d?&&ZtF?t>$uE&-Gzfr3>}!z zM@L$HXf&PRroVxmE}CnZNJGdL|ga| ztZ~yP%vZNRSpRS!TfO$6(NM|+-lyaNtu1vR@aLnPE%ByD?4!up#Oc~8kV_vu@oTeyCE1Y+^cz`jmchSi6wfyUS;}6J4 z_Y->r9$;5I+g!8~7Zkf7L*STiJFajEGoZ18e5F$4bcC|>)dkWBd4$dT4zdJ+`(02E zR{)lwJ0Wr+uW%)9env9HB6dK`P5(Sgw0@sUNy|YQwz+C@O69G-+o{%@7Vf9yx}RJEw9_y)G4%Xuz`yuLHSuU<~3ULhnt7usKX_Yn9tZ15E}YIoR3 zFnJNI#5#ZW^T2LI++|^DPTjqdT&$v&vFWO)vqA$Ns1+aCp5mN<+z8r|F}(AG6;)o- zXaF|`!)?N5L0Z{3sYP(`z`fb~*rf~IrH;Anw-%hEc*gL(#0@U~MCed>XG>zmjU^MI zLoX4$8L>9q)>=mq5fS3L++&*V$g*Lj(VVEw*aT(m4}zc z6O^T21e?yT@!8hcjgY1|?2~JBFXbUZ%JEdvMy<))1u^o2v4jV9>s&gC#}JDxc{qcw z=19cVlQ|sX)6TgFzzftZ;dXAk%;w@gce&}kMJz_xR z+rz?V{`F$mcjx=Ih*RQ$gOo2sj{(V=KD$Ch>(B#Xr=58=h===mj!o|3z3wEn>7*+J zkGzUfUhzTAmpG8mtA57idKVg&f3A8slfSIb4T-=zAofeG9ZcZ~g14cDgZ|V7B*gZ5 zTbE%^I72GF5J&n#tOgqop~BUH4iV?BD@)&H%g2n@Hho^))N_bag!TYY8+qE&QW8`( z7i>%Cs^9Lhk-5dj>po-C{!wshx=tLa z%v$^t>wzqwI4$8++&^?_dIJ#lz%Am(ms!+dOGjlioy|>3@wOmFkY_Y79fd3#6(fS0 zK0@WwXu6D+!Gr4XjuzQwy--`jBxaXh1nnYXfT456s~3;TvJdC)PndaufRpG`h+L%& zSAwmQQ?$2}1910HTm}+h5jF+psI`!a$_L-}BH8i#BItSLEZ(76 z4cQmY^Q`uM1kGyWKhtOM|)tGo4zSGUCTj>v3}8n#@AUJ58#TE#rR@Y zncyFRgrVt|^Tm7rK^aHat9~x*4uO*e=auOWAbPdy}0#`#K{8(=AO=$8y zGCD-p=K9@7%i&@biSt}R6&jNmRk*9k7leaBI7(!$dRpOaTU)R^hUjoaIk}*q87f0! z=75dWYy~R6NEx3umqs(za$` zvzwGRhDps#sk*mgz!N2B;Fv@E0u>E?@=;y78+n}{yMdu57d0D>W;YmphIC@rv*#dteg{PO02 z3%sKn)0^`0wNKxRMP*J$rHOw0glN{Za&#}*dn6L;EzhK`y2+z{>4;U_m4LoIFs~~- z5RarPxzMWDT&VMcZqA*B%cG71(}O}B!-*qRWYt`_7m}`~-K>9!BJoa7>wbO(^)gP% zeU&(H+!P}3oIAY7rlVC9s~)py_nd5>)5KOJM$glgGn8zzNW@@C2IrktGt_o~A)n{N zB1N+e?6-E-Wpup}#TtUSQ9IrDf!j!lOIZ11hjlle@IjW0{)$Nl>!Q0D_yp^qjD zL7H!_`k8rnVM#I)fz31}P3s}hYRc&-JCd4tW(#7Pc-QN}^|pE>+PSItv?uwG6{VxO zSd7nI#UEnYUM0vWT&0a_aWvH(L4z5c<(tmGiI`)~?@6l9JfmVjQ~W|aN922~mh~|- zr_ifrkK|pRd+9-o;`=zYzMezbroIf%Q2?lL^0uUxz&k{jD7JcPspFRY`^~P2Ht2s0 zt{I%jsi8Mv&Q(0b-eb2N;1~T799)~koPtV0VY;na# zDy^iN-jst=*tX?sC|9j*l@c6{r%J5%P*%A|lDlK!LD4L{5|l+D3O%Q5`JU~X{pt5P zB`s*X{?3A((Wy&m3c9jRS&C+G{+Et)@wgs;3FV}RNG)jeDBZrWdQoK|K5hNuJRs8? zx0))fw03$M3cHALs8ZEC7~WqJCh+6_;)I$Efu8{l+BWVn5{L5L7vi@jCqGkQ>*Bs! zK^oU2o|Fi;kh5jyFit|;t7Yi7k*FOwya0$LfnwG}Dm5R#EXv#zNQtI7R4KvTVtl)n z$(ZX!kS{l8DSCb}$)y=sojNR=%n~re9dqUzAD3B-_FA&6d@KH#sSt?e4F#qyR%>3Aj8yZ^?vBK!$4b#@cS0{r z7$aHD7~1Nv-MbX22l*1yJ%tN-i_0}6o4qoT#~oK;eC?gQ2aW)XVxLYtH;-hR_b*EqD?pKaNcjrt1f5^~Cp zLI=U_dx~(iW>U*~`G*ITNQqfX=vtOxCQ;iF*;#k_C$t8%jAMjD+niz*rN4h6 zUdUZhs{2^cY?&F3yY!OPw|%G4>OOBBaic{P!RY-WCv>knI=xiCi0dACuDi3TQ(<-q zWBth3-GgX4(bqJxBbys(L7~E?@C|;vv}eL)HT8E1a@S=kGSe&li@mGJS#awA(HY9e^h2@yp|gVFck&5@r09ijyo3)x!qT~F;~fvL?{s~H0zaNmw|2K8%oQEY zOX}X)J}6dW^R8&xS@5xx!!f1H8_BuPmO|L-wxJ+Phm0NTW+n zTJHVES5;(D-h~V=Y>)k&O<q3Afc}CsC+w_{Voct$Orq| z9g-aqFDckZizO0VC01H~%0nlXGL`RMgS8k^s)^N{r+?(2rTSi|I4AX4n<%y*C`RX7 zZlf|foweUHTq@)OdodMzoY^YBJV3u?n-A_kPebMQMXDR@UIU((#+9>kc`+TCa+CB+ zLwdFm?pRtt7duGoatII1TQq#YCZx1BK@M(xB@gq?l%sXuU}dAlN=27GO8e7{wd^Cw z{$qI3!3ga4uqq{sknp;F#G^=PRi>Ed6&KMgCh%ry$NAGlvCENdoKrUSUe+`3mwO~X zylS(2_ALKB%LN*(M>Dtms((AmK$l$m4QE5H< z1VP~D~fJs=yKu1-`?)Ric9k7Nx97v#)?^=m$`>b>Z@H;CnTVEnx0F=#m(wKu zC$P>iE2gTTt+{H{@sE=OW^f}(B*=;Im*jb(Gx5!QgiX>XbZ(ps&fRp~zgiS~A57zA zhgR1>J;S?9kDmk4^#N*nT-f28M+&<1**K7z*%paaTnX<KO z+w8rJ3ct#9yzA>qfs+1c8kx|%qnIj)hEsOjVS#~a`Z;FTogt$46mw-ht;uRQAD8h; zrF<14>6^mM!}2j^^Gr4(nUJ5kg?i8xaj|l;jGIzxdAnhY0~cmqvBYjrX~ScnW9NLt zd_^s^DR!>tzfya@8R>h5v?6pJ7Ba*|w z$qSf`-(h^4n&IC0iWnS4ySVzTUBoAv%3G7ji=dgeFDv=ROtUD~8EzZuGP(EeZ$~DF zzkRc(YZQ6~nK_mloqEs%fx3UPdTzYYw~CywY=P9I6Y05jT}Rye_X(OS$Yl=&cDXKI zfeNS(H_en?iZhoBW7#O{lONf*p~}PShvXMrBFXE5&bQi)xe`(2Ru}m#{E2A(t=96n zEh$GU+tXlT2i+P9d*daJ5dR5+({YZCJCIA){zeI-`9&;t;V?9bi+8ch;fn342-)Oa z5BJ*)YzDeHS@|;uzusFwkC~i25rfw()buFJ;JxujWAB6O_Bj(M1tR?Z+097Fb(}4} zXCP*KuzLMm>f@^m8TY&IwC>AnK(7ENw9Zx3&`;STtTUIB)EZWyw}e6o7EjwB2S^ju zk7E}yPF%j2?`+hIUX|Jk%MRA>R(;|8sksjg$x+8|NgEFp-%Jzks$UeVUK+~hw|3Db>7xC&*QZ3lrw{lX zZcPt8>1i#zZg;ZA3SM2^M>ml>mEq_7m);_hWg&|{cyqk0iDl`FKi=RSv~Ha81^w|E z0%hNYFFa~x`HPR%?eMN9bi6}-4#$1nY2@yR+-0!11mF11M$vf-&ka@NeVO(G`=1q| z8i#%yFFqMR;;<+cx_{1Kk*#mNj*Um3Wx{QI7fv{y=U&6jRT)Iv7mjDrnf7NmP0q}#wcC( zMa{>W#7pIupdDTOsE8}VO2#no?wT!-eZ6lW` zynM=aL|!}eaULBcxBFjSX?+iVK5FZ7EnD7 z!!p21^nid0vTZ#|sPUdsMqh*yOB5A0l%dCB@tKvby0@oQ41!C+et{>6vu0u`I&!PZ zyb6=GUn2*q;wd-60trc*M-uhQjed3%Ow=eJsXi>K9-qg-@*ZFEbyk%I??UHWS9fn{ zxQJ%w=5z(QYr+9FcfArr5U}2U;=r9eHkSA2pirv1-cFNz>*Z#+B0-GihbySm6uXy* zWKbN6tan%Bc_TbpEh9g^FC#=N0?23Z_BpVkeYrUv9ZR-0(N~n?>f#HZuCfke`8oVJ zMTkbj-Bw$bINvW6S&u*MWfSQ~+U1bscWd!2RW$d;4Q=$^SbBQJ1Nvu}O#O!K z{PdaBD;R@Snd??>%KoUb;-%Gmpi~O!l*@KcI+rxJkK=**TBF7Yr}5<;#VW?R^W!8! zRk+h*ZV#rk@!Svj5yLx!kU!6M>9hD?Z8>HZmvHv^F2BI5%t1eg?TYYPv&kGYuHjBT ztybVs{J#1r<36EYk?I}P?_H(D5X30k#L8&ZL$G)EN*XvMnfk+PP9uB$DQTQgS1LKEB@vRJTitS$Jv$ z!OddBZd`R>ghodHI3(V4n2mNaH`0**+VPv5-h)ex9XmSoK9{|KieAD{H&}anv(jCP za}1_RRs>#`e2whquTH$G>Z2B&5Tvb6SReZw%6a!rwwx=sH$&SDLPxe8d%OGFj$6yg zL{9war!e@3)g%`x58s%87o%2g-ilN^Cckap4+JWEAQb{2{(lqx@}x+XgIk@c#Z@cE*FWtt)M0=$r&OsVn&g0E)-o z_kf#}cXc!J_NnHkzebQ2pqJbz?WTWt8O=~n>)n}VvL7eeJbb#oQw%$Jp1Hzzn4tjvt2nWqtuc<+znJgO3QFZcO zR4!Igf~=h2ndW~`hK`kNrrTJaa7R8mG0pba3?BoPPfEt6Pi~|&JftW~M{_v(=$1I` zbJI@}q^+!+?K=@gj*od^aiOgS!QZ-f&xZE)gGTKoGPu6vrj^L|CSKk2fL#zU@&$MM zS-hKmX;^sLMA5Z^m|}A&sXl2>FtL~5Wo34P6h&5-EX2-zDQqSe3z1K7ipLJ;Vi`*@ zpLv^36&0<-P5Ul&6w%#$n%hl(=wf(U;ZvYTj?F^uNlr4ziDE8(Jy_iKNesI_2GjU$ zS8fE2wVj>LlRo_km@;Jd{*P1iY~uc z5aVa>EcszYT*%BpnOkh+aqspAGY4eo>IAQ9ec?kgj+=0L*LoJ3_2?B!m?HkkY;GHw zTg%8A9K%bePY78E(vm~3e%Eo+Z(mO9C=Pzm?!O+3my*izS^j7xPVh84eO0# zLhj`dZYhKM;lk8T8#+EzmQGnh7tc+(-9j7c?AT$)u4q^%)LDJdNVAj^r?+!Z3Y1pz z*6eKFWxr#iw<5+T!dDw8-xl-YwW)Hu7`A)~BO>kEqdW-UXbXXHGT`vVeX|E-ZsEu& z2_1RJC(z|OL(f-G*mJSGHHB|n-rtp#fDl{kiJ| z+w6)-{nMoof}^jb!F&{rw;A5|Z|Uw?rdBV8Rgsbk3|kAiI3l^Qwx*WlwvmuhBTKP< z9J+Ff$4!43m-O1C?xSw{N>U+;LIW!x2h{L1Ew6jZ($}R!O0M67veay1=hb~&Tq%a- zX0Ja`=k*T2D_{cbJucjPVnExbGqheaN5M@$my2Gm7i@I`9Nc}n`#=)r$x{AiGIKNL zTJhaHR|s7gW2G0Y{80=$x2$g#jf1veY~8q3f15 zF|6PcMvP7)K<6ifH&GRV_)lgbel}xClfa4?*^nc-zTrOBTM-xf{9u@}wCxVI?ieem z?S&Nw|v{1g$5CHZ_AF^!hMHaFcOp6G!TwsTslkQf!rVr>rZEa;zZ}2_tYut%`_1ed~(Cvt-WrsT>UoKw+*DPC&!NjAV zq5K=ZYq%SzW_ zE5K$ohWFIoG$d$y0{PN*K2bqGh8;TYAUkP*>gDh>J#92Yy)+lv)a!P*ZzMQ{vit_+bnkp$iH1^e<>A4A z95j}Jbwg(DPKfWv+bh&R51fHu#F*3rC8QuOPk^oOA%02=+;e8QAFDNLq09~99nSdXp-yIexd|iaSHB`E_Ke*q%ur82 zI-8(vG*^rG=+ri|i9L&co9dK^@?JHdi-t0*>kv2@gP16tPkUH0@eq1aXs-HmaK_yT ze;O*iaA=R(xyGN%glWOTBzJZhy?fggzUA*2QJdo3Wwyc>rghd zc8W$2QTiWe+ItlHR~u!u+C%Q5hiR-dMKl6Oj zJDloYf6%COIoLhbsIq4>`dMkHzp}IA9m++(cGs~iYqZX$s)MB&_X=VX5aG>P>1j@A z0*CB4sM{J)!z_hBi@Ze(b`b{#2GLaRR*6iv_O#)r_yQRXX2>T?L_%XV&p@UpDy(tS zVbl3UG$o_%n)z=*%6?-X{V|dV4&7`#>I@0KiT#sf*eSLN=`Yt@q5&e3v8c9EJ33zDG3#yl1RO>%x z^aOnu_DQKI7_$sm+&z}Q-!&Rl^&6Y&cIP7e6!o^gm;k+n0M>Tr{UX%FA z?3_(05^#myjNwkcNHeG+GyNnnnLKtU%t?tZOX!WZM(*yWLeonvq61>GZ9#AqMmY3V zuN(*-?ItL0UK`kZQ>=l8)o~B^UXtAjo|a-(lL7-=*OC(bgvlEt6nbvLwLed1P53pw zeK%Lj&>OVi_UybNdt>BrM*@b}PNrQ4Ee*^d$Ie3SDy4ja@sr8QYbA~QtH?HO!eleA zSL+K36wTJ~(9Wr@guADykTYAoTpyb|yieB3QGS&0p77NmB{C&=(|f*80WNoL$ureM ziH!pA{vx1nm)<-d4Gy$04dFR$pAzJHWEc{-5>Xk)16YhT-`nOAfRB-UP|-Tx=mC@n z@TM1xdYB4P*}U(kT`s+-XqL-CpYe?8bBiR`7IDzI(zQ<$(Oj@RzV@#~6W}}g!m7YB z82xZMa>P^80)3C|3^MG?;}V6-1k9TUIM=iB=)0@0HLu;U&Z6uyg^Av;o0EFxMgAai zRrBh~UO3(v{Au+EMr@kW^Y}|jqve`%#-%Mwr~97v%*V$|O1bbVzMtJ}$9*d=ZC4dM zo)aRUt29Ein(#c?mCQZDuv8Y~J^byD#A&+@P8!BxSvAPbi1MbFJ0?!QD`8jMUHA1E ztOS?Rm+1;#J>I#Q$W8X)oOHi?wtQ}<$l%AtH4%Dr-;q=x!z=njrUfmIO+num{uCKS}H7Rkr>paWGD}74_ zJ{~3|qZHFpWfTHQ1g10$F z;|qtz@cf$sR`A|E%i74Ka;or|#~<&^;{tKHNDLi(Bf2_F@b0Cl*u=gvIOR;E9(;?-Ybumv$OKOCPt06yq_Hf1Z$!O zhk?leur%o99Ou>-_ogDFO~-! zA~Jjrt2Vd%+OB}|8HCNZyw8q879pmc0X#B6P#F-(t(=I3OW+S8=@UygKbkmA3}xAz zY7j(%!h`E)2lj9~E$&W~rP1FijRteD@>SQn3>-<5UKIJjn_&&K2{Ea!I<~}KbL(Vr zERYygl|f)46&!0@?CAvz#1NKEAg-AKsUwEL@@kqdG)OQclzBS_G_6?1UU$X#QHsXSVB`;Tq-qBe@&b&2e^mV=1SRR z0!BN)C?QjW^hX|W)+O(f;H5Pow@RyzWG>9rl;i5lo?PiAzhy%_WHX#>)69EXsv>j=v z;PZ%y!FaFtvqYdLWnE-8K*OUDod(uNeDP*BrxhCiv=-guYS&t=wEAt8b ziKE~hsiJygI;+PUFo3;x~u1^uZnYW8Uqv+CRMiDd}k;Ku!8`j za%NL1{qG*_}*RXY^0dvU!>p zXr|wkM%g(5N{&r8%mZ#d@NO-r=Xm{O;ldQ7yl@X5V7x{o@R8BbSh`#wF>9~23LGAN5gh0xyZ<9hG+mem+|~|SOOWjf z*rqr}ErVie z?X`wd!ApS6KXOah1USGV8p1P2fPp9MEJnX~kz)u|<{{0Z0Gi#6ar z8r<7%tdT4OR9HaewuSpL1Sby3Ei(8SK zCK7(GKUAr2Fs;z;TZTQg%bAqSi>Rh>(#k6pq7ls<939TXUON-kwQ?Vk3>|qat|$|~ zxc2zuBRcwW#ZcI$X<14w^~E&}L^XtG2-Y{Y?0YEqOpjx#*Uu^CDm`^oV5>Q4{6lurmQEza>86 zvz2o;jhjgo9_BcvmbbV~f8rA}2J(Vq`1KDeP5KcB@HX;lL!^Qez%lqj+`pm1TN;Uj z4Wu_m4w8Ou&&l@LpM|JpKy#t$+6f3`0!}}=XU%(iFlY|jn=4)~{ki>pYvh_=+j*Gh zx_LjhH|3_)Kp0UK!MUZo>UIJ2iYhSP88NF0P+CRjs^121961W&?r_?Diw%8L0Q~wx zCH}ZwcLvE3KZvYVybu9NDti%}8#v-kDE+zJ%OR|dI0EF~&+2M@299n*Q~Y52kbDC& z053|{HrvaJBPn15wk%0_t!WAmb-vu)2jreHr@F^#94InTYzf@aOakh!VxR$ zz)C8wNdl7I72vdXOXo!d3nF4V#)Xs`93S7dMg~B==z2o@Ej+F_e{G9>{eT1kr%KC3 z{%6;BL}Bw+F{yciBAwM+(A)SVPo&FHK;i^Qg!vV&A#RqYI;)9_ zz?-5%cIMQtUCL|{k_a3q7Dek;0zZe~{xBIehTwiE3vP&fz9YgzVH?5w3~$TCjm2%x z-NKD7NN8{bs$}wwA4C$dl*Jfc2sL;BsAgcyPhoXKTESuv%+FbJT@gMH=EOr`Cbg+- z%jIYw@et%$%d~ITZp+<(0Zy=iZjJ&cq!{3UI;}faVEc2s@OWCY z_%N)X=N!z0U+b>q=1efSOT#9hn(}-QEKd9(uN(Kp>MVfN$fD=>bP2T}5{C8D`OOQ- z>OMiBdWO1|GFtMyR2zg!lyyoa<<|wkayI$uG-Lj9D1HKDrp`)s(h_eVAuUu9@}~sa zcOhP{8C=~4;uoik?903$o}n$vDA`7lDt9ToI+~YHtKEjXt!LA>>r72-?-L=b7S_KK zVasts!i*OTY27iFgg8CTPH=KGH}jvcwh49Gl%F!w^;|UhMdP=yBeB<7)kkM8jd7Jd z3w-Ey3wKCEx%W=j*L!R7D5+O43R5%pi|tho-dsn)ZszCfuwAd+x{<1n#UYE~g9I;D z*zs4~CGQRN>h_EsWK?(r%Y;Z6vQAu)Ix~7Pd{0rc8$1<>dEv6-t}uS+oD42hqO9eT z;F(PMqK~Q}KD&`!tfUlV@jla@s;g5foi*T(EV&5bZK;TpZV3X%@;!MV$56x-57a!N zhdo~{86upRus^VFT8F@)d=MT^Bu9p)5xx|_Lvv{<%OBGR8M<9oMm*P^mVub(E&|8K zhLpDebv~M%Zj~+5Uf}r91WxuG zj^L=8R0J`m0U>;*5v1f(sIragwK`H1>B?VM50RqCQeM$5&q!w9?@x4z zg*pj`(Zkb(N3A}EEl|Ixg%=JYD?6!>L2J`%TJoP(P^`xe)DOgT98plir8Eup($z|< z{P&zxOzK{)n^W(W%PqSt=EW7+1{*<>bGmH3uBId{(TD3Xo{l>u@8(M^%i^GK)IIP4 z6uToOs(LwJ+z+x}E;_7*8A`FCgM$J5*mC3_r|ad(3y;*u|MIJInny&*Az ztzP9|D)+HbNOG=#)ozw%ouHa-jlN^T$(i1Yw7mq5J2rX263gzf-!gNNwFUF1)?!Ba zTqTg@#8S*CFJBHUTOaddMoF6N4Mf4Ic0qE4-jQDRYsilza(LRFuamW5T6lKHD|Pz< z=Ev=8g^hT`o+4Uq+a$GVM~(ufq0>q@z2)wC$Vv*Q>gxpFZS$7oTNVoKKq=#&syj4JOd8b$eEKS#GFvH=>Q^E zoSD&C_#Xq!qaq5fHURgIe_=)pY-9nz_=vXD%%}*!{rny~HvcE}&zj`rp@ryeF>lW! ze1m!$m+c-YtUl3M9Fs(*PrCes=UH(PYu@dj-_=g=t4!0c&x}HY4VZYr%J4t@9HVs% zPoqicI%-Hw0xd*KkXFOkB12*cns%z2Jt>@Fm!K1)%wG^5J2E0^=?KphKf8U}A4Dcu z6f{gB!~$PBJRm#*buU%XYsC1MkF5Ugs$i=MSO`l{Tual34CIQGQq$ty(ST&L`~F2? z^$DSD5EiCE0LOW473`g(*7cs+_!Oe;oW}?u5>U_Pe{2Yq7xKN2{x=Lrj3%&&ew{dL z-!A)5*NHTGE*%_|7Ox9;9GOwjyQAL?U8j2<`)!v}1wwjcwR)(64b<4EwEKbBM55LT z+kicI0tG0&PK{;!Nv+$DN<7oRrmHL~sx7aQaqz;sbp%GTRecOHRu7CF`s25#7EbC%T{y-0c}nLWfhy z&-j(9oUguKJm*D?Ktl?|5e!hlK@XfP zMI7a78fuh@i9`fUUW$9(qkv4h zlZ2)l>JWn|GDca~{bZ93MdpaQ@;QG30yTvZFj929n9XBgnh1xWOn<4vrvEH_2)X#9 zXT7XPw8k>>LiP-rSBKs>GXK~25Z_4rGdnw0bSUahi|l+)fQBf`)>;g$%x|`Y-i{A% zy!s1eelzd82R^DksYHWC+#F?JXlRgN@H61hgD(B<=%gcSjxWgazEQIT8DeIu~59Dc}9*N zQ8(2oIbu$cASr+#mR1E~{%5VcQKdiwZ3>W9h+`u!XLQ`@OapiR;-uZWAdJ35eO|R^ z3|IQtG%_|RjOJa&lYNBK-!mD%UU~RbqRfzA)gPM8p9H zoS8B5DCGfrLi!8{;az1wvV}D2tq;ytiKhE;Z(1Ih8%>7og0O}RdPVP}7k;Q~iin)E z($f+#y0+(edF|h*U{~LvZJkCyH^u0~&W1Aq@wXRq#4|{Dx$h>@&Q_epNs^A1Z?q7Sj3tQT%OzqSV;!akSRpDYmETX%A@knX3ctf z_0Fka2fldpt0M#(og_HlVLs1`L7(+>H0kPzHKgaI4Rnc{YVtMG_+lZxf{-xUXhw)w?D-5dAO6uDSOXk`T zM%@{FB|P*E_EETfWou6iCUdPA-lO(A8hxAENzvT&o4tY@e*(6w_Xrj7^G)g?)pDF1 z9StU75z5uIsc=?T6Vb%qYk$<(+T?6sxR7m9`VHFLxG8dnsc-;H*FTG3MaP*f1J24vFpe*Hjd zR&DG$uAT}{B?G?aWa3aA)OdeVcAEUv^$5nB?we3 z7-wQ|OX^RnnEljp7$J|i$##ohmD_#l3dNy`?1~jHR__uj@7BJ|mb)_t?0Rc#x3A4K z)zA1!L4bV*1p1$7E<4rxZw~Y7APhptPoUe8HU-B&E@Nbv{&sTRD0?r)jDElmxc*ss zZxn-!eM~xvf~+{g54c+_ctb}oMY0$FAAA80H<6{Y{R}~mnZRJ#s!njW!2pLR70to% zE1RBda2B!_JYo`-O`{g&1Tdn023p-ANfn{;b)yh#W1Pdew{#1^+^~)~1yhk2{?4U# z`Q7e}6Le29?DF+xQ9G5p)^bEdf!Ci$4GXB}=lC)K?G6JhSN#gEMEz7qQLeoD5U}=6 zs#v`s&@INtA!iEPR44^(7V@ad!Rm=ZY_}-=bm1Se42$ty;y(7b6NHCyA`keg!?;ErxKb_)6-U_DgZ38AZ?KMk%G|H|&7O|&NpN2IV=5#OW zsj~}FfV?SBT0tDV766Nq#NMPFsn+$V#QeydGuN6%0?hUw{;SxbVa70VZxi-erO-Sj zST2&=g~Xb6%hwV*nY&Jt{n!Zx<0~POBYwsQEYDe;+RVE&sC)91*6|3HzNul*@ha{f=+C`KG<>1X(Q}anE3MV zDVUvnAdxc#)-+%v(GQPWGUH=iP)j9Hg>K^ol7gjuo!Oi4!fU=YjGe6n!^g@$W?XW-8IAzzG8l zK>?>8VMs#(%AUSFlq?AP93;5W;o|f&&hv;_7BmHm!mPf;)C8|Y8{*@eAo25<^;9n^ z3uQSwdvxn?xOD#`8eo53A!jS2qDqL&I%>y}Rh|UGY^_-(xVitnhRpo5dNCTYv&Fle zRPkRKPM=`c?&8El=FoeBL(%m^Paf(mLh|x=gnNdbynAG#_w>-vlE=D`MD*Mf{J~}1 zopR#S_I6As9uIb~T-z~KLC*FW1zm)3T!bY44b{<+9ll+?Q<0-|EM>Fe0R{v2h1Y!1HU*SvEnbUZmd(X{%hK0qHC?Oy+-dNg;Y_(6Q*i^9lkr-4IoApBjwUC=#Zii<|?A zdtb1ZC0dJtGalG;OEuHUd(O*l#|ECXHd0_s3-2^%QO8kUDO~!1s-Rl|? zo!y$s{D;*WOXi3UMz|}bdQBe;>_^pJW6yKt!5kqN{HR3@kG?yT(>(Cyg0f#?W}_!> z{*QQkKJ1!c>K@@YCH0o6wWbTP`i`g_y)}*W6@lwes$b!c^J@I82+L@o%YdLBM%K&((!(d2Q#1JoR6v9G>SE% z@5TjHss?W8$6isJ29BGxB-hu@G8?8ykgu+ZzLUUWS6Nh9@QLmf9Va$u%A)=A%@Jtz z*>Fp--W}@7m^Dy>)d`QyfaUR@JXhh796mY1w|Jq@@n6y)ITw}IN~Qht?h+F*@cEA! z;c@#n83_iqJ6^!fFC#G%<9TFDS|Of?;Hcs$qMYcNel{`W>4mAZ`NntX1W9c+O%5tO zgh&BPZps|g_(Si@3`CZ$C0UUof4Gr~yIZ)$i4Cj{L!t&j<0Iw?OJ^V`ojoPty&O|6 z?L@0<85CLH0XG`FenU_Co(3vzHx!$1JS+AliR4n~{i@d0$!KV_=(nl*m!*xC~xxj>J!iq0~JKK&xpNahGPUl_N2<$icL2X*%$_?@1#s>!GM| zzuA3E;>;7}x};rBKK_Xu{+`!tDM_x;8Ayqd@MJM*Kq?iOEDF>6Cfn#<|C%&%_sDrp ztEVe|RRtA8Z=b>=v>{6%k)1zcafSpK8+N}Hw*l&wOC=kCI18A)vIqp6Ky{^_zSA;BnnlH*K z#zoHcvbDR17l;fz#f3)#m#0vLK1TXKl!ZpKlUd*vA2r4H`i}z+&_{LDJogotW&;Sf}#5Hyk9ebV=H2&m)#tK~ixQ zAPd64UiXhY9+>3Z?epJ4l*NiI|3hOfsEtdwaCe^9 zl3fD%)*~j_EZND5f2;tlJQ0s`|M)QA-SCkq`Zkee8+C_ zz3}5z;y84Axpz|oSMT?7@a9W271IVQMPzd>XTp;x$|>}O-lcJpQ`RWz|6mQ-Tdpjj zwbvpzT}oQ64nT@^w%bKx6(0BQZ11Nb)oaq3LTh7yRr}|VHDCqGb0ur$K41oe+Lwtf z)Ok`rDTtea`ddl%d6F~QN_g>6cH|`I6lOby^13i?2iyPAJ@mg;(^?myIm~ua<@IK3 zJjq8I@@mHQ9|tlHXkQ*+0fzyKXQXdSQ($L*XG8;vyTGBl0BX!lc^U9l;JjNFdOD8m zeFGeRcME&f&56-IqY~5;J#TM3fE_oOu98#ExZJsPgx|?tF3txK62CL@hR&=R;THt; z%#HAul2dFAZr)@II`;-{l5{6PqC!lRq}==js$1a)wP?JodMsQQs8Ru zlv9RbD*rVrW02P@2|rU_N8mEq0l~_2^yzD~%yS2AXv*t!IIHwi|D$>kV8u#Wmjb`F z%<{-5P>&_aukP~`)By(f{{_EDB9WH+%?ZSP+)%oRC6V3~&BR&FeJV@j+4dtY#fl@y zKZLM;Jlf9qi0b7VhBzw-h%~5?D~^`& z1t+%s`!5x0di^iLRIHZS9wAEw+a-K6(Rss|xfbWC;dM#d24I&2n+u!!-@UnPb0c>xg& zoxvf7*4w^Kae!y!<@wbTc4Z-uU?ok(>M18Mj;9)Z(iIMhIV7DKd2dY5hjhrtaxU4}UjG?314y}l;Ge}p!HXxl}-<1obNM`qU{_x^fj z!15i?KmJ?aeu$~dF#{||P{c&fK1z+nMVFL!(Z{{hji9P8ws38dKUi3UvHo@2ln0da zq}LCx<>kto_3RR{<2Kl1N#si8O0Unmq*I9Yu=!`2vHX-bbRl#m$g!F{X_?|gpgh;Y zPjzmQlsPH?CBiTr_T?-H20wqIn1~lgBKP`@iDWp3p{$)?vt>;qv}8yl8k=%(wn6|x(RKAB_UuPkP>C&ezw^HU>@5~ zc3BkwQ_0vbG(M`bSOl+%R=X_e??gKja^H_zF5+~ROI>^7*F6U>tp)Rp)kbF{rJ5AO zouedgrJ21vx&`}a@9|>IkBn32n*X&WyG2Z>KK}ojbuvxZjtJg_tZSQ}B$D`8B5(jC z+nmh)UXl-OB22Z;3}rvnGKI)xnIEH8*q?5o%8oMry>Lkt?|lrl=f zhsqCFO*Z&}&9!rO$qGr@Ntstu1cGqg$xmFr<;`vGFoaP?n@#*flBZ@uJyRTf&gVC! z*&t9Kr12z2r8#-9jbo63<(fY4R@L*$^-2pe4l6zYJ>=wma@vd-YqrOuE4g_CijT^E zvcE<>SKG^LI~%Nc>_Rb?>exlWAJ0wKj5~rz!3`G9hV=PC=pbNgIO|DX39bxL1?@Ck zI~ii-7d`uRDIRKkG_EeaS3z<_6YfGdl^n3g$LwV<=c>Fg(^Fupl25R_>^{n; zol#HA!9`2+LK)Su*9?De*MynsNXkji4M^4b>~NDbp>+o^hhpzQ^vlB}P+$L0%M-bl*E1doc9g~ln}kC`g$S=+8>JC z>q&Rsj|B+NV*Mh|L4j8thV5Lu5 z({}n>3us+k6mNVD6nDQNAq0h}(z@CKhwKtVO!FB(uQSaxgOUs;HmmRSWpTru86~?U z^W=d={j4&PkJF!EjvTLmH^QJ3mRSB$@>=FrILZ@U$vc^G=(-{Sg=pY823`wA9A$1i zWjU>BYXH<0gQ`lUsZi)LQ7>742a(>rkNE3$L{-q!2-R9;64 zhT}>KP7S?d*S3w1X$BTNZMf#9U4Ud9xxMM~7w@k5TTDS##n_9GU2bOdJHk?hlQ%`b zxQN5Wj_^5jir#%giD~8uh~}JZ526FhmAnP)$BsaAHl3~iMd4&*PzBq!DGNNtsr-Z& z*C+KGK;%H9p!g`k8N+0EkOqb^H4(aJNOT_F19o}Z_5~BjiV#Tvh zwgW}qtTgbvE1c{(0&8x*T*k=qnX+S@#*+@ZQ&44-{aj*`LS$&EY+W?7W;DSWLeN9a zW1dA>p8_F*$L)@cUXsIA|H7T#de(M5wmb4pYXIz_LSdbnbz41+(^B4pQ(_(e=tws!$ z+i>7sDw?pvpFi!6xg-U}{rY;91E<687hg^(xTVO>y}A}v!4|y9O8Wk9KBJwf>dm-L z>VLWZ8&#|NgS)oEPm6kemUm2rQVRWk5V{6_hZFi$6+IjVIiqj3R7{@C9Fau4*q~D0 z<3Szf^L{@?#KJaP=PTF*vhJ^VI4kGW1LQ;ncraVLPo-DdiDGvz@k0t2-IIhJ%m1)# z=C-92P>5vXUv5iZN*(rymvx@w%C`$*gRF&m^mtZO_mznmM)5Oo22BYW!cu9>FgB~< zDG=Hv(yg;pg9gvTr?gg{n5gI#a5cVSt){wP>$ z!rABh%J|w%cdLtuYp+8~ha@^2=i;y>pnvJ(QDulic!hHN9W%HW2Uj;4a$`!rjn^+; zHd?=m#~Vo9aw2LE+4)53;7jF@kK-?;{Fm}xFIA(@Er)tk6dfL?G$4fKdVT}Zmy@(} zRcN20oM6zS)u>RBU(dZul{rwaDLfjtW6tZ|yZlmUb)mERjta5q3~4o~?mkTDtS8HV zS>xt&5GERnt;-mJr&TJ+Q$_`1u+4QQ9Q}p?qA_+kK*>H3aAf#B^m{rW4Sm}W>L_S9 zeCVi(>O(?>qk#RcLj9H1p{NQ?47x5j^M(;DcV}M8%yXg4j2?*tfG0U~gjp~Ea2${x zrP_Z!ou-ae%Y?IoM*D~tB&H8GRZ-oar4sEaof)KlkXhn%e3vOb49vn48li=Z08-F}q1T{%xu%%vpOI-ele6Kp{hSHdY+YS# z722uk!-!4IUac*60PmYGJS<`U*qtxpi^)H$K}dC<2g`!A0JPcb){{#?mL3BZmYLdYf< z>{RMG9uSB`^u42F0Gb)YcrDsT9&QNHkTqI_S^8I@p`u`ahMvk>?s*ze;R+}0xNA*> zS?gn(;gzKfECM*04_nU+t}J;>SvnTmN>nOEe`bj`O`4;i`D^&}YN zoDQlS9(sYpb(&;b@P=F}DniRxP-2ba2rxfmL^W)GixJX>Xm>JY)-q0-o3hjkGxWs- zSLNLoQKt}9cGLx2$FC^LmA?uph}+xc_K1$q0)@>?SxP(w750k2%DRjoP`S_nz!ZX) zf5-(PFwhJ|x=2JH;eQRdR%=p3^|^sa-m$bSHOpwRSf8C{ta+@4gfelF$Zji!`1+TfiztGQq(1z7DWT#z*iZ7pd<0ai0|{lq#ycpy^m? z-JyH_bRnj^4`$;#A+5pom3Z8^rp$@K^}%;>Li4K8j!zErX5M1cq1e@9Wl zUPSw-rw3^4DnU>LbT3b{v7i4^D&pG9v7$Wg>iNGlnt0UP@rt-_%jDdVO4i#lUbXRmFPs zt3o9x86Ebj^Hh|c3>Qb4yu2I`8&$9o&>7|jybB{TfBA5Ls!&1JtfN5AD5k6dxn(wk zkGK3Z-(N_9Oc`gGo6mYPCRJEhGF}Y2Ft=K?j5!-cb^P6!gb-BTyL0+*ivufkYFNd0 z@l}DviIK-J%5d8vYIV(~$7iLWXykW3BB39T*~tEIg4e+YsV+F0ASh0gwrIP(xd(U z5GRL}tH*^IAk~DhTNy2|)tSE`L8MR6`?R-^yXCY^Bu%dv+RSR>%v(dL$cS2kp~~GF zh0uGH?Sx~OR?A}P2bs*duK*d+GgM)R78LzgR52=aoO#=&6nf8V@M#l>T_5Qm!m?Sq zGg55yHk@1?SUP-;k_Vj`G#3PoBX@a4Pzx4Y{DgyMK6)i-CJ*@3wl=~#`+Te#F)W(T zsS|AO^fF;}t&OWzPygu@cK%f*ovFUt7GsVuS2Jin&lX}v$HxF*i3S}0nI2|(b0DRn zKENHfH@nEuu=*>A<4`&s$4Ag0^4!$ynHfhFqz;fn68mRFMhZ9@{2qdQ>C)U-)Zjf$ zYBQ$p_A@g~DMSVn#sKtEw`1j#!m3(7uUNHT7{`%@LF{J)DWcm?-P;K(t6ctlsi91| z;H8Gg?R{CSEOTYu)CUDDRqgG5ju>}R37RE{X?PPmz<@*pi!-L`XwOU`{7`Kux2=$s zWvg3Zm$%rXr=^u;O^mz#!oBs^G^895#a{@rUeV4=LU0x1?nQ1&_b`e@>gmlLaQ-7| z3*y+}$gL7Z^5iyg|_W%kHL2M+14miEJ zPNS8PQW0YQ9r};#c|=1Y_#GBmQ=Gd3nW!}@#~H1RtdW;)DSDO%t&Ci}JMqmNtCMqz ztvcTk8{IZy&_h}^N{9Aayp7a~txk?}3B4DgiDgl7D=Avcm$nfa!YRa5xKuD_nV`$> z7Jr}y8GJt(LcBL(pSH12lL+lii%rX5sDs9Fyt|L!B;kb1gzF#Qf|!~NZ1BF+{Bid0 z3+;`mPLtDDHn2Z&Oqe&hVg{z+wwSw@e=+1E5v`dqGkTkq)UV9P$s3(9H+oAsmu}Gc zey8Abmfz~tjxSJWrqjaSU*RgbRX=qR_==O+Wz|2cT4mqEX>}h?Y|1GOMW)p_I@f1} z8pmk*Qvy%w=i5fkJX?Gz&PqXN|I|=PEf&+8xo9S0T9qa9KbE|xH?Ddqe|+gf2e9|` z%gg)z$=t^g&%+3m!e_#6-3ggB25$<)QvArTno~IzR1HAB6UO>OtB2h_YXRc$z00L& zm95Ln|4alE|0 zCjnEK{@{FhAGW&2QMe%vYq`VFr+;qP%)k|I@C4cCaO!uVg@u`iA z5A}okR1KE%Sa>5Rlu+v&Tpxd8Wy6ozZ}39)jN~M}oAg>R^QIEUuqb)m)yBk-U}5au z*TwtXBk^ZO?P64@<@*S&lY|+eTk60`LAg6WgQX+SeZ{$3+;=Zpn+lhg?xR=Mjwq11 zy^aHW1ou8-5->y?V-J8QJYep%;M!K`!`k)X1^0inHd3(Xe;^P{0TrO#x*r+f1{Ql!#~Ux%F3pCKq`?}5(W^qWZlWh3TzUCmRFr5d;VWa%qZrtijF9e9ez%rW`i zxh8YJ#8<&{y;FDO`W(jg?ReGk&&QF7niS(I&dsd-tpp3n7-?AOMYn;R?_o`Ce~60J zK0VAN2J&`-O?;HsD_BFIeYnv;mHM`^#E|J_Rk_LRVY(4?!i5a{ z2W52s<;P_dkQurCOcmdPgcK(O_l#lvh#iS<6 zMiT5(NBiV#w2v$GuVQRBMSwve`^W5feVpgFen$3F=CIrQ%<+^uMI}^ANe4bpKk2I`e zPlVm)Jd!jzs7h#z1J!=c?ZBxHOU?@cl>~!%)3`ltv%L%g>>mV1B98JIDR~?HwI>s+L9P?!$AgIvT|0^_f1?_qYF`{rC|5PO4X>OW5rk3H5d} zDtyae($&}&=io=&-qc^`cn(wguuy=OCtpsr4okHY>Ly)hoL8w=6*mr07P z;ritO8rhx~*Z3W)IcJC*cB>`GKQy0@|5Y`qz+f-*`x#ud-2LxAdpn`30rAi$MMl0I z30vs}aDSB?;H`LBNt}hBu^ucD;UgGF#5+UAw=66#S8l%!Qa4zob;5%$UkMP#WCPMYRAYkDbQiFQza-$Gvm$g8zaU-?AQG}DsH5Uv*|6=AiZ*{ ztDUUGjCFm`m59`X#1xDiEJwh-m5;Cj?cIS9H2xVzLhnlFSRhHON8`bd_z$wvC2v_& z|NX|8u`pZ~y(a$ai~UhnkmPVm=5sqTU9u)~_Qfxt8W)S_644VC<8H^;d1yPBFUrK~ zzvDh(B;O3@ooVfCLSoZmR zs<3wO`z6WP>)E?q;t-(gq11knC5+w0Hlo((`Xn2_zf7EB^-5*ySd>3oaJ_z!dP4Rp zrsmv%~BK>OT;%D?C0QcqF}GjNYKq@Ff#5|r@&&7rWH2msNo=#pJeDu zWI<}Lv8WFnlkSFrT^L^Lyd>nSS0t1eTEBeDPWbC^#Lb(nvxf;e&JLRd{*dLrvG$gW z@jVxf%i;oyvMOL-xqK>i`ijCIupl`Jj>MzQ$Io1N<0*kP-sCH^7MWf!lXH0+WI+oW zIcS>)CvV)at<@K)cQ~hClI45gCtddv!^XURoG#FUawhBXn$`0qR^H`OImCDn%Tjt= zm~JQqwc1(<%RA;vdc+Pu^v@vrQWKo@`izW`*k*!O?<}&a@1dH_zqA$l}-f>1wB-G$)qwhaSF4K2!2dQP#qTf`m$AV0z;UmTxdu zM7NYXoMUg0m8_fOir>_HULY}~VEm~C>dYTmJ}o%-Fh}f%`KSE=kGMg78sF`#iL$9V z6|&TH`Mj3g(1i`XzTB+9rvy-)o09S0s&*bgKQF zT~l^+1ds61f?(D`y-GpAvmZ6z-MArW3Ed8ll4NS?mMg94Bo$Vjo z=|t^eS|#0%C3b#9gDfy4zK+3&bb5Ke5B9rLDO=|HzG}!$x#|Z44_#?yG6n{xfwE6O zD8BE{Q^qtUseDO$lAO!gUBSj^!W+fddnX;bEG1fh^(7$XJ z%4Vu38Drk8{^A}8?3nH0eLd(-H=c9un6)jdUl9i_(%_fhi@^;ok0|qjgm{l+IX#aMr0t&$UNsF+3O*J0;)y5lagXZwyME7x&NbOaf!wGxp?ws0jZ zft5sJOs3$Faew(1W7#ktBXt48|LKw!-q2TizP8`d=(8GD#za}>Qu1;?DVJ5hy@(mD zp=O$Vk6=2b6e?q=|3`dTHMm({l!MvU`}NVp(2ar@1ajBS!Y&p?F~+Y5DJ^7(zM-Fv=LPq|QUUI5 z#H&|fBZ@G`bBef$z3sC{%8ZC0l1CKJ@CQmjFTzMKjT-_S2+bUw+MXe9Rkmy<_=6|& zo2@N4;w2|es}(lb+d1e0^LDe#cNHR1t~P7|JMfIxUJF0kmxv~im|&@Mi7A8?bHu#K zqo=`T5}rf^3DS}0 zv3KH5AQ?Jk<8a}1{X>_Sk?PEJTe-X35a`4#IRKi~A&?xSD8sGdcK$nfKg=XPBKdgy zG(S3`Kv`3Jh1Ee^_ZKZF;li4CDGN+vJdSv;Q2Ykq58qYZ_FtOEEi@sgSz>WQ72Ya_ zZ&Vyqnt&8X2A2+R-H*oEXBU)S63$Z|21#+W91U-w2&z;;?@XS33yNepRFE4Uveq6z z1Md+tAUlr~>&iEN<#{vGRQU#I;|H2P9I!tAI$ofEN%TmpCoWkVp{n>j5lZSC-f}E3qI}&U zXNsGV?YwW03Qr6tR`haQo_o{pHRA>FN;>t${*iC<| zklBxdJCnAI)*X~fscqXa{zbLMz?8sW_dT878|G$r1(L%ZFOZmdo07kii*&;`n}CK|IyYcu6E`(>(R9jqlvJe%EvmtY9H-(SlkL*MdKKVv#S2<;K*T97IKU zS6DV|-B{?ZNQZk?*F~j(MvQd0!@t)j2&WjY1J!ws^2ndr%Ih?dR^CUyL*k4%_53VgD-GCk3?3 zX85q5p-U`HaZ^j+=?P|&?>MJB*;kZzDKA#8R3WVaN}i4t@=@!eorBt!TGBf-d>9DZ zG%ANd9dlbB4RKDYV~ISpImN3gr(vKXT;0%r_HRc-J|0g!XM)oT9;2?1@v@EC-*5bt2JMf5?!gbUZ{bik>La(Z7cZ_x3LjG~j& zR~kQV3({@WqtvZh?vzXN0By;y4V(Szrrp7BSA07F5_n^?N{^4ZQ@&nG?jD;+a&SWt z;(Ln^<~2NUH93a`1#Pu2dc}RqA$q=D5j++YDs|yf!@ZEP-S}}sf!ZwXP;H<3cgFeA zc|1uW+`RO`uYR7oVZx>B94V}V?r?PE*l1aF|1#3tPv^#6eCB>!8upiFoj7i44Si4V z#AmlwCJ^B}p9?OwV3^A5@XRLlBO2(`2~wK9 z`|U{OR);Z;{vaPLPx{bdX!>{N$9+iAn{RDd5AEr<9dN73Z}oR~Pi;?cpv`LcouQ{U zW=X;RLK+)ZRJ%J12j}rQI&Ck>@GNEasBU}~X~jR@wa?#4IIZ?cjhb}5@x~swGoJ`K z7Mp*gzP8eF zkbkH<8MIz2b^fX~|Hi7~<>B|=&WRx*Nq2K?E%}6O>=hMN6_tmp(tB4$+pladVO%QW zWlt*_>M?#)UX#aR8EkQ48Q{O57AaWmmK*EdsFZsMxx-;85xlxjyThHi;^U5>ML*Xx zG{$|H?5pUjup&oDrxr2ZFemeshTfM4AJxp@aYSa@3*PW4zpa}X4AB`Fhxv}VStHJv zSEG^(hAV0BZQ|~p|Eep#o06RErF-_y;V*hTKk!Fzb z>8yI3@Wpt>%qJ@tWu;k3rkU7pk9OH28# zlH&YdhiTNftUiSv-Q5T&lh-dexHUQY1SFTF)u!&}U(Bske7yUX;rN5*#{RbF;sWlw znYge&m1LW|#EtZM$O|~FmA+s!&)PhEb=!^?U`=Zr6f}PSyEFHG28v0*!TwLU)^n^| zZne`MP3`8adUq~V#`m%m(;(vy>{u`jiiyWD*z8j+c&)r^tyk-6^l&1cM-|l5HTvQ2 zft@+G0kfLr+1WiE_b%?3gl_}y-AT6IJ|~B@hh}Rg$$bO)=KWR3d@G@zhVXMA zo5+rt+~o;Z)$2Ju{1+83U@u-$^ORTFb-(|Bau<)Ac6UuMYho`+vNe|SllhgTsZuq~Zs`98`UWG(_a_|Z^OuB#=uHa87wVG5h7f5v>U2}p_jGjh z4Rv%0yZO4i^s^@fM;V>#QGU$zjl9>B?5Cac&&8~Wf{LnW?6*Jh>+h31(=z7w($c@= zO@C^buCJewrl)^#U}#`41@|oUeAxTd35~YFNS#sgm*tPM?CWtnadP>@oD3rDPpuVty#yqRGk0o5ffM%eT&;fFfyNN~WD z3N%6jHg;GpeJo1^bze4vhijkJ!85&d=35(S7S(=y_mvg{gR@YRGUT}UVzo6zR`1-S}<%_5BJPJWM zm6om!M2$H|3wbbPB%s{)wrr$?@3Ic?Go z_-2-dJZq~gox9}hJ1f6bxyd-se^ISetGw3VQmgzS*JaFhdSIxp%U7H5I;)8Kx3*%W zZsmkwT}WpY#WfGDtM2PNZr4kDxwgN>MYUPIogA}cpVGROe-ty|_&*PkdO~9vkivVd z{aOflqSH=6CaSG#OXp91aq_h@4OjquQk=WV9zXulo@Nq+^IE_J|C^nD`>W2G!~uv= zpUN9Yw}3TW8NNgDnzK2+59zg;@l?zLyq3Y-{FSUBTu?8z)EccCFH?uCK_MNET zt}|&#|LlPyye-!jr!3>X&e5Cl1fi<^&VZxfMuBM^_D= z2S-A+dyRW}@*(fs@;!Bfv$eb?_3n4G-W96U>es%P=Czmbsj~U0tryetf6+LWNTyqIgaI?qy=Ah zo^0fTTus2IP@Aif*4}`!1Fk=umAA_~oYW?!MZ#IW(0$?&((mI9AC_81yS@k6U$Sq( zOuSz2a=M~V-qR+6_M1P!D>(#|F;sdv`9n7hh0>cCsYHJL`V2=Cezmaq5*oBG&oL`V z@x=qRwF?v?BUA&6<2u@g!PX9RCtXc1#rTt2KjGZp?3Mr9{cG^5FIAvKad%bs>X3aO zWN1iUIn!Bsds@6J6%s$%n2A)5dVsKM2*|e?<{RP0e*fbJTd1$Bsi~%;982SqJ}A| z{x0e;?<(V7J>blH-IpYOsXrr_5bxKr^le~1_)cca?X$)2Q8))PPKeHK`k~W9&w*@? z{Hk~4abhBcr8=95z!j7MzG%2XC1bu>9%L_~QEtQaoGPU@=fY>V7`8Dtr#Ebn2PKiM|bT;{#0~FK??$d^eE>`!FCda3Y)mbN=hRBeLP80l4g@8<~`6B4<&93s+3) z;;qT2Sox_DBJEU4uRgV|{}O)btu{bCRH4mfyVq+yoEd~0TzmMnIPG|ngJZz&yX5&h zzqmVGHzM%chL@4F4Ej*|eVvia!r4jD*meK%HeKqwz+E(sCXsA-{*$|Ba7%w<%VKC73T*M>2=z6VR>@pOU51Hm| zMFxpH@pV==)GG632sEPNP*^q?458M;nJO8#khOmH=VR+&=JEER94SHQlsGlh@ksFj zEWzBS$KP^tS5;px_(V0%lBSQ=?DFOEy_tBkbaPiIuVEy27{}7(#{{=$y5*idoJ)$L zS;?a_B^*Lb_;<0(9f&Mn*RGCR(Hd6#+2sXW*Oz4oEam9acZ+`S@Pp6r_oY57Z_chj zIVyAgxa|LFiTkap`S=u8lz55JMJqP{GF8;pnp?5*w3i>B{8GEneaPtJvGU;Mlx&o_ zt@9~lIk9g&`Z_fKqLqU*8yx8*ukW5mNMZJ%IVRv9oj8|D;%2YesfaIZ8Dcy=>47lJ zf|qTv9Ea6RxjH*nR=eQ`nov{DinfK7{0*jzTpLY1RS&V6+b-XB%A8#h<=>+_=)Ph# z!6?KJy})n!x|`6@5#U2dn%ztC^XH$8v4!&ScS+gKmoi9fa}ltH|4HM$zWwrN!RnZ$ z(OJ{-MBTuB8nk~WwmAQGoYMJN{d7YHNyn~)b+maaOhW`bUtF)q)4wGV2(n@t&hyL6 zrgBLbHm%@>S#!gDgGAy-gkN`u%}tDaU$Xb`6=yj|PGph+H~s!VP+6qwdr2EzL)pc>U&;>4b1@UcZlbd0pXme=eQT zAI}IEqf>l|sAWAz2K)TbgP-HKnO-eVM>3H~rzS8`v>!WekDutfRheXY#)WjTiz|q95WU?{Cyh}vfpUN%0QP2Z)l$Dp>HOx2;D8f|1a|4>*%$5v-i!~?+PmuuT!D;+c0P%aCF+4Tq&wmugH^uW#LABZlgP@{)|_AW9T zS>!OkT>c<^defEvz6+!BV{03luzO@N-49Yt81h&hV^C`o-aT9Qe~3EQ0(-;-y=Gu; zDCp=eZg0PZ_Yn0bQ}_dDZdq@q@DQbTS83b<>H=uG*FHkV(TiE%bv-i3UY9#fZ9TaJJLJq2*~mKzR&g22kI?LrmULYIR*NfM zyuQMt$p&0UJ_O#!IVw`hc=QPsTZ#*bG3%ebJw|V^l|9~uYGHkPpo$8@Jw{y(8@g0B zG>jgTZyL>pzix%J+7DeGqwcMNpC%lGM6bk6s5kKgs>i8!JDWY;5GY_{_G@ZeJr+>_k!o+Eaa1 zY*u5a5E^Cz1A1or*e<@r@7O&RcFU>D*!?sW@}sfGYf@2}^k@3mC(w}*)eYn7vC*9E zmwcX~mS4f2Lc?g*_@hVzRzdNZ&sA(KRwK>$c33&@XNTHH&^ADD-nQy?Kh= zQ0vH=+VOrr&prdn>(SHM5P6TXE9OI1< z^TKBKjYcP_!yZ6a&$3I!FHBbP?y_}EW8{(2ZlFT)NH#I>g=NYVZ*J!SHra{wur>$p zMcO{&W5HHG7V5=5GdFg8i8eVX*U|aN2~pxmJ2x%e+kav&Q4d37RNL;W^5LiA*T&p1 z?X~cx?U(;D-E@<`2Tk|~D{b?#y$>3YUk&_{n%T57=id5Czal=9 z#(THMPT_~4(c@*M;%3rPbuE7-%`NKh_AMK?v(ptMaYQ ztPx9rEN{?|pY7S0;lAIqah(vYJlH(0Hzp|)klvmn)zK^{+OFHePww9g+q>R=j4{p8 zen>QPI?B)g-l7*n5$qjfOgIx6ZfdLSn%&&?8N2yU|E&*c{Gg&$pNMi(C--h$>={ke zNNk$mw`qbv{do5z9J;~SM;f)hU5ybvn>skQFBQ?@eVW>m-7;=HcncNPT$=r)U1I3K zF#f8eyo3v_h0r?`=~Iz-IQmpDh}gkeNX;SVTONB2P1OZIgmg7o8RpL2nV4G4*8 z#xJVIm?pkavF(zuvF97vT6)Kx?Ah7=YA%&$Y2{}rgacLEJc`=8<;_|@6Q4_K$TRt4 z3kf}UFqf9;>h>F_`_s&$QSP(^M0?H2Z;=usU2b@FkaDXeqAg> z@3)-2B4YG=b(iKK(weq|yZ0zRx*>6*R==^3cEibVu$;D|ulFf(^vuMGS{s{vppjd= zrnPZfKInZK=bRBgQBwgIWb|Cnrjjq9c^>uu&coEz`ZWaC0FF^w*joRdR$8a?=iE?V z@au7IymP&8G7D*DMOW655wXCQ=t;kCji{gOlkUW*#)ev9i$MKiEyNa4t}UA+g&6bv z(P)pS&#I)lr*?!NBQAbXnRS8o z9^viAU0FJuvbpM9OX$^b=Rd~3$|wY~i!uFss-eWj##If~evc@

    NG;^QX)Q^f5ok zE-D0S>+7Rp9xfY?N>sa1{s$C5vWz|828z6hqG39*=5H_SL;C*7-1~2+t1DEsH25`( zv>RT9!zov8>m!;dpUG~%VN4W5tJu$bum1^+E$`*`f zAeDVX(G#aqiB`DdGde5v*jkX2hZQA$TwqLNXTbYv zY-OAGE(k#v0;sUeXZBPbVoWs*)OB2a9|L_(^B}e+S=CTa5T%E6|>2jYJ zl6sEdZY}cStQf&plv+S5C!HgxxuvO9_b==7FUxmVu{g+(YoQQ5cdkxsE5eD8ET_R) zOPrxSYxjLc$qZ9`V_HFr1GID4Eyk2r7j*XwJ-{dxDG#ooF0DLqy74Vh07JA884j*o zEwUBl2cL{HO$~L}c$u!lN?Ii1Q-g;3vEe21Rv5M49@awa>rN`}p$Thh{=Wj`zNVMO zR^qD~8YeWx!f2w8zuK6l=BwD!UsXd>lZkVKws@*BqE@+e$v7p2JF+yKRkV=B_J^w) zS{qrTk6P1U70IryqFqsH#!=G^A4Ptok7vp94IH~@{0)7bv?u6XTw|->gm(#zv>0F$ z8o&8K#hYJKzIhZI7E6l`-_n%5ncWM`75)B76p2Rs2#Zi8+O7OF1rr}IUH^Tyi}Tj? zemQ$JIjZZ~{p%?y8{fD!7gBw4`vt4Xkv1fuu=%)&ceLyhdRL6qEqwi>X#M@2SIfU0$i$epxnEM?)F&0=>)iOT%{RYmX-J+s+y6+aNc=z8LwzGO+ z$9a1d1qpxeHds2w7}hqWCH?Q|jC@I?wYeo68M(*oW=13s?#i6#C3u>*SZ`6CZ}Ex| zMYikLbs25fzm|U76axx=-r@Si@YA9)$Qqy>KNi1B0Gp{W59X44eyFfS2T!!rvb~&+ z5=47>EC{8#61^k~bzXOjeZV$lq`GQAb#YbS($apFrTqpKmzDJ|$qy_WP~E>!T9WTy zQ`Wb-e?DJ5NGNj9!5aOeRDbGJ_Ky}SYYJ8UYw|VKgDT5P`wplqE*(@{QZuNks%l_q zO-)TnX=T2DUdTha(OUSA{zyG)1$%x4TF-ZnB5=i%NIP z3*-E(NX6!)O z#QNt0?IVcJ)7X@+ip3>mo$I1J16!o*XL2eOoY^^!iA&bAR3u*U3$>B*|cAT*x<== zE$i(G|8ffhMV|7rLib%!6D27XBL1cU0X;?67Ha)$y$cI_aAK5y(+HQPxP`yhQ~X-K zYUe)tj(%zEA9Bx4{C*5K!M7qe3-9dP!#}hLPd#D#h^p6X9rjGI>9pOm_?KQ5#Y}dH zF+RbjT|4`ye%1)0?s9bOM9sAmg;D#@)`+2|Ud|tO6HAE`mZYGCJh1Y#bhZy5~l+B%EzdUm6SzVlydWo(PWFjnM;oZVMZ8k;kmPLb9pO&v5+2ALT zJT&?Ti%_3QFUooAhN#6Axq;0m{tUYJx=i^N*HGmH&{$0!E8><-Q`i)(2;`#QH%Bw0 zXhpTVKS4ktN^h_y76P&Tx9HQZR8Cwjn<-YYXb=rG@gShI8*x$M&|8+GmqbsjQ-bmz zLzb`kn%0)h(rYI$FfHoi`+u>tn)>_FKe6~>!?8qqjzt-cD6H( z;Aw%&rl|UB5@u`J&MrRKE{7Ec^ertbt*ojkEv`g&@TfJKEz`anTdOPN*@nC@*vWRG z=f$?m3i*+2FyXFEhf_3I!Ucx4cSKWNEn|f6zHHaMl9$!&om8{{bFwiF+^S+l3JR6| z^QC=jss@#oVATO#Vf=Ut(*A!11FI^F2UO+5DNWYJevRZ8s7ibz?TT3`HWot7+ zZOCj-ij!dR`i1(|G3$MuJtwKybdmsC{}&v}w#GE|iHbS7LjBnFEy!m#9-?BS|3Xt! zLsK+V3VO2Ey}KpuRA#8ujuC!Arvtlp8>*A-MfXj&Wd{=l$}_8t<(@=sb1P#S`_eu# z_ngP(>son6W(W6jNHN94q+~att*g`7a~@m3{Sqy3@LvnOpkkZCA;97>+qot~Qm#g% zGrMVTWtLjqGag$H&5}hbWjCFs;>~h=ehjS{N9S^+UIZT6v;9i8hN>fQ3@RFd*MevP&N zkD$8Y#t7Pi0+2`YmsQ&$#zwLM#ul{h$0pu|@r{N0X1=5nrB;2VTtrWH%S~0h8yQdI zpITur(Qn6Ox1`UA_X^`%=u{0pks=C6d)9wRThihvOX&}(Ccn(v!7X-paf)mo>K17^ zwJRga-6m7A-_nuF2U(ID6iY$Sr0;{H&7z&Gg~(Rhs94plntnAkRsE`JD)WWD)iuS{ z{cHLc7nfF5^)D$Y?mM8QZ+>9E0o64F{Ns(*O)pSRSR}jEIVv`^s43}JS~6%r>45wo zVUTc@F%5pHVuP8Q(t)M@`{#?x29*et`^DBmaO*_%pPGDaofO3At2<@4zE{N}aS7o& zBd**HCGOg)`q^#hpJ&mi#ISuHw|7eWevOu(l}UR2IY*2Z9zoWa1}F}W4JB&AzPgg< zUkKrL*=?!kWjloqVvj)Bw8(DjijG9LQ`d}3{kpd{%g)*Ds7+fye`eSm8<)g_hHl>-WcDvPmj zt{&M;v!JVa%n51t+xef}Y0ZnO-*;m~ z?ZkqqR)OKCp$L-PcW3&22|gLe;oG;!kQkpOqD{$&Z!y$d=N?sh-_;U4CTL zgG5ym{`8(?Ankv!;KrH;T_PvhzthgY-TluFq<@ahNWyon_BGWcre|E7T06gZT^0@o za)+@SZ)mDw{s6-mvis1*jp7&8RP}#+ocnyB;-7Rw)5wOF7B*Fgh7`lBh18I}RBULI zXugr_IX~K8&kmv8DVEY))6iO94NFfX#N?KqhR}}N8SErYg~CL(#qPe5GUX&9vO_5z zjcv9W1Vek%hZ@rih0vbLo&Yfu_((T8Q&(d|4LjOWuE8`lj8VhQoPFECEuxYqu>BI1 z;7CyvR#y*{M=J*F8&2%&!YtgWS}AeJK7}H;*gf6%o%_--Y%+V)t$czRtvXM&783ip zcwpB>x7Jsg7!zAKB<((d9sG6e7q&WGW3y`<%A1%-^ZQH@FYjVXhGq9Bk8mD))Uu&HzO`|_x^kiDhAT^rSdZ!_GXG>)63q9F|9{4AxNTSV@zTp{`Fp)?R~ zil5Nc0ZBGPwVkz)JFJj=VNrfda?(lZRXW9rFq)@QgYW7wztHOPcXBR6vBu z3MV}Uvb@RUhruNN5@Y%wpxsXzg?1DEf#zs!IpcC2>6V^(s{gMHs_c;) z+56pyldbjP{49E}(B_Uarg@rivAjNCn$=uxI@j6$!PouG9!Y)j1#u|0OcbpkOt2P0 zM^XP!p`v9X2bCvB_))CT#?}aaS;f|vA~+ncH}ifoiV4XWBlzge?3ueK;HXAx(w(FN zW12q0o_dowt;gZzzC!>9`=c@aZ+vX8U<3be)P>Vk+dh!J*%-0M?4@F}c4A|p577{C zQ{@sJvd7S%xjqi*3a(L=4F~m6F3vK0EIA3YN~NBu+0yS0=zSB>$DsjNt4 z$|R6xkEaDK8jg35G0j*VIBI=+DJLhIJ>Dh3vW~2|CEwC2te&k?t~N~egpDoMi(##e zRMjZ_w4FtEKvIq}-;2{cNnh`*Iq^Kt7RgiXgiT6zoCQ=UK{H;Ww|$-5xw!#?o< z6(5!qVwDPW+=)M65qcXemeC+SFsF-COk=P7B>Mj9;tXF@>&znY-3(Q0q|kYscdTtu z!%arf@Te4q4};B~^lSKMmg^J#zC8ZGT%e5C0?(dI%W9N>-6eu>Yflh!$e!W`svSLO zvNRkeMf99P^CK2I6jJ6Ar<=czT5#BEt%Pd!RBA+*vsYBxGOD%GB^GTIU~*OVR9aE` zAa-%JBkOgc9`i7Qw2PLcBv?B-D<=;@)9;?1!op4VABZ}xuayhL&z4gt6&>vw{R6C? z#;`v6R~@2=z4W?< zN>*jCy=_~mQNC?e(Wrp!D2#02Uswkgo#-~^swn@C7NXr3*5LDLgxsBMHSJ7}W@n%T zfc35cD#{M)_VvK+W`Zg*!Fj5H8 z^7WUp4fLRD*c%DQs5)wSy7~Jke2zXU+pjcGpdqWaFsdO|9w~al=UWSr#uHVn?;6#> z_A#Ov@BV&Qrjh2X<@_A=4U$MknY9o(y|;=L>mS7yd!_i#(L zGt51z*7}i6LZwu;o!?A%L2uoL4Aw?p?Z$3Pc00d;)lB0pYR2~SsP#n!I@ozMl>oC^ zD%qA1%BWst-Oq*0wu_DF-~Xdx#gJO@0R{x3U@+5_EmcaD^g8&w+)&>Hhq zLQAhPrfK>tSTn30llN|2T45YVOVriuj>c4>kJ`-`{c8LUDmEdlrGOqES?$tD0#|K~ z_L^*0I{w1&-=xo~a{{FeA^j88C+)T_Gk(-MA$*-!Hf+PGw1(m>5nW<)*X z`~5Q>Rz~L7GffR+(Sxy?XW7X|sMyZ0WqcH3J6_q@j=d+-mfaP~e;4&?xEY@Mio_lL zpm+)eech>|CAQl7axDg{Or?Us$=i<0% zk7kTD;ua_GucofGz^f@sQ{QuFp^8OYhLn)h`>HhpZdS3JD*|Y9k4IKTvzifp)9D<_ zA{)<7R4YX3v1O%mTU2aWNheIQ$yU@E(to;JhK6{&?b?Yl2E%$q-0XRKDbtv`$03|u zyIH5A=4Yer&ZAf`8kF|?>T0=thers0B$1>RUV-Xx>aJ6jslAVmtWty2rK zj!xRoyl^`en>lKVw`1w6xiArW;-K|PpJXpwV^75%C7a-6qQa94R1}+e5jC4jV{fcQ z2n}NShS`gjs@U+mmR9GhrOGusTMMC!X=f$&J+~B^YPds>`m3j`5j9=Kc4{?MFNxng zpj=(Z>?Nt>!!wW|!ZF<%QBJs|Ym7?BG)Z&zOWwxk(Nr%i?WLNH5p?M;DmID_p@wL= zE!vl>^j+Jf)9f&{Qv@_MRJT^~nZ6t0Y^$OWm&<7I&yt}XCVC3?zyZL=HPY}U>#r_y-Jt_)vJRp1|Fud2D+)s!~B^-F;Cz)fAw>=iVw zq@;o(M>V$=d}@XZUf&+VkTxpYF~VoN25zP6RsX!Nq|Lf(*`2hgVWxcS1|8fO zz?aj`UNx4wMCHG|mV9h~TT0Wrn*Kc&$)}Y*)=y9#C7aOHw)`JyK-bWs3ayQG@IWld zJX%S-(;7h(cECa~PHU(Y>Vo@9N7-vPSFtbdwD6m09+l7gmBHBTY%@#I5hiDGS}P0e z?&MAr_DwEp?po^Kn6S?10$a6<&akm^H7K&z(FzpH;US=Tz0d2qcT_BDX>`GRTPcg+ z`rTA)!Z^A%bO?T7SE$&My`CBvTT2^VPhw*h=;gfK_I}!>w6pwY01?lZlksRCL>R7yv zbYHhp<}6$64u3zgWt1PQa%r1di;#*pD|fGRqasZ$*IUvaO_c#|>u6uBYYJ3aAzCKw z;G!1C`lYYiXc&DXC&sgmNm?7fof;4O(CTU{*E{IA{dyJaV#41y<(v3xi3VRst0>Fm z_CHiCG{3HP3=i=Xgn+WsX?j$_o>pyrR9!eI+Ss-q+C{M=o9X0XZ(;Wy0<8F<3+?h?#Y-z_u7~M&msn_yzG>cPmwo!HG$0{~O zsk3P_=8oBlGQ9#jP`!&n5$pMBT3YISw-GJ^%{D9;haUQAc&B$9hiGv0&qJIP<>hZ zW&+p$75fhTKAJkRV*Mc!+vAe*1n#3gosDDb8k#Y%TlNa=y2;;(TGrQ}3m!LFfD)cBtkcumE&c?c+%)Q0x4 z7BUYGQL$jlG5Px18n(Zkb~ypGEaV)^gVcqwNC@pL&F{mJlKB%KDLq7Yp%c05&b{+9i8obgXMMsA;Rkb$JD${V2q_=Bk3p+mR=w~jEU1>kH9tlbi z(sJJ!1#fI>@FysGiQ2?w2^<%mpv|tb7XC9&x|Q{=iGRifrP&L}@s(s7l=dVo9yO|H z^)*I1nH6)_xeSXGOIc^}Bn6bvN4#NzPey4JxxOju`=+NT%9a)72;p$lY!{0Mr`%Af zgI~{on!@U@;_tOdYY~{aZSR!(47T)b`WXtI`znFphBEhJ&r+Yse7TE)bc49|z3r9J zMEpg|P;~J%%6A)vVL9IJ+QKn>$~v;=DEN`3EfB=(JE2l#_BndsqxpGS^0E4Zfg1qP zL$%YB=jmn|_<34JHB_tN=6-jGGS)ZsPx|@y?K#_Xq&cb>9mNPySvHfBlYKEfLcz(= zwS|tqWkO?AGCP-XX-<24ANUd##iDx79pjLH4DDI94VUooGJTUQlx9qAeFH`okeH4( zBIrf2eS$HyCI%%E;BgOu>Id0jz$-L0znI@pb4#A<7DdsT7aG$LEn2gk)-jY)go~;# z8zbV?4l1@VF{XiKjYiAVKd7h@)T=Z#ujT*`SY^AvDLZa>m7<@=vTF)~I_wx|2xDVv zXV4IsI)-);(OT!%i86hBD|72nGbmGX8As~*3V@&(kex}hs|pn@uoJ7TIli4M;vT8w2G=sziU3%>s)Po=BF6LmU-Lp@&z^reHMKk zd?r?DE&DcgKdj>p2|m^riaTfDej{-o1-6gc!R1$8=og=7Q>MFb@M&-zSfh1| zU9+hPQlo9}klI*6k`$cxj?-IqH&3-ZeAnQ1JqGx*yhAR4`rfP~#ziBmXu3wpSoWRI zp`Lv)Kf|~>Uo1o@ew>{{%g1cdrJm|1I3Tw1ZtEw^r9FNcNw`+%M?G2A3T-jQ?A%!@ zmfLSqjO|<{D4#md zFSfL;NM2ICpW8&6s8nLfY;$Di(+F$|2O9h$P&5;4^sj9`ZHTg=H+Ps)!+4kOnJt#p z)84MIdE~X^vRX2Rt$o)wG-LLKu7mT20p6qcRnD)eMGae~|E_lwEU?>)g!=f5I>H6cNR4jbB zVGIjPh{7x`QLfy4_G4GN+TBCF8g5ET?GQCy`uA4Z$bd#4!yYX|Fpci)XY_f~6YlDOmfA736Z0m) z){^NgkM*6YpZbE zT3u<4IEp@I8}gcCi^Qq!-OZnW2W)UeH;}$?;{EQvd@kskMuK-^i5Sq_Ob|8e+0-t`KSFfz8ocwKdJ0p? z8*!@Cm}Zu#SdJPob@@i_Qlg-WPppO5N>^sCgU6a`r9y*j^Kzw2Y3LM#q}YC5fa+^{ z%1pG3O8`d;Y&#m$zo%2M*>q#RYP4P=F|R0aIZw0#VWrHoUsGf&^*lMpj6^@Iou*B+ zSVa$@LPbrjG2fIQra>V($(lwkQnAvV8fhs=Det}jefC?| z;drWG9tTkWQBJ@ryZTTS>!vi-BGg~!k#nmlyp#=32x3A$k%V%YKhGK(aMS8fdyX)* zL^lWC-=Ag;#dBX0ySDfZMM)+58zbmDr%dGAQ8Q*!r(Q6oiD~w6Z^(#pA&xIfDgMTo zhG~_iLPa~_1_nV6w}H^d&Y4Bb`nv+NoSiE1Tpad_!t6wJ4*I6V~y&kh-<>Ag1usG_&>4uD%ha zZLOFeXe=_B-+r^CXiMJPO@n?&)YBj&CX*wil&+&$Jk#_w>rK(7GuuT?+x*3KG;Xv)cU9mbzltdhojrM%$SDU;$ig2T1GiJ*$o1>T0?_M+qQqAO`>kG zdl}_xqeOw=!~Dztnf4wiM%#AvjZF2WJufj~18IMz=~FrXJysbe5u%h)vCIBK4!MHe zLZPuN>IYJ8j2DjO(>71z7y93`*uxD0ogHCcVJc-$vMl^RMr1SlD-FFyB^dT>9ivMM z+v(7+^!ix{DlrpkBr3I!F-gfu54VEgz5o&%<^f^9^B3_I?AbMu7K}ZK zw4(JF1za}7PBON(0gD=>78)bwZwe3MJ&tBrB?PHp@ZU6KVmSs5DhQfxd`J2p8WFP! zGL94Ew)pG)hfc-v{2H5T$K;#VA1CAg3e7r*NhrY^P(Q zPCFWFhU4Y5nWW|PQ=iV?l4io0dKC^eeGFGlhjp_#gyoo4jms*S7zIQ)@X|z=^fl2D9K~nW(}Ny%AHFG#AisTliaQXsE&dtDv09XD*-t z!m0c%X}O~)PSAa^6w-98MLrJy`-a$42od&~_u%OmCNe#jaRGFlIHZFa-KtHr@JnmU zpID4mc>b3>7gfKv>&sal$hf(IvNYa&DF%(LcOlTQJ%T?x;6h%rV z=R|8`x%RZ3Knce7^`G8aTQ$15CC~HuSde+j>}cjX(43OK9owFp^0lloZznf`yWM}H z9jJF>iJqG98&*AB+H82h*4xf?q_IhJ0;$I*;5XiK9UoV*`I$z9yn3(MnCq0tM@kgw ziagK+V;Z4#`bv)I)uCt>-IX={t`?zCJNl%v4)FoqQOrd6Pui^BTxYtW27Zch<+XlW zEc&`=k~!ZZRF!B7Lkjt7A?;h2&oOB*xh}L=$-b=+VYNM6G+WqwQd?SpCZ?^ibJVd8 zW&_vF-WP4i?Zgi&8*_&bgkq`u*>$bpNUG)2!^$i7b8_-5AOYRDPpEoMz2Fe7k z)1zVX78W8OLqTMn;*b=cJIh*#ZAhUmY?R|LQDf;#Ys8(Y;tje`qld}%3SIRj%2T$H zGr0{vH;>UbotkDJscF~f=aQZxB zg!Q0W$!xVC#9Hg}ShAA5ne%8p+|o|;?4mU4^{qtbHlp5@?rlThAAIsGVXD|p`2t*ZgZyx+mS%S-L0bpft98a_tJ%>Df(Zb{39 zk1EzAq7YPD1*cE6HB1A-a}CyKdic-Knp?Ld7E53k3M=NerdeD??AeE%sMN2qbcNj3 zPJE$Tf{JIpcjA>>?BHb^r@|1ms?%EwEb+^!&!%$TpKL?lmqlAorz zp|y#vs0pbox$P1ajU6O(gcn*1sqHsViO!RRl-T8QO|0iETVzl7O;y^>JwW(gtp0X449qBt}q0k0ldiU+v49$kOylY00#L zKkso(wQNbPgUi1Oy{*l^$?Z;oeP^;u8`V%7wEnb)~J-1>vNw1x&B9o5l(cT~dC zxwbv%nbA^>YdWm5m(&dU((=Pdb}P*-#sA0lNv`kRDpozLsWl3#$>v-YfQ$V#^&{6v z6Wk8b@8eZ-1yQkFKU&J?)0)=$dKUE=RT>|qbdVw;#k8%{$nGUXbmuYMT$`(Tr5A+k zf>SZ2MbXf@C}J8XtoOqDm)Hxl!N<+Mtb<#=FY=D3|8>fgcegLFIbVbOtGeFl-3BP3 zxWgv@um~s*=UUjU4>v~801D$^&QwFK^|e(z>b@JVgf!HGly=LubeeVO@-lN5QPBAb zzF#k;cEb`Io2&A|ENQAS4ZNsgT?PTMPBV(B>TE5929hVJP*Drh1)A+`mH@RAIf` zu2qcX`w`L1V6bvQ9J#X9DmJrfCa$(cXl`EgJ2!|1fGp3kxloXtJX0Ue4RRG}qw`QY zn$)#VHb&5%T~sV6D}-3pW4FRbDIs53fEsB%2gcN5H@k~90+y+mW=aT*#SKb6J>P4% zij7t@fhz$q zk7bXG2)=@vW6NhYQ7t!={&{N49pjJ?2s6!?rp{HdEXqjO- z$u%!yPgx_r6BJUMbHgaEjJHZExET#lU0igt-+&uVL2TE@u4|m2(XIy+XIkV{6&q+0 z!W(8ZD4_@d+s5|YO2sPe5VQVacpMYj;ZA=Nw(JK2S(4H#8hL#pU{NbAlR6*#=n7_kQqSFufO$I_tN z-dv7{19i6;E%sl{-fS&JgE*oiFZW_LqjLw5FTI^V!TOPc@GGh1TE*PlK{UdzP`+8$ zN-FQy8l#{6XMl=-2c#^HK=>WC41rm#}wK7cVp&O(Ty`F7qjOFePAe$6i;< z%UVfGkq2L(Vv`|_NF}sL-<|tZ8>~o8RsVOhdj<}DeF+FXPcZowWHE$uSD0d9~Zw-6k1{7BC`QFemm#X;SCZvRn z_fw5&f*yBOjNqw;yfo}*hB%g-__^!_5z*S{*DCk|o}F(WOHZ56z8b^f4R1YBH+ZXZ zb+2;A9gujdjbVcuj|iJWA9tUM1u!=^Qe_=!i0*UOa>u)&s)J5%rQT3@(%UGPhMqg# z#nQQ_&{S34+T@39LMV6cc$$0j&!MSKWLQbd+zGp@_*lIqU+KlrBSDwc6~;6|6*Xw`Wvq zBMiaxzN)DKojZwIH>*cyV=)Yo>B!YH?0W1;?=)?#eh>bD0j~gTGzun>D%re|E z{r7%Fje1iXi}PQ)NLHPVB#3+%gPT-SNg@-Bnj1kUVR26c2q6h4TO)$*hQ(lOBDM(| z)m^>VZ+?xS2_^p)LMjFcWrlJm?{8nKZ*C;06pba^{ZNR(6BeN{+{GNJZeZy*(zyMU zL^ZbN_%^<@VROoLD)AjOG)bBYBdifZmAv^Jti=Zy6tN*;+6E<^N*s$u4u4YliYAlnD>dRrFDb z*WXmz*yz`kQyXt={zQ`&H*u+;+o#2c=(}lZt!ioIPg!YmrZZ1zN*W`Ah&t`(}2h$z+mYZE8tR&F{TD`Knb7}L!4Dz@crWzy8JKKk!FM1#w{ z{WGX0b}oN%jft}M(#~;#98nE>2ouIsHq@~>u(TIeLz8*#PA80^l7QGLUS&)(IsGMROzs(sX>^{3|CS7;c17d*m7q04>Y?hm9E*1Y$sOYXN{+kd)=M`qj4;fuJU_L zqg}BA`=G-I)>xMp^7hl^#t5pTe1l4M7TQ`L-berCHj&UW1uWY=jXEkqO7VwXJ>Yd$ zlO8fP+Zd7cW9>Wb$w*za>;GS|_gwuF6lx9S@S1)mg!_RM*w53~T?0j+GiHZm&a@1qsxJ**Mp!UCgn)cQIlMefOluFypvkEeh@ za@_45(9qP%w3?*Ipb4~&${XS+UgtxKubV)X-gs*t)xb|8b%7HD6-&-;2|H-cM3a%H ztr0USd0~8qR>-l=O{DLc_hh4_beS3zWd%&yO~nGQVkw<2FG&XmkG25$oO*UmwPU1V zhcCgOqxgha-xm@SsaVAN#*=4Mso2tS3#FS)*MFCdO2UQ1AX{@RcLvSC$XnaxrIrS@ zugUCb$@H-YMBGa{Lh6Xg-(9IZ|Wn6mb+b!b5c2&OEIwxsd4d$Q#oD zubszg+5FpWe_i1BJYMyBY)4l%oKzr8+3?&2lpDoDlUgX^Z{&IhE*HG5V)I8En3U{O(!Grl zav^PGuuzGXafQNYp%Z37;}=p}u3$GZt^w2t^)Ve%f>~xgJ`Mx8uoH@2F5kG!Iw^av2Du;ebMFg7-I34s=_+nesdKYNoOo0~>gMG?&%<4_!0 zWmuF=7p9h2N~MwR?(XjH?(XhfN*d{A>5}elkX{-I0qJf<5cu}}{y*2uGw0mrj=6^Y zcVmBzuFFOYLuLbk#&U8~p(t?oX#!tex3hBh+U{S#&IQf`@;Y+3MYi8uK6o-`>6LWz zhO(jyGIKl#$_%(tkkH${Tn!+Bp&Yv~mA97t@vPz)%s77*cbK|i&ZIOX=X>@7k9S19rxDKA}T3qpL z;meLOJ~Oq5eW+?g(c}e{viEJQE7xG}4+CW5YaWyh=?`lrUvRrHcq_iDGvLnIrTls< zir&IjG@t7X>5u8zdrsLg`kP#rGj=TV z@|TL#&NI-p3@4V+5=IfxrdYInL-mTrAlwQk0ObRP^n8;Hg0!jbn99&p6dzgsW0%;! zyvb0N!%DEsC!D`N#^XnC?AuD1ez1W`%-kZ{n~7$!e;3}Ey*O9=s&q5C%O&CHO$ zQFh5P>->21-ZL)3W2*bv^K3!rAixq~TZHXRWL$y4Oo@fVSJ1hvh1?Xm71)B?UKsi! z%5cOoag^uqIEQPrHZYEytD;)7C~ArHcYN{Z<3DpQUk1{+|BtO71McnP4{d3OFXX6_3uzsrp&^+GM?wpH*N`d+#wVTpMp--8>f3KryMuPA=@$q-oAtFTA= zjxQkZQaO_Qux`WOACkA5kne8wm1_0Yt>BLTwNuBv&TbZL_@m+Qo0$YZtKswIA8#VD zA(o?-@7uDLq?r)uu+~2_Ygku?wH7_J`*#A=u(I#fmWdy|-qmrZ1nB;yGd}Ei$AUtt zZE|K!yNi4vI`=y*H40bi#wVmJ?{>^lzu_(oNp;ziY*<26jPcSPk(!X?<^OLkfwhv~E`i-^gw#7%MY$fFQ~jTU&4B?}3=ejB{-EMwx>_FZOMiq=p>314;(kh2 z`=WzG>rflyANe~7eyP7p)vuzEX)S>#Bmg=EY#Byo#&B26?hR!i*=^=bOGEaS`cHzl)_@i$- z!TCJ8r}kaR4ekB8Ao610QYsw5!@zu<8k+mG)&z}_>y=P{yk(~xYcgCcJTGcNs8(~PVAqh+2RFZg-Q z+`WM@zT~&_YOFIlwDMXbx=(IJDAKcutuWHR7ruA3Al)gW@BIttlNR=z*RZs#AFB3U zPb#;BOp9FQ?9ER(%Zqhd|PELH_$QU1yiSlAdubBtVw&896-`;Iz>@nd*UkpRb26f1kivbFZ%OPs~C z2}9NTx~D~PHEh=4-?euQ3O`#5XG`?+r$vHIJ+JaT`Dp(fnQmQaUsEfejhcx_(jOt4 zi**$ZNeb=s1L}$;#Frj>0zRtG|rcS5*Vf{_kRL+@T| z6>4f7@BYFrJj&v1_iL#S-Wax)_zJzqzGP@+Jk*^TZt)((zv${de%7k0A<)t=(9qy) zWH9Bf>MpD4u7TjasWUfN#GCd?vtvz+zb)iWg}~Q3)*zx+T?pDi!X)(Hn`>ap;h!;? z>b?=AlX6vs7I%j32$|T=WxvVdQ8##*y}v!E;^1KtaWz(4gPX%65OHdd(5ud}SkHC! zb4k@W*hIh34@(2Q+O^fgrkOfln}0Q@hQmLj)6ugqUKO#{&fsBIP2nMC;^_Wip3eHs zh=#AGEl~BTp*5cUHMub3pDbhT%Wt~OvaHeosqiFg2;=7DJT%9rhU zm<8%Q&J%%?Z8Z98a+Poa>R-l^47!%c5MGzxu+*xx9ZKZMWynjIhsP}n8aG<0Cl?Q_ zZuZdZOf~`z9yL`9LEZK2G{}?%c9Ls3i{)ES6=_epv{JOji}vpMNm(f(kBRhlgC86` z*v9nf1s({_@;1jae#NQM^E6FMup}+1>cXB>V&;Qz_q5Ig$c;FjLVr~0S>bs!{o^NR ze{jyuQQ!2?y8d@ssUo&1g986+-GRAm3Q|{#DyHpd)KtTaf51>Rp0iwrOIWNdA2(ikk}K0w7wy_r;cIl{-Z`}? zI#TW}iufpRzwaq8L$KG9Rntj>PltfRwhS)rhOo?49nND&K;}uf=&Li0*QC7Su<&0Q zd39=aHoGHL2<+sv9D8l(FE7|xGb^5)2NX5FG z8`1USYyc?PrgNRul?_t^Sq5BENYZEB4)B*PrMk$>`7H9%q8?8o9lX{g`~#DVA>Q>> zW2qzt0B}*Itw6gvL_L=QyR`ZMY;c-OWPMAGawtjP7-^E#%%?)Yd!Gvoc(ckcx%7y} zwQrN#_`>r!%eWb$K{3r#AO(-_iYxY_{cG=cb-_U6JvP@ww!qTKx`LNyW&TC0bSMse zucP;xRqISb;`5Gp0A!z**t&&PVkq5fxB|arLg-AO4tAYzlYx%lI?~W-X;Yj01c}!9 ztW3t18ozH`Tp6db4OUm3fB`14WW&xXpFK#is2UE!YT~G&VQa}G(LtAznym!Lm*qpP z-9bSTjPk)){W4}hB|Jz-ej}|DDpblw==pn?hoGhvVa*HTjo+cBnyuMrGQ9hGFD zzui9lGN!5|FjbqNjw!iAm+h#xl9J$h>q;icJ_I6Q*pU7_HrmhKbv>806{HdD_9;VA z3f|%4#=3Mi)DW%Xd3~j4tFA-5G`x6qmVff?KbQeP@_Wxp;48t*iBppLzI7>TUjUZF zLktztQNy2=&X{QgP4CL-?Hu^B1ll7Wq{HFEg#2fMTIC#iAXGRPO7f%}$l~w!nOG1Q zP^}oD^aIIC2cQCGIXPFpGC%FiX=eM^?zQLcb_+z>{& z3FY^wV*=a~EFpR|SSu(@#Lan$FoS&sSKL%93Y=WnYVSaln}i5cDaX`h4-Hd9$3mYjcjZNgKjJnhwukideisz$*NNgU2+;^1=?TgU~)Qd#Cn=uqbYR@O*Ws$Ll1$Gms;$HC=h{dw&zKT}V{ zA{Q3*xi~^FLr{>Kv|*mLfB&+(ieDWH^iYE(@29+b;l{IhNGD9cD>TA*XP7pkma z>_JEVV1i0$Y=O*Tl~ryJ@70dVnKb&&ZEwzWKlH&8k`1Cdj50)}i4L(JqRu@qQ_6R?zPSncW%1Z0(_vju zKVa`@q=6pVWgh{Gn{KYcKpd47P_3rVS6U3WdKz=@_JEKHpB!qcDa{k9^WYW0ZK}Fa zgH4RM65HVB)a;CDH^!0(oiBo4MKsk6Dk|iZlsg5{xv*vMwYZ32$?H@qW^wxmDNe2t zPsL3+0n9qGjU+?S=+2fy6jb?K=bz}r9Lho4%^vDSg~-+M{-*Cc^0EX`DCNalpZS7M z?C4f85*YkW()D)#4nKPP+sGv*c?RuQ$;MdqTIv^&wx^X|OvsdYm1yWbwN@C}eTEejKZ?%CiGJxgGKc|BUGq)sIM z*3?8`5>g2nW|39nArD5-Uulg0$YdQYA6g6)U&7{+M3JpZ(86|6)axb zwTabXVn{!9L|=?BX@wyy{ZcPE@)!4hN{GxhJE92RfrX~K?oIvBKqLIc%r8IQmkod4_7RfyKii9Qsaa9c@ zK)+LiS=y*4pS|^> zQVXSyYa-UFHCe6{^3hQJ8k+ZW((gu)E^$2NegugbjtVlIiW{NBLjRaRTxPexZTf5o zot@)~v@=0W(e8+~1h~&ne+gT3rqD1A7D&MJ5M0mv_jBl>Y?Z`0&rtHTh>SuyPn8kc zysE>{5gu~V*yx5>&Xz(*OI?139>-&;?RYVJ5iQ3>#>FXE@oBB{kWa76-=MOTuiLnr zM++&SgR?x`e`m8-VSgH@lPHi`3zPPvEJt{mmHygJMV`>gsqk#CXm~$u^gL=WZ=Tud z#}Yr+ztZInt^fz4(}+73n-F5R&oFr>HJ3ugWB+zH#uRJ!R2~r55KQ~2wE&|LfDe-x zGvxv~nPhqpVJ-fKr+)R%xV|tM*9Od&n-AU){vLVIE@dwyMCT0nZaNahcB0STviK4S z)kIpQnxgVJf_{6XL`>?l-7LJdoG||Kau?u4Q${>ESV{^#`KrOr2;MsK$2L;uih{)lDF{y^-a11YpYpqU6xg%~G(0we0Eg$SW`#Pj z#;2`jpua1Z^~IkWf*%hA7=)GwEbQ!fr0D?wv`ypBFi{EQsIEd_PXiX8iFB{C=IE~~ z8&Jn)3?0~_p7ye4caAW5viN5`UAZZ+BnO11It6Stmo6k%)m>Zw*}z}@DSdN1|+6_tka7PGB+5AkcR7~ zUaXb3+F{XD#!Fa+WX-ko)e^FZQY7~m9VN+$86Rgn_*|IFOr|FQzmb6EvgX5sZ<;$0 zzY3j?8=df@@>fAhCV~%D_L-2f#(9A`x9SD^iZ_WxZm?UfC88*Nak?}1No{-7KI#y5 zlqLYZs(b8=Rn#kmKR~6=5Lj z^%}bsRc+a5{))*=<2-%{8LQwL{2NWlH%10M9(Y&`)k4ufc@H9dByq9g4xL*?<_P?) zVKMI5n@OKr$sC|^Iq_f1Mf&KX{^l?Tr63YfdzcP`9>TTSO*Y`#3~<*}vtFUH)cOpw zPzF}^8keW;azl8>#I9?}RxpAc=gKDd=UNK~A>DBW=Jp^LX_Z!fj#bCrOWrp{H5Oi~ zUi2bC2>z8E77QxMmyYILA|qT@QG;gt6oIofA$BI#Eeld zag{&<9@Ila_5yeb*Sm%Eunl-7$&RD#r38kRr!wD1kRU~nM}8l)nv%Jj3q#@!DPm+) zbYllgGnFT>LacaUBb}~`-=?d zuyxW09|Nf(j*!ZY_(Y>=OTN#%ZsbdYy zgKaGqWZh4#9HFkd(}AQsnJui)lBeBB{2Hy$R)>b=n*=0ANqmp%bY0vNq&ckJ;Z>^6gb8M#K3A)^v_8tug4Z`;#@m zg)AOAca~g7pU-MNPX=8bWr8m?ZI9?A0r%Kh>6X>)N^(o9s;M&lLXnYcGv zbR+CcFIThk)eNQ%UUot$Ocj#YzTfV%j0AP7#!IO*EKc<3uOD;q_c;CcI)gzP5@R&$ z-{#^7dIpvjS6ej(%pNg6N7(R@S1|b`G4@sYAW zo>`ik42{@3;}oD{u`>g|Ui2WeSPx69FF81^oX|4`YpP+|&{n5yW-i0hOw(DnMB@Tn ztrI{|ZN^%`rLDdL-Ot!ubmd^l@TIno0wjGIQlHfpb%5)^ZjN?mV?5T7K?T5J_p-Ys zglbpF*R8ax`XhR)mm}Z}lcX(5keKUBPa(NoY2Hi7W0U=L7BZ%(^@mAcSxyh=zZidx_X~)V)0kBwXe=8@OY~%`` zuVLnaeE3KFRrq66N>Ff~_{Kxy1Qc4US-VH*RCMJ6LT7Jo7ZMyk*JZ$c43}SITYBY6 zM3Ye($ELM%%7b|wSbxdOY$tJln{8YB9kS`?H|3^;8nClo)g@DEco@894zyI`(-&L8 z)141R`Kt^NcDGOTT#dt!{K!S*xd>dNp7THd@wYhY6j5@GjhB=2Oj*(JI`d`LmX;bP z`-&OpNNh=H1;;!zb0^LwLW%p2Rg!-O?JdwXKJ)#uA4_eyNvg56{hllYV+-v{3qDlZ zA(}P=?Rjm3AeuvA{AN>DMO^&*iJYvRT_r)RSurA4??eiL8U(oAx;?`(-+*)~E-DJ^ z+@-yaz(wm7<4jSiY-rDJ!;Vh&Fl8|cpcJRYGbZ_osjj_qUC0NBGNtGQSb{a+gG^j#?C5F{U8D?wKLQPHKnAk* zXrX_$?H`LJqf+Z*cYQyOAipXbmS;XKdLojaTtA}OG4_a904*7LQHb~k z#oY~tLIMqF|0ip3X}CfZuiueEBLN5H}l$;*=|zw9OD912uxmVuR~?iBlp5rB1p`M zx-jrNYpQB5An#lI4D|zR0EpA6*a-99vk&}IW#o-=8nIo=KPsVWX^5;g`N=&kxZu7nUd2sygo6VcTfjFP^%W6M%gLn^!z(J@IO}~LAstbl z-V2e=n>O;qEB3@4@6)5mH`E}BndLEb0v2LZYnWH8h^8dM2nKY-OCc@OP4i!MwZvf6Tbhc$5LY(LtZJg*!0Q11mof= z!MJGCsp7#R_u&5DoFc80?X`4k;-)f;CJ_oZu~syuTI znrhx0fIyWqHUR*QfPuIKx({(hMJig+UUTB0TES`6rVi{$k^fAH6lBozbEh%}1Iz^h zTES;5Wlagm8l6Z+<|F-V^Wf5N#i1e4tuFP}4M}JkIA3d+Xu^*_X?&3=kq`dLNgeEq z15ybTbwIp1rm-}66v48CsnaQsf{$(AaDd^SwP$==bUY2c?ba6^2>UWpI~J72!G>v(8; z6n{_F+$OB}JOA8!69a;b(keB(At( zijD}qBAAyy7Ud%t+`L{W>BD2L;67#(XfQ%;4{yCZDG#Ez8m*2O`c`^H6S19v_~f3_ z@NY)ag)%FwcoI^)ZikJCfu=tb`2$=KpWP>k@YgU-gCFK6i1;i|{Q#pjwsz<7{hn5! z_`6VbNK>P0<}|U2r531aOh=K}Jl~Lc@JShof~&=|q88@iIw6}_S##!oixBO$9yUrY zAur4l7oRV7Pn8vjO*YF!# zOW|h!nXpih{)9YZuhZjwhq=C(iBnn3IO}=heD!xf2ya1w{_~2gkK9ZRjPMw%VgV|O)m8CJN!&uw6KHt3fUrgzfI5AK}lyMj6)cM96 zorObDRH>{O=P|gied2BJKa8A7YMiBR?~s<_eZaDTb9wiTh4Xf9&rz&P@IWE-Ne;LK zH*m8nruD<)?)VLV>esGlu)X43^@_;sW@lNm`2kM1DBl{u&yP&UDxHlEeA>9>Mt9t~ zd^Zo37t(&14V00a0GIE@ok=m>9u}jRPi4C_ph56@z(I(kEPL1CBu;uqIjJaO6le}$ zMwWnPk~Db-DUJlqK?0la^`WV`-1o0Z#0Rf!*tFE)=*2Z}T$NzjJ+1PvzeRg6awm3- zgEhU`=5*7Qn2Ql2)axKsN1JqHgg)CRQWf@lJ}LzS?p!pCq4)*dan^l6gTid!P{gy z`WPvoM8_|~hm~lB6GODEHS~T#~jgyYV zI&n10M%XTDFutD>#|W8|foDJ=Twr4;DD{h0+Uf#|`8v>m)rt+&ct^T86Mbn0Pm^yT zc_({?>oA*@+9u!LMzY$SChD%ZE??`hfK=rf7nvu5*>u@dA8>Y{@eo%-r(Zw6VkTM3 zlj{E;VT3fV67kYoHK14Vog@S7htQaXrm4CJTlE&_(Ig-Rm3_$sX>5Dy%J8glM_u7~ zvE+HeLZ@2zk-vT=P~J8{W261GFVU~qV^9xV1_1GE7X>1zJ{E z#~eQ4KG@nQ;t2Uh12<;5ohZJx)|NTUz*dZ)Se7jie=*)hrp2Li0DOEBI-6KFmip5f zI?#(KRhqyg5g`b!iRX6)`SAchJ{rF(qtd!46Fni{=Fz9`4c$_<8$-%@zHnn!%E8%JGAco8l6IUwR`g+(B*=o&ACo>yGaSkjbG>8qXsl zE2~plC+%Y&Y{YPtx?5WfK2fL z6nhZ~H%zuZl&VmfBvq~*+hQ@z%=Bg&n7QSB$%u zd@l&quC3yPbXkOT7dx5tcUvR#Ki_>j2=9Uf?e>gub&; zZd)qMzY!lk+7MQxPyBJ3-a{qDQTjkF?aO?XS1;rPUBy~cO}DcSuX~Pj2&DKil7qbl zPl@zB5HU6{oH5Vn9oSzdtP2oYi|v zx}~sFTBkuvM8u94e~ssK*u+t(?OEU^ou^~_r!#DcIEe=iFac?Qp3Zdk`_h0)P+@+h z_3sgy4jp{+KoyZLz6w4H;FKR2hjf$~$nk&9AZ!W4DfgN6*#v>S$A7^KyF< zXIP#GPhP^;>RZJJ^}SZNwa_NzqLx-_$JMiy$`#vu@k%1C{-#$3ugGSg0JpmMA9Dx0 z*#5lRKct!f@LIM`5lOvlp29SGVQMk*p2QHzFiDj~uXFm6r#T;Ql?258k-gIyp5YXM zFlC_*B_thEA*m^;&TVw;V(a1iO~?XjH4I+ck;OUSG=LzN5-cIs6V7K66KQ1NETl6h z>Pj-Ror=b|@2K?|=;A?VRs#2ckRW8wR~3cC&mDwaXw&gyo@ts{G#I)L#~t+!1N=?DDw<*U@k*CaOwsB1~wsMCS~>mop#)k0D?Oj9A|U zq2L_*`+d%3rP6aENQ5Zd;Mn6EJnSrSAD~Yj) zo*Q!qSL=Mp;=V<{Ln;lHKfKvHf)F*Ec5B>f%`f9@*V}H`P&teLlp1F1KtB=5L4VRr z#jO_>*bby6Jh3*!Pb5n3dgOljqtaSxTsZGog1Bp<&kd7? zJ4`~^Nj$iNAQBv?6gXgs78pyHJr|wRjZe7+Oxn`PwxAr>&k>|@3;NG54#b0J5Lrmm zIgkkrz=QiM22x72lU9;C6+SlTht*J-9>@#ZKrYY{@-*eU!G2<>Qx@tq!uMB1MGf_v zyV>pliZ#rZQdlw{;s@1otYhP)S;6ki@1|P~8u83+z5Mo|X>{H!z^Pp;)Y%zQ_1M~q zU;&b0s<#7_;39Fl$2@pvtHCxZZUb#V@yeAyH^*2HaS%N5HJXl<3r`1GblIob6KQq8U7LOpG5NKv;9Ym! zEwsdGAZlHcisl*`mqZ=?xLH3HQ=v)#D|A~9u);bVLm%riZAl; z0_d2P0ER7Ynjhi6#+8&C+v176TcGedS=<;R9m*dJ(n50OauekZ)8b0_=nBn`Y%{0a zk`NgbV%-Mcp|Uc!EOFw!{L&3JKMI0QRpKRQyID%xVZF~<23v=F1pN+A^#kW+%4w=* zWWh?VS3##tBTZ<%s2@`$F}>00+;Z7zOMv3E3m$|-t%J^H6isl7)Vqp$M>1zj6?!&& z%1(P4EV*f@{{?fXD|V3x9j=NBX3Rd0YSK_9-L&6(Nc~33TUwrZ&4w)Q>Q+E+H!uRb z0^6~A#L~IyX&CWCjH{Hj7*6VrbJP8p$ywfTARr<}SzO(k#_kRfAg_Qn2WQ=2K$2lO z%Zw*=r1E|1zrg$p#m-*J>?fm52FN~o8?&E^WIH+@Bgy3jr-xv%XJRoEbxZe8?@w%O z60Sbv!ukvmWW*Bs`fImCQk#`C44H02t>7)@T9b!DBWcoF5k6b}XvDs41s1onPp2;m z=7~yA#GTGJ5L`)_XRcz_T5wT8<}!Y47e*F|6Ge&J!}D&gXC+=7wt%3VGp=|Ju%aSD zzi+Q!Q%!)^FF7!JH>Dz+HIaNppMm+q6kJ>CLjw2f8I-iC^dMZHeoBPjhRvSjLJ;A5 zFol%-Ft&N5t3Wv?N#!qEO_#!ZTj00LsYML zyTIqoc>2;6$O>NDBWS{=A^|BR=_{mliUcUWYoFQvp-r?RAk8ih^K#B4kGSA!Hh>{a*Wn*VWI#J-{ToB^n=SI5H zUHKR*i02I%`$chqxvHm=LBTPHh0y>|e1PpVSnUNOJ2h<)5VNsK^lTT%^48WJK45wL zuSyhZ^7`;jVaLqS*{X9a2-W%Nu4grKGuziw2m7`8Rep;0?tVO4^wtn)j7RkDLw2 zWW>n=1B^>q7nNv{pH-+YrKj`X6QTkTAq!EJl~kx5v-HS8qPhpMw7J|M8%OZSudN-Q zrzH3H5J2S0$qv7VG6{i1F9L7M-Z@f zgWDDJ&og6q7l`WUH5m0^Nj|M_RP6uLXs8E^=C|70D*l3t`PJ{vn216=LpD7b$!Bc0 z(CyCxdlISxd!l^B!AxHYX8xuY_8ij{6OoH`FDi-7L#D4k6f{rV9qPLovgnF_rZZre1T;4-I*YC#Q>`{QSfi}IO%xU2{;O5 zNUUz;X&6eeOKhkLw0^&p*avFNQZvR`e!q#N1T&r#(ez5(v_NgP(4Wj?fGkMq7N~qNg zE__Orm!z{h2j@s2A$_{w4ScG^zm2LSBqXu^6K^Qn%kWzq=YcehM|n{{I?9(q9?_B; z*GSicpgW3&Zf=BtX?Eu4WFa&X4otGkjBr^fNjvYA=*i3kq>xo$dCRa9m78(c@s_H! z8!Pm7@AS}u)pF3{2I=JBLel4erKtN_Ue(Tkbyu>eydS@`p!#rx=1j6wm{0UZ#h3lv z=#D)H^&dZh3nBK=5YF)I#m!yGalnuJv)SZ=bnMHOJFV8_x+ya?aWdF z*k-?D@}bre?q($HeYXB1MLUlbH<8T+9Pd%}E@N796t{^Qg; zba_>Zi$4E;=7Nv-9=7BRoXaxzP5zoo4zpYBRfFlF#R*&&1^XUVo9th1U5lSFr`hT5 za{O%|*6bJzZ_qFT%dpW`Jr?go!H3Cw-3*1pVnudd^Iw-R-`Ir2S(1gkEtmF1~uMoab!xPDc*!aw4zLf&SlXF1Be@-+`T5V+b52@)K%o=q+Z1DN% z=&%V-S;#kV$YDO$)6?B#t8NI8Y@&mH9IExIoJdXO0!le;gO(ODMr%7Ztbw`MbSSy? z`^cadwbnndZ`fPJDROjx{fim>!Z)8(2Nf6Y)7K|hM#eLp$GWbza?cFgDAxd7xK5(qdjSI{Jy}Z_0w(7JiTltu{HdBW=Ko5 z2zwUMK}-8m*|sMH`uiNhm&1blRY-G&8T94>C7ezGBy4dKqaGWGY721Sk{s~}uNlB3 z8}ysa7cdBUgAP?-1sJGA@K1h-Hv(ua!Q?7F_s!-fHy0ZI*EP;8;kf=%<;D+8pH3WT*p_vU=nR0ZvJA^z$XD@ttNPI5Q`0)EXa82;q0Hm73H+rpR*^T&EtJfV$>Q2ArFUo;l7b->RNB|b@(MT zVSXUI$~D=3A6ImoyYmVz=@}JMgwP$W?2^D4neLEcp(@3Mqp-EGwY>kQuz%Qj?-h&3 zF9d3PdWk`Kiz%&0=G(^Ia_dBz9ihD?QY7#&ZrStee`$SW<2?q zbNu7@*ousbcxe9+Xy{xp(X}Kjh0otiUc)q(k&PC(dig}in|s@ z>pMzS1cAhHIXLQoC53}#g$f*5;gXtGs10jD1R zs&Vuv-adJM;Y=DOhMLF9zU#IH0Z$`p7J~L&+8gksm$3ujpBc?JFHZh$c9|?j@w9Jm ze!0&ozdRn3O}(j%EsB<4i7FMLy7)zH>uozt>)#{X?A#csIKVCJyJVbcpR2 zv8>WjYBr(=3(S2k6mdc%A{D}g=Iy}-1X?W-(%Rh-IUN&|;HlWyoja8sBG$&DDdA6bKD9^~|w6T3?+pO~5$W=mMNyo5$$HMsUlwW_Tu) zp~br;df&5D12c>$Jw*R~Py6LQq*EDr3g*N&v-ixAM{4|h#vy9f|vNsw!e zUll)9v*@w`ukx9nm4$om+sk66;*>6Tt!QBd3h<{*{j}qft0*TWvYjdx+7ZHjAlpxy zar;mj2X8+PG`G(^Ur{2zMHTM5ACBUy`*l#rJni$0xB?2?V2Waocl@E7rT*!)gz)zY zHOAzZ$_db;bHf;~hc$ieThPq$^h<`$(KIb_2IaV@CLS_N5ucJ~27>B1wH-sA7|P)8 z(eUTDI-pojpsFJ9nTVpZ!MZS{5PgoBvse)jGFuhoW!=j8SG9v$&)~9R<@m=A3r7T> zWGSlUHHSY}1eTaODqm(ypMld-DYSO1MIg}OkfB!6W&oIy`u2*B*uO7wUP)+h28I(U zQiUiI{98m*?H^`$|A^k*Ya%V19JRInE?}gd4RNy4<#tA&l=b!;*nRkOv<{5h&&x!w zm+c}J%=ed)YXIr>GCO=MLVs?HsPnE&9QkZjRgrLahtBVjc{vQwWTik3&l_f6OSrFm zULY5bB9=A(qdn*%$-q!!bA1>-A0nrKI-_x!-OGyl!E|K1B~yN8Bw^xDJT(8kZ=`O} z+-*hM`U1?=T`G5f4N@<>hH> z7lbx7D}>+osrA}Sle1$#&N??IsT#J_6;AKBg}f;@G~0#F+RI0%G&{e5m-720?=2Qf z*8D&*Yo6iHV>x{%Z#tWVkdPM+z%01j?beSSov(06v;?mghWb_lz0)OgLKs((@V^kr z2J37&5kHYFL(i`QSQ%@d=dtRF{vPQ))8ERcJiv!6e%<(j&GiB^P?_-&+n~CAKhu`( zA9LqG9Ia7jRx@9z3L%uz%;9SAnavYyo^m5mxKx_7>*9uPjld`~?0oyOm(a{YYG6=W z221GoKoFAj$rv=uIt5RgR_vvw4VyqV%Wu1R1!vl~-}*eorD6yvzz`7Nx%n(uHJHl0 zRBVS$cp+V$L;iU9-_7&mkpJ$T8Q1W+r`oey8GAwYP3~u{swnij!dNN2{%xox#Z*86 zLHzBLUD_XJIVn4KB#3VgZ)jA?P{SkIv1$JiRC7)?P{A|m-v+C)ZDenr2ekwcF%&hk zNs=}>Tx1l3+kxV$`5+Ec(xafS;Zhs)E=oZ4-TOAkP7eQ8v&ojAen|%{QeRaOOOY|f2b|+BWKhj_5 ziFqq3$&nKnf&%<3Q0Zwdlo8Dt*pjW z52!qn@5R_?)11NJXqlK$8}AMZVw1cbkDm8`vS5)67no(M#`c()PVP=&M=e8-v){7G zOrD3TT*20NL@g`8ecr*Y!SIW^kT*6^bC1<$SrM9p3S9XChkaE^By?3( zx?6Wn>|{h0IoRmyhT=VQH%sMMH6I?_QNd>FLIX~1UPd8!%=4RJMdCxl4%~=XF5`mw zw@_(#=RT!tpu#ixRLUFLuezB1k*;`-4{WDFz@h<&~|WZ zu>uVvL=s@_(e~BXf`HzR4c9wOQI3tNzpcqMWsohSY-DU^o3zd24jP2ciD`)e7+?KL zIp?|cyzrCR!E^W;BtbRPa3?-T0dPMjHLnl#`_55mSCVhWCCuAHcLHQQ*a3F(!JIGA z6A-E?(H4Th|DF*aC~)K%Xleft`Gyr&7%Nb$C$MRYZ7al(qm}DETVw(N#}IJ=+P-#p z01EcL^3&u*1~PVGUyGA7=^P%Wl6T&uJ>(l+Q1 z(=43g!Q8A0O{{!}M(m zSAbE7XHg}a6>l!H|A@9ad*FAJFiQ~5T1Vz&#QsOgru?w8Qz$l{(ojk{#?%Pc=r!?W z#?^ooFjoIwDNY2TR1qo)KsQ=*D6=hzsu%NhNC;oGVR;ylW7H5*?OiF~=0G#Us^FWcAr z06?AWG`qTVV{gh>cnSgLF|4I>c%uc`v5(D-DDdtCs6fnSL6?*i4AM-Zv7)ScdsZVE z@hpc}#x`nu9MLUJc|uS1-rQdH+E&rKF~gw~iNZ@bFPL7eO0a|I5?vA1(ysR!4BbnZ zgbg+WOf3>K?1|(in_UUyWKDBblLV3>-}aq=LL*a z?N%$Yr82YF+jJ*e#uUYOkPic~qkd0LHJDF{UZz`>UG`nyLPS>RTg7%S8Ir_E^MFDHbC znInKH{zsD$f{WeSLympfKDQ5`pMk&f`IpQzc$CN!E0daJL4PK1`tN@UAdOsGF>z{n zv@Qm^erltf0C%gBp<@>Cl3MwF+SLJgtA;OtW{?w)3gzFQLC{lUswe_~&vLUoR~e5a zybEzs$xj2fP_CUKcJhja6VAH#V4mOozL|ehQ#!d9k)N1(|7xD9aG$RZ2QP>JfjHv3 zjfnO9?oxEiyFr$|Ih*_nzgm9#T9^lsgiGNdv|PUl=~4o}eM6IyRYDdesSHDX z{LR#;B2=8dU>r~(SDlDJcN^QdouZ`RhajxIM{A6LBK7dCa2VF4C113~h!87-;6gNn z)O}FHtbOOP5=RcYkxnz*+L;fHiNigVZ?3)Z#LV-)jbpd4j=hE-3S@mjmmxm>%#M_aM?89lvWUOBbT!>HC?K59+`dQ0Qvx{dB2_yj=aY zEyn3!27VRTC-HJ{B;Oku%wj>Q`n6sZHfnZvd5z2h*Nf|@YDm6HMtvAuiY~+^&=P%j z1+9LfrrNAxXK|_!JQe))$5B2QJkXM@e?5VUI(6;BN1+vtwc z5!2g#{BVOoyS8q_e04^9C=x>FQL1$5r*w|8v#UApKk1zB85FboP1YT|zi_2J1)d%- zAP9Q{&vrAo*|c+cgTiHRd1$VP zV3K=^ayw$$IDP)RxT^j3+yLjPPm%>DVK5z!5aCpN$37v^;9Pooa#pDzB=zB%`@X z@u8OoZat;t^Uya)|5E|(LF#7{&d(ed`F)IZ`{m=`lGPJMM$Ya1_?B@@AnMuu%cI{2 zUB3SqL_O&MxtvzO9fD%B`sHo{oyT<&zVTt)e5Vbsp`+t zB|llBT~Ylih%s|Ngq_(u+ORqqse4>&G_Rq|Iy+v1M z=Pm))N92l7(xpNWioIMJg|3<30T+H}7#KDI&wLp0?991lcN6BV+~kQ+z$J?4T~pqW zpflL&+skdzUczQpn8W+&nj(_16M5>TBxYVGxpxVh%P*YZ%;0DCFyneT=zk}oO@p9JkRra?s>h-W*Jxm5PvL-n*$|!#!jga47XY=nihXujKJL%*!&69W8H?$ffx74>b;w{$qFIUu6=+dA(xJ1>s&P8Ms|<<`vMiEab) zC_S5Rgh?^Vwfz(J3s9Yal)Lc zE48MNeaG<2$0j0waI^h7d@xZXwEThu)jF`yRAx-ziwNKCq4oCqtEnY@H<0l{%7>IB zb079GXM0qVsjdIDa1H0R>>%#ezf9}}Kb^K%`I)vN-%4ROp7&jHuJhQsKmbt*myOAo z2Ef~HRCPq;y6XA$8y=A(AL5zW4TV2u>epbc7kpfHcOyh-_DSpjwaNo-$V!L*g_mJd zL%JiTT>l|1OPNe)QNLwQSI2JDSEuT7>0DCVs?Ff*(%6K$H3d({w0&+U1o6LRbn(Se z%fg5BNxD;z8qw>2!e9LIG>9u>lpXc~@_sDP5r3Iqme-0vg>Rb+*$-ri$rzuHReqP? zX!6%ShP?a2e=;X}zf^<^veCrmyQ0fHOJB;*{Nxv-acnx{NU`KAaMwQuCG{C)Af3gp zyOyNub4lan>MyzE%5R|tV}9lwns9!q6|~AF_d*5U?v^|A7Cgd2ErRPoESLSS_-Ad6 z9;y9XX(%)?c95|azMdJkAX8yH>J{*sQt*8BAnL+52`95L4>c-QtlpISfQZOH{&d~w zNs)mxs|*_2_2{)nOP5|GXB8zz^K#IL2b*z^-y{CopAL_A^~*#>5M?WZL@}oW>uha~Vu*njG0``?ILwR&JRGyv3#m*OZFNEZ^=&hZcG`_@ z-N3;gCCEwX?55WVy&eaM0gx%pwpOjirAWssh|BgLQ7)v{nHThA7@n=_nnjH>soEPV zuuMdhGCDgwb1J6ej99M@{1UTTZS(u7FXlp~Ez68!l&&P}M1%}|sM|MH+b(`P%p1&t z%#TMOgjR&xE&!4@JiR_TK1QPzFKZ@t^feUE%UO$m+(CzYT-5rlfT6#{bph@QZ1WJl z>aa8QfG+nQ`K;;db18-2jr1hRwyT19PT>nv_r5n89yumu`jZ!_EtHTxvuiS@(%WFE zta@-eHA-3G<<}&=RIeA8zVJflO4pYM)=Q^BUYZ@NsnGVXJqqz|c14d3<22SI?^;`A zs`j=n{x6M;$4ATyx#R9aOZ8~38c)uT^oW1QKfVu0XLNPJQav#faI71SanldZTa@In zWHpqxHv2<&Z~KA%H1{ZMf2(Uc+OR4yy+EyaiymZ_(EJ;!p|0K_5G^|U0Xim;#5jlF zTz_!C3Lwm;e`}G;o&5wF*4I-UP57vbZjqc7?d39(l{G|5KV?<1NZX6J(@OdlAXpZk zaOXwngZ*-L`xjiQHjX2MLlqI%rjW0h-dP{OA3Yh9eR111XG{8}D*wtBAK%!FZ!Io@ z+6{~{!&SESBJPG$ew*mru-9}MbCoOgn|KQU-kF)iuR?9qF^taPg%Nt5Ry);E@t|V+ zaW4VO=-*3?G1q~gwRR6pFYtIM(fkqC+*h{MvU}NclEQzc@}w-&D~vwNTnGMesI!?# zQ$XWVJdf~yEteC&txg-Z%NacDW@o(~G5&&F3wBcxL252g4obCD)5gO%F8%YTh$S@bF#G=DUJ?RhT^1g$-ZRyA11YUj%jKELKNR_j8AvCVV`Fj;WPNov0Leb1;m^WM zM6}`T{O8o?w zAY9raCgsIdG83%SIWl{nOXf;4)8fj>NaaT8|DHfCYk&XizD1+VTT(>J^0WV8r1HrR z;=-p)`&B`i=Vvw-B3)-5CpxMqlS;bzWLFj4f8TrpWBjA`<+D4!k(#G(x!zO`)qZZ* z(Rv_t-_M^zMj`2Wel(hvzdH zqwssR7Ok7N>D0-kCdP=Z?2Ni=azCeYueLu01{*7#nD|d zw^~21vJBU8e=HFBt4MPxF^WC%s+~&Ve=3(0)1$L8EHl%c#kM-~NwxMmlq5ajIaUqlYG=j<*DLLWqUzg^gH1U_g`k|E%8ZM!)y$Ch4 zj%&_LvbDb!?$OeFbLv;S1*X^Rl33wOy_Fg_`byT^lBZ0XFP(_xd;hGwXR^GD9ndu7 zx_R|zua)g-#b}ZVpwd!%?Axj|Cpq^TsD^OY+kz;Jbja9&Fba5 z@z2K9vV8s|&CB@jE@;`p(lq*8;i{K~3l?t%sL0+G+WoL5J+YNUhES+x~vcI&$XX>cyff`eiYPQW6vU=qRVb?;%0&%vV)B;oY{Mp-Unj&9+q0`?Cz}`fLwBiSt{EVu%`(+)wVmL~vK}%GY;y zV5xR+3T(y!11ddEGE6VybtHtAV13PFG}``LO(Ul2z77XJZ&Bm6Mt74`7GoZ6jY2}Lf ze$=9Qx$SG!woZa(Ch2mg`)pQ1XWpku>2la+uH{9I#%mcKvfZ;#vpe^V1mat7MqPj9 z_d%Ej-UDmAE<5t!=b;LXqf|Jb-};3SaUpfzmlJgoHQs{KzDbYbGtI6{F5SBic)c?< z*d@T&{`lue++<0xInB1{J9k|{&mVr`;_v9O_O({VH|_&k*sgN0msYYlNSxyzQ1dF8 zZRxrVo%nAnew98<5ri&E)A8iCHb7qhy)`Y1&Ammf*r1)8a?Q{FlNcN?aK`Y_*xsw^z)u7Nr8^~FcDxsq~qFLk}1yRSaKzPZq9bx^BHJ%{4}HjE&>>T|TC(k4(-+zY+ljMR!Fds13XBJvnA^Se zU-Wgz*flVDjV%1KqF=~dN&B~hGI=%kB{2FaCtTt7s?hJGl}{>@;l~4J!mQJLEp$JX ziViFz3s4d@xzDp0JX)qBIs7vSSy$evaQ@Nb;Vt8hdnldE^lnGX^fG?WMOXT^*2gzT zd158u!#B3QZO?WCIus*J3Sb-l<7AIFGxkv&lq-X{)pS&GEJ8d*)m&`zwaSj9Ju-KO7bA%!BYnjUN2G_ z`RW#@sdIhP^AWGGXt#he8`UwrCjbCbd7gYGDLf#+@~FHlZv z#r>A=j>Uwhoye-jCg*CI+^GTCAL+3!t4A`;JfIJ8*{WW++<#M<6t%XDoykI#pUIst zxy(Cvg;MmvePb?4lCqq_iL95^*Z8j#+z8DbEPCt8C131DujO#-&5zzy)Cv$ja$o)5 zR!CB`onZ`j1-JN`icl+~sh@|Hku}J@VsewnO>@16q|APW%#P59J&lbTI$wd0X-VH2T2d;y|%xZ=gDN$VK$l=;6K` z)lv<3q+Oxbl}|fyU6hU{bWJrN>;_m;ziK7^nJn*8DU&7yAnr2go}~ZdWdEY#(}W(KpV)r9oQ^OcOe8G;S!>^?I>{(zhxRv4&?~nwar9t? z;;21(j~clK?wr2Pknn2Jk3giP5b@5;)1_PYfc_w(##xju*qOz~y*vf@H~K9bZP zsm{4v!5zil`{g-+ep(IMn;hwtQBUg{^^LY-H(-*60^2M}k`?P{zV)%dN#D?`OdGZ0 z6HyBiXPZkY{iEXGXzm#P@R}0*ccnQOIJoc7HTvbdmH5jpLgvMT52Q}&WiUfYSH=)& zihmnqYjG1mss^`^+&CiEUY#%B`F$MVGdWzX~vPUA~Ox1&wD z44-*beNko-)E5ZQOMd*8Kk(e6&|7x6pKx^|!tky`vbH(MfcLJ}ce~mG9i~~sRoyFI z$xZ%CYWWuFLHK`50WTCzqi3qwq-YkNl{$=Gv{naU{_xs$H0mnKTEE-jHobtK<2BHf zk1$geTFHOLma)kr%p=ED>-8C;sm^uMsB}&#VbV0pW+sn5<`$DE^uN8qxYg<3j{QbE zIAN*4ukk)J=CLLD{C@)Cw(+Phg+0si@P*=eN!nJgP~UO%h~9sjBfmz5slZ7UA*d&{ zmLI}?3HJVV2~g(rEZGeh$k7!NKMBikeY*Oqqz2@xmM|?~WMWnQ0ane_$6>y@L>L()(J7Q(j7#cRMwz|@F7P}uswN%EN zh;*HJK8EkR>_n%gh7NR+0)6p=e~{}Ba}1B*9;EyKqD(9`R>+6ms&T`|3N zyL)BV!oQr}zQQrws+NkZ`8g>!`yveH!ipW~ zvgAdRqF5*Ary1^`eFqo-YdpdfSu&WG1YnofR)B$h)X=<@I_={P zXIY-cOUZ^cPNN-S*871MvENt)A}(r6B~;v>WOsbGe(3d8h53g@sOa(e2p=oKm;Hmr zA$~HcO~Sb>;G>od>JBk>Gx0z*LZ0vX?Y~`DR?JuEda^ zx=ADDW#3D|IzRC1#}$vriaEpn?QmHBNwGTc407!Hh#1iiyPdRwlNzM`**)f+ZH0oo zqW&t}mWlC~OLNM)Nj!lx;?1B8<6*1&Je-XTq8Z)+=~yc3QTJtHYPyg*!uCC^>>vPI zv+?JaS4pND&%-Z-E1%s}+V-~wfmsbME;6jCh1_jvJ5t>RMctD~)3UwVgcP2ES(y2iwy$toME`V8IYA;ez35WzG7BOStA1Da zdd`|dFIkSolU{1|HjqSwQdbff&(t-A6#1fRe4c&tmHFf#AjdU8alAQX^KZFi+S4v> zAufi|gzhdQQqdXF*Jst%mexJW)9&Ml`s?(+TZ*2GW}sMtm+;|?JHOn>YX|4+&Jtgo z1FpaE$Rht6c#*n9%Q@oBa}~qNTrI^b*^r~?3+F$<=+sgxwPP``D0qM0gfEWds~$cxau#}-b9y^< zI7$L(zMCnn4|w7D8&{tcxu>F#b^B38oD?QJ!{z!(AY^r`>&P!GDVICS@W;Q91Y4qyhHF|>zEcnsAv?*c96eMi3dh}28z%$JN z()Vxv2Lre+9Dd6$`1oIU;3wpSMRK4=B6^MLi-5tSamAS~kc^D;u$2YZr(0d4`o@(v zSzwk;%OgLR7OO6tWHx7qPdHkBdEwD38l_)W{+NM-S)Oa$zg<-k{_wr@nv(e#${;Fb zW}A=3fx)xTPpykJblM^>^GLt*wo;^1g6zY5X)1jkcF}c*eC}9p^t<|BbVVau9e(pk zx}QkPA0el2DxRvBHS_%kZl&lnjj1)E7PC689{}JdXYh~pX@C4eOX_)dc`uxV?7Ds1=&$9W`T^&>Xj^dn>ma=oi!0f0V)lDXGcywWIJ!Gx_P>6fj zVIG&Qpw@p8U%TL_t=AEHEu6e($7VcBS4Epr8Ro>H*FXL77ZJp24Q`%<+g`;mz`JGm!Oflb*+yv37QnH!!W>*EMQk-y8PKL-OILEZtK$O5`s*~wkOKUY?MRW@9`N$t0zT4$JADGzDh@D=y;&(o0q zf5iw*J)Z>KOPk>-PJVrnS6u40I^xM=IjlhkGh+;9G|mu}5Ch%Sy*EJ$FX#d^;y-|f zH&TAuA#CUGyCYH>hRywK3%|t@|F7_O zbry9QB~_#Wdd>ko+>RG>t46&PS!#7BN9ll)9Ysu!@&WrKE}p*Q@YMTk(7!%zFQU3* zdwL5a)06r#dFRaY{_UK0T{4dOx;J+I^sINg1Gvgn^CIElVrGwDlYd#{4$5IVA6y9S9->RZ!cWp`4`pO}Oz*Kq>x5sF z{Zw9LdcA4*^VY`km!Ln3R{~zWb~9Z0&+-yT|NC`+UashIAL*J^lHCaK(jQKa)|U_= zi})l+H>{4Y%vqaxe83*h%wybi_`~JR31&$8V%)g!D`~c=HlNSb>i<<$Q=>r;7Gv#T z9hq4)3(KPWj<_lzR0;^`{_<9~{-fNpQt~e)ahKKo*Ck$`;}Y1=u@Y)Smnri-+#4>> zWz$_&1of=6v~362F6-3NZ2C6|1)PJW%*ETa8}7Y)sGV%~y62+s6Zr4rM4#af=Vr$8 z|I|%aH#@% zD`9?LCO!bv-;r(G-h0Ans2NzEqNx4sjn{Dv|8cJpTO_0} ze-&Nj)9{x4p^g>!w{PPA@}}hb=`q2P3-q(2uCCn=EfHeZ@cQvfXF1O&B)L8oNM@P= z88aO6n!^&JP|jS*6Fh@zpM<3^U-x?jpDRy=QW+Xv^gc=zeW>4ic>Z{uOLA47?S0pa zLwYslHf~A$92GXPhMF}FA3h!H`#zHg-c?6EcDjp72zGuf1l`UKPZ6K(NKW@T5KyHT zf3Y#q&m#9=W1#wVt%FMMiWX+2OQtIG@0(#H-#>4=Z30@JHjqBNQM)1c3Hy57k~=}9 z_B5icid&deMK$!ftU%hgZb@3dU3?_5>oqg0txy0%h5rphhn&{%ke=Ig>VzN@;}N5n z?t?1s>-Oyc`kfcjkWv;{<9P$*W+xb-mBcEj^h*FsL=%<$3i5r1+*GItiH$oJg zE7k%4o z2)?2pMcV_JPOGy=Kq&-HoIubGKn+Ld8$5yt^d=dUE=gQBf2RKF&v%j<(UW;q<*7T>!JjKe3W4^+l ze@5zjR`vUF)EV~Xr^IQ@7n4aR%^NK6MR{3nsr0MWkHz#UOfTpthYF# zhQcb1NmhtbIS^#(5|xd|B-0BJDq?xaF$-iALIrsU0JvML71zA|R zpB?N6BFd+gmF=;Tz=fdTxmIMxi3V#$Q6k&@ims)^ukU{!^WO;os0|GBwK@vtQ3k0} zkDWpP8Bf97I4rV4MJoz&mrL_@N9;(byN`!#`*tP*P))TYvlDv0Rv5|WenYZxdSsM| zQ~lSi-+c-;{m?q8>l}JP(f{UgMtVcpoOWdePn0X(MlswR7aqDd+<4ySJMXjgrK^al zio`f8^Y0xyG;^dzBPKP2N_R}W_yXBgALi;%jRM{(EnpufY0Omkk+~m+5aF zTS+Z)3IFF^!XDRq6yz8U!X^EqAykLE)3WZbq`EZxxBV@=Vv;3BqBLVlr7JfhX4`g$ zY6>>b=$z!`(zUCOhJW8CBq%=ht{cN}aOpGVD;1Sa1K$jVw*`?s;h8T1VUhH?nGSI# z1y6bdA4voWe@wX8DVK@XZ&>oJx^{w^O!~!=c%#aLzgPSVQ;0|i;^ z;kYv4*M%Vd^-}Fc?@L-hPQ+Oc*Lt5+&jZhBqteuF%elw&cKC)@q1ybWGTsO=k!g4= z4jwndGP%lK>KZd*^)_&@Br4uzyi2y9J8hPgn(%3xOjDQa*FJvK+6sKe!OS9Yjj4jy zGsBtQzGw7fTwLvV0DIZqtHKYuf&2^G3?gXOHHVYCzc2P|X7bUD`dyU;@ht~ZE9;c% zw$Z~(MQ#5vUM-1x$grzQuY${8OnTA!JL1ltP}?CS`@_*Eb@KkV`UuN=-Lh{`HRGL-Y#aajB!^^mRQC+m1zCmN)PJuK z1BW4;oeyLO4A=4E0xo)G-Ip_bV}dWwk99gFw7Sk1KB9mtx$VH31h$3KF9Hc zA?8y>w#WvR%bGynfJ@7b3>~rW7HAFULXLE;fNiHWdz0=}m=eXAJN2hRjkJ=a(0#o& zms(=UEWa(VZ2>dk-S0lvVt4G_&*!zvtq0=gFasfQGYkUln;qiNxVp`snE7?A;Tf;O zRkS;}$D-aLjxXj~K<+hkAT1E|1y_*){g*sN`^7BirK>}7946-=| zpAASxv6=(>(Hd{9v_8-R9(w9$Hxb9${P%YCn0IP^h}RW)tjY|THn%s30t1gb4kjCM zwK73_&$3odgJ*?Xwwgc*Y=mq8npD6*5tzuSg_bFtG467MmvvC)SbYYnf>=uiz?pEK>lYS_vN|?}8`s}+BhTdf?{ z%AsG#sUlMnR(!U~tLNj1)z!T6$TSNaM?yl&zD`ra;+MKxzQr2xTLV_g-&=gGM2;BC za@uLxa5ZWHJzsw;VrHV^MFH;^YzbO5D_yfKGDRv zkVwEu)A26rw2RL~ltK1!U&uo0)vo3rA9dWt?g*y?!0`!Lgw|%Hr%SvA7ozP57))^8 ztD9c+^Ff?{TBn}fZff(!V)LsyaZit@JH^DO5X;V=$dLZkWS+dFBi;2?=uhM}wyCrC zzg!0^0k@NE0dGsho4aXsW+HR3w?5XjCtG4$+(V_>eI6|}?6kP&f*Px)y#e5_v4@(A z&sq$SZlbFkmlVy)(8Q62eAUyq_3@l+#Y2WV3<}|2h4(eRe!{W#;rT&n&4T+)xibm= zR*euV0z5ml^$fykA5pQk`)WQ#(G&6g@Vt=WDq@1Rv9yRkKvBzVPR2CMQ)M+pr*@n{ zc4lokr}U+Yf0oCB7f~BBk$QC)L@D7othBN%a#YJ@@(*xb#*+@z9)<{nH-nYh{b^zd zFb~(H8c&-YI@kx-`Xa_omwIHoT~+e$?nb%&2JE(Fz2)ye+<+}blTc(pz?GqcKC1<< z;p#xvI;|Da{^jQOMwer6azntcsLA6}vHB>qU6q>ik&n_J&o~il+%PA#syolNHv=wK zTlHONIhsXU17Qp2r^yP|^TB8vb0qX|yW{6-ar^ap@T7O*T+5v`8jjFoMsud#KtqVlhZ^(3i@!ph?9u)$-A!$JQgt9VtjYdfC7%S zs4LgX^4<>}mTekjhXeMXJ$;^Y9m2DT({2D z592Gd&FkT*I~L%0fAVc}5ACZPGhy|cB^`YVrA-Ub=f12q3%lZ{Gn@S+2y|fx4B~%r zFX7fGt27-k$-P%4R13UODo$qS#x?=V&HncEPbn<=pY*l7+UswxEHxlw21>bZn8E4g_Hf$T{cZ%$c!|P%~#U(U7xH7m0sQPM7_XzQ=j<#$!q?-U}AIIl~Cy+Xb5p84feoO)wcDQ zqDB*8L2(8>(Y(Oket0N5)A>UWQgX!JaTtTH3AJzTWT@SaH$sH&^UnT7yLWz5)HrQw z^t6Vex5R?hWoIo2^!^KMwU~H#Uh5f4LYd9KkI&ZyAoI!j<^b}X9+}t%V21B`;z~nS zy-#u9b(Xf(&1=wLKV-=`Qed=m9rOKwED6Ivn`_}{(#8Y;hb@zY)TG&wwEFYWXHmeZ zGNWZodpfc}140pBN8iE{O!m+kM+W^NE5umelgxblX8JoE7l{`o~18jFBmapv)<>oJRmSRn*~0s2;D5fg7rhOW9DRBCWto=v~Z48eKDFE{W11< z$H*P68jQqk;GtzX-#gGme1TRJ`XQfSe?IbWX8#Nbc${;Hnnf1XqH2lze-Ba7?fxY* zn@;eyfP7Wck+OZC686?`*k1czGxlQ*3TY*n+@yiT;p##+*Il{K)XsmD+1TbMwyi9s zf5Jn7ozCdQ>7W`U2FHi1(HiZrA(1m7?S0J;$ZhMkgfwU`p16tiL@$RL1sjO>Xys#9 zjnFc0cV1!J<<~JkH`$`$<_Ytp5zs9KHMHNk0XCEj-@{Vu4XkV$;K)6cXX}1K3M3c; zB=*KX7+vLz2f)@rSbhy)+pqu}frh-BM-b9rr1c}qCI)l~&`&!Qy8-~VAHu1pA1ZJ% zk_(l|(YYc3X2OCThll{*A)MjkDR%ccf*l zjar=p8^~V7EEf!V^h;z4se(ON?163nT%480{A9>vFejEkh+f28ktJ;NsVZye#2_b0 zN4&@0)8`ba?(>w=V2kw9+5IU9VX$#cr15o_wSl~P&z%QqTWkg&w~(Sxn^@ARu6d11 zS(+qlc0DnWglYFfMo=gZdJ>54__42z2UX_Wkj}|XhO7B?!H3WLmk&!$aeOF=aauEnvGzAd*NCK zCf;Yb^u+d!_ouioW%-9QiL)|p=Y;cRMPR2diAY&?CgN&$bQ;|N!Ka0+3&s#EPr7@Z zo9Yn=XJS+l+I*O(h#vupk$sUZ6kDg4L|EsMDORmH4K)oR^z;L)0g#>PekD%8I<68Z--=mdTbSTjUh2 zlTVj7Mfm*)dV9wv8i%oz7LQOcVlo)Kk$49Bzn~8!LU^ez`eACmLO-+vVCIb8OYW+ABa2MPd)wyKsJF<(UMeLOe^xV zJv0hEO_%}^u^pZ;Xd3D$U!By6GRuJz&(;On3`sT6r85x##VSZ_Q6Ng&M(nY*DbzPC|`2VvTpU8XoMK&idOE*4i0- zmUTqj{*?QGtPBWPRz_C9f-w}tHi<$-rw07tB<#E(%&E>AKb#MheSiXQML@9kW!37S z`;ACaSws}-bW5cUztX>Vj6%qfYswItfAI(0u72ldWZOU_=QJ8Ny$utvh3uL0YG5O+ z%tN5VVgfG!z##l?Hu9$lY4pkL*FC^<*zuJ{bs_->U_s8iB(?}{;?Cgt>LC!^K`?p% z3)(%E`aiSnXI;4{twD&`E0TYR zq3BwI8@Gt0a^R+B<4EFCgCLb0uQs}d!V!f?6^t*#)EQ;!vpF1(#sAIo9h`m7JKn&I>_{V&KQx3yjx=i7&1$`j0SjNzlzIq5XL}Q>jcS}TU9B>WvgB!d*54ELCnl8z&JUp&5kmaV zLzYWCm#-6f|8}&3DIZnc(5f)-SmUlI-vfB)YFRWY_bdRp;{<5}gCn$Hz8gSlnrA13 z_M;%OYLb*7sG1iM1oH$It%Z=wsg<2TR6pwwnfa5=CSgIs9q%1G)KN}=2(x@6($sQx z|165us0DWiTfPayw6UI`rcgzo0R?w7`e>cscJDMfxE+;TSG7+}LE2)?L}pQ^z@Q^@ zcr7w;#Kd+93eaIv;Z%|&O zA0nfGVDABwp9ia|zr*T|>hqbAKv+M;1-PQifB<({ASmAsTtMY;K=Af;U@SYOfdRQ@ z#xR581g(Q8KZ2f96UH1yNFS};gpJED3pHt={i9V6{Ly$fO2g_ftXwJaRZqvXNd60$ zZ_Slvb3@Wm{}jj*G}a5iK~6z1FydS_(an4pCHbnS2S_YHniI9^$Z3KH7TzB1j-ABr z*)!yh1e^;3hGW}XI|wj^cGM-(+XtM2e|vjq>R^9?~;{`Wcx5Abpbu&F!F2FuZpi1i&|tc2O=+UksrP5_~?| zrpJ#Vt0GD?C|=F=3JB^+YET&{@*Ic9vDM-}tLE7NkiO9NJ)%1D73?^f$~t4vPy?I% z7jfflI7VaBM1qU>3tMCkMhhWSTl^IIX8TWo^cI$)e3 z>pA#?PS=2)?1S$nHE7kdIRvy$1v7i9DxeV%j8rCQG}@{zH+G!YG?8a&4&=$B(&?r- zsnB`I&vQx{jAR?QzR-lWQr^rHnQ03l@0$m9IW&?4jv8_4hhM%ryDr3K zmQ&+cvFEr=;BSL^2x(h38vPL6ip9g1t2H3@f3kWO!MHPgEAjwL3dM$Kl4=t3eWxbI z{rAbckmbWH39|Ybh+-iP3~oF`B_b$xjcSt0hbhr+l}Owm6w%O6g{o6johXVgA;^P7 z-j@hmKW(1c)XJ9Z(CJX|#1&+#Z5A-R%<(ahSPEtQ{pRW`_x(lH zifdW-Sc;Ph1&dQ|uz$PxjoBcDnf;Eg;S(1rq12c6CmucJ8R32wnNsZY>_N=a!H1Ff zD1Q*?jGS8!J8r{wqUs1iwS?B$j+tRsbYoseNAam)%1bqoz`R^qc~9>Go)8XqWS*#k zZA-NBkWJB6vfrCR*`?fyGv{&7jP;G`)7GPvY_%09>vy*@e)8~ZPmG>wBX+wR(|v#t zc>-_pgn2j2%%Q+df%wYy3Ud%+$m5mBif*_vII(u78_z26x9|sTeqHbPzP(0_nu_}y zgd!$A@|J-vE!pSU>-Trgn~>V|%U@w~IlIv!LbM6fLk53(S8i51@SG=6q`MAtCEFA} zyfzzo{%-%jGSEFZyCUCi3+wr=O=+u93WwmW_q}B>n{o>0uZ}HDay6&d1hoEnZocjCH~8-;#SSJt|(P zn#K@D*0R%z98sqJLYL;}%C}jF-?j9!NGzOlF$YeB$a=8=&q7y_(az*0q&H+IXdGK!q#&^^wM`legt8-G6iCEwhil zunuI&Rz|)~^S0FNxacLn|5sPkfVWX(^jP`{jb7MojE>Y9hWYZr2l(ta{af$m0-eJp z;js)a7O~=XSnP8%V0>(;y0v76E~lCIJbx#D-4%MJeILp(2xc`% zgzFQxMw2%Pxyz6CjvIDTb->nFkG-QX#9l|EcHyH*ZumkDYe;WsOGgN)Dw^)NPnhy5(?BYCCSzUO zaA2V57^_gn86 zNjYilYmhVt_U=D-HSZ%o(ipEF8@(EEXFo5JC(Y){506-6hSJyMwgUTm`-fu}5pJ8i z`5$kL1a-)|9NqIea<;d@a72(7DjsL{e@G4wwS;Rq-QLfF!MsJ@O3SHcpAAZO;h!Ei zj^_PTDG$w>f73<_t}N*sW&ck@F0bNjyqj}FB}P!~h+AeC^h-I)>3Z% zSZ;#eFnY8bFOqiNRQ|X>+M5#1gS5Z#!{g}K=^2M+Sz?{Ww}ns1<)$&SHo~#qLg%}( zc1)A)VuCSOgI9j3JYR_xuaudg^CfZ-9#5Z!Ge+-uf6V{!O4af*@OE?)#SN$&u@NZT z;F_eaAhAN2Gq5X{%GeUt;DU zl`fzq^-h%arBKl+=02k5tD5UMq=G?l$0PU^>r0~#`$#y7*{AfgZdAFp@aPqa#5pn* zI&HwXC+m_64^Pgh`#Bh!8xfXH4{k@(j@~VTeIb~%FwfEfGY>lp+}@~$fU}C<6XfVBTbES#J<+vd@V!p{5FcURH0u@c|YfYl?C1*oJsdLBwZY*y)JJ#OP!q&pMAt{KSoZcW=YN=Sy+8t zW-TMxO*4i!&q3ojx_WhcG2U9OvUfay_1IS|AIZ#}XU$Hx>KP#VB|7&3nxVjE5Ff3wP{hssgVt&X+c>U6q&F}$uS?-nL zZ1qe1F-@@FH=!JQD@#x9;rQI5!g+PMiW1&E>m!C#fV2)<4oe(%Wh%qx2am6uWBaVv ziNz=QF9oA>jQ(r?g?T!(dWetX$h>eV3w$s2?$CFQ90pH?vdTBr0zcP%Oa_i+t8Xu; z2frp6C!sFC*8|?9ErUfBCn@vAW_(65+B%^-{I0`+>2&Ot@DJnFSvmvR83HPuMvuqt`OdyCXXi zIsc(%fAJ>SFHK z0NW6fQ*=mQqqL_60^}G7`nkNexvm0N%YoyC_w}yWMtq>77{1qAR zjrSo@&EtH@===|*jQef_7!@#o%jDja<&$p7^AabQ%*T3dEPDkSkl$rryS9EJOp`EX zd802Ei3nC#SI6%I)f~P^kl>`9DiLmAS7{m-bDIK>c26y7c$N4%&wyN&^K3(;MQZv? z5mC!@H>-LY`{u5D0VL)y>^c>laYfO5SP2B`+@SjvLA%}& zw-}~^v2m!tWjO>6EH1sS4E24(-YzP0U=M0j?$O!>zta$vzM97{fynd{wdWf2CB4j) zW1U((W^b`{Sc3B5HREO#T$23?cZ`Djub9*1tM-4IF&BKPo^#Uj-QI;j9G^YATW7Fn ze)6UMUZ5e}K8arc>(22l;(uA4?Zf&>s3B>MDp#@dRIh+_CC_O2F8H+teBvo*B$#c# z^E{|g@Ez!Ay6X6EAeUd?Btq~jrY&~ELe-g6br(C2@$D+AFrxRB{%SYjc{NE(^6T$| zB>Y~NWzkIRGka?gloxwNdgd+d{{a_3=)Wc%l|8+f*BZ%zd3T{R{YF#cQurAu)8TFe z%?>ktwQ6{C&tuYLii1yQLB}-A`E3n;XU6ljC$Hi7jqq9X#2<89YBUSo z$@255=D=HOnE3pJ%luq;3vrxXs}B#6v}dM{n0JEHpd)6NOfb7%wlwY>@@M4_)@UGq zGh}SyJm6??{l>lEO#eJRtqb}$gT)Mtz)_-oj!e<{<|K6PN`7U9p_ac_OvObylWSR) z=e?zqBnW1&=IiH{8n@h}aZNme@i~;E#wLWr8L`66*YuHbn^NPQ}CYZ-_W6~)a?u6Px+8M_d-ie>J zW7Zw52B)=}N$2dyso)zZf3|uL{!%s*pPy)Zwho%Bq%@NSfjwx?x$JcPfpyTbW}VH& z+`TppsftFv@3Wl8UgS^4++G5o+{)IbqH<_@)1KF3ii59eNWV4DLb|_mi8FIXuXZnA z&mb6Ts1iPF!civ9b;AzA;b_qIR~L8fCV93Jt#_{Iuq5(Z7_WgJ%PV2rQpR5}gUU3_ z<@cQ6-duR7R!|XgMXljb&+kXTIj{ZTOFYIs`(RPR0D`$GW2`R(Vm;0HdOw(q(sPUz zXU7jeRmTW^>h+}ug~5YqMvY1-@-bbfo~0wNA3ofq3EuMmC+C%ttNbzFm7_JBU%;Qz_+mEj#N6f4>)_4YgCnpNb65B73qKF+l6-Ad5Hy$3?lF^Z&Lex=oN?SM z5BCC}qxE&v#n)mVJe{%M<62uBID2hF3>*k%{n#yE0L)ol-4?bHdG#rrhl#+UwC9PM zUM_)-EA5$}SC5)Wo_#TSg#Hz1KK{t$r@yh?)B^ff`1*rUtQ`rTuX*x)HworWt*3H^ z{jnQ!Jd!2Q`~&(=821eGiaf}_{$&r&XX1R9+zQTP+Vi=y91kLYn{l6q8X+x*!B1v9 zvz~uZop3moGb1Kt63lAntB0z;F|33|^to2;)cpM}X?U(b%pNw8)0 zEzCv!Mo-obf&~iiRbBQ4&h<9V$^d6U{Ci{MIdXy<85 z)z6a+7U0{`&hPk%YzoK2WJW3l`f;KE)&dA-1pZi|NLDOI!ZWf zS@Fwf%zo<7`l~xaQ_(Lqwd`w~GWcIC^Ls8p|B6>fg&x7Y)wF#r*|BW+9KCGn>_*_l zwC_6MSNoN!NbIUKNoDX^dxjX(f$tpQ2BEo6+(i#Mg;`_I&9-x*5!A-LAxUzE-wnAPl^qAYcH$F;Q8U>!8PUJAGY>pKO{2nI)0KK=K*Sm*SLvAycxl+oUwNexy(9rzY+ z`SJfNQR#Uf^D2sRJfea5=Jxx!n5bfN^0%BDO8Y*Eeq~ScJTZs%8yte!Qlg%ZTEL&H z8@T2ct^<^cEt0&DKSO)Zr;*Yel4tFa8P^+3Fh?gmTTdK(?LG6ikA}XjWn{4d#SXq?zb8%Fl)h#;5(auopyJu9YQdBo2RVQc<{}9nKYGc zcA@s!HNBGo1ar!0=jN;3#L=_faA9sNG}#mS{Veu?;8KjWnXg{o{)RKF9Qtl!ic}B7 zGuI@2@gwA`{8L}8fq!mSM%HWO534w2dmx`PaeTsi;4e1=KgDBBjAQ&=vF6;07&`?u zf_XbSnf#oV{psh*f9<(%)s7~Ns}UABNE7;nA_d#N!}H_$RKAtPE3Cu0M*Dm{)Vc^$ zIUi%i{z2Q7M^m}Ie`gXJXrfUAMMRX4CLu{_@HLc77bzvuq~sQ*GMBhiQb@Q`2_=#y zL`iN)QQb_1216OTitk$A{jt`0*YCIQJ!iG<^Vi3-KF_cp=e*~A_q+GA$@2rpkJ>|k zU#j$15+|T|1pZLb zEO{A%xzaCft&)K?roCLb1^#;z>`#tIK1x5eMoZE`9R4MP>m3Jj?$M(0cjkUV+&yX` zUO#{X8FNaa*Ztx1=*_Ru%fXqO8>c=6*wRemdOOAhLf%+~?%eNnVIoGka z{wjojgxVjTU*4%NAbj4QXZ(8IHO|oQmOJd7L@;;ST7J%B<$H)#M!mlkL>^dff}b^t zG|so1R^W_d%oFMz*)@=Z(UhIm1at1xeEl#DIiF#y`=ZH(dE;QKWO`NU1HmFH^-AH7 z31-Q4DILiLzCvBwz%Lu3)`Gv9v0uP@au9MhuDi6B3r@LEbEWoF+zy?b4=cd%pUHk3epQuD@6TZkK zC!6@;u+5{ceHBC&g*-sc?{60QU4l=~y;b>Jfnyis`ey=Hbu>0h63kk9w|0Ll^!v^Y z`)djO#KsDn!(u;M_z7q9coE~kKRbePZOJZ6K^=0+6^-h^u@&f^Dt2-?Vu@!SH4la# zRht~CX6VCo1@WU|x1R8MJEYO6_9b{TY5vh-&34z;@WzP5sy>%$v%%$BUi||EwhH87}2n zPcRm7p?d-dD-p-1BOiaO&{|oHB_sd4`vK&yc!6pxfD~#MMB2d5=STS0OkFXG&s{z+p4y1d4*^ko88aPc7?b3?`WEDy`f; z9Jt4Htf3m#BuS;q>SPkknKmTx?JQtpfv&5(@41L&&@)DEH1Iv@o^jh`A8?$g{fdQ^ zQ5NkOi8V3*7k(?u+=hG}1s%?P2fe&Ob;Km#q%e8iYSdY?$s}nz_#^lB z2Nywqk=n~taYqO^B~5ER2mW783Gx};@be2hzU3?GaL-##m?GtHqJS7&e5k5UbmCZ8X zGe+n+i%EOxp$IDhrI zCBG+_yMeLpF7EjgqGz}I#}!_I?IgzMP*=YUwkp(Ty|EX{Vf+0=XYU;F&ob7&o{Ek{ zK1PiD$u{x5u)WJzU!m1l4ZcF;D-~d_Q|QIxHNcOBzJ}{RTS|UkS?b%{hb<(Sn@)Xp zD_y=3{1-ycqh?i3h3);0L3c$7<|(bbT*h&?8lGf(M?c>!XL5V{xci@`0p7x{WRH!=`Dom!M9N+NF931NL^kMxDD3-ul^ zEiV&eDKFVxJiu>dt}D1%g?wbGe)y$dCK_Xzur*ZSDQeQgSU>#GIuH6|_8!hB;opt1 z4!_oSEOMK?D*DHDda@Ezmp&T*)%(&W8OHK=Xy_W$1tQ$`Qh zfuBvM{(<^`WWVYX)Yf6HFOZ$6#M<4cTwCpJsbHeuUzZ&Cvaz;W`s4t+;+zAEKTMqmcVwoy@I19 z!MwGMIlW4iS%~{3-c|1`^7*3XxT+rdNP+HA1(DI_oAEwIgLU5b2*JGV)O`V6Gf#ql zWv*Q9F@jm*emOGL1anLn?;XaA<9!d?`JAkp3iv;A|1)nU{7hx^bmcfE!;ebBOG`;` z{^ZV6J4-NkO%G?40(@$miwY=%etXlhXNzI0W8w0}3wpnZq!=yeS5W(#D<03)r?$&zd~HVKrh!GxoZkWxz>@MC;ns0H-wZ)q7am>cD4SlqRH13Yh#`-a=VZv|SP z>0NdM&pi7_sx9zD-18bA?+ik$gF1yTHxtbHC{WK*ep#>vd2(*Dq@3O1KivCzVjKJ~ zk!5Xf1!v9X@F*$ZTa5Q6` pubb<((+p#@U_4vp$|XTRTQnkPFZc=q?cZ0>M*Z2@ z3t}Tp;OEzMe`hlwFG|cwpCDG8RY;>D!R%sPn-vd$kHwBE9s~THaTc48EBGu$so_%d z!KtJ6f|D6@gK)T8sOQ`XA`jS^#1GG1ptY3wnQxI>8TGzPZ}3BKvfYxp&l1cr@k+Y* z4f;tf<7Z6=j-|eb;+N{<`!j~2Zo!Ou14DKTIC)RQS%HY9E3ZES zemKjiYxQX|o9hePQ$|65>cIc%W* zWuBm(ocWA>olgRuq0Sj z&_PFm4bqO4at89rGW%f!e5?J2lP}`l(0yp9f;!X~7Ih6q4(meOX6}dn_a}S&)`P!` zu~va!qHkLxpEZlrl@|hQ{wsU@)&0%MwS%i_+8h{3Fl!NG?^{QvJ<)TXeDIch3*6PI zFOde@weI}%=8{;aKNtM+2spRlwpuR1oN{VUPJVH}hdoZL z2NuiEOeC1MP@uCKog`ipKKqbj=^Q2aNstbBJdI#(%*!F?dNAi@QK$EZEA-nMb~UCz zUuRJpvjet|KbP>%z-OpnYsGh_!Zs%_*#vP}jsopfq{)Sp!>HjjhM#8v+0Y++bMAB@ zun)CA0Ke?Y7~pp>p2sh}PCy;@Z@xOo0G!ne#I*eIzwl(tljy{thAiz@Q-ijFpKcU< zqztuPNWEuvSg;(iI0Bs)W*&NcA))`+>61R2VAhV*JQD?ix!9 z2jl+M+^P+nf%9?&m%vF`u$7DbS}_^_yR7j2Rd%TDA!`56YC}Ebv&f8J&#OI4^deDl zdx9nchYP(feebnHur+IF^?im|ntn}VT%k{|>1mXK-fCCw{w`qeAuE#cITWc+* zdJ@I~dr*7fu9%G+I3A*6*LCpO+nqSnqZ+m&sB=5Bnm)i*L7?6jG%+flLVi0ryZ!8D zL=wyj^H;u;M=)kDck|_zL=8oX^<%0(-X|iarZY0red;zxW;K zAbi%)N^4dP#v7eym*W7R7Sw(_7bZM~Z78=@`~qxWMZWC4he}r4?`IPZTY>Qm za&X~xqGxF^`l~q3xQkeEl_yp<5zO-(65pK(ep+ObRyN``Fh1M64}AhBQ6fvc1Af#O z_0PEoy%Kfa>BqMs(U4E}XFxQeXKglosYXi3Rc63+S&zR1nWzh@G8 z9n?kmEIqd`MH-03rS8wtd6WQ-DD~V8eknV?i168~yFPl9!8YF}T+aSpqFryXe&WJF41phi2?6*t#PP=9|>zy8(G9vW%RoI z-25DM2r{xdSpi$OUzLkq1Ai1~oz(`lc#Ng7xn6ufe0F{eT{jQ#P!OzDvvPHIK5IVP;?xP)PGnpsdu;;Xzw^22kWg@>oI@h&VOvh!x6){riSPXF z{fgy=;OF{?&ApFtt(aO9H4K<}zRaP-T8wwQ(ESShb|oNgBxCPVZIBr9-)Z&uRusl% zLOstVLem-i|4^_0y}zD@pRF~*=E*OraUW2h#SPm;zW{g1mP{Oru|&t1t1zj4Bir_s<4TVH?C1vo^Y^(umhm3;*AoXME;`H$Ve|2HIX zSus8*>>uCVwtInpck_~_qp0l^b7A8ur*`NgZpS^RXo5wYDjLpz2WDj#`b;30tz}i( zy$bwmwufiu63msDKPvewaN&j~+j@d|i?u`&Zv!u-_Cln|zPDBI8MK?mdFhmceC*d~ z=xqQtaF`Tm417YMIW&G5G1M2fyZan@@fiC9f%@n0i~d_J_~{VnY>34d98vS#V?AxS z1anNJ-<_z0pHsH{e8+xC{HQt#_~Q?DK7_@4NrH*6n(( z`+n~Cwcow>Gofu$u5IaR;Ldj*hZ70rewyxJ6^a~sTOWM*1DwU`-ZcsY3nYyAUYFne zJq(buxYlkt9`IDkdo$bjrx91M>05sT@>w_ZBr_N}*mPJZ?@1!841BNt(=T>FM~=~+T}%>P;se6Gy-=?Cl=e=2dRpDp-ZF(E!h z;7s20XHP%Dtlde~<=^$4-6kcofEATF2|d8W?{b{L7kHQ-_iP97JM+krKxn4?PtJT_ ztFsh2)cW5(sSO+vwObLG_wx_U0id&8_a-1#xbC|-L#Wk;|H-=xN1iP7A5!KRPpHsD zol9xYzU-MM2TsYo=+O(H(`GlcFJUy#gx@Z1(H=cG-c2p{>$avznQwW z5FPfkW=m`Aq0D(K&(EkD6U@FE5%kj_{N`z29`8k5>D^4~u*fA0 zZ5J{c6MXMfgSevc=N0A9mfie3dMWU$Q#U0igOe;MyuJf{6ipL<4?j;rdO*J$eCZMI zD^l(+jXpXuI^XTV317tei*{{}S%W!p4jl10%axH<=$D#J->XjOh|#|5+v2bTHHoKv z|4bWeS{nMInv=`+LmgH+M@2{BJwlB2zAwuO=15R}`-}v(5)q|-_yrC0GIU`j?psFtt%*t1qHQMax;cJp$Z$v8y6U0Q zW_(^sl=aIFP2I@(;bo(tXW-1EoH@R9%S?O+9M+_NI)hvl@={W_BcJ`nj?W6<7s+p! zbr*4GP!^*5C}3YXZW`r2L4=W_3430RmhV^JBFz4n_x}!-_6=DWK1xJ_ieL8Ec~*^%z7<= z4fX$C<^P{NK9&=Xz)O3Bo?Xz{x+wFgJHf1zi92;0z;It%1@EoUdlW6Q;~*#yfPvoQWga{g~woPaUu4@=L~Y|KT1+0GTOZ9~w{11<+-E5Y$} zU>V;9C+u>GnlEr}l~eE*f;k>Cb6JbQ7u3E}vky9jDn&)@;C$tjUSPw|tH}+DBbYmu z(YzX^jfbJL;P~aDoyZ}9(RV{bLJ7IK(_ViDF9|_EiEeH|Dp`%MVquJ{Q>cfel_@$F)Lq9l_SKJJo9F?>& z8MU2C`Q z^%5pnqCSdp{B5m__L03r*$PLzRX1W^(OqK;UM_?Gt-*$AW(2d=d>c1bh+xjaTz8kR zz+oYagwhG-&c1s{F%>#*E*_H`1}AgeTaW4B#0O8-dH|f4yM2cQ!8{Sl{u1kb<-l1! zj;`<8tqsU?8|`^{bT%Bl9sN4WX#T&|!db{i{G^}sH?(zZU>%Ny-+?k8^+fAI^gWL< zC;4LlYQk##yr0YY-j?=%vu%7F_>nU6g?*sut0yUf&x^Z{(VWte+H>R4h&%Kl#Qq-Y zY_GNA*)DuuvTJD@^H~V%7;;Wn+F_jsY{F=bo=j{V;!0BP!H(}d1^*?5D<)$2zTMLN zlsf) zLGn?IOD*a!g);9V%ES$v8EI0gD#+n_4cp5Y^$eoyN5pT_0``9Y{tryDNrR4O?Vrx& z(D{Y-zN@C|8<|(f$~QmWJ^^#=5>7Mh=6|%kM{}VsAKLML7r|_o;_7ok1oNg0&^G2X zhq+78cITG`;-i2+jd*^@v-BFYRlaO}WSC&il{rk>He_Ew&K4s+tAgLEcGRLKD=5#` zm5-#M?^ssvY(Ox#V)gq>3*_wMdf|p2+Gf>9C@8@1y>Q-C9r#UGor`FN-^THB@Ez!k z&6RR(2j`ts%&jJT)|K9MT`}+{yz9Pih?=CFI^MPo_)?0hV*qrfP}UsrTWHe@Xckf4 zC2EZAUrzLu>RqF*63iB)TvuNQpIVMQDf2w(Ok;KuH2R-Rjez`D`1^}Pt@DN*JV>P(mn&K=sh{d8s` zl!P2Ebu_(ShQ7Ewj5}Qjd{as=Y6ZdEbl>MC#lZ95{hJu9q2VYrk5R6-nicZsqdx6E zB*PPP!0{LT+=@DL7t`(&m|J-DdwnSLIkk^E;Bp%anAk;aqu6DrMh~%?snfF`-<~!}~VD zzqd(gx;Ai_l!A3E@MX#~9l!M)-9|Vpsj1W4ClSmwOi;JJ1-}{PUC_jFx8b);4E%5s z__=I}kOgAx>K?UC0yuob?SHL-rXB5=&a)yPaE^#A8=iu`FYlz|GqLM0W}vouv~xM0 zC#fL+z|5Bx>ydNn@gv%wkb@m%-{Xbc0{EZ(>AV2-;hui+BYB$bnTfcAeiPl^As>^f ze`@pHQVtc^6TVZ-p7cS2IX5Zq|2tmZBYyUrp{_$A;K)+`e^)PdBYpu@${cn39Bt@N z)-+xr4V@R1a}0x2wnJ08X~FpuB@Jn97bKwtK!11z3D{sTJXirM(7Lxn|^7K76Wb(-fokIoX17) z9jHay=DMDzlYj^6Ebj|~e^o70O%?phYU2g2A+FZNu%X-VkN%UYHW=}2|&Xz0t{pKmP-z8viw0}or&ij^_q zajx=08T9eC^nalKn@I`&LC%z7Ra34%m3_a$pF(>*m;Bg7IP7H}k}CxW=FK*tZY~C152o!Pw55UlhOXDvQ&?;2C?iIJ@@fj)*}(}oW?Ss%->F4J|53+&uO3I>RG$U z-`GWz{TT`!go&SPkv-CU`m4{Aw!8%qsdgR&a}G80bKI_^Bd4Ceg#xv}2Wi)Gu4%~u zXH+{Kht4!^+(r(zWiic{(XaiT-X(G9yY|>3$y8u_*AGuegP*S!sE21@Zl>&7vnTM& z$Ezz#q2|lfDq@0>+a#4&qDAPte=C0uE@?L4pAx)MPz_C|0fpo&@RvTez0iUjB1ioG z#5Su6ImDiozvhoT7ic6M4}hkC=}0yC?Sf*;FGQyxvo)fdV9pxackHDadEm5O;rFMl zjV6A9fa0#}8Q^#_T0_(#Hw8JI{lpst=8B5&b3U51f>W;|>U0aSGAZ+6p6lL4+j83Z z!!lmbVXcg|3~Pao*m)*-(%GK3!|3nDo|pQ5$kR16!QU3KIwWQsCwT&_d(n23%Sdy6_0t!`@@I5bj+DYf@JGAL*WN(g zWN7!z_;%nma+`U}aS!t3tx_6ko<4KMQO}tX&s6s!?l5JJgka4f_?L8M`}0trX`)-a zPXN0yT9-8b=ybBr5$nOl?XMaLX4l0C+}sX)w<0DagJ7OAe#{QLk1N$XC zmWrPzM=Z6_W6QH979m&k}?J)#%^WC~TZGih|_X%WT zvsP|^&Z`)e-3KwAJ=daU(^uq{d!t}gGH`|V+yYTDpM%Y&oClqGeGTz*Sd{yU6(UKP z|Ir|}X>~Zktkolahditm4gIyW|5FkolfX%N`=~VvIEYbwI6}JUmnY@>(-@8Zvd&P( zK;v$0g8oj*dJ_|o|D)~NqiWjvc6;r;i9;ts$t|7ArK^-nij+$dDitM)bP*-#Cb^VC z=_Hj~M52%oDXHE>NsE^i^O>{V-fOKn z*KazJyr9p;&V(Si)=MSZx zS6}M&40%PWCj7mC`6SOvu#mfP4*G|GB&#|ifB(svP2Olb+2v&PF63SPlC0*yo3G*0 zG*#qZ%dw5+(+)}KZ_YTq&l*^-E4ow*I&)`+E|ex%tT_KzXFqU!U0(-QLqER2IMVD~dgX}n7d839zXt1C zjA*3Sg+NDT&VW24j79p~WUmfj7e_8S_Z7~==j06k!9U=^>-2wU@?S%r$%8jTPVY%w z5Ocx&%wqk_1el$MPb2CY%*u5G@#y9Q47*keU6AKg15kSHjZe_ zXv0|eZ6R-L^x$XPH7;#`zKKKI{zp@zMv~ti-j%JRD#U@CZ7Noz6U?X{sCEd!@6+em zSDy7pK3%?Mi8H}`Nu}t^R>&U-|Da}x{9*-%bq@VhhEXDD-8``mRt%>Q#6v;k5TDxZMq! zN~J@+^ne?}Ufz|0|6x2){%xJ~?(y2V#p7B>z>o8dng_i4%h1maXlqZMM=u%yy*r@e z-QyY^xzZNo`hed??ZrK3+z;0c;VEauUjuuw*60?Ed|PS4XV%rU4w(Sl$y(gu$fNg! z!}Ez@;|yHd2oF54iM%Q` zUZc3H&ZN5w4LMG%NBfIR(PkH6xte7?~u;vQX+YwMad2ObX+I(S;VIQ;AAc| zO-)W8aRpAJ*3Iww&VbHxs-~Q;*@$la(0woZ09P*?KS&$6(6g9156wi$=Vm`KmSxoa z-S33WNCjw?Qs2or-k1l0p7{M$JorhSC@r3gnhSeapR;Wp)=D_M>K?x%P&dj1ZC|O} z(pMl@z+>Gb=gcI)kB;io4`Ku}w$!txLkp#$b5Pq>aV)`no12IK2q0KE@qLp~Eb`Lr zH@v;!;Tr2Te5kT1H2wE;8JE@bD0uS<$juByUn+i2vb&(8Y7r^35`L_2n`@-NLprDH z)uIkLXVTV@s)=!<)|}+Ugq+T>Hqmeg|IZ#j+b`38PTKN%?TS5PNHF7&TD5*6!Gbxg z`@z^krzQbyi||XpQ&f2ZO>OGAT&+9wdBv>t77RltqV4z$gZc63Yrw3|8Vleu z-D|-(OPDViHdjLqIF{2HI-=3XMi=uiL1?RI51qTz9Hy2%!n`TZ@4FX%_{%w6SCl5m zz;hqg^9|WT!(%GuYVf^r4dw(3b#+R9{eqvCYA!mTFTg)P$R(-+bI5mz=hF5^pC9nw zZ){O-9)Ne## zNiy;ZTSW6ycQhlf{5s663i#y=QO?I-U$GW7??Xgm3Bi2bI^Vy9z%yLew)24VBo;3y zgU-YrpGhYgeS&^M$D3d1XG1V=O{(HmMdY9T);h0fyr?n881+y7XXd}h(%5P67BMMZ z)dbk6PSe`kyDv^_ zMn5X!Fvhn-*f`dXIpp0urb_eP`Ktu;o33-wPqps=-%ySV|5Wu6!WZPNe4$&6ehung zhd2ORmdOlBhUP=obEtQ&eF~lR)ShkEEy(kesQ0Ba+72&XzP$|Co!S%V9cB)19s!aQKN2kT&EemY2S2^XHNIY6{!H5PhI6{MxgKVT zzHYx9H!Kdg;zFP1a*RdqjCO%wEzvBb&RNLGE+cvV8EU`N36*-17kfqZH8g%8$umEx z{c?)u)`34SwtDS8^kuSop4VmM6|3b_79d|!=MlUFIwb{#FVhGXG}o%?Mu3yp8HZ5$!e@n!Bmg;^M5dxKVB z8^O$sh|EMS=sa_cGwKbjrc?Cv8~9mc-`{ga{wZ~a%Ql@o$Sbm5+bgMeLC5V-!+~7j zIEiCYrof%7>n3VmJHYXw&Ls(*eGB=2^|+Q`Pea_H6!RI_|ERw^@a+w*t&1zN^>l{t zh3cGY7mG%o{5E*#%~}I9XP+_rSVow&9|PW!t#ZtcU`B3uevS%ojNGYI3*b!2(dJiy zRmJj8g=5~{E~+^(9{u)8topmV)@|RtiMQ}w!(T(4v(qAOP1Z$(<~=^I`Jt~l$s}L;MZplBI2KyU@0_!__O3VCJ-s_)2A9&#d*K z&=<(D&aG(pFDb^_&&Rl0y&!l#(&KlEWtVP6zb2g4)I>wN?L6jrKK1_8@*{B=mv-^e zcmcfWr`T8T!8{z3O^Q7LEHn0w_HN)x-or1LTi(FUU%vGPK6yFDj1Ql#8|o*20N+o) zr=CS4`Swb3&B5$XeV|qd9BZHTem=oGCzVPbu1f?-n_m_^#5KyRUt6PMk?*yk*|!w< z@ozl?`6oizU5ip_-49O5x~Qr; zaJtld5BOc2X-T&6^y$(*C`d4uc=>K{r%CWAnLEEA!nlXHWh2G03Z~NY& z?Ql-_K8wEUVg4ocw>uX@KRjt({v%*NE8zv%4TKZSTJJZf{uww2sddAuywN1jU&zVN zt?Vy^&pW{So8C6s6q?1Jl3=F2t>J|NyctsU>Ia(1L+4P9-H%Z4 z*HPC4QnKmb?4rJVm2#hg@6xX1qmF)4sC}U~)ClF4jic``2><9(djzF<8xTUo#7 zMI+C3H~95hwKDy?J$S1mG$6m&|IIsS@;ryQGhX0)=d@o)G!95i!#t$3zIWzPkMS}~ z3fmtp!PqxZb;%AV_(Dg1q|v@_q{b-!7aLSe3pFR8Uve2Vqp9^=WhqB+ z&i&1%BO3eMXG5p9vF*!pcndo^|J-_ldCocOPo;n}`QsaY8aTSfjy`JeueHnLVmE&T zb)PP9odEva9{;WXiHOW@h0o}^!gCDpRh=EoBFvjmGwi!Qx#wp>HQuRjAeeV%RpJ>} zV1F62=MLZ;8*)HWhhTnJf2qeKkl!a}cdakM0-Zk9d-8zW%MZm(0oI-JApQfvLOW`G zic1Xh@xil+)ZIhpMnE%H;%4wSV8eEQ3p3!!v)&hF!M`%KKV(@_IP&$>JyGmq3Fy!K z%Eixynjq-dQP-kfTMD}8v&UyL4!AKC9+arIrqRmiD|F}aZ~4$q;k375Z;mPcUQX0~ zWr>*qbdnF8x^$$w-<-bA8-Ziz_0<3GMEEz%KR+W@@L?{nPwL76M&vh)DQwI<(}!T8 zD&=kK_l+dam+x_1ve^@2puhIF?&Cxw_>Xt+^PbaraH4Tks*1Gb4dZm)N|K)~`tml9 z9{rJEf!gTa2it(vhsk$51!q!O!NEPqdn&9R9Rj@Q!|1e^z{~fX5PrsW!yVcA-|gUM zzsC>He<5Ek@lY=p`FByqu}?6EFRIQvHazzxifz8oB6>63)Ndi`J-wgNuGH{{U+L98jrSa zKJPQ`5-d78r76zfYd#pzwHx|w75&$5#~4SgN-ofZ zA8XI@v(wPFjnkT=Hvc|!S{{k!8{%&uZ%bYCbY97ZXWht>*w642ac1W=Ti^qn?tS!P z#$j9`thK&H!zoZ3`hih>OEWNDGetIjBNGa~i<)R&+Uy+0wenDUNB}sOS?f87hVh#W z@?3*g-*QrI6YxxfnF zqxNe46Jg>z6`mjHL^|lev$a^KW+u=|?YM9xSMLArMa*$$kOS1W5r zu%PrO7oS`rX~s5a8s-k}xK6NeQj9 z0x^~d2`mF=V$l@GgJ}CXxFz`syg45|sq`B8K=*HL^MH4=)~jS1R$?r&oa!wYKSK;rnso|nKJn$n}*B@09o6uIs>HC2#vNoGyKDRSFH67uhjQZ{V81?}i397zd zn%xVGSCi9k*+SpJ;E((2W1N67s#A3doabnC|9z?2R`Yum!&~nO@%~A`vp+>@<&pjF zd`s3ka-y-{){pR+>7347;}UzHuO*s7zg_osoWcJ4z8#J^mcWB0rcK=rpX_^DqOA`@ zhq)89ISTx7Ic$8!WjQz&S1zSR0C#YzS>2p1fqAIlG;g9YK|7nY<+)P7rwdGlBro`b zy2e-#=m2lysn2u!#Rc$Cl)P-QJ2)BCS>CDPM(FEiUgn7qV5{8OxzjPXNl~}Yt06yX z&Z2jVfz^TpUDKdBOIDNjKeSzWRE}Hwe#evsA{;7}GBlC~DvhEv5=u##it11@Mx~@d zsYF5pAreAmR_Tb4G~hJQsiVlOBr@jv*4dY}-o5;u-+5bn_g~k#*R}6`?ftyNe)e#0 zC-_qpH{E{)e-d@ii=fT@;}hchDd!G3_q}hc1UYG?xJ#9r<#$iPiC}h=ZpoZ1f;oSd zsAxUHoZ6x=!Lrg)ZQ!2>@YYF09NSriBdvieXE13Kw7-kTAkK*0&e5L<=J^Pf>x0QM zlB*E2o^j6ehIAM>H$TPhJ%aWo4A@`&0l0IG^k!4wv4uwzKA~MBO_sT90oO3zKfbN7 z6Y;Hu`h2P-ZzT7(aaK^dAlOnK#Lo_5d?%IOQ-r(UWNs~v2qBo8Pkm3%obN!KI-zn; z{VH3f5B>bvN@;Zupy65dffd=%xtp3#*fXUVZSf7#>~YIf_bry z)3(S17hM>bvJ#v--kb6!p{&@d=KHRwD^jQ&eUmE}Kuzxdq0pvKR@$tCwj@#i`>Ofc-~T_JZ5b2L9y#u^dKc6LjcyAF2}?>Jk0`{sz2^I*YwsZVcKx zwby%YkG=3j|4gCQJ612ZMa+|1#3!?Wms0mLw(N64+3`oUrpyG#^y8ptJA!%URQ@_a z+j!<0_%@c_M&C7bO+22djlTNGxK~O^VIuk`lJU1o7<=7w2mQ%eRe5bLTLwG37mo0N+mP z;FE5|;ZkSrVuG^3iHKU)Ed|bC>bxhDaXWIM!J%H`@O11uzo;6Lsf;+W)cs;hW7LVC zo%>UBCJkFwBff<8Nc}ma4o;$kgZM|(ry*3ncVVnOu$shV(^sW^Gw~%3o;&sKf3-Ry-ZpOT?54$QL#BW`X+aR>vt9I(ECe+({Sabh3 za7q<@j)sAAp>MFZKRDYN*9+R#Y=#DJ#`QiXW51S0y>UY2zGgC6$wcT(5$YbR8QCwu zudi4Zssil2et{exZPAMO^YI$^+g@tBIlvzkVXj&aoM>Fec>;Wj%JUiCxd>&0L<4KG z(8lv&rmq|E>=v#OEtLW;quwjUpEr_oR_u2%FYU7k=3W|9>b;#{UW4_OR~y0cPlYp69Zk3RD7ADpWm+eR=)hwxr~Og`fr$m+W;gu@zkGvkgPV(y}T17~p*p-0SO(zY&wdEL|*K(!awQC9%txZ=L8 z9pXg))Y% z?vP%ur|3@oO3Lzddz}MT&|;sxAaU697Mc_Qb26!Y$QdCfsLSQqhmFzTT>jCRH$vy6dmDZ413OdiP!TUYQFaFPo?>+6 z0^(=X&Z}zyHuC1n&qW+Zd%5^~1hdxr^qfiuXYx|}SGnL6FB*EjAMgU|?!Ppp)#M$O ztJLdU=zp+%Nm)*yO2yYVh?7F;XBX=bKl@2z_lc)?AJ$QRq-O_z<IC!RssC~I zj8lluqsA?Qmb671F&C?ic;*4V3@fLv7~=1x#t$ye#_*dl?n73N5CO-dbLZt2v}+IJ z`G`yPGT^J}=eIXNgO*ThxIWIFh(AX}qjCfKK~kuD7zOSA5d-wY)XtM0TM#EOF3b?| zd5@lW#GQpUvHn)$C4fD9J^s958HhY7&p%jwFeI33F^ZjB035-X6O7-qgm5?yseOj8 zJk5!pXF=t1|I_C!@w4ry`!~ZQ2SGy#e{wkXopbS0jO%i8MqfdB>!!qK5#fDuUuoc=~{!|{< z6I0w#*Yk48jkD4A{M{SPzxTs2k8eh=QP#)mJ&9?`2H;#tf3Nb8 zV7_Q+r}`w|aa4}7)lDgg)7S4NO95p+G2VwBHOQHaK{?`#;}F-0IfTP=IytKRJ@~FF z@@Eov;4d1Vr@+rm{bh6e$RTO;*CrkLCdo_LHK+Y_5Pxlb1#zUKV-Mo zeJ8N|a+|Y?1hbZ}b~1?}n61_8yeolXPAL0IsCPX<3qPOYcr8>qhXkxBd(D|25P65NKFM-5V<#r3B5K-xu~_f%9@}eSZ$Y zynfVgBa>ZuERM3tjB{?@tc2))09R#ArF}ARt6AZpiv+V*T4<&`fqysSIM%7E82nKV z5_&EKvyQf=ACmbVhcVBIdC?ohkD%t4#AoKBY_;f*rG7LozYT=X%L@4y>OU4fxF6~b zXIuvqw8v9?(5|FxXUSUx^EnEFoVKasq4^$_(^y2m4P`%=3Ho*K9S47cP-m}wAbDK15vhsI^U5zJ`e9{ zu6j;tP6YE!S_YX15zJeuDvai5lD80N2z7Q?!Z?HY+4^ToN@9S=GTwXpZjS-saKBPH zEyb6aBfieu9}4{+)@QIP;@ph)ww?w2oG}Ocyq(Qx?>nk*hq>)QpE%ZBl{Ey%Ka|B_ zol)UvV|-@*n+|BsdS>}@F~OXhR4(!DYu>@1&3Kkv(8{Wfwve{`LG35JdHogfbEY%q zD-O4}CLDGh^*x<6w2An6rD8vpB32nKiTJ7~0;|P<)dRlO+yo9aOZVG^II1hT3iAkN zMdf>L+7FK5@pC6-;qQ60EqVj^MpVwF7wUu2#trjN*S|&CFGBr3oMc@_8!OJ9Sh@sd z2QaQF?C}2vJt5woa$KP2Hsf8!!q~X%GH954=j+up;6%nf{44c`quxo&1pQ+oWoDe49s2e*+9j$zs=^C#-UNRb`3z+j`c#~GgE`zP8K;X^2xi*^jPMU3 zm_H@TYU~z*IlHJla_odB;IoDLe>`cX0DcwYoG_E!Y>t7>cq&(IqofI9&ZIsY7W=>R z)wX zf`32g+!32|X7hJE%6zm4+H&yj-QTPczcnzU`T_Jz-=X_(P8{)bR~>b7C78pO`f_pt z!F=OZUspeZ+2bp3w7&(P{;x@uevh&uvyQ7Kg1^0OMDs*ojgrPk0pPSq-P1e(-2GFz zJ$JGjq$ytX4w!vKz(FZyH-_5ZkR`eW!xqwb&ynAHrwrrDiKCFD1bmrUgb z(X!#-w=c;_&9W4nbfNCVG0(Ole0D11{bhpYupkccJ(q z8QwBt_jz#sx^g7sBc6+ALxO2H_?v~w1^wK~1pVefy<3?(myk2DY}@qv8HWkx-C_sr zTo1o2btiw(+YD&y zIjd|Ij`#}-IqJ2*t1Z*k9S7$Nm9KK7xd!}GRUAzVpz~x?xo<4Ne5v1lHEyT}xPkpX}cW#A0SE%1iCQI0O8fUju81MKf zs(eK_-0jt8Til?t%iX8b9{%!Trn1ZHtOGQ4j9TPB*>`vV8v7L4z7+ANWjEu-?bb+x9zuRd(~Y=7WJYEY87w21iGie`D% zcfdJct}^@*!5s5V?XOjUV@m|fUVDFq_*ub)AFgdDn6J@w=j#!~IZ%1QHU#mV8Q()I z_gI1-#~Qc!#`m(BOngDxoADSL5@s`T`uz19G~|>x=-HtyEm zhDXT2FH7x{U%EOJWvi%lN!i6EsF&Zd_8Rnatb|%mXR@Bceb7^`@#<+cV#*o{a(um8 zpi?eklg(Z5uLs-@&qCeoFo#|9P*z{d=iOC;x!vm1?fbwVR(@>cL^AGY=TdV-*QfR+ zey+l}jR%#%F)qGs9RX~9c#vZw!JOf4o`&AQ4!dQgx(Md$QFo~rJ0_v*8ET&V$kH^F zm2?;MOSTykKQCw9ikBwf%ow4v)CD*=w5Y2dIQJ>XgN=8X6@jgb2f&{pC%0A#ZF#~t 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

    8RD*1|1UyD+{>Y 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 z%0D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%0AGd;7;y9r}AJ_iVWky@%4u9v{#>p`j}8 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 z
    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

    2B>=waR#oZQ#tF({xLGWB^_x$3| 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